|  | 
| 1 | 1 | package com.posthog.server | 
| 2 | 2 | 
 | 
| 3 | 3 | import com.posthog.PostHogStatelessInterface | 
|  | 4 | +import okhttp3.mockwebserver.MockResponse | 
| 4 | 5 | import org.mockito.kotlin.mock | 
| 5 | 6 | import org.mockito.kotlin.verify | 
| 6 | 7 | import org.mockito.kotlin.whenever | 
| @@ -493,6 +494,108 @@ internal class PostHogTest { | 
| 493 | 494 |         ) | 
| 494 | 495 |     } | 
| 495 | 496 | 
 | 
|  | 497 | +    @Test | 
|  | 498 | +    fun `capture with sendFeatureFlags appends flags to event properties`() { | 
|  | 499 | +        val flagsResponse = | 
|  | 500 | +            """ | 
|  | 501 | +            { | 
|  | 502 | +                "flags": { | 
|  | 503 | +                    "flag1": { | 
|  | 504 | +                        "key": "flag1", | 
|  | 505 | +                        "enabled": true, | 
|  | 506 | +                        "variant": "variant_a", | 
|  | 507 | +                        "metadata": { "version": 1, "payload": null, "id": 1 }, | 
|  | 508 | +                        "reason": { "kind": "condition_match", "condition_match_type": "Test", "condition_index": 0 } | 
|  | 509 | +                    }, | 
|  | 510 | +                    "flag2": { | 
|  | 511 | +                        "key": "flag2", | 
|  | 512 | +                        "enabled": true, | 
|  | 513 | +                        "variant": null, | 
|  | 514 | +                        "metadata": { "version": 1, "payload": null, "id": 2 }, | 
|  | 515 | +                        "reason": { "kind": "condition_match", "condition_match_type": "Test", "condition_index": 0 } | 
|  | 516 | +                    }, | 
|  | 517 | +                    "flag3": { | 
|  | 518 | +                        "key": "flag3", | 
|  | 519 | +                        "enabled": false, | 
|  | 520 | +                        "variant": null, | 
|  | 521 | +                        "metadata": { "version": 1, "payload": null, "id": 3 }, | 
|  | 522 | +                        "reason": { "kind": "condition_match", "condition_match_type": "Test", "condition_index": 0 } | 
|  | 523 | +                    } | 
|  | 524 | +                } | 
|  | 525 | +            } | 
|  | 526 | +            """.trimIndent() | 
|  | 527 | + | 
|  | 528 | +        val mockServer = | 
|  | 529 | +            createMockHttp( | 
|  | 530 | +                jsonResponse(flagsResponse), | 
|  | 531 | +                MockResponse().setResponseCode(200).setBody("{}"), | 
|  | 532 | +            ) | 
|  | 533 | +        val url = mockServer.url("/") | 
|  | 534 | + | 
|  | 535 | +        val config = PostHogConfig(apiKey = TEST_API_KEY, host = url.toString()) | 
|  | 536 | +        val postHog = PostHog() | 
|  | 537 | +        postHog.setup(config) | 
|  | 538 | + | 
|  | 539 | +        // Capture with sendFeatureFlags | 
|  | 540 | +        val sendFeatureFlagOptions = | 
|  | 541 | +            PostHogSendFeatureFlagOptions.builder() | 
|  | 542 | +                .personProperty("email" , "[email protected]" ) | 
|  | 543 | +                .build() | 
|  | 544 | + | 
|  | 545 | +        postHog.capture( | 
|  | 546 | +            distinctId = "user123", | 
|  | 547 | +            event = "test_event", | 
|  | 548 | +            properties = mapOf("prop" to "value"), | 
|  | 549 | +            userProperties = null, | 
|  | 550 | +            userPropertiesSetOnce = null, | 
|  | 551 | +            groups = null, | 
|  | 552 | +            timestamp = null, | 
|  | 553 | +            sendFeatureFlags = sendFeatureFlagOptions, | 
|  | 554 | +        ) | 
|  | 555 | + | 
|  | 556 | +        postHog.flush() | 
|  | 557 | + | 
|  | 558 | +        mockServer.takeRequest() // flags request | 
|  | 559 | +        val batchRequest = mockServer.takeRequest() | 
|  | 560 | + | 
|  | 561 | +        // Decompress the batch body if gzipped | 
|  | 562 | +        val batchBody = | 
|  | 563 | +            if (batchRequest.getHeader("Content-Encoding") == "gzip") { | 
|  | 564 | +                batchRequest.body.unGzip() | 
|  | 565 | +            } else { | 
|  | 566 | +                batchRequest.body.readUtf8() | 
|  | 567 | +            } | 
|  | 568 | + | 
|  | 569 | +        // Parse the batch request JSON | 
|  | 570 | +        val gson = com.google.gson.Gson() | 
|  | 571 | +        @Suppress("UNCHECKED_CAST") | 
|  | 572 | +        val batchData = gson.fromJson(batchBody, Map::class.java) as Map<String, Any> | 
|  | 573 | +        @Suppress("UNCHECKED_CAST") | 
|  | 574 | +        val batch = batchData["batch"] as List<Map<String, Any>> | 
|  | 575 | + | 
|  | 576 | +        assertEquals(1, batch.size) | 
|  | 577 | + | 
|  | 578 | +        val event = batch[0] | 
|  | 579 | +        assertEquals("test_event", event["event"]) | 
|  | 580 | +        assertEquals("user123", event["distinct_id"]) | 
|  | 581 | + | 
|  | 582 | +        @Suppress("UNCHECKED_CAST") | 
|  | 583 | +        val properties = event["properties"] as Map<String, Any> | 
|  | 584 | +        assertEquals("value", properties["prop"]) | 
|  | 585 | +        assertEquals("variant_a", properties["\$feature/flag1"]) | 
|  | 586 | +        assertEquals(true, properties["\$feature/flag2"]) | 
|  | 587 | +        assertEquals(false, properties["\$feature/flag3"]) | 
|  | 588 | + | 
|  | 589 | +        @Suppress("UNCHECKED_CAST") | 
|  | 590 | +        val activeFlags = properties["\$active_feature_flags"] as? List<String> | 
|  | 591 | +        assertEquals(2, activeFlags?.size) | 
|  | 592 | +        assertEquals(true, activeFlags?.contains("flag1")) | 
|  | 593 | +        assertEquals(true, activeFlags?.contains("flag2")) | 
|  | 594 | + | 
|  | 595 | +        mockServer.shutdown() | 
|  | 596 | +        postHog.close() | 
|  | 597 | +    } | 
|  | 598 | + | 
| 496 | 599 |     @Test | 
| 497 | 600 |     fun `isFeatureEnabled propagates parameters as expected`() { | 
| 498 | 601 |         val mockInstance = createMockStateless() | 
|  | 
0 commit comments