Skip to content

Commit c9daf17

Browse files
committed
Add threaded, asyncio, and global ldclient tests
1 parent 5165ffb commit c9daf17

File tree

1 file changed

+71
-6
lines changed

1 file changed

+71
-6
lines changed
Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1+
import asyncio
2+
import concurrent.futures as cf
3+
4+
import ldclient
5+
16
import sentry_sdk
7+
import pytest
28

39
from ldclient import LDClient
410
from ldclient.config import Config
@@ -8,25 +14,84 @@
814
from sentry_sdk.integrations.launchdarkly import LaunchDarklyIntegration
915

1016
# Ref: https://docs.launchdarkly.com/sdk/features/test-data-sources#python
17+
# https://launchdarkly-python-sdk.readthedocs.io/en/latest/api-testing.html#ldclient.integrations.test_data.TestData
1118

1219

13-
def test_launchdarkly_integration(sentry_init):
20+
@pytest.mark.parametrize(
21+
"use_global_client",
22+
(False, True),
23+
)
24+
def test_launchdarkly_integration(sentry_init, use_global_client):
1425
td = TestData.data_source()
15-
client = LDClient(config=Config("sdk-key", update_processor_class=td))
16-
sentry_init(integrations=[LaunchDarklyIntegration(client=client)])
26+
config = Config("sdk-key", update_processor_class=td)
27+
if use_global_client:
28+
ldclient.set_config(config)
29+
sentry_init(integrations=[LaunchDarklyIntegration()])
30+
client = ldclient.get()
31+
else:
32+
client = LDClient(config=config)
33+
sentry_init(integrations=[LaunchDarklyIntegration(client=client)])
1734

1835
# Set test values
1936
td.update(td.flag("hello").variation_for_all(True))
2037
td.update(td.flag("world").variation_for_all(True))
21-
td.update(td.flag("goodbye").variation_for_all(False))
2238

2339
# Evaluate
2440
client.variation("hello", Context.create("my-org", "organization"), False)
2541
client.variation("world", Context.create("user1", "user"), False)
26-
client.variation("goodbye", Context.create("user2", "user"), False)
42+
client.variation("other", Context.create("user2", "user"), False)
2743

2844
assert sentry_sdk.get_current_scope().flags.get() == [
2945
{"flag": "hello", "result": True},
3046
{"flag": "world", "result": True},
31-
{"flag": "goodbye", "result": False},
47+
{"flag": "other", "result": False},
3248
]
49+
50+
51+
def test_launchdarkly_integration_threaded(sentry_init):
52+
td = TestData.data_source()
53+
client = LDClient(config=Config("sdk-key", update_processor_class=td))
54+
sentry_init(integrations=[LaunchDarklyIntegration(client=client)])
55+
context = Context.create("user1")
56+
57+
def task(flag_key):
58+
# Create a new isolation scope for the thread. This means the evaluations in each task are captured separately.
59+
with sentry_sdk.isolation_scope():
60+
client.variation(flag_key, context, False)
61+
return [f["flag"] for f in sentry_sdk.get_current_scope().flags.get()]
62+
63+
td.update(td.flag("hello").variation_for_all(True))
64+
td.update(td.flag("world").variation_for_all(False))
65+
client.variation(
66+
"hello", context, False
67+
) # Captured before splitting isolation scopes.
68+
69+
with cf.ThreadPoolExecutor(max_workers=2) as pool:
70+
results = list(pool.map(task, ["world", "other"]))
71+
72+
assert results[0] == ["hello", "world"]
73+
assert results[1] == ["hello", "other"]
74+
75+
76+
def test_launchdarkly_integration_asyncio(sentry_init):
77+
"""Assert concurrently evaluated flags do not pollute one another."""
78+
td = TestData.data_source()
79+
client = LDClient(config=Config("sdk-key", update_processor_class=td))
80+
sentry_init(integrations=[LaunchDarklyIntegration(client=client)])
81+
context = Context.create("user1")
82+
83+
async def task(flag_key):
84+
with sentry_sdk.isolation_scope():
85+
client.variation(flag_key, context, False)
86+
return [f["flag"] for f in sentry_sdk.get_current_scope().flags.get()]
87+
88+
async def runner():
89+
return asyncio.gather(task("world"), task("other"))
90+
91+
td.update(td.flag("hello").variation_for_all(True))
92+
td.update(td.flag("world").variation_for_all(False))
93+
client.variation("hello", context, False)
94+
95+
results = asyncio.run(runner()).result()
96+
assert results[0] == ["hello", "world"]
97+
assert results[1] == ["hello", "other"]

0 commit comments

Comments
 (0)