1
1
import contextlib
2
+ import os
2
3
import typing
3
4
from unittest .mock import AsyncMock , MagicMock , Mock , patch
4
5
8
9
from fastapi .testclient import TestClient as FastAPITestClient
9
10
from litestar .middleware .base import DefineMiddleware
10
11
from litestar .testing import TestClient as LitestarTestClient
12
+ from opentelemetry .instrumentation .dependencies import DependencyConflictError
13
+ from opentelemetry .instrumentation .environment_variables import OTEL_PYTHON_DISABLED_INSTRUMENTATIONS
11
14
12
15
from microbootstrap import OpentelemetryConfig
13
16
from microbootstrap .bootstrappers .fastapi import FastApiOpentelemetryInstrument
14
17
from microbootstrap .bootstrappers .litestar import LitestarOpentelemetryInstrument
18
+ from microbootstrap .instruments import opentelemetry_instrument
15
19
from microbootstrap .instruments .opentelemetry_instrument import OpentelemetryInstrument
16
20
17
21
18
22
def test_opentelemetry_is_ready (
19
23
minimal_opentelemetry_config : OpentelemetryConfig ,
20
24
) -> None :
21
- opentelemetry_instrument : typing .Final = OpentelemetryInstrument (minimal_opentelemetry_config )
22
- assert opentelemetry_instrument .is_ready ()
25
+ test_opentelemetry_instrument : typing .Final = OpentelemetryInstrument (minimal_opentelemetry_config )
26
+ assert test_opentelemetry_instrument .is_ready ()
23
27
24
28
25
29
def test_opentelemetry_bootstrap_is_not_ready (minimal_opentelemetry_config : OpentelemetryConfig ) -> None :
26
30
minimal_opentelemetry_config .service_debug = False
27
31
minimal_opentelemetry_config .opentelemetry_endpoint = None
28
- opentelemetry_instrument : typing .Final = OpentelemetryInstrument (minimal_opentelemetry_config )
29
- assert not opentelemetry_instrument .is_ready ()
32
+ test_opentelemetry_instrument : typing .Final = OpentelemetryInstrument (minimal_opentelemetry_config )
33
+ assert not test_opentelemetry_instrument .is_ready ()
30
34
31
35
32
36
def test_opentelemetry_bootstrap_after (
33
37
default_litestar_app : litestar .Litestar ,
34
38
minimal_opentelemetry_config : OpentelemetryConfig ,
35
39
) -> None :
36
- opentelemetry_instrument : typing .Final = OpentelemetryInstrument (minimal_opentelemetry_config )
37
- assert opentelemetry_instrument .bootstrap_after (default_litestar_app ) == default_litestar_app
40
+ test_opentelemetry_instrument : typing .Final = OpentelemetryInstrument (minimal_opentelemetry_config )
41
+ assert test_opentelemetry_instrument .bootstrap_after (default_litestar_app ) == default_litestar_app
38
42
39
43
40
44
def test_opentelemetry_teardown (
41
45
minimal_opentelemetry_config : OpentelemetryConfig ,
42
46
) -> None :
43
- opentelemetry_instrument : typing .Final = OpentelemetryInstrument (minimal_opentelemetry_config )
44
- assert opentelemetry_instrument .teardown () is None # type: ignore[func-returns-value]
47
+ test_opentelemetry_instrument : typing .Final = OpentelemetryInstrument (minimal_opentelemetry_config )
48
+ assert test_opentelemetry_instrument .teardown () is None # type: ignore[func-returns-value]
45
49
46
50
47
51
def test_litestar_opentelemetry_bootstrap (
48
52
minimal_opentelemetry_config : OpentelemetryConfig ,
49
53
magic_mock : MagicMock ,
50
54
) -> None :
51
55
minimal_opentelemetry_config .opentelemetry_instrumentors = [magic_mock ]
52
- opentelemetry_instrument : typing .Final = LitestarOpentelemetryInstrument (minimal_opentelemetry_config )
56
+ test_opentelemetry_instrument : typing .Final = LitestarOpentelemetryInstrument (minimal_opentelemetry_config )
53
57
54
- opentelemetry_instrument .bootstrap ()
55
- opentelemetry_bootstrap_result : typing .Final = opentelemetry_instrument .bootstrap_before ()
58
+ test_opentelemetry_instrument .bootstrap ()
59
+ opentelemetry_bootstrap_result : typing .Final = test_opentelemetry_instrument .bootstrap_before ()
56
60
57
61
assert opentelemetry_bootstrap_result
58
62
assert "middleware" in opentelemetry_bootstrap_result
@@ -66,18 +70,18 @@ def test_litestar_opentelemetry_teardown(
66
70
magic_mock : MagicMock ,
67
71
) -> None :
68
72
minimal_opentelemetry_config .opentelemetry_instrumentors = [magic_mock ]
69
- opentelemetry_instrument : typing .Final = LitestarOpentelemetryInstrument (minimal_opentelemetry_config )
73
+ test_opentelemetry_instrument : typing .Final = LitestarOpentelemetryInstrument (minimal_opentelemetry_config )
70
74
71
- opentelemetry_instrument .teardown ()
75
+ test_opentelemetry_instrument .teardown ()
72
76
73
77
74
78
def test_litestar_opentelemetry_bootstrap_working (
75
79
minimal_opentelemetry_config : OpentelemetryConfig ,
76
80
async_mock : AsyncMock ,
77
81
) -> None :
78
- opentelemetry_instrument : typing .Final = LitestarOpentelemetryInstrument (minimal_opentelemetry_config )
79
- opentelemetry_instrument .bootstrap ()
80
- opentelemetry_bootstrap_result : typing .Final = opentelemetry_instrument .bootstrap_before ()
82
+ test_opentelemetry_instrument : typing .Final = LitestarOpentelemetryInstrument (minimal_opentelemetry_config )
83
+ test_opentelemetry_instrument .bootstrap ()
84
+ opentelemetry_bootstrap_result : typing .Final = test_opentelemetry_instrument .bootstrap_before ()
81
85
82
86
opentelemetry_middleware = opentelemetry_bootstrap_result ["middleware" ][0 ]
83
87
assert isinstance (opentelemetry_middleware , DefineMiddleware )
@@ -104,9 +108,9 @@ def test_fastapi_opentelemetry_bootstrap_working(
104
108
) -> None :
105
109
monkeypatch .setattr ("opentelemetry.sdk.trace.TracerProvider.shutdown" , Mock ())
106
110
107
- opentelemetry_instrument : typing .Final = FastApiOpentelemetryInstrument (minimal_opentelemetry_config )
108
- opentelemetry_instrument .bootstrap ()
109
- fastapi_application : typing .Final = opentelemetry_instrument .bootstrap_after (fastapi .FastAPI ())
111
+ test_opentelemetry_instrument : typing .Final = FastApiOpentelemetryInstrument (minimal_opentelemetry_config )
112
+ test_opentelemetry_instrument .bootstrap ()
113
+ fastapi_application : typing .Final = test_opentelemetry_instrument .bootstrap_after (fastapi .FastAPI ())
110
114
111
115
@fastapi_application .get ("/test-handler" )
112
116
async def test_handler () -> None :
@@ -115,3 +119,47 @@ async def test_handler() -> None:
115
119
with patch ("opentelemetry.trace.use_span" ) as mock_capture_event :
116
120
FastAPITestClient (app = fastapi_application ).get ("/test-handler" )
117
121
assert mock_capture_event .called
122
+
123
+
124
+ @pytest .mark .parametrize (
125
+ ("instruments" , "result" ),
126
+ [
127
+ (
128
+ [
129
+ MagicMock (),
130
+ MagicMock (load = MagicMock (side_effect = ImportError )),
131
+ MagicMock (load = MagicMock (side_effect = DependencyConflictError ("Hello" ))),
132
+ MagicMock (load = MagicMock (side_effect = ModuleNotFoundError )),
133
+ ],
134
+ "ok" ,
135
+ ),
136
+ (
137
+ [
138
+ MagicMock (load = MagicMock (side_effect = ValueError )),
139
+ ],
140
+ "raise" ,
141
+ ),
142
+ (
143
+ [
144
+ MagicMock (load = MagicMock (side_effect = ValueError )),
145
+ ],
146
+ "exclude" ,
147
+ ),
148
+ ],
149
+ )
150
+ def test_instrumentator_loader (instruments : list [MagicMock ], result : str , monkeypatch : pytest .MonkeyPatch ) -> None :
151
+ if result == "exclude" :
152
+ monkeypatch .setenv (OTEL_PYTHON_DISABLED_INSTRUMENTATIONS , "exclude_this,exclude_that" )
153
+ instruments [0 ].name = "exclude_this"
154
+ monkeypatch .setattr (
155
+ opentelemetry_instrument ,
156
+ "entry_points" ,
157
+ MagicMock (return_value = [* instruments ]),
158
+ )
159
+
160
+ if result != "raise" :
161
+ opentelemetry_instrument ._load_instrumentors (MagicMock ()) # noqa: SLF001
162
+ return
163
+
164
+ with pytest .raises (ValueError ): # noqa: PT011
165
+ opentelemetry_instrument ._load_instrumentors (MagicMock ()) # noqa: SLF001
0 commit comments