Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add flag evaluation metadata to evaluation details #111

Merged
merged 4 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions android/src/main/java/dev/openfeature/sdk/FlagEvaluationDetails.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import dev.openfeature.sdk.exceptions.ErrorCode

data class FlagEvaluationDetails<T>(
val flagKey: String,
override val value: T,
override val variant: String? = null,
override val reason: String? = null,
override val errorCode: ErrorCode? = null,
override val errorMessage: String? = null
) : BaseEvaluation<T> {
val value: T,
val variant: String? = null,
val reason: String? = null,
val errorCode: ErrorCode? = null,
val errorMessage: String? = null,
val metadata: EvaluationMetadata = EvaluationMetadata.EMPTY
) {
companion object
}

Expand All @@ -18,11 +19,12 @@ fun <T> FlagEvaluationDetails.Companion.from(
flagKey: String
): FlagEvaluationDetails<T> {
return FlagEvaluationDetails(
flagKey,
providerEval.value,
providerEval.variant,
providerEval.reason,
providerEval.errorCode,
providerEval.errorMessage
flagKey = flagKey,
value = providerEval.value,
variant = providerEval.variant,
reason = providerEval.reason,
errorCode = providerEval.errorCode,
errorMessage = providerEval.errorMessage,
metadata = providerEval.metadata
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package dev.openfeature.sdk

class EvaluationMetadata internal constructor(private val values: Map<String, Any>) {

fun getString(key: String): String? = values[key] as? String

fun getBoolean(key: String): Boolean? = values[key] as? Boolean

fun getInt(key: String): Int? = values[key] as? Int

fun getDouble(key: String): Double? = values[key] as? Double

companion object {
fun builder(): Builder {
return Builder()
}

val EMPTY = EvaluationMetadata(emptyMap())
}

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as EvaluationMetadata

return values == other.values
}

override fun hashCode(): Int {
return values.hashCode()
}
}

class Builder {
private val values: MutableMap<String, Any> = mutableMapOf()

fun putString(key: String, value: String): Builder {
values[key] = value
return this
}

fun putInt(key: String, value: Int): Builder {
values[key] = value
return this
}

fun putDouble(key: String, value: Double): Builder {
values[key] = value
return this
}

fun putBoolean(key: String, value: Boolean): Builder {
values[key] = value
return this
}

fun build(): EvaluationMetadata {
return EvaluationMetadata(values.toMap())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ data class ProviderEvaluation<T>(
val variant: String? = null,
val reason: String? = null,
val errorCode: ErrorCode? = null,
val errorMessage: String? = null
val errorMessage: String? = null,
val metadata: EvaluationMetadata = EvaluationMetadata.EMPTY
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package dev.openfeature.sdk

import org.junit.Assert
import org.junit.Test

class EvaluationMetadataTest {

private val metadata = EvaluationMetadata.builder()
.putString("key1", "value1")
.putInt("key2", 42)
.putBoolean("key3", true)
.putDouble("key4", 2.71828)
.build()

@Test
fun testAddAndGet() {
Assert.assertEquals("value1", metadata.getString("key1"))
Assert.assertEquals(42, metadata.getInt("key2"))
Assert.assertEquals(true, metadata.getBoolean("key3"))
Assert.assertEquals(2.71828, metadata.getDouble("key4"))
}

@Test
fun testGetNonExistentKey() {
Assert.assertNull(metadata.getString("key5"))
}

@Test
fun testInvalidType() {
Assert.assertNull(metadata.getString("key2"))
Assert.assertNull(metadata.getInt("key3"))
Assert.assertNull(metadata.getBoolean("key4"))
Assert.assertNull(metadata.getDouble("key1"))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ class FlagEvaluationsTests {
Assert.assertEquals(booleanDetails, client.getBooleanDetails(key, false))
Assert.assertEquals(booleanDetails, client.getBooleanDetails(key, false, FlagEvaluationOptions()))

val stringDetails = FlagEvaluationDetails(key, "tset")
// in DoSomethingProvider, the string evaluation is special since it contains some metadata values
val stringDetails = FlagEvaluationDetails(key, "tset", metadata = DoSomethingProvider.evaluationMetadata)
Assert.assertEquals(stringDetails, client.getStringDetails(key, "test"))
Assert.assertEquals(stringDetails, client.getStringDetails(key, "test", FlagEvaluationOptions()))

Expand All @@ -93,6 +94,18 @@ class FlagEvaluationsTests {
Assert.assertEquals(objectDetails, client.getObjectDetails(key, Value.Structure(mapOf()), FlagEvaluationOptions()))
}

@Test
fun testMetadataFlagEvaluation() = runTest {
OpenFeatureAPI.setProvider(DoSomethingProvider())
val client = OpenFeatureAPI.getClient()
val key = "key"

val details = client.getStringDetails(key, "default")
val metadata: EvaluationMetadata = details.metadata
Assert.assertEquals("value1", metadata.getString("key1"))
Assert.assertEquals(42, metadata.getInt("key2"))
}

@Test
fun testHooksAreFired() = runTest {
OpenFeatureAPI.setProvider(NoOpProvider())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.openfeature.sdk.helpers

import dev.openfeature.sdk.EvaluationContext
import dev.openfeature.sdk.EvaluationMetadata
import dev.openfeature.sdk.FeatureProvider
import dev.openfeature.sdk.Hook
import dev.openfeature.sdk.ProviderEvaluation
Expand All @@ -19,6 +20,12 @@ class DoSomethingProvider(
override val metadata: ProviderMetadata = DoSomethingProviderMetadata(),
private var dispatcher: CoroutineDispatcher = Dispatchers.IO
) : FeatureProvider {
companion object {
val evaluationMetadata = EvaluationMetadata.builder()
.putString("key1", "value1")
.putInt("key2", 42)
.build()
}
private var eventHandler = EventHandler(dispatcher)

override fun initialize(initialContext: EvaluationContext?) {
Expand Down Expand Up @@ -51,7 +58,10 @@ class DoSomethingProvider(
defaultValue: String,
context: EvaluationContext?
): ProviderEvaluation<String> {
return ProviderEvaluation(defaultValue.reversed())
return ProviderEvaluation(
value = defaultValue.reversed(),
metadata = evaluationMetadata
)
}

override fun getIntegerEvaluation(
Expand Down