1
- import asyncio
2
1
import concurrent .futures as cf
2
+ import sys
3
3
4
4
import ldclient
5
-
6
- import sentry_sdk
7
5
import pytest
8
6
9
7
from ldclient import LDClient
10
8
from ldclient .config import Config
11
9
from ldclient .context import Context
12
10
from ldclient .integrations .test_data import TestData
13
11
12
+ import sentry_sdk
14
13
from sentry_sdk .integrations import DidNotEnable
15
14
from sentry_sdk .integrations .launchdarkly import LaunchDarklyIntegration
16
15
19
18
"use_global_client" ,
20
19
(False , True ),
21
20
)
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
+ ):
23
24
td = TestData .data_source ()
24
25
config = Config ("sdk-key" , update_processor_class = td )
26
+
27
+ uninstall_integration (LaunchDarklyIntegration .identifier )
25
28
if use_global_client :
26
29
ldclient .set_config (config )
27
30
sentry_init (integrations = [LaunchDarklyIntegration ()])
@@ -39,60 +42,130 @@ def test_launchdarkly_integration(sentry_init, use_global_client):
39
42
client .variation ("world" , Context .create ("user1" , "user" ), False )
40
43
client .variation ("other" , Context .create ("user2" , "user" ), False )
41
44
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!" ))
47
47
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
+ }
48
56
49
- def test_launchdarkly_integration_threaded (sentry_init ):
57
+
58
+ def test_launchdarkly_integration_threaded (
59
+ sentry_init , capture_events , uninstall_integration
60
+ ):
50
61
td = TestData .data_source ()
51
62
client = LDClient (config = Config ("sdk-key" , update_processor_class = td ))
52
- sentry_init (integrations = [LaunchDarklyIntegration (ld_client = client )])
53
63
context = Context .create ("user1" )
54
64
65
+ uninstall_integration (LaunchDarklyIntegration .identifier )
66
+ sentry_init (integrations = [LaunchDarklyIntegration (ld_client = client )])
67
+ events = capture_events ()
68
+
55
69
def task (flag_key ):
56
70
# Creates a new isolation scope for the thread.
57
71
# This means the evaluations in each task are captured separately.
58
72
with sentry_sdk .isolation_scope ():
59
73
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!" ))
61
77
62
78
td .update (td .flag ("hello" ).variation_for_all (True ))
63
79
td .update (td .flag ("world" ).variation_for_all (False ))
64
80
# Capture an eval before we split isolation scopes.
65
81
client .variation ("hello" , context , False )
66
82
67
83
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."""
72
117
118
+ asyncio = pytest .importorskip ("asyncio" )
73
119
74
- def test_launchdarkly_integration_asyncio (sentry_init ):
75
- """Assert concurrently evaluated flags do not pollute one another."""
76
120
td = TestData .data_source ()
77
121
client = LDClient (config = Config ("sdk-key" , update_processor_class = td ))
78
- sentry_init (integrations = [LaunchDarklyIntegration (ld_client = client )])
79
122
context = Context .create ("user1" )
80
123
124
+ uninstall_integration (LaunchDarklyIntegration .identifier )
125
+ sentry_init (integrations = [LaunchDarklyIntegration (ld_client = client )])
126
+ events = capture_events ()
127
+
81
128
async def task (flag_key ):
82
129
with sentry_sdk .isolation_scope ():
83
130
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!" ))
85
134
86
135
async def runner ():
87
136
return asyncio .gather (task ("world" ), task ("other" ))
88
137
89
138
td .update (td .flag ("hello" ).variation_for_all (True ))
90
139
td .update (td .flag ("world" ).variation_for_all (False ))
140
+ # Capture an eval before we split isolation scopes.
91
141
client .variation ("hello" , context , False )
92
142
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
+ }
96
169
97
170
98
171
def test_launchdarkly_integration_did_not_enable (monkeypatch ):
0 commit comments