From 2724ddfbcce6604619fc691bca467d389421272b Mon Sep 17 00:00:00 2001 From: Ram Kumar Date: Tue, 18 Feb 2025 18:01:02 +0530 Subject: [PATCH 1/4] Add error call back --- .../com/featurevisor/sdk/FeaturevisorError.kt | 4 ++-- .../kotlin/com/featurevisor/sdk/Instance+Fetch.kt | 10 +++++++++- src/main/kotlin/com/featurevisor/sdk/Instance.kt | 2 +- .../kotlin/com/featurevisor/sdk/EmitterTest.kt | 15 +++++++++++++++ 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/com/featurevisor/sdk/FeaturevisorError.kt b/src/main/kotlin/com/featurevisor/sdk/FeaturevisorError.kt index 949f81d..9bc29e0 100644 --- a/src/main/kotlin/com/featurevisor/sdk/FeaturevisorError.kt +++ b/src/main/kotlin/com/featurevisor/sdk/FeaturevisorError.kt @@ -1,6 +1,6 @@ package com.featurevisor.sdk -sealed class FeaturevisorError(message: String) : Throwable(message = message) { +sealed class FeaturevisorError(message: String, var code: Int = 0) : Throwable(message = message) { /// Thrown when attempting to init Featurevisor instance without passing datafile and datafileUrl. /// At least one of them is required to init the SDK correctly @@ -12,7 +12,7 @@ sealed class FeaturevisorError(message: String) : Throwable(message = message) { /// - Parameters: /// - data: The data being parsed. /// - errorMessage: The message from the error which occured during parsing. - class UnparsableJson(val data: String?, errorMessage: String) : FeaturevisorError(errorMessage) + class UnparsableJson(val data: String?, errorMessage: String, code: Int = 0) : FeaturevisorError(errorMessage, code) /// Thrown when attempting to construct an invalid URL. /// - Parameter string: The invalid URL string. diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt index acec439..faf43b4 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt @@ -148,7 +148,15 @@ private suspend fun fetchWithRetry( logger?.error("Request failed with message: ${response.message}") delay(retryInterval) } else { - completion(Result.failure(FeaturevisorError.UnparsableJson(responseBodyString, response.message))) + completion( + Result.failure( + FeaturevisorError.UnparsableJson( + responseBodyString, + response.message, + response.code, + ) + ) + ) } } } catch (e: IOException) { diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance.kt b/src/main/kotlin/com/featurevisor/sdk/Instance.kt index ad98c9f..b4987a4 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance.kt @@ -122,7 +122,7 @@ class FeaturevisorInstance private constructor(options: InstanceOptions) { if (refreshInterval != null) startRefreshing() }.onFailure { error -> logger?.error("Failed to fetch datafile: $error") - emitter.emit(ERROR) + emitter.emit(ERROR, error) } cancelFetchRetry() } diff --git a/src/test/kotlin/com/featurevisor/sdk/EmitterTest.kt b/src/test/kotlin/com/featurevisor/sdk/EmitterTest.kt index 18dd185..252aaef 100644 --- a/src/test/kotlin/com/featurevisor/sdk/EmitterTest.kt +++ b/src/test/kotlin/com/featurevisor/sdk/EmitterTest.kt @@ -4,6 +4,7 @@ import com.featurevisor.types.EventName.ACTIVATION import com.featurevisor.types.EventName.READY import com.featurevisor.types.EventName.REFRESH import com.featurevisor.types.EventName.UPDATE +import com.featurevisor.types.EventName.ERROR import com.featurevisor.types.EventName.values import io.mockk.every import io.mockk.mockk @@ -24,6 +25,9 @@ class EmitterTest { private val activationCallback: Listener = mockk { every { this@mockk(emptyArray()) } answers { nothing } } + private val errorCallback: Listener = mockk { + every { this@mockk(any()) } answers { nothing } + } private val systemUnderTest = Emitter() @@ -85,4 +89,15 @@ class EmitterTest { activationCallback(any()) } } + + @Test + fun `add error listener and confirm it is invoked`() { + systemUnderTest.addListener(ERROR, errorCallback) + + systemUnderTest.emit(ERROR, "data") + + verify(exactly = 1) { + errorCallback(arrayOf("data")) + } + } } From 3f5802f465725c30c44df1102b4ab58dc1d2fa9b Mon Sep 17 00:00:00 2001 From: HARSHIT SINHA <47042785+hsinha610@users.noreply.github.com> Date: Thu, 21 Aug 2025 17:27:03 +0530 Subject: [PATCH 2/4] Removed: BODY_BYTE_COUNT limit from datafile response production datafile size crossed 1MB (1000000 bytes to 1000107 bytes) so while reading the response body with BODY_BYTE_COUNT limit of 1000000 bytes, last 107 bytes were not getting read resulting in Invalid response body hence resulting in JSON parsing exception. --- src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt b/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt index faf43b4..5753fe5 100644 --- a/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt +++ b/src/main/kotlin/com/featurevisor/sdk/Instance+Fetch.kt @@ -84,7 +84,6 @@ internal suspend fun fetchDatafileContent( } } -const val BODY_BYTE_COUNT = 1000000L private val client = OkHttpClient() private suspend fun fetchDatafileContentFromUrl( @@ -135,8 +134,8 @@ private suspend fun fetchWithRetry( val call = client.newCall(request) try { val response = call.execute() - val responseBody = response.peekBody(BODY_BYTE_COUNT) - val responseBodyString = responseBody.string() + val responseBody = response.body + val responseBodyString = responseBody?.string().orEmpty() if (response.isSuccessful) { val json = Json { ignoreUnknownKeys = true } FeaturevisorInstance.companionLogger?.debug(responseBodyString) From 2917ed5dfdf230c391b214190cfbcfeb7c01199f Mon Sep 17 00:00:00 2001 From: HARSHIT SINHA <47042785+hsinha610@users.noreply.github.com> Date: Thu, 21 Aug 2025 17:39:54 +0530 Subject: [PATCH 3/4] Updated - actions/cache version from v3.0.2 to v3 --- .github/workflows/checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 89bb7db..4211211 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -16,7 +16,7 @@ jobs: java-version: 11 - name: Setup build cache - uses: actions/cache@v3.0.2 + uses: actions/cache@v3 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }} From f7b2a8f4dc3fed717e072fa4f609200008c7d5d2 Mon Sep 17 00:00:00 2001 From: HARSHIT SINHA <47042785+hsinha610@users.noreply.github.com> Date: Thu, 21 Aug 2025 17:43:57 +0530 Subject: [PATCH 4/4] Update actions/cache version from v3.0.2 to v3 --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 597b106..a0f5f76 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -19,7 +19,7 @@ jobs: java-version: 11 - name: Setup build cache - uses: actions/cache@v3.0.2 + uses: actions/cache@v3 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle.kts') }}