1- import asyncio
21import concurrent .futures as cf
2+ import sys
33
44import ldclient
5-
6- import sentry_sdk
75import pytest
86
97from ldclient import LDClient
108from ldclient .config import Config
119from ldclient .context import Context
1210from ldclient .integrations .test_data import TestData
1311
12+ import sentry_sdk
1413from sentry_sdk .integrations import DidNotEnable
1514from sentry_sdk .integrations .launchdarkly import LaunchDarklyIntegration
1615
1918 "use_global_client" ,
2019 (False , True ),
2120)
22- def test_launchdarkly_integration (sentry_init , use_global_client ):
21+ def test_launchdarkly_integration (
22+ sentry_init , use_global_client , capture_events , uninstall_integration
23+ ):
2324 td = TestData .data_source ()
2425 config = Config ("sdk-key" , update_processor_class = td )
26+
27+ uninstall_integration (LaunchDarklyIntegration .identifier )
2528 if use_global_client :
2629 ldclient .set_config (config )
2730 sentry_init (integrations = [LaunchDarklyIntegration ()])
@@ -39,60 +42,130 @@ def test_launchdarkly_integration(sentry_init, use_global_client):
3942 client .variation ("world" , Context .create ("user1" , "user" ), False )
4043 client .variation ("other" , Context .create ("user2" , "user" ), False )
4144
42- assert sentry_sdk .get_current_scope ().flags .get () == [
43- {"flag" : "hello" , "result" : True },
44- {"flag" : "world" , "result" : True },
45- {"flag" : "other" , "result" : False },
46- ]
45+ events = capture_events ()
46+ sentry_sdk .capture_exception (Exception ("something wrong!" ))
4747
48+ assert len (events ) == 1
49+ assert events [0 ]["contexts" ]["flags" ] == {
50+ "values" : [
51+ {"flag" : "hello" , "result" : True },
52+ {"flag" : "world" , "result" : True },
53+ {"flag" : "other" , "result" : False },
54+ ]
55+ }
4856
49- def test_launchdarkly_integration_threaded (sentry_init ):
57+
58+ def test_launchdarkly_integration_threaded (
59+ sentry_init , capture_events , uninstall_integration
60+ ):
5061 td = TestData .data_source ()
5162 client = LDClient (config = Config ("sdk-key" , update_processor_class = td ))
52- sentry_init (integrations = [LaunchDarklyIntegration (ld_client = client )])
5363 context = Context .create ("user1" )
5464
65+ uninstall_integration (LaunchDarklyIntegration .identifier )
66+ sentry_init (integrations = [LaunchDarklyIntegration (ld_client = client )])
67+ events = capture_events ()
68+
5569 def task (flag_key ):
5670 # Creates a new isolation scope for the thread.
5771 # This means the evaluations in each task are captured separately.
5872 with sentry_sdk .isolation_scope ():
5973 client .variation (flag_key , context , False )
60- return [f ["flag" ] for f in sentry_sdk .get_current_scope ().flags .get ()]
74+ # use a tag to identify to identify events later on
75+ sentry_sdk .set_tag ("task_id" , flag_key )
76+ sentry_sdk .capture_exception (Exception ("something wrong!" ))
6177
6278 td .update (td .flag ("hello" ).variation_for_all (True ))
6379 td .update (td .flag ("world" ).variation_for_all (False ))
6480 # Capture an eval before we split isolation scopes.
6581 client .variation ("hello" , context , False )
6682
6783 with cf .ThreadPoolExecutor (max_workers = 2 ) as pool :
68- results = list (pool .map (task , ["world" , "other" ]))
69-
70- assert results [0 ] == ["hello" , "world" ]
71- assert results [1 ] == ["hello" , "other" ]
84+ pool .map (task , ["world" , "other" ])
85+
86+ # Capture error in original scope
87+ sentry_sdk .set_tag ("task_id" , "0" )
88+ sentry_sdk .capture_exception (Exception ("something wrong!" ))
89+
90+ assert len (events ) == 3
91+ events .sort (key = lambda e : e ["tags" ]["task_id" ])
92+
93+ assert events [0 ]["contexts" ]["flags" ] == {
94+ "values" : [
95+ {"flag" : "hello" , "result" : True },
96+ ]
97+ }
98+ assert events [1 ]["contexts" ]["flags" ] == {
99+ "values" : [
100+ {"flag" : "hello" , "result" : True },
101+ {"flag" : "other" , "result" : False },
102+ ]
103+ }
104+ assert events [2 ]["contexts" ]["flags" ] == {
105+ "values" : [
106+ {"flag" : "hello" , "result" : True },
107+ {"flag" : "world" , "result" : False },
108+ ]
109+ }
110+
111+
112+ @pytest .mark .skipif (sys .version_info < (3 , 7 ), reason = "requires python3.7 or higher" )
113+ def test_launchdarkly_integration_asyncio (
114+ sentry_init , capture_events , uninstall_integration
115+ ):
116+ """Assert concurrently evaluated flags do not pollute one another."""
72117
118+ asyncio = pytest .importorskip ("asyncio" )
73119
74- def test_launchdarkly_integration_asyncio (sentry_init ):
75- """Assert concurrently evaluated flags do not pollute one another."""
76120 td = TestData .data_source ()
77121 client = LDClient (config = Config ("sdk-key" , update_processor_class = td ))
78- sentry_init (integrations = [LaunchDarklyIntegration (ld_client = client )])
79122 context = Context .create ("user1" )
80123
124+ uninstall_integration (LaunchDarklyIntegration .identifier )
125+ sentry_init (integrations = [LaunchDarklyIntegration (ld_client = client )])
126+ events = capture_events ()
127+
81128 async def task (flag_key ):
82129 with sentry_sdk .isolation_scope ():
83130 client .variation (flag_key , context , False )
84- return [f ["flag" ] for f in sentry_sdk .get_current_scope ().flags .get ()]
131+ # use a tag to identify to identify events later on
132+ sentry_sdk .set_tag ("task_id" , flag_key )
133+ sentry_sdk .capture_exception (Exception ("something wrong!" ))
85134
86135 async def runner ():
87136 return asyncio .gather (task ("world" ), task ("other" ))
88137
89138 td .update (td .flag ("hello" ).variation_for_all (True ))
90139 td .update (td .flag ("world" ).variation_for_all (False ))
140+ # Capture an eval before we split isolation scopes.
91141 client .variation ("hello" , context , False )
92142
93- results = asyncio .run (runner ()).result ()
94- assert results [0 ] == ["hello" , "world" ]
95- assert results [1 ] == ["hello" , "other" ]
143+ asyncio .run (runner ())
144+
145+ # Capture error in original scope
146+ sentry_sdk .set_tag ("task_id" , "0" )
147+ sentry_sdk .capture_exception (Exception ("something wrong!" ))
148+
149+ assert len (events ) == 3
150+ events .sort (key = lambda e : e ["tags" ]["task_id" ])
151+
152+ assert events [0 ]["contexts" ]["flags" ] == {
153+ "values" : [
154+ {"flag" : "hello" , "result" : True },
155+ ]
156+ }
157+ assert events [1 ]["contexts" ]["flags" ] == {
158+ "values" : [
159+ {"flag" : "hello" , "result" : True },
160+ {"flag" : "other" , "result" : False },
161+ ]
162+ }
163+ assert events [2 ]["contexts" ]["flags" ] == {
164+ "values" : [
165+ {"flag" : "hello" , "result" : True },
166+ {"flag" : "world" , "result" : False },
167+ ]
168+ }
96169
97170
98171def test_launchdarkly_integration_did_not_enable (monkeypatch ):
0 commit comments