Skip to content

Commit

Permalink
fix: On context change (#69)
Browse files Browse the repository at this point in the history
* add the eventing onContext change to set the provider values as stale, fetch the values and update the cache

* add a test scenario for checking if we get new values after the context update

* docs: update comment

---------

Co-authored-by: Nicklas Lundin <nicklasl@spotify.com>
  • Loading branch information
vahidlazio and nicklasl authored Sep 12, 2023
1 parent f1dd972 commit 0904cd6
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,22 @@ class ConfidenceFeatureProvider private constructor(
}

override fun initialize(initialContext: EvaluationContext?) {
if (initialContext == null) return
initialContext?.let {
internalInitialize(
initialContext,
initialisationStrategy
)
}
}

private fun internalInitialize(
initialContext: EvaluationContext,
strategy: InitialisationStrategy
) {
// refresh cache with the last stored data
storage.read()?.let(cache::refresh)

if (initialisationStrategy == InitialisationStrategy.ActivateAndFetchAsync) {
if (strategy == InitialisationStrategy.ActivateAndFetchAsync) {
eventsPublisher.publish(OpenFeatureEvents.ProviderReady)
}

Expand All @@ -84,7 +94,7 @@ class ConfidenceFeatureProvider private constructor(
initialContext
)

when (initialisationStrategy) {
when (strategy) {
InitialisationStrategy.FetchAndActivate -> {
// refresh the cache from the stored data
cache.refresh(data = storedData)
Expand All @@ -108,7 +118,14 @@ class ConfidenceFeatureProvider private constructor(
newContext: EvaluationContext
) {
if (newContext != oldContext) {
initialize(newContext)
eventsPublisher.publish(OpenFeatureEvents.ProviderStale)

// on the new context we want to fetch new values and update
// the storage & cache right away which is why we pass `InitialisationStrategy.FetchAndActivate`
internalInitialize(
newContext,
InitialisationStrategy.FetchAndActivate
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ internal class ConfidenceFeatureProviderTests {
private val mockClient: ConfidenceClient = mock()
private val mockContext: Context = mock()
private val instant = Instant.parse("2023-03-01T14:01:46.645Z")
private val blueStringValues = mutableMapOf(
"mystring" to Value.String("blue")
)
private val resolvedValueAsMap = mutableMapOf(
"mystring" to Value.String("red"),
"myboolean" to Value.Boolean(false),
Expand Down Expand Up @@ -313,6 +316,53 @@ internal class ConfidenceFeatureProviderTests {
assertNull(evalNull.errorCode)
}

@Test
fun testNewContextFetchValuesAgain() = runTest {
val testDispatcher = UnconfinedTestDispatcher(testScheduler)
val confidenceFeatureProvider = ConfidenceFeatureProvider.create(
context = mockContext,
clientSecret = "",
cache = InMemoryCache(),
client = mockClient,
eventsPublisher = EventHandler.eventsPublisher(testDispatcher),
dispatcher = testDispatcher
)

val evaluationContext1 = ImmutableContext("foo")
val evaluationContext2 = ImmutableContext("bar")

whenever(mockClient.resolve(eq(listOf()), eq(evaluationContext1))).thenReturn(
ResolveResponse.Resolved(
ResolveFlags(resolvedFlags, "token1")
)
)

val newExpectedValue = resolvedFlags.list[0].copy(value = ImmutableStructure(blueStringValues))
whenever(mockClient.resolve(eq(listOf()), eq(evaluationContext2))).thenReturn(
ResolveResponse.Resolved(
ResolveFlags(Flags(listOf(newExpectedValue)), "token1")
)
)

confidenceFeatureProvider.initialize(evaluationContext1)
advanceUntilIdle()

val evalString1 = confidenceFeatureProvider.getStringEvaluation(
"test-kotlin-flag-1.mystring",
"default",
evaluationContext1
)
assertEquals("red", evalString1.value)
confidenceFeatureProvider.onContextSet(evaluationContext1, evaluationContext2)
advanceUntilIdle()
val evalString2 = confidenceFeatureProvider.getStringEvaluation(
"test-kotlin-flag-1.mystring",
"default",
evaluationContext2
)
assertEquals("blue", evalString2.value)
}

@Test
fun testApplyOnMultipleEvaluations() = runTest {
val testDispatcher = UnconfinedTestDispatcher(testScheduler)
Expand Down

0 comments on commit 0904cd6

Please sign in to comment.