Skip to content

Commit 29c5cbc

Browse files
committed
improve test
1 parent 1fc5a30 commit 29c5cbc

File tree

1 file changed

+72
-11
lines changed

1 file changed

+72
-11
lines changed

packages/service-library/tests/fastapi/test_tracing.py

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,24 @@ def set_and_clean_settings_env_vars(
5555
monkeypatch.setenv(
5656
"TRACING_OPENTELEMETRY_COLLECTOR_PORT", f"{tracing_settings_in[1]}"
5757
)
58+
sampling_probability_mocked = False
59+
if tracing_settings_in[2]:
60+
sampling_probability_mocked = True
61+
monkeypatch.setenv("TRACING_SAMPLING_PROBABILITY", f"{tracing_settings_in[2]}")
5862
yield
5963
if endpoint_mocked:
6064
monkeypatch.delenv("TRACING_OPENTELEMETRY_COLLECTOR_ENDPOINT")
6165
if port_mocked:
6266
monkeypatch.delenv("TRACING_OPENTELEMETRY_COLLECTOR_PORT")
67+
if sampling_probability_mocked:
68+
monkeypatch.delenv("TRACING_SAMPLING_PROBABILITY")
6369

6470

6571
@pytest.mark.parametrize(
6672
"tracing_settings_in",
6773
[
68-
("http://opentelemetry-collector", 4318),
69-
("http://opentelemetry-collector", "4318"),
74+
("http://opentelemetry-collector", 4318, 1.0),
75+
("http://opentelemetry-collector", "4318", 1.0),
7076
],
7177
indirect=True,
7278
)
@@ -91,15 +97,16 @@ async def test_valid_tracing_settings(
9197
@pytest.mark.parametrize(
9298
"tracing_settings_in",
9399
[
94-
("http://opentelemetry-collector", 80),
95-
("http://opentelemetry-collector", 1238712936),
96-
("opentelemetry-collector", 4318),
97-
("httsdasp://ot@##el-collector", 4318),
98-
(" !@#$%^&*()[]{};:,<>?\\|`~+=/'\"", 4318),
100+
("http://opentelemetry-collector", 80, 0.5),
101+
("http://opentelemetry-collector", 1238712936, 0.5),
102+
("opentelemetry-collector", 4318, 0.5),
103+
("httsdasp://ot@##el-collector", 4318, 0.5),
104+
(" !@#$%^&*()[]{};:,<>?\\|`~+=/'\"", 4318, 0.5),
99105
# The following exceeds max DNS name length
100106
(
101107
"".join(random.choice(string.ascii_letters) for _ in range(300)),
102108
"1238712936",
109+
0.5,
103110
), # noqa: S311
104111
],
105112
indirect=True,
@@ -143,14 +150,14 @@ def manage_package(request):
143150
"tracing_settings_in, manage_package",
144151
[
145152
(
146-
("http://opentelemetry-collector", 4318),
153+
("http://opentelemetry-collector", 4318, 1.0),
147154
(
148155
"opentelemetry-instrumentation-botocore",
149156
"opentelemetry.instrumentation.botocore",
150157
),
151158
),
152159
(
153-
("http://opentelemetry-collector", "4318"),
160+
("http://opentelemetry-collector", "4318", 1.0),
154161
(
155162
"opentelemetry-instrumentation-aiopg",
156163
"opentelemetry.instrumentation.aiopg",
@@ -184,7 +191,7 @@ async def test_tracing_setup_package_detection(
184191
@pytest.mark.parametrize(
185192
"tracing_settings_in",
186193
[
187-
("http://opentelemetry-collector", 4318),
194+
("http://opentelemetry-collector", 4318, 1.0),
188195
],
189196
indirect=True,
190197
)
@@ -233,7 +240,7 @@ async def handler(handler_data: dict):
233240
@pytest.mark.parametrize(
234241
"tracing_settings_in",
235242
[
236-
("http://opentelemetry-collector", 4318),
243+
("http://opentelemetry-collector", 4318, 1.0),
237244
],
238245
indirect=True,
239246
)
@@ -284,3 +291,57 @@ async def handler(handler_data: dict):
284291
for span in spans
285292
if span.context is not None and span.attributes is not None
286293
)
294+
295+
296+
@pytest.mark.parametrize(
297+
"tracing_settings_in",
298+
[
299+
("http://opentelemetry-collector", 4318, 0.05),
300+
],
301+
indirect=True,
302+
)
303+
async def test_tracing_sampling_probability_effective(
304+
mock_otel_collector: InMemorySpanExporter,
305+
mocked_app: FastAPI,
306+
set_and_clean_settings_env_vars: Callable[[], None],
307+
tracing_settings_in: Callable[[], dict[str, Any]],
308+
):
309+
"""
310+
This test checks that the TRACING_SAMPLING_PROBABILITY setting in TracingSettings
311+
is effective by sending 1000 requests and verifying that the number of collected traces
312+
is close to 0.05 * 1000 (with some tolerance).
313+
"""
314+
n_requests = 1000
315+
tolerance_probability = 0.5
316+
317+
tracing_settings = TracingSettings()
318+
319+
async def handler():
320+
return PlainTextResponse("ok")
321+
322+
mocked_app.get("/")(handler)
323+
324+
async for _ in get_tracing_instrumentation_lifespan(
325+
tracing_settings=tracing_settings,
326+
service_name="Mock-OpenTelemetry-Pytest",
327+
)(app=mocked_app):
328+
initialize_fastapi_app_tracing(mocked_app, add_response_trace_id_header=True)
329+
client = TestClient(mocked_app)
330+
for _ in range(n_requests):
331+
client.get("/")
332+
spans = mock_otel_collector.get_finished_spans()
333+
trace_ids = set()
334+
for span in spans:
335+
if span.context is not None:
336+
trace_ids.add(span.context.trace_id)
337+
num_traces = len(trace_ids)
338+
expected_num_traces = int(
339+
tracing_settings.TRACING_SAMPLING_PROBABILITY * n_requests
340+
)
341+
# Allow a 50% tolerance due to randomness
342+
tolerance = int(tolerance_probability * expected_num_traces)
343+
assert (
344+
expected_num_traces - tolerance
345+
<= num_traces
346+
<= expected_num_traces + tolerance
347+
), f"Expected roughly {expected_num_traces} distinct trace ids, got {num_traces}"

0 commit comments

Comments
 (0)