Skip to content

Commit 50ef8fd

Browse files
committed
basic tests
1 parent ce834c8 commit 50ef8fd

File tree

2 files changed

+106
-3
lines changed

2 files changed

+106
-3
lines changed

plugins/core/jetbrains-community/src/software/aws/toolkits/jetbrains/core/notifications/NotificationPollingService.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ object ETagState : PersistentStateComponent<ETagState.State> {
5757

5858
@Service(Service.Level.APP)
5959
class NotificationPollingService : Disposable {
60+
private val firstPollDone = AtomicBoolean(false)
6061
private val observers = mutableListOf<() -> Unit>()
6162
private val alarm = AlarmFactory.getInstance().create(Alarm.ThreadToUse.POOLED_THREAD, this)
6263
private val pollingIntervalMs = Duration.ofMinutes(10).toMillis()
@@ -90,7 +91,7 @@ class NotificationPollingService : Disposable {
9091
try {
9192
val newETag = getNotificationETag()
9293
if (newETag == ETagState.getState().etag) {
93-
if (firstPoll.compareAndSet(false, true)) {
94+
if (firstPollDone.compareAndSet(false, true)) {
9495
notifyObservers()
9596
}
9697
return false
@@ -119,7 +120,7 @@ class NotificationPollingService : Disposable {
119120
HttpRequests.request(NOTIFICATION_ENDPOINT)
120121
.userAgent("AWS Toolkit for JetBrains")
121122
.connect { request ->
122-
request.connection.headerFields["ETag"]?.firstOrNull() ?: ""
123+
request.connection.headerFields["ETag"]?.firstOrNull().orEmpty()
123124
}
124125

125126
private fun emitFailureMetric(e: Exception?) {
@@ -146,7 +147,6 @@ class NotificationPollingService : Disposable {
146147
}
147148

148149
companion object {
149-
private val firstPoll = AtomicBoolean(false)
150150
private val LOG = getLogger<NotificationPollingService>()
151151
fun getInstance(): NotificationPollingService =
152152
ApplicationManager.getApplication().getService(NotificationPollingService::class.java)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.core.notifications
5+
6+
import com.intellij.util.io.HttpRequests
7+
import io.mockk.*
8+
import org.junit.jupiter.api.AfterEach
9+
import org.junit.jupiter.api.BeforeEach
10+
import org.junit.jupiter.api.Test
11+
import software.aws.toolkits.core.utils.RemoteResourceResolver
12+
import software.aws.toolkits.jetbrains.core.RemoteResourceResolverProvider
13+
import java.nio.file.Path
14+
import java.util.concurrent.CompletableFuture
15+
import java.util.concurrent.atomic.AtomicBoolean
16+
17+
class NotificationPollingServiceTest {
18+
private lateinit var sut: NotificationPollingService
19+
private lateinit var mockResolver: RemoteResourceResolver
20+
private lateinit var mockProvider: RemoteResourceResolverProvider
21+
private lateinit var observer: () -> Unit
22+
private val testPath = Path.of("/test/path")
23+
24+
@BeforeEach
25+
fun setUp() {
26+
sut = NotificationPollingService()
27+
28+
mockResolver = mockk<RemoteResourceResolver> {
29+
every { resolve(any()) } returns CompletableFuture.completedFuture(testPath)
30+
}
31+
32+
mockProvider = mockk<RemoteResourceResolverProvider> {
33+
every { get() } returns mockResolver
34+
}
35+
36+
val providerField = NotificationPollingService::class.java
37+
.getDeclaredField("resourceResolver")
38+
providerField.isAccessible = true
39+
providerField.set(sut, mockProvider)
40+
41+
// Create mock observers
42+
observer = mockk<() -> Unit>()
43+
every { observer.invoke() } just Runs
44+
45+
val observersField = NotificationPollingService::class.java
46+
.getDeclaredField("observers")
47+
.apply { isAccessible = true }
48+
49+
observersField.set(sut, mutableListOf(observer))
50+
}
51+
52+
@AfterEach
53+
fun tearDown() {
54+
sut.dispose()
55+
}
56+
57+
@Test
58+
fun `test pollForNotifications when ETag matches - no new notifications`() {
59+
ETagState.getState().etag = "same"
60+
val firstPollField = NotificationPollingService::class.java
61+
.getDeclaredField("firstPollDone")
62+
.apply { isAccessible = true }
63+
firstPollField.set(sut, AtomicBoolean(true))
64+
65+
mockkStatic(HttpRequests::class) {
66+
every {
67+
HttpRequests.request(any<String>())
68+
.userAgent(any())
69+
.connect<String>(any())
70+
} returns "same"
71+
sut.startPolling()
72+
}
73+
verify(exactly = 0) { observer.invoke() }
74+
}
75+
76+
@Test
77+
fun `test pollForNotifications when ETag matches on startup - notify observers`() {
78+
ETagState.getState().etag = "same"
79+
mockkStatic(HttpRequests::class) {
80+
every {
81+
HttpRequests.request(any<String>())
82+
.userAgent(any())
83+
.connect<String>(any())
84+
} returns "same"
85+
sut.startPolling()
86+
}
87+
verify(exactly = 1) { observer.invoke() }
88+
}
89+
90+
@Test
91+
fun `test pollForNotifications when ETag different - notify observers`() {
92+
ETagState.getState().etag = "oldETag"
93+
mockkStatic(HttpRequests::class) {
94+
every {
95+
HttpRequests.request(any<String>())
96+
.userAgent(any())
97+
.connect<String>(any())
98+
} returns "newEtag"
99+
sut.startPolling()
100+
}
101+
verify(exactly = 1) { observer.invoke() }
102+
}
103+
}

0 commit comments

Comments
 (0)