diff --git a/tests/instruments/test_cors_instrument.py b/tests/instruments/test_cors_instrument.py new file mode 100644 index 0000000..7ea6e98 --- /dev/null +++ b/tests/instruments/test_cors_instrument.py @@ -0,0 +1,43 @@ +from lite_bootstrap.instruments.cors_instrument import CorsConfig, CorsInstrument + + +def test_cors_instrument_not_ready_without_origins_or_regex() -> None: + instrument = CorsInstrument(bootstrap_config=CorsConfig()) + assert not instrument.is_ready() + assert instrument.not_ready_message == "cors_allowed_origins or cors_allowed_origin_regex must be provided" + + +def test_cors_instrument_ready_with_origins() -> None: + instrument = CorsInstrument(bootstrap_config=CorsConfig(cors_allowed_origins=["http://test"])) + assert instrument.is_ready() + + +def test_cors_instrument_ready_with_regex() -> None: + instrument = CorsInstrument(bootstrap_config=CorsConfig(cors_allowed_origin_regex=r"https?://.*")) + assert instrument.is_ready() + + +def test_cors_instrument_ready_with_both() -> None: + instrument = CorsInstrument( + bootstrap_config=CorsConfig( + cors_allowed_origins=["http://test"], + cors_allowed_origin_regex=r"https?://.*", + ), + ) + assert instrument.is_ready() + + +def test_cors_instrument_config_defaults() -> None: + config = CorsConfig() + assert config.cors_allowed_origins == [] + assert config.cors_allowed_methods == [] + assert config.cors_allowed_headers == [] + assert config.cors_exposed_headers == [] + assert config.cors_allowed_credentials is False + assert config.cors_allowed_origin_regex is None + expected_max_age = 600 + assert config.cors_max_age == expected_max_age + + +def test_cors_check_dependencies() -> None: + assert CorsInstrument.check_dependencies() is True diff --git a/tests/instruments/test_healthchecks_instrument.py b/tests/instruments/test_healthchecks_instrument.py new file mode 100644 index 0000000..16e07a8 --- /dev/null +++ b/tests/instruments/test_healthchecks_instrument.py @@ -0,0 +1,45 @@ +from lite_bootstrap.instruments.healthchecks_instrument import HealthChecksConfig, HealthChecksInstrument + + +def test_healthchecks_instrument_ready_by_default() -> None: + instrument = HealthChecksInstrument(bootstrap_config=HealthChecksConfig()) + assert instrument.is_ready() + + +def test_healthchecks_instrument_not_ready_when_disabled() -> None: + instrument = HealthChecksInstrument(bootstrap_config=HealthChecksConfig(health_checks_enabled=False)) + assert not instrument.is_ready() + assert instrument.not_ready_message == "health_checks_enabled is False" + + +def test_healthchecks_render_data_default() -> None: + instrument = HealthChecksInstrument(bootstrap_config=HealthChecksConfig()) + data = instrument.render_health_check_data() + assert data == { + "service_version": "1.0.0", + "service_name": "micro-service", + "health_status": True, + } + + +def test_healthchecks_render_data_custom() -> None: + instrument = HealthChecksInstrument( + bootstrap_config=HealthChecksConfig(service_name="my-svc", service_version="2.0.0"), + ) + data = instrument.render_health_check_data() + assert data == { + "service_version": "2.0.0", + "service_name": "my-svc", + "health_status": True, + } + + +def test_healthchecks_config_defaults() -> None: + config = HealthChecksConfig() + assert config.health_checks_enabled is True + assert config.health_checks_path == "/health/" + assert config.health_checks_include_in_schema is False + + +def test_healthchecks_check_dependencies() -> None: + assert HealthChecksInstrument.check_dependencies() is True diff --git a/tests/instruments/test_prometheus_instrument.py b/tests/instruments/test_prometheus_instrument.py new file mode 100644 index 0000000..a802d3a --- /dev/null +++ b/tests/instruments/test_prometheus_instrument.py @@ -0,0 +1,35 @@ +from lite_bootstrap.instruments.prometheus_instrument import PrometheusConfig, PrometheusInstrument + + +def test_prometheus_instrument_ready_with_default_path() -> None: + instrument = PrometheusInstrument(bootstrap_config=PrometheusConfig()) + assert instrument.is_ready() + + +def test_prometheus_instrument_not_ready_with_empty_path() -> None: + instrument = PrometheusInstrument(bootstrap_config=PrometheusConfig(prometheus_metrics_path="")) + assert not instrument.is_ready() + assert instrument.not_ready_message == "prometheus_metrics_path is empty or not valid" + + +def test_prometheus_instrument_not_ready_with_invalid_path() -> None: + # No leading slash → invalid per is_valid_path regex. + instrument = PrometheusInstrument(bootstrap_config=PrometheusConfig(prometheus_metrics_path="metrics")) + assert not instrument.is_ready() + + +def test_prometheus_instrument_ready_with_custom_valid_path() -> None: + instrument = PrometheusInstrument( + bootstrap_config=PrometheusConfig(prometheus_metrics_path="/custom-metrics/"), + ) + assert instrument.is_ready() + + +def test_prometheus_config_defaults() -> None: + config = PrometheusConfig() + assert config.prometheus_metrics_path == "/metrics" + assert config.prometheus_metrics_include_in_schema is False + + +def test_prometheus_check_dependencies() -> None: + assert PrometheusInstrument.check_dependencies() is True diff --git a/tests/instruments/test_swagger_instrument.py b/tests/instruments/test_swagger_instrument.py new file mode 100644 index 0000000..10fee98 --- /dev/null +++ b/tests/instruments/test_swagger_instrument.py @@ -0,0 +1,17 @@ +from lite_bootstrap.instruments.swagger_instrument import SwaggerConfig, SwaggerInstrument + + +def test_swagger_instrument_ready_by_default() -> None: + instrument = SwaggerInstrument(bootstrap_config=SwaggerConfig()) + assert instrument.is_ready() + + +def test_swagger_config_defaults() -> None: + config = SwaggerConfig() + assert config.swagger_static_path == "/static" + assert config.swagger_path == "/docs" + assert config.swagger_offline_docs is False + + +def test_swagger_check_dependencies() -> None: + assert SwaggerInstrument.check_dependencies() is True diff --git a/tests/test_path.py b/tests/test_path.py new file mode 100644 index 0000000..8480cfb --- /dev/null +++ b/tests/test_path.py @@ -0,0 +1,38 @@ +import pytest + +from lite_bootstrap.helpers.path import is_valid_path + + +@pytest.mark.parametrize( + "path", + [ + "/metrics", + "/health/", + "/api/v1/users", + "/foo.bar", + "/foo_bar", + "/foo-bar", + "/a", + "/a/", + ], +) +def test_is_valid_path_accepts_valid(path: str) -> None: + assert is_valid_path(path) is True + + +@pytest.mark.parametrize( + "path", + [ + "", + "foo", + "foo/", + "/foo bar", + "/foo?bar", + "/foo#bar", + "/", + "//foo", + "/foo//bar", + ], +) +def test_is_valid_path_rejects_invalid(path: str) -> None: + assert is_valid_path(path) is False