8000 testing extras · modern-python/lite-bootstrap@b5cb975 · GitHub
[go: up one dir, main page]

Skip to content

Commit b5cb975

Browse files
committed
testing extras
1 parent ba315f0 commit b5cb975

File tree

7 files changed

+180
-120
lines changed

7 files changed

+180
-120
lines changed

lite_bootstrap/bootstrappers/fastapi_bootstrapper.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ class FastAPIBootstrapper(BaseBootstrapper["fastapi.FastAPI"]):
123123
bootstrap_config: FastAPIConfig
124124
not_ready_message = "fastapi is not installed"
125125

126+
def __init__(self, bootstrap_config: FastAPIConfig) -> None:
127+
super().__init__(bootstrap_config)
128+
self.bootstrap_config.application.title = bootstrap_config.service_name
129+
self.bootstrap_config.application.debug = bootstrap_config.service_debug
130+
self.bootstrap_config.application.version = bootstrap_config.service_version
131+
126132
def is_ready(self) -> bool:
127133
return import_checker.is_fastapi_installed
128134

lite_bootstrap/bootstrappers/litestar_bootstrapper.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,5 @@ class LitestarBootstrapper(BaseBootstrapper["litestar.Litestar"]):
128128
def is_ready(self) -> bool:
129129
return import_checker.is_litestar_installed
130130

131-
def __init__(self, bootstrap_config: LitestarConfig) -> None:
132-
super().__init__(bootstrap_config)
133-
134131
def _prepare_application(self) -> "litestar.Litestar":
135132
return litestar.Litestar.from_config(self.bootstrap_config.application_config)

tests/conftest.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1+
import contextlib
2+
import sys
13
import typing
4+
from importlib import reload
25
from unittest.mock import Mock
36

47
import pytest
58
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor # type: ignore[attr-defined]
69

10+
from lite_bootstrap import import_checker
11+
712

813
class CustomInstrumentor(BaseInstrumentor): # type: ignore[misc]
914
def inst 6D40 rumentation_dependencies(self) -> typing.Collection[str]:
@@ -16,3 +21,15 @@ def _uninstrument(self, **kwargs: typing.Mapping[str, typing.Any]) -> None:
1621
@pytest.fixture(autouse=True)
1722
def mock_sentry_init(monkeypatch: pytest.MonkeyPatch) -> None:
1823
monkeypatch.setattr("sentry_sdk.init", Mock)
24+
25+
26+
@contextlib.contextmanager
27+
def emulate_package_missing(package_name: str) -> typing.Iterator[None]:
28+
old_module = sys.modules[package_name]
29+
sys.modules[package_name] = None # type: ignore[assignment]
30+
reload(import_checker)
31+
try:
32+
yield
33+
finally:
34+
sys.modules[package_name] = old_module
35+
reload(import_checker)

tests/test_fastapi_bootstrap.py

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,65 @@
44
from starlette import status
55
from starlette.testclient import TestClient
66

7-
from lite_bootstrap import FastAPIBootstrapper, FastAPIConfig, import_checker
8-
from tests.conftest import CustomInstrumentor
7+
from lite_bootstrap import FastAPIBootstrapper, FastAPIConfig
8+
from tests.conftest import CustomInstrumentor, emulate_package_missing
99

1010

1111
logger = structlog.getLogger(__name__)
1212

1313

14-
def test_fastapi_bootstrap() -> None:
15-
health_checks_path = "/custom-health/"
16-
prometheus_metrics_path = "/custom-metrics/"
17-
bootstrapper = FastAPIBootstrapper(
18-
bootstrap_config=FastAPIConfig(
19-
service_name="microservice",
20-
service_version="2.0.0",
21-
service_environment="test",
22-
service_debug=False,
23-
opentelemetry_endpoint="otl",
24-
opentelemetry_instrumentors=[CustomInstrumentor()],
25-
opentelemetry_span_exporter=ConsoleSpanExporter(),
26-
prometheus_metrics_path=prometheus_metrics_path,
27-
sentry_dsn="https://testdsn@localhost/1",
28-
health_checks_path=health_checks_path,
29-
logging_buffer_capacity=0,
30-
),
14+
@pytest.fixture
15+
def fastapi_config() -> FastAPIConfig:
16+
return FastAPIConfig(
17+
service_name="microservice",
18+
service_version="2.0.0",
19+
service_environment="test",
20+
service_debug=False,
21+
opentelemetry_endpoint="otl",
22+
opentelemetry_instrumentors=[CustomInstrumentor()],
23+
opentelemetry_span_exporter=ConsoleSpanExporter(),
24+
prometheus_metrics_path="/custom-metrics/",
25+
sentry_dsn="https://testdsn@localhost/1",
26+
health_checks_path="/custom-health/",
27+
logging_buffer_capacity=0,
3128
)
29+
30+
31+
def test_fastapi_bootstrap(fastapi_config: FastAPIConfig) -> None:
32+
bootstrapper = FastAPIBootstrapper(bootstrap_config=fastapi_config)
3233
application = bootstrapper.bootstrap()
3334
test_client = TestClient(application)
3435

3536
logger.info("testing logging", key="value")
3637

3738
try:
38-
response = test_client.get(health_checks_path)
39+
response = test_client.get(fastapi_config.health_checks_path)
3940
assert response.status_code == status.HTTP_200_OK
4041
assert response.json() == {"health_status": True, "service_name": "microservice", "service_version": "2.0.0"}
4142

42-
response = test_client.get(prometheus_metrics_path)
43+
response = test_client.get(fastapi_config.prometheus_metrics_path)
4344
assert response.status_code == status.HTTP_200_OK
4445
assert response.text
4546
finally:
4647
bootstrapper.teardown()
4748

4849

4950
def test_fastapi_bootstrapper_not_ready() -> None:
50-
import_checker.is_fastapi_installed = False
51-
try:
52-
with pytest.raises(RuntimeError, match="fastapi is not installed"):
53-
FastAPIBootstrapper(bootstrap_config=FastAPIConfig())
54-
finally:
55-
import_checker.is_fastapi_installed = True
51+
with emulate_package_missing("fastapi"), pytest.raises(RuntimeError, match="fastapi is not installed"):
52+
FastAPIBootstrapper(bootstrap_config=FastAPIConfig())
53+
54+
55+
@pytest.mark.parametrize(
56+
"package_name",
57+
[
58+
"opentelemetry",
59+
"sentry_sdk",
60+
"structlog",
61+
"prometheus_fastapi_instrumentator",
62+
],
63+
)
64+
def test_fastapi_bootstrapper_with_missing_instrument_dependency(
65+
fastapi_config: FastAPIConfig, package_name: str
66+
) -> None:
67+
with emulate_package_missing(package_name), pytest.warns(UserWarning, match=package_name):
68+
FastAPIBootstrapper(bootstrap_config=fastapi_config)

tests/test_faststream_bootstrap.py

Lines changed: 48 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1+
import typing
2+
13
import pytest
24
import structlog
5+
from faststream.broker.core.usecase import BrokerUsecase
36
from faststream.redis import RedisBroker, TestRedisBroker
47
from faststream.redis.opentelemetry import RedisTelemetryMiddleware
58
from faststream.redis.prometheus import RedisPrometheusMiddleware
69
from opentelemetry.sdk.trace.export import ConsoleSpanExporter
710
from starlette import status
811
from starlette.testclient import TestClient
912

10-
from lite_bootstrap import FastStreamBootstrapper, FastStreamConfig, import_checker
11-
from tests.conftest import CustomInstrumentor
13+
from lite_bootstrap import FastStreamBootstrapper, FastStreamConfig
14+
from tests.conftest import CustomInstrumentor, emulate_package_missing
1215

1316

1417
logger = structlog.getLogger(__name__)
@@ -19,73 +22,68 @@ def broker() -> RedisBroker:
1922
return RedisBroker()
2023

2124

22-
async def test_faststream_bootstrap(broker: RedisBroker) -> None:
23-
prometheus_metrics_path = "/custom-metrics/"
24-
health_check_path = "/custom-health/"
25-
bootstrapper = FastStreamBootstrapper(
26-
bootstrap_config=FastStreamConfig(
27-
broker=broker,
28-
service_name="microservice",
29-
service_version="2.0.0",
30-
service_environment="test",
31-
service_debug=False,
32-
opentelemetry_endpoint="otl",
33-
opentelemetry_instrumentors=[CustomInstrumentor()],
34-
opentelemetry_span_exporter=ConsoleSpanExporter(),
35-
opentelemetry_middleware_cls=RedisTelemetryMiddleware,
36-
prometheus_metrics_path=prometheus_metrics_path,
37-
prometheus_middleware_cls=RedisPrometheusMiddleware,
38-
sentry_dsn="https://testdsn@localhost/1",
39-
health_checks_path=health_check_path,
40-
logging_buffer_capacity=0,
41-
),
25+
def build_faststream_config(broker: BrokerUsecase[typing.Any, typing.Any] | None = None) -> FastStreamConfig:
26+
return FastStreamConfig(
27+
service_name="microservice",
28+
service_version="2.0.0",
29+
service_environment="test",
30+
service_debug=False,
31+
opentelemetry_endpoint="otl",
32+
opentelemetry_instrumentors=[CustomInstrumentor()],
33+
opentelemetry_span_exporter=ConsoleSpanExporter(),
34+
opentelemetry_middleware_cls=RedisTelemetryMiddleware,
35+
prometheus_metrics_path="/custom-metrics/",
36+
prometheus_middleware_cls=RedisPrometheusMiddleware,
37+
sentry_dsn="https://testdsn@localhost/1",
38+
health_checks_path="/custom-health/",
39+
logging_buffer_capacity=0,
40+
broker=broker,
4241
)
42+
43+
44+
async def test_faststream_bootstrap(broker: RedisBroker) -> None:
45+
bootstrap_config = build_faststream_config(broker=broker)
46+
bootstrapper = FastStreamBootstrapper(bootstrap_config=bootstrap_config)
4347
application = bootstrapper.bootstrap()
4448
test_client = TestClient(app=application)
4549

4650
logger.info("testing logging", key="value")
4751

4852
async with TestRedisBroker(broker):
49-
response = test_client.get(health_check_path)
53+
response = test_client.get(bootstrap_config.health_checks_path)
5054
assert response.status_code == status.HTTP_200_OK
5155
assert response.json() == {"health_status": True, "service_name": "microservice", "service_version": "2.0.0"}
5256

53-
response = test_client.get(prometheus_metrics_path)
57+
response = test_client.get(bootstrap_config.prometheus_metrics_path)
5458
assert response.status_code == status.HTTP_200_OK
5559

5660

5761
async def test_faststream_bootstrap_health_check_wo_broker() -> None:
58-
health_check_path = "/custom-health-check-path"
59-
bootstrapper = FastStreamBootstrapper(
60-
bootstrap_config=FastStreamConfig(
61-
service_name="microservice",
62-
service_version="2.0.0",
63-
service_environment="test",
64-
service_debug=False,
65-
opentelemetry_endpoint="otl",
66-
opentelemetry_instrumentors=[CustomInstrumentor()],
67-
opentelemetry_span_exporter=ConsoleSpanExporter(),
68-
opentelemetry_middleware_cls=RedisTelemetryMiddleware,
69-
prometheus_middleware_cls=RedisPrometheusMiddleware,
70-
sentry_dsn="https://testdsn@localhost/1",
71-
health_checks_path=health_check_path,
72-
logging_buffer_capacity=0,
73-
),
74-
)
62+
bootstrap_config = build_faststream_config()
63+
bootstrapper = FastStreamBootstrapper(bootstrap_config=bootstrap_config)
7564
application = bootstrapper.bootstrap()
7665
test_client = TestClient(app=application)
7766

78-
response = test_client.get(health_check_path)
67+
response = test_client.get(bootstrap_config.health_checks_path)
7968
assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR
8069
assert response.text == "Service is unhealthy"
8170

8271

8372
def test_faststream_bootstrapper_not_ready() -> None:
84-
import_checker.is_faststream_installed = False
85-
try:
86-
with pytest.raises(RuntimeError, match="faststream is not installed"):
87-
FastStreamBootstrapper(
88-
bootstrap_config=FastStreamConfig(),
89-
)
90-
finally:
91-
import_checker.is_faststream_installed = True
73+
with emulate_package_missing("faststream"), pytest.raises(RuntimeError, match="faststream is not installed"):
74+
FastStreamBootstrapper(bootstrap_config=FastStreamConfig())
75+
76+
77+
@pytest.mark.parametrize(
78+
"package_name",
79+
[
80+
"opentelemetry",
81+
"sentry_sdk",
82+
"structlog",
83+
"prometheus_client",
84+
],
85+
)
86+
def test_faststream_bootstrapper_with_missing_instrument_dependency(broker: RedisBroker, package_name: str) -> None:
87+
bootstrap_config = build_faststream_config(broker=broker)
88+
with emulate_package_missing(package_name), pytest.warns(UserWarning, match=package_name):
89+
FastStreamBootstrapper(bootstrap_config=bootstrap_config)

tests/test_free_bootstrap.py

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,26 @@
33
from opentelemetry.sdk.trace.export import ConsoleSpanExporter
44

55
from lite_bootstrap import FreeBootstrapper, FreeBootstrapperConfig
6-
from tests.conftest import CustomInstrumentor
6+
from tests.conftest import CustomInstrumentor, emulate_package_missing
77

88

99
logger = structlog.getLogger(__name__)
1010

1111

12-
def test_free_bootstrap() -> None:
13-
bootstrapper = FreeBootstrapper(
14-
bootstrap_config=FreeBootstrapperConfig(
15-
service_debug=False,
16-
opentelemetry_endpoint="otl",
17-
opentelemetry_instrumentors=[CustomInstrumentor()],
18-
opentelemetry_span_exporter=ConsoleSpanExporter(),
19-
sentry_dsn="https://testdsn@localhost/1",
20-
logging_buffer_capacity=0,
21-
),
12+
@pytest.fixture
13+
def free_bootstrapper_config() -> FreeBootstrapperConfig:
14+
return FreeBootstrapperConfig(
15+
service_debug=False,
16+
opentelemetry_endpoint="otl",
17+
opentelemetry_instrumentors=[CustomInstrumentor()],
18+
opentelemetry_span_exporter=ConsoleSpanExporter(),
19+
sentry_dsn="https://testdsn@localhost/1",
20+
logging_buffer_capacity=0,
2221
)
22+
23+
24+
def test_free_bootstrap(free_bootstrapper_config: FreeBootstrapperConfig) -> None:
25+
bootstrapper = FreeBootstrapper(bootstrap_config=free_bootstrapper_config)
2326
bootstrapper.bootstrap()
2427
try:
2528
logger.info("testing logging", key="value")
@@ -36,3 +39,18 @@ def test_free_bootstrap_logging_not_ready() -> None:
3639
sentry_dsn="https://testdsn@localhost/1",
3740
),
3841
)
42+
43+
44+
@pytest.mark.parametrize(
45+
"package_name",
46+
[
47+
"opentelemetry",
48+
"sentry_sdk",
49+
"structlog",
50+
],
51+
)
52+
def test_free_bootstrapper_with_missing_instrument_dependency(
53+
free_bootstrapper_config: FreeBootstrapperConfig, package_name: str
54+
) -> None:
55+
with emulate_package_missing(package_name), pytest.warns(UserWarning, match=package_name):
56+
FreeBootstrapper(bootstrap_config=free_bootstrapper_config)

0 commit comments

Comments
 (0)
0