-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Send a standard user-agent header #1
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
base: main
Are you sure you want to change the base?
Changes from all commits
5cea695
b184964
e7b671f
97643e4
6416cb7
2d6527f
c1c4edc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,188 @@ | ||
| package com.flagsmith | ||
|
|
||
| import com.flagsmith.entities.Trait | ||
| import com.flagsmith.mockResponses.MockEndpoint | ||
| import com.flagsmith.mockResponses.mockResponseFor | ||
| import kotlinx.coroutines.runBlocking | ||
| import org.junit.After | ||
| import org.junit.Assert.assertEquals | ||
| import org.junit.Assert.assertTrue | ||
| import org.junit.Before | ||
| import org.junit.Test | ||
| import org.mockserver.integration.ClientAndServer | ||
| import org.mockserver.model.HttpRequest.request | ||
|
|
||
| class UserAgentTests { | ||
|
|
||
| private lateinit var mockServer: ClientAndServer | ||
| private lateinit var flagsmith: Flagsmith | ||
|
|
||
| companion object { | ||
| // Expected version set by release-please in FlagsmithRetrofitService.getSdkVersion() | ||
| // x-release-please-start-version | ||
| private const val EXPECTED_SDK_VERSION = "1.8.0" | ||
| // x-release-please-end | ||
| private const val EXPECTED_USER_AGENT = "flagsmith-kotlin-android-sdk/$EXPECTED_SDK_VERSION" | ||
| } | ||
|
|
||
| @Before | ||
| fun setup() { | ||
| mockServer = ClientAndServer.startClientAndServer() | ||
| } | ||
|
|
||
| @After | ||
| fun tearDown() { | ||
| mockServer.stop() | ||
| } | ||
|
|
||
| @Test | ||
| fun testUserAgentHeaderSentWithGetFlags() { | ||
| // Given - SDK version is set by release-please | ||
| flagsmith = Flagsmith( | ||
| environmentKey = "test-key", | ||
| baseUrl = "http://localhost:${mockServer.localPort}", | ||
| context = null, | ||
| enableAnalytics = false, | ||
| cacheConfig = FlagsmithCacheConfig(enableCache = false) | ||
| ) | ||
|
|
||
| mockServer.mockResponseFor(MockEndpoint.GET_FLAGS) | ||
|
|
||
| // When | ||
| runBlocking { | ||
| val result = flagsmith.getFeatureFlagsSync() | ||
| assertTrue(result.isSuccess) | ||
| } | ||
|
|
||
| // Then - Verify User-Agent contains the SDK version from release-please | ||
| mockServer.verify( | ||
| request() | ||
| .withPath("/flags/") | ||
| .withMethod("GET") | ||
| .withHeader("User-Agent", EXPECTED_USER_AGENT) | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun testUserAgentHeaderSentWithNullContext() { | ||
| // Given - Context being null doesn't affect SDK version retrieval | ||
| flagsmith = Flagsmith( | ||
| environmentKey = "test-key", | ||
| baseUrl = "http://localhost:${mockServer.localPort}", | ||
| context = null, | ||
| enableAnalytics = false, | ||
| cacheConfig = FlagsmithCacheConfig(enableCache = false) | ||
| ) | ||
|
|
||
| mockServer.mockResponseFor(MockEndpoint.GET_FLAGS) | ||
|
|
||
| // When | ||
| runBlocking { | ||
| val result = flagsmith.getFeatureFlagsSync() | ||
| assertTrue(result.isSuccess) | ||
| } | ||
|
|
||
| // Then - Should get the SDK version from release-please | ||
| mockServer.verify( | ||
| request() | ||
| .withPath("/flags/") | ||
| .withMethod("GET") | ||
| .withHeader("User-Agent", EXPECTED_USER_AGENT) | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun testUserAgentHeaderSentWithIdentityRequest() { | ||
| // Given - Testing that User-Agent header is sent consistently across all API endpoints | ||
| flagsmith = Flagsmith( | ||
| environmentKey = "test-key", | ||
| baseUrl = "http://localhost:${mockServer.localPort}", | ||
| context = null, | ||
| enableAnalytics = false, | ||
| cacheConfig = FlagsmithCacheConfig(enableCache = false) | ||
| ) | ||
|
|
||
| mockServer.mockResponseFor(MockEndpoint.GET_IDENTITIES) | ||
|
|
||
| // When | ||
| runBlocking { | ||
| val result = flagsmith.getIdentitySync("test-user") | ||
| assertTrue(result.isSuccess) | ||
| } | ||
|
|
||
| // Then - Verify User-Agent header is sent with GET /identities/ | ||
| mockServer.verify( | ||
| request() | ||
| .withPath("/identities/") | ||
| .withMethod("GET") | ||
| .withQueryStringParameter("identifier", "test-user") | ||
| .withHeader("User-Agent", EXPECTED_USER_AGENT) | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun testUserAgentHeaderSentWithTraitRequest() { | ||
| // Given - Testing that User-Agent header is sent with POST requests | ||
| flagsmith = Flagsmith( | ||
| environmentKey = "test-key", | ||
| baseUrl = "http://localhost:${mockServer.localPort}", | ||
| context = null, | ||
| enableAnalytics = false, | ||
| cacheConfig = FlagsmithCacheConfig(enableCache = false) | ||
| ) | ||
|
|
||
| mockServer.mockResponseFor(MockEndpoint.SET_TRAIT) | ||
|
|
||
| // When | ||
| runBlocking { | ||
| val result = flagsmith.setTraitSync(Trait(key = "test-key", traitValue = "test-value"), "test-user") | ||
| assertTrue(result.isSuccess) | ||
| } | ||
|
|
||
| // Then - Verify User-Agent header is sent with POST /identities/ | ||
| mockServer.verify( | ||
| request() | ||
| .withPath("/identities/") | ||
| .withMethod("POST") | ||
| .withHeader("User-Agent", EXPECTED_USER_AGENT) | ||
| ) | ||
| } | ||
|
|
||
| @Test | ||
| fun testUserAgentFormat() { | ||
| // Given | ||
| flagsmith = Flagsmith( | ||
| environmentKey = "test-key", | ||
| baseUrl = "http://localhost:${mockServer.localPort}", | ||
| context = null, | ||
| enableAnalytics = false, | ||
| cacheConfig = FlagsmithCacheConfig(enableCache = false) | ||
| ) | ||
|
|
||
| mockServer.mockResponseFor(MockEndpoint.GET_FLAGS) | ||
|
|
||
| // When | ||
| runBlocking { | ||
| flagsmith.getFeatureFlagsSync() | ||
| } | ||
|
|
||
| // Then - Verify User-Agent follows the format: flagsmith-kotlin-android-sdk/{version} | ||
| val requests = mockServer.retrieveRecordedRequests( | ||
| request().withPath("/flags/") | ||
| ) | ||
|
|
||
| assertEquals(1, requests.size) | ||
| val userAgentHeader = requests[0].getFirstHeader("User-Agent") | ||
|
|
||
| // Verify format | ||
| assertTrue("User-Agent should start with 'flagsmith-kotlin-android-sdk/'", | ||
| userAgentHeader.startsWith("flagsmith-kotlin-android-sdk/")) | ||
|
|
||
| // Verify version part exists and is not empty | ||
| val version = userAgentHeader.substringAfter("flagsmith-kotlin-android-sdk/") | ||
| assertTrue("Version should not be empty", version.isNotEmpty()) | ||
|
|
||
| // Should be the version set by release-please | ||
| assertEquals(EXPECTED_SDK_VERSION, version) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,141 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package com.flagsmith.internal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import com.flagsmith.FlagsmithCacheConfig | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import okhttp3.OkHttpClient | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import okhttp3.Request | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import okhttp3.mockwebserver.MockResponse | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import okhttp3.mockwebserver.MockWebServer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.junit.After | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.junit.Assert.assertEquals | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.junit.Assert.assertNotNull | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.junit.Assert.assertTrue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.junit.Before | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.junit.Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Unit tests for SDK version retrieval functionality in FlagsmithRetrofitService. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * These tests verify that getSdkVersion() correctly returns the version set by release-please. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class SdkVersionRetrievalTest { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private lateinit var mockServer: MockWebServer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| companion object { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // This should match the version in getSdkVersion() and in .release-please-manifest.json | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // x-release-please-start-version | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private const val EXPECTED_SDK_VERSION = "1.8.0" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // x-release-please-end | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private const val USER_AGENT_PREFIX = "flagsmith-kotlin-android-sdk" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Before | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun setup() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mockServer = MockWebServer() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mockServer.start() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @After | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun tearDown() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mockServer.shutdown() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun testUserAgentInterceptorReturnsValidFormat() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Given - Create a client with the user agent interceptor | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val interceptor = FlagsmithRetrofitService.userAgentInterceptor() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val client = OkHttpClient.Builder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .addInterceptor(interceptor) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mockServer.enqueue(MockResponse().setResponseCode(200).setBody("{}")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // When - Make a request | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val request = Request.Builder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .url(mockServer.url("/")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client.newCall(request).execute().use { response -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Then - Verify the request was made with the correct User-Agent header | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val recordedRequest = mockServer.takeRequest() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val userAgent = recordedRequest.getHeader("User-Agent") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertNotNull("User-Agent header should be present", userAgent) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertTrue( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "User-Agent should start with correct prefix: $userAgent", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userAgent!!.startsWith("$USER_AGENT_PREFIX/") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun testVersionFormatIsValid() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Given - Create a client with the user agent interceptor | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val interceptor = FlagsmithRetrofitService.userAgentInterceptor() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val client = OkHttpClient.Builder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .addInterceptor(interceptor) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mockServer.enqueue(MockResponse().setResponseCode(200).setBody("{}")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // When - Make a request | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val request = Request.Builder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .url(mockServer.url("/")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client.newCall(request).execute().use { response -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Then - Verify version format is semantic versioning compatible | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val recordedRequest = mockServer.takeRequest() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val userAgent = recordedRequest.getHeader("User-Agent")!! | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val version = userAgent.substringAfter("$USER_AGENT_PREFIX/") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertTrue("Version should not be empty", version.isNotEmpty()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertTrue("Version should not contain whitespace", version.trim() == version) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Version should match semantic versioning pattern (X.Y.Z) or be a valid identifier | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val semverPattern = Regex("^\\d+\\.\\d+\\.\\d+.*$") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertTrue( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Version should follow semantic versioning or be a valid identifier: $version", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| semverPattern.matches(version) || version.matches(Regex("^[a-zA-Z0-9._-]+$")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+71
to
+102
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainWhitespace assertion doesn’t fully match the message; tighten the check The intent of assertTrue("Version should not contain whitespace", version.trim() == version)is that the version “should not contain whitespace”, but this only rejects leading/trailing whitespace. Internal whitespace (e.g. You can align the assertion with the message by rejecting any whitespace character: - assertTrue("Version should not contain whitespace", version.trim() == version)
+ assertTrue(
+ "Version should not contain whitespace",
+ !version.any { it.isWhitespace() }
+ )The rest of the format checks (semantic-version‑compatible or a simple identifier like I'll verify this review comment by inspecting the actual test file and confirming the whitespace assertion logic. Length of output: 5074 🏁 Script executed: #!/bin/bash
# Also search for similar whitespace patterns in the codebase
rg -n "trim()" --type kotlin -C 3 | head -50Length of output: 3772 🏁 Script executed: #!/bin/bash
# Check for isWhitespace usage in Kotlin files
rg -n "isWhitespace()" --type kotlinLength of output: 0 🏁 Script executed: #!/bin/bash
# Verify Kotlin String has 'any' method with isWhitespace
rg -n "\.any\s*{" --type kotlin -C 2 | head -30Length of output: 81 I need to verify that the suggested Kotlin syntax is valid and standard. Let me check the Kotlin documentation. 💡 Result: Use Char.isWhitespace() inside String.any { ... }. Example: Notes:
Sources: Whitespace assertion doesn't fully match the message; tighten the check The assertion Align the assertion with the message by rejecting any whitespace character: - assertTrue("Version should not contain whitespace", version.trim() == version)
+ assertTrue(
+ "Version should not contain whitespace",
+ !version.any { it.isWhitespace() }
+ )The rest of the format checks (semantic versioning or simple identifiers) are reasonable. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fun testUserAgentHeaderIsPersistentAcrossRequests() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Given - Create a client with the user agent interceptor | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val interceptor = FlagsmithRetrofitService.userAgentInterceptor() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val client = OkHttpClient.Builder() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .addInterceptor(interceptor) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .build() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mockServer.enqueue(MockResponse().setResponseCode(200).setBody("{}")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mockServer.enqueue(MockResponse().setResponseCode(200).setBody("{}")) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // When - Make multiple requests | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val request1 = Request.Builder().url(mockServer.url("/first")).build() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val request2 = Request.Builder().url(mockServer.url("/second")).build() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client.newCall(request1).execute().close() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| client.newCall(request2).execute().close() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Then - Both requests should have the same User-Agent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val recordedRequest1 = mockServer.takeRequest() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val recordedRequest2 = mockServer.takeRequest() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val userAgent1 = recordedRequest1.getHeader("User-Agent") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| val userAgent2 = recordedRequest2.getHeader("User-Agent") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertEquals( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "User-Agent should be consistent across requests", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userAgent1, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userAgent2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assertEquals( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "User-Agent should be the expected value", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$USER_AGENT_PREFIX/$EXPECTED_SDK_VERSION", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userAgent1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.