Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ private fun Value.friendlyString(): String {
return when (this) {
is Value.String -> this.string
is Value.Integer -> this.integer.toString()
is Value.Long -> this.long.toString()
is Value.Double -> this.double.toString()
is Value.Boolean -> this.boolean.toString()
is Value.Instant -> this.instant.toString()
Expand Down
1 change: 1 addition & 0 deletions Provider/api/Provider.api
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ public final class com/spotify/confidence/openfeature/ConfidenceFeatureProvider
public fun getDoubleEvaluation (Ljava/lang/String;DLdev/openfeature/kotlin/sdk/EvaluationContext;)Ldev/openfeature/kotlin/sdk/ProviderEvaluation;
public fun getHooks ()Ljava/util/List;
public fun getIntegerEvaluation (Ljava/lang/String;ILdev/openfeature/kotlin/sdk/EvaluationContext;)Ldev/openfeature/kotlin/sdk/ProviderEvaluation;
public fun getLongEvaluation (Ljava/lang/String;JLdev/openfeature/kotlin/sdk/EvaluationContext;)Ldev/openfeature/kotlin/sdk/ProviderEvaluation;
public fun getMetadata ()Ldev/openfeature/kotlin/sdk/ProviderMetadata;
public fun getObjectEvaluation (Ljava/lang/String;Ldev/openfeature/kotlin/sdk/Value;Ldev/openfeature/kotlin/sdk/EvaluationContext;)Ldev/openfeature/kotlin/sdk/ProviderEvaluation;
public fun getStringEvaluation (Ljava/lang/String;Ljava/lang/String;Ldev/openfeature/kotlin/sdk/EvaluationContext;)Ldev/openfeature/kotlin/sdk/ProviderEvaluation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,25 @@ class ConfidenceFeatureProvider private constructor(
return generateEvaluation(key, defaultValue)
}

override fun getLongEvaluation(
key: String,
defaultValue: Long,
context: EvaluationContext?
): ProviderEvaluation<Long> {
val evaluation = generateEvaluation<Any>(key, defaultValue)
return ProviderEvaluation(
value = when (val value = evaluation.value) {
is Int -> value.toLong()
is Long -> value
else -> throw OpenFeatureError.ParseError("Flag value is not an integer")
},
reason = evaluation.reason,
variant = evaluation.variant,
errorCode = evaluation.errorCode,
errorMessage = evaluation.errorMessage
)
}

override fun getObjectEvaluation(
key: String,
defaultValue: Value,
Expand Down Expand Up @@ -207,6 +226,7 @@ internal fun Value.toConfidenceValue(): ConfidenceValue = when (this) {
is Value.Boolean -> ConfidenceValue.Boolean(this.boolean)
is Value.Double -> ConfidenceValue.Double(this.double)
is Value.Integer -> ConfidenceValue.Integer(this.integer)
is Value.Long -> this.long.toConfidenceValue()
is Value.List -> {
// if types are different, return an empty list
if (this.list.map { it.javaClass.simpleName }.groupBy { it }.size > 1) {
Expand Down Expand Up @@ -271,8 +291,7 @@ private fun OpenFeatureError.toProviderErrorEvent(): OpenFeatureProviderEvents.P
eventDetails = OpenFeatureProviderEvents.EventDetails(
message = message,
errorCode = errorCode()
),
error = this
)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.spotify.confidence.openfeature
import com.spotify.confidence.ConfidenceValue
import dev.openfeature.kotlin.sdk.EvaluationContext
import dev.openfeature.kotlin.sdk.TrackingEventDetails
import dev.openfeature.kotlin.sdk.exceptions.OpenFeatureError

internal fun mergeEventContext(
sessionContext: Map<String, ConfidenceValue>,
Expand Down Expand Up @@ -37,12 +38,16 @@ internal fun TrackingEventDetails?.toTrackingData(): Map<String, ConfidenceValue
) + structure.asMap().mapValues { it.value.toConfidenceValue() }
}

private fun Number.toConfidenceValue(): ConfidenceValue = when (this) {
private const val MAX_EXACT_DOUBLE_INTEGER = 9_007_199_254_740_992L

internal fun Number.toConfidenceValue(): ConfidenceValue = when (this) {
is Int -> ConfidenceValue.Integer(this)
is Long -> if (this in Int.MIN_VALUE..Int.MAX_VALUE) {
ConfidenceValue.Integer(toInt())
} else {
} else if (this in -MAX_EXACT_DOUBLE_INTEGER..MAX_EXACT_DOUBLE_INTEGER) {
ConfidenceValue.Double(toDouble())
} else {
throw OpenFeatureError.ParseError("Long value cannot be represented exactly by Confidence")
}
is Double -> ConfidenceValue.Double(this)
is Float -> ConfidenceValue.Double(toDouble())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ package com.spotify.confidence.openfeature

import com.spotify.confidence.Confidence
import com.spotify.confidence.ConfidenceValue
import com.spotify.confidence.Evaluation
import com.spotify.confidence.ResolveReason
import dev.openfeature.kotlin.sdk.ImmutableContext
import dev.openfeature.kotlin.sdk.ImmutableStructure
import dev.openfeature.kotlin.sdk.TrackingEventDetails
import dev.openfeature.kotlin.sdk.Value
import dev.openfeature.kotlin.sdk.events.OpenFeatureProviderEvents
import dev.openfeature.kotlin.sdk.exceptions.ErrorCode
import dev.openfeature.kotlin.sdk.exceptions.OpenFeatureError
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
Expand All @@ -23,6 +26,31 @@ import org.junit.Test
import com.spotify.confidence.Result as ConfidenceResult

class ConfidenceFeatureProviderTrackTest {
@Test
fun longEvaluationWidensIntegerFlagValueAndPreservesLongDefault() {
val confidence = mockk<Confidence>(relaxed = true)
every { confidence.getFlag<Any>("size", any()) } returns
Evaluation(42, reason = ResolveReason.RESOLVE_REASON_MATCH)
every { confidence.getFlag<Any>("missing", any()) } answers
{ Evaluation(secondArg(), reason = ResolveReason.ERROR) }
val provider = ConfidenceFeatureProvider.create(confidence)

assertEquals(42L, provider.getLongEvaluation("size", 0L, null).value)
assertEquals(Long.MAX_VALUE, provider.getLongEvaluation("missing", Long.MAX_VALUE, null).value)
}

@Test
fun longEvaluationRejectsDoubleFlagValue() {
val confidence = mockk<Confidence>(relaxed = true)
every { confidence.getFlag<Any>("size", any()) } returns
Evaluation(42.0, reason = ResolveReason.RESOLVE_REASON_MATCH)
val provider = ConfidenceFeatureProvider.create(confidence)

org.junit.Assert.assertThrows(OpenFeatureError.ParseError::class.java) {
provider.getLongEvaluation("size", 0L, null)
}
}

@Test
fun shutdownStopsConfidence() {
val confidence = mockk<Confidence>(relaxed = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package com.spotify.confidence.openfeature

import com.spotify.confidence.ConfidenceValue
import dev.openfeature.kotlin.sdk.Value
import dev.openfeature.kotlin.sdk.exceptions.OpenFeatureError
import org.junit.Assert.assertEquals
import org.junit.Assert.assertThrows
import org.junit.Test

class ValueMappingsTest {
Expand Down Expand Up @@ -35,6 +37,15 @@ class ValueMappingsTest {
assertEquals(42, confidenceValue.asInteger()?.integer)
}

@Test
fun openFeatureLongValueToConfidenceValue() {
assertEquals(ConfidenceValue.Integer(42), Value.Long(42).toConfidenceValue())
assertEquals(ConfidenceValue.Double(3_000_000_000.0), Value.Long(3_000_000_000).toConfidenceValue())
assertThrows(OpenFeatureError.ParseError::class.java) {
Value.Long(9_007_199_254_740_993L).toConfidenceValue()
}
}

@Test
fun openFeatureStructureValueToConfidenceValueStruct() {
val value = Value.Structure(mapOf("key" to Value.String("value")))
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ okHttp = "4.12.0"
kotlinxSerialization = "1.6.0"

# Provider
openFeatureSDK = "0.8.0"
openFeatureSDK = "0.9.0"

# Sample app
activityCompose = "1.3.1"
Expand Down
Loading