Skip to content

Commit 4a54161

Browse files
committed
state listeners
1 parent a913a5c commit 4a54161

File tree

3 files changed

+34
-91
lines changed

3 files changed

+34
-91
lines changed

features/dd-sdk-android-flags/src/main/kotlin/com/datadog/android/flags/internal/NoOpFlagsClient.kt

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import com.datadog.android.flags.FlagsClient
1111
import com.datadog.android.flags.FlagsStateListener
1212
import com.datadog.android.flags.model.ErrorCode
1313
import com.datadog.android.flags.model.EvaluationContext
14-
import com.datadog.android.flags.model.FlagsClientState
1514
import com.datadog.android.flags.model.ResolutionDetails
1615
import org.json.JSONObject
1716

@@ -116,12 +115,6 @@ internal class NoOpFlagsClient(
116115
return defaultValue
117116
}
118117

119-
/**
120-
* Returns [FlagsClientState.ERROR] as this is a no-op client.
121-
* @return Always [FlagsClientState.ERROR].
122-
*/
123-
override fun getCurrentState(): FlagsClientState = FlagsClientState.ERROR
124-
125118
/**
126119
* No-op implementation that ignores listener registration.
127120
* @param listener Ignored listener.

features/dd-sdk-android-flags/src/test/kotlin/com/datadog/android/flags/NoOpFlagsClientTest.kt

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import com.datadog.android.flags.internal.LogWithPolicy
1111
import com.datadog.android.flags.internal.NoOpFlagsClient
1212
import com.datadog.android.flags.model.ErrorCode
1313
import com.datadog.android.flags.model.EvaluationContext
14-
import com.datadog.android.flags.model.FlagsClientState
1514
import fr.xgouchet.elmyr.Forge
1615
import fr.xgouchet.elmyr.annotation.StringForgery
1716
import fr.xgouchet.elmyr.junit5.ForgeExtension
@@ -26,6 +25,7 @@ import org.mockito.junit.jupiter.MockitoExtension
2625
import org.mockito.junit.jupiter.MockitoSettings
2726
import org.mockito.kotlin.argThat
2827
import org.mockito.kotlin.eq
28+
import org.mockito.kotlin.mock
2929
import org.mockito.kotlin.verify
3030
import org.mockito.kotlin.verifyNoInteractions
3131
import org.mockito.quality.Strictness
@@ -430,19 +430,10 @@ internal class NoOpFlagsClientTest {
430430

431431
// region State Management
432432

433-
@Test
434-
fun `M return ERROR state W getCurrentState()`() {
435-
// When
436-
val result = testedClient.getCurrentState()
437-
438-
// Then
439-
assertThat(result).isEqualTo(FlagsClientState.ERROR)
440-
}
441-
442433
@Test
443434
fun `M do nothing W addStateListener()`() {
444435
// Given
445-
val mockListener = org.mockito.Mockito.mock(FlagsStateListener::class.java)
436+
val mockListener = mock<FlagsStateListener>()
446437

447438
// When
448439
testedClient.addStateListener(mockListener)
@@ -455,7 +446,7 @@ internal class NoOpFlagsClientTest {
455446
@Test
456447
fun `M do nothing W removeStateListener()`() {
457448
// Given
458-
val mockListener = org.mockito.Mockito.mock(FlagsStateListener::class.java)
449+
val mockListener = mock<FlagsStateListener>()
459450

460451
// When
461452
testedClient.removeStateListener(mockListener)

features/dd-sdk-android-flags/src/test/kotlin/com/datadog/android/flags/internal/DatadogFlagsClientTest.kt

Lines changed: 31 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import com.datadog.android.flags.internal.model.VariationType
1717
import com.datadog.android.flags.internal.repository.FlagsRepository
1818
import com.datadog.android.flags.model.ErrorCode
1919
import com.datadog.android.flags.model.EvaluationContext
20-
import com.datadog.android.flags.model.FlagsClientState
2120
import com.datadog.android.flags.model.ResolutionReason
2221
import com.datadog.android.flags.utils.forge.ForgeConfigurator
2322
import com.datadog.android.internal.utils.DDCoreSubscription
@@ -43,6 +42,7 @@ import org.mockito.kotlin.verify
4342
import org.mockito.kotlin.verifyNoInteractions
4443
import org.mockito.kotlin.whenever
4544
import org.mockito.quality.Strictness
45+
import java.util.concurrent.ExecutorService
4646

4747
@Extensions(
4848
ExtendWith(MockitoExtension::class),
@@ -70,6 +70,9 @@ internal class DatadogFlagsClientTest {
7070
@Mock
7171
lateinit var mockRumEvaluationLogger: RumEvaluationLogger
7272

73+
@Mock
74+
lateinit var mockExecutorService: ExecutorService
75+
7376
private lateinit var testedClient: DatadogFlagsClient
7477

7578
@StringForgery
@@ -83,6 +86,12 @@ internal class DatadogFlagsClientTest {
8386
whenever(mockFeatureSdkCore.internalLogger) doReturn mockInternalLogger
8487
whenever(mockFeatureSdkCore.getFeature(RUM_FEATURE_NAME)) doReturn mock()
8588

89+
// Mock executor to run tasks synchronously for testing
90+
whenever(mockExecutorService.execute(any())).thenAnswer { invocation ->
91+
val runnable = invocation.getArgument<Runnable>(0)
92+
runnable.run()
93+
}
94+
8695
// Mock evaluation context as ready by default
8796
// Tests that need to test "not ready" state should override this
8897
val defaultContext = EvaluationContext(
@@ -101,7 +110,10 @@ internal class DatadogFlagsClientTest {
101110
),
102111
rumEvaluationLogger = mockRumEvaluationLogger,
103112
processor = mockProcessor,
104-
flagStateChannel = FlagsStateChannel(DDCoreSubscription.create())
113+
flagStateManager = FlagsStateManager(
114+
subscription = DDCoreSubscription.create(),
115+
executorService = mockExecutorService
116+
)
105117
)
106118
}
107119

@@ -642,7 +654,11 @@ internal class DatadogFlagsClientTest {
642654
flagsRepository = customRepository,
643655
flagsConfiguration = forge.getForgery(),
644656
rumEvaluationLogger = mockRumEvaluationLogger,
645-
processor = mockProcessor
657+
processor = mockProcessor,
658+
flagStateManager = FlagsStateManager(
659+
subscription = DDCoreSubscription.create(),
660+
executorService = mockExecutorService
661+
)
646662
)
647663

648664
// When
@@ -941,7 +957,11 @@ internal class DatadogFlagsClientTest {
941957
rumIntegrationEnabled = false
942958
),
943959
rumEvaluationLogger = mockRumEvaluationLogger,
944-
processor = mockProcessor
960+
processor = mockProcessor,
961+
flagStateManager = FlagsStateManager(
962+
subscription = DDCoreSubscription.create(),
963+
executorService = mockExecutorService
964+
)
945965
)
946966

947967
// When
@@ -1045,7 +1065,11 @@ internal class DatadogFlagsClientTest {
10451065
rumIntegrationEnabled = false
10461066
),
10471067
rumEvaluationLogger = mockRumEvaluationLogger,
1048-
processor = mockProcessor
1068+
processor = mockProcessor,
1069+
flagStateManager = FlagsStateManager(
1070+
subscription = DDCoreSubscription.create(),
1071+
executorService = mockExecutorService
1072+
)
10491073
)
10501074
whenever(mockFlagsRepository.getPrecomputedFlagWithContext(fakeFlagKey)) doReturn
10511075
(fakeFlag to fakeEvaluationContext)
@@ -1299,15 +1323,6 @@ internal class DatadogFlagsClientTest {
12991323

13001324
// region State Management
13011325

1302-
@Test
1303-
fun `M return NOT_READY W getCurrentState() {initial state}`() {
1304-
// When
1305-
val result = testedClient.getCurrentState()
1306-
1307-
// Then
1308-
assertThat(result).isEqualTo(FlagsClientState.NOT_READY)
1309-
}
1310-
13111326
@Test
13121327
fun `M add listener W addStateListener()`() {
13131328
// Given
@@ -1335,64 +1350,8 @@ internal class DatadogFlagsClientTest {
13351350
verifyNoInteractions(mockListener)
13361351
}
13371352

1338-
@Test
1339-
fun `M notify listener W updateState() called`() {
1340-
// Given
1341-
val mockListener = mock(FlagsStateListener::class.java)
1342-
testedClient.addStateListener(mockListener)
1343-
1344-
// When
1345-
testedClient.updateState(FlagsClientState.READY, null)
1346-
1347-
// Then
1348-
verify(mockListener).onStateChanged(FlagsClientState.READY, null)
1349-
assertThat(testedClient.getCurrentState()).isEqualTo(FlagsClientState.READY)
1350-
}
1351-
1352-
@Test
1353-
fun `M notify listener with error W updateState(ERROR) called`() {
1354-
// Given
1355-
val mockListener = mock(FlagsStateListener::class.java)
1356-
val fakeError = RuntimeException("Test error")
1357-
testedClient.addStateListener(mockListener)
1358-
1359-
// When
1360-
testedClient.updateState(FlagsClientState.ERROR, fakeError)
1361-
1362-
// Then
1363-
verify(mockListener).onStateChanged(FlagsClientState.ERROR, fakeError)
1364-
assertThat(testedClient.getCurrentState()).isEqualTo(FlagsClientState.ERROR)
1365-
}
1366-
1367-
@Test
1368-
fun `M notify all listeners W updateState() with multiple listeners`() {
1369-
// Given
1370-
val mockListener1 = mock(FlagsStateListener::class.java)
1371-
val mockListener2 = mock(FlagsStateListener::class.java)
1372-
testedClient.addStateListener(mockListener1)
1373-
testedClient.addStateListener(mockListener2)
1374-
1375-
// When
1376-
testedClient.updateState(FlagsClientState.RECONCILING, null)
1377-
1378-
// Then
1379-
verify(mockListener1).onStateChanged(FlagsClientState.RECONCILING, null)
1380-
verify(mockListener2).onStateChanged(FlagsClientState.RECONCILING, null)
1381-
}
1382-
1383-
@Test
1384-
fun `M not notify removed listener W removeStateListener() then updateState()`() {
1385-
// Given
1386-
val mockListener = mock(FlagsStateListener::class.java)
1387-
testedClient.addStateListener(mockListener)
1388-
testedClient.removeStateListener(mockListener)
1389-
1390-
// When
1391-
testedClient.updateState(FlagsClientState.READY, null)
1392-
1393-
// Then
1394-
verifyNoInteractions(mockListener)
1395-
}
1353+
// Note: updateState() tests removed - this is now an internal method called only by
1354+
// EvaluationsManager. State notification testing is covered in FlagsStateManagerTest.
13961355

13971356
// endregion
13981357
}

0 commit comments

Comments
 (0)