Skip to content

Commit

Permalink
feat: Support exporter metadata in Android provider (#2944)
Browse files Browse the repository at this point in the history
* feat: Support exporter metadata in Android provider

Signed-off-by: Thomas Poignant <[email protected]>

* adding test

Signed-off-by: Thomas Poignant <[email protected]>

---------

Signed-off-by: Thomas Poignant <[email protected]>
  • Loading branch information
thomaspoignant authored Jan 16, 2025
1 parent 95f13c2 commit 6ce4960
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ data class GoFeatureFlagOptions(
* when calling the evaluation API.
* default: 1000 ms
*/
val flushIntervalMs: Long = 300000
val flushIntervalMs: Long = 300000,

/**
* (optional) exporter metadata is a set of key-value that will be added to the metadata when calling the
* exporter API. All those informations will be added to the event produce by the exporter.
*
* ‼️Important: If you are using a GO Feature Flag relay proxy before version v1.41.0, the information
* of this field will not be added to your feature events.
*/
val exporterMetadata: Map<String, Any> = emptyMap(),
)

Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ class GoFeatureFlagApi(private val options: GoFeatureFlagOptions) {
}

val mediaType = "application/json".toMediaTypeOrNull()
val requestBody = gson.toJson(Events(events)).toRequestBody(mediaType)

val metadata = options.exporterMetadata.toMutableMap()
metadata["provider"] = "android"
metadata["openfeature"] = true
val requestBody = gson.toJson(Events(events, metadata)).toRequestBody(mediaType)
val reqBuilder = okhttp3.Request.Builder()
.url(urlBuilder.build())
.post(requestBody)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ package org.gofeatureflag.openfeature.hook

data class Events(
val events: List<Event>?,
val meta: Map<String, String> = mapOf("provider" to "android", "openfeature" to "true")
val meta: Map<String, Any> = emptyMap()
)
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,59 @@ class GoFeatureFlagProviderTest {
val got2 = Gson().fromJson(recordedRequest2.body.readUtf8(), Events::class.java)
assertEquals(3, got2.events?.size)
}

@Test
fun `should call the hook and send metadata`() {
val jsonFilePath =
javaClass.classLoader?.getResource("org.gofeatureflag.openfeature.ofrep/valid_api_response.json")?.file
val jsonString = String(Files.readAllBytes(Paths.get(jsonFilePath)))
mockWebServer!!.enqueue(MockResponse().setBody(jsonString).setResponseCode(200))
mockWebServer!!.enqueue(MockResponse().setBody("{}").setResponseCode(200))
mockWebServer!!.enqueue(MockResponse().setBody("{}").setResponseCode(200))
val options =
GoFeatureFlagOptions(
endpoint = mockWebServer!!.url("/").toString(),
flushIntervalMs = 100,
pollingIntervalInMillis = 10000,
exporterMetadata = mapOf("device" to "Pixel 4", "appVersion" to "1.0.0")
)

val provider = GoFeatureFlagProvider(options)
val ctx = ImmutableContext(targetingKey = "123")
runBlocking {
OpenFeatureAPI.setProviderAndWait(
provider = provider,
dispatcher = Dispatchers.IO,
initialContext = ctx
)
}

val client = OpenFeatureAPI.getClient()
client.getStringValue("title-flag", "default")
client.getStringValue("title-flag", "default")
client.getStringValue("title-flag", "default")
client.getStringValue("title-flag", "default")
client.getStringValue("title-flag", "default")
client.getStringValue("title-flag", "default")
Thread.sleep(1000)
client.getStringValue("title-flag", "default")
client.getStringValue("title-flag", "default")
client.getStringValue("title-flag", "default")
Thread.sleep(1000)
mockWebServer!!.takeRequest()
val recordedRequest: RecordedRequest = mockWebServer!!.takeRequest()
val got = Gson().fromJson(recordedRequest.body.readUtf8(), Events::class.java)
assertEquals(6, got.events?.size)
assertEquals("Pixel 4", got.meta["device"])
assertEquals("1.0.0", got.meta["appVersion"])
assertEquals("android", got.meta["provider"])
assertEquals(true, got.meta["openfeature"])
val recordedRequest2: RecordedRequest = mockWebServer!!.takeRequest()
val got2 = Gson().fromJson(recordedRequest2.body.readUtf8(), Events::class.java)
assertEquals(3, got2.events?.size)
assertEquals("Pixel 4", got2.meta["device"])
assertEquals("1.0.0", got2.meta["appVersion"])
assertEquals("android", got2.meta["provider"])
assertEquals(true, got2.meta["openfeature"])
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,24 @@ class GoFeatureFlagApiTest {
val got = recordedRequest.body.readUtf8()
JSONAssert.assertEquals(want, got, false)
}

@Test
fun `should have a valid body request when using exporter metadata`(): Unit = runBlocking {
mockWebServer!!.enqueue(MockResponse().setBody("{}").setResponseCode(200))
val api =
GoFeatureFlagApi(
GoFeatureFlagOptions(
endpoint = mockWebServer!!.url("/").toString(),
apiKey = "my-api-key",
exporterMetadata = mapOf("appVersion" to "1.0.0", "device" to "Pixel 4")
)
)
api.postEventsToDataCollector(defaultEventList)
val recordedRequest: RecordedRequest = mockWebServer!!.takeRequest()
val jsonFilePath =
javaClass.classLoader?.getResource("org/gofeatureflag/openfeature/hook/valid_result_metadata.json")?.file
val want = File(jsonFilePath.toString()).readText(Charsets.UTF_8)
val got = recordedRequest.body.readUtf8()
JSONAssert.assertEquals(want, got, false)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
],
"meta": {
"provider": "android",
"openfeature": "true"
"openfeature": true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"events": [
{
"contextKind": "contextKind",
"creationDate": 1721650841,
"key": "flag-1",
"kind": "feature",
"userKey": "981f2662-1fb4-4732-ac6d-8399d9205aa9",
"value": true,
"default": false,
"variation": "enabled"
}
],
"meta": {
"provider": "android",
"openfeature": true,
"appVersion": "1.0.0",
"device": "Pixel 4"
}
}

0 comments on commit 6ce4960

Please sign in to comment.