Skip to content

Commit 466115b

Browse files
feat: Update observeEvents() API (#89)
Signed-off-by: Fabrizio Demaria <[email protected]>
1 parent 1d4c24f commit 466115b

File tree

5 files changed

+55
-10
lines changed

5 files changed

+55
-10
lines changed

android/src/main/java/dev/openfeature/sdk/OpenFeatureAPI.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
package dev.openfeature.sdk
22

3+
import kotlinx.coroutines.flow.MutableSharedFlow
4+
import kotlinx.coroutines.flow.SharedFlow
5+
36
@Suppress("TooManyFunctions")
47
object OpenFeatureAPI {
58
private var provider: FeatureProvider? = null
69
private var context: EvaluationContext? = null
10+
private val providersFlow: MutableSharedFlow<FeatureProvider> = MutableSharedFlow(replay = 1)
11+
internal val sharedProvidersFlow: SharedFlow<FeatureProvider> get() = providersFlow
712

813
var hooks: List<Hook<*>> = listOf()
914
private set
1015

1116
fun setProvider(provider: FeatureProvider, initialContext: EvaluationContext? = null) {
1217
this@OpenFeatureAPI.provider = provider
18+
providersFlow.tryEmit(provider)
1319
if (initialContext != null) context = initialContext
1420
try {
1521
provider.initialize(context)

android/src/main/java/dev/openfeature/sdk/async/Extensions.kt

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import dev.openfeature.sdk.events.observe
99
import kotlinx.coroutines.CoroutineDispatcher
1010
import kotlinx.coroutines.CoroutineScope
1111
import kotlinx.coroutines.Dispatchers
12+
import kotlinx.coroutines.ExperimentalCoroutinesApi
1213
import kotlinx.coroutines.cancel
1314
import kotlinx.coroutines.flow.Flow
15+
import kotlinx.coroutines.flow.flatMapLatest
1416
import kotlinx.coroutines.flow.onStart
1517
import kotlinx.coroutines.flow.take
1618
import kotlinx.coroutines.launch
@@ -42,6 +44,16 @@ internal fun FeatureProvider.observeProviderReady() = observe<OpenFeatureEvents.
4244
}
4345
}
4446

47+
/*
48+
Observe events from currently configured Provider.
49+
*/
50+
@OptIn(ExperimentalCoroutinesApi::class)
51+
fun OpenFeatureAPI.observeEvents(): Flow<OpenFeatureEvents> {
52+
return sharedProvidersFlow.flatMapLatest { provider ->
53+
provider.observe()
54+
}
55+
}
56+
4557
internal fun FeatureProvider.observeProviderError() = observe<OpenFeatureEvents.ProviderError>()
4658
.onStart {
4759
val status = getProviderStatus()
@@ -50,10 +62,6 @@ internal fun FeatureProvider.observeProviderError() = observe<OpenFeatureEvents.
5062
}
5163
}
5264

53-
inline fun <reified T : OpenFeatureEvents> OpenFeatureAPI.observeEvents(): Flow<T>? {
54-
return getProvider()?.observe<T>()
55-
}
56-
5765
suspend fun FeatureProvider.awaitReadyOrError(
5866
dispatcher: CoroutineDispatcher = Dispatchers.IO
5967
) = suspendCancellableCoroutine { continuation ->

android/src/test/java/dev/openfeature/sdk/DeveloperExperienceTests.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package dev.openfeature.sdk
22

3+
import dev.openfeature.sdk.async.observeEvents
34
import dev.openfeature.sdk.async.setProviderAndWait
45
import dev.openfeature.sdk.exceptions.ErrorCode
56
import dev.openfeature.sdk.helpers.AlwaysBrokenProvider
7+
import dev.openfeature.sdk.helpers.DoSomethingProvider
68
import dev.openfeature.sdk.helpers.GenericSpyHookMock
79
import dev.openfeature.sdk.helpers.SlowProvider
810
import kotlinx.coroutines.CoroutineScope
911
import kotlinx.coroutines.ExperimentalCoroutinesApi
1012
import kotlinx.coroutines.launch
1113
import kotlinx.coroutines.test.StandardTestDispatcher
1214
import kotlinx.coroutines.test.UnconfinedTestDispatcher
15+
import kotlinx.coroutines.test.advanceUntilIdle
1316
import kotlinx.coroutines.test.runTest
1417
import org.junit.Assert
1518
import org.junit.Test
@@ -86,4 +89,24 @@ class DeveloperExperienceTests {
8689
val booleanValue = OpenFeatureAPI.getClient().getBooleanValue("test", false)
8790
Assert.assertFalse(booleanValue)
8891
}
92+
93+
@Test
94+
fun testObserveEvents() = runTest {
95+
val dispatcher = StandardTestDispatcher(testScheduler)
96+
var eventCount = 0
97+
CoroutineScope(dispatcher).launch {
98+
OpenFeatureAPI.observeEvents().collect {
99+
eventCount++
100+
}
101+
}
102+
CoroutineScope(dispatcher).launch {
103+
OpenFeatureAPI.setProviderAndWait(
104+
DoSomethingProvider(dispatcher = dispatcher),
105+
dispatcher,
106+
ImmutableContext()
107+
)
108+
}
109+
advanceUntilIdle()
110+
Assert.assertEquals(eventCount, 1)
111+
}
89112
}

android/src/test/java/dev/openfeature/sdk/helpers/DoSomethingProvider.kt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,25 @@ import dev.openfeature.sdk.Hook
66
import dev.openfeature.sdk.ProviderEvaluation
77
import dev.openfeature.sdk.ProviderMetadata
88
import dev.openfeature.sdk.Value
9+
import dev.openfeature.sdk.events.EventHandler
910
import dev.openfeature.sdk.events.OpenFeatureEvents
11+
import kotlinx.coroutines.CoroutineDispatcher
12+
import kotlinx.coroutines.CoroutineScope
13+
import kotlinx.coroutines.Dispatchers
1014
import kotlinx.coroutines.flow.Flow
11-
import kotlinx.coroutines.flow.flowOf
15+
import kotlinx.coroutines.launch
1216

1317
class DoSomethingProvider(
1418
override val hooks: List<Hook<*>> = listOf(),
15-
override val metadata: ProviderMetadata = DoSomethingProviderMetadata()
19+
override val metadata: ProviderMetadata = DoSomethingProviderMetadata(),
20+
private var dispatcher: CoroutineDispatcher = Dispatchers.IO
1621
) : FeatureProvider {
22+
private var eventHandler = EventHandler(dispatcher)
23+
1724
override fun initialize(initialContext: EvaluationContext?) {
18-
// no-op
25+
CoroutineScope(dispatcher).launch {
26+
eventHandler.publish(OpenFeatureEvents.ProviderReady)
27+
}
1928
}
2029

2130
override fun shutdown() {
@@ -69,7 +78,7 @@ class DoSomethingProvider(
6978
return ProviderEvaluation(Value.Null)
7079
}
7180

72-
override fun observe(): Flow<OpenFeatureEvents> = flowOf()
81+
override fun observe(): Flow<OpenFeatureEvents> = eventHandler.observe()
7382

7483
override fun getProviderStatus(): OpenFeatureEvents = OpenFeatureEvents.ProviderReady
7584

android/src/test/java/dev/openfeature/sdk/helpers/SlowProvider.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import kotlinx.coroutines.CoroutineDispatcher
1313
import kotlinx.coroutines.CoroutineScope
1414
import kotlinx.coroutines.delay
1515
import kotlinx.coroutines.flow.Flow
16-
import kotlinx.coroutines.flow.flowOf
1716
import kotlinx.coroutines.launch
1817

1918
class SlowProvider(override val hooks: List<Hook<*>> = listOf(), private var dispatcher: CoroutineDispatcher) : FeatureProvider {
@@ -84,7 +83,7 @@ class SlowProvider(override val hooks: List<Hook<*>> = listOf(), private var dis
8483
return ProviderEvaluation(Value.Null)
8584
}
8685

87-
override fun observe(): Flow<OpenFeatureEvents> = flowOf()
86+
override fun observe(): Flow<OpenFeatureEvents> = eventHandler.observe()
8887

8988
override fun getProviderStatus(): OpenFeatureEvents = if (ready) {
9089
OpenFeatureEvents.ProviderReady

0 commit comments

Comments
 (0)