|
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", "test@example.com") |
| 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