from pathlib import Path import pytest NGINX_CONFIG = """server { listen 80; server_name mo.wooo.work; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name mo.wooo.work; location / { proxy_pass http://127.0.0.1:5003; } } """ NGINX_FRAGMENT = """location = /metrics { allow 127.0.0.1; allow 172.16.0.0/12; deny all; proxy_pass http://127.0.0.1:5003/metrics; } """ PROMETHEUS_CONFIG = """global: scrape_interval: 60s scrape_configs: - job_name: existing static_configs: - targets: ['127.0.0.1:9090'] """ PROMETHEUS_SNIPPET = """ - job_name: 'ewoooc-app' scheme: http metrics_path: /metrics static_configs: - targets: ['172.20.0.1:19191'] """ NGINX_BRIDGE = """server { listen 172.20.0.1:19191; server_name ewooooc-metrics.internal; location = /metrics { allow 172.16.0.0/12; deny all; proxy_pass https://192.168.0.188/metrics; } } """ def test_render_nginx_config_targets_only_tls_server_and_is_idempotent(): from services.metrics_edge_controlled_apply_service import render_nginx_config rendered = render_nginx_config(NGINX_CONFIG, NGINX_FRAGMENT) second = render_nginx_config(rendered, NGINX_FRAGMENT) assert rendered == second assert rendered.count("location = /metrics") == 1 assert rendered.index("listen 443") < rendered.index("location = /metrics") assert rendered.index("location = /metrics") < rendered.index("location / {") def test_render_prometheus_config_is_idempotent(): from services.metrics_edge_controlled_apply_service import render_prometheus_config rendered = render_prometheus_config(PROMETHEUS_CONFIG, PROMETHEUS_SNIPPET) second = render_prometheus_config(rendered, PROMETHEUS_SNIPPET) assert rendered == second assert rendered.count("job_name: 'ewoooc-app'") == 1 def test_render_standalone_nginx_bridge_is_idempotent(): from services.metrics_edge_controlled_apply_service import render_nginx_config rendered = render_nginx_config("", NGINX_BRIDGE) second = render_nginx_config(rendered, NGINX_BRIDGE) assert rendered == second assert rendered.count("listen 172.20.0.1:19191") == 1 def test_build_plan_is_no_write_and_commit_safe(tmp_path: Path): from services.metrics_edge_controlled_apply_service import build_metrics_edge_plan paths = { "nginx_config": tmp_path / "nginx.conf", "prometheus_config": tmp_path / "prometheus.yml", "nginx_fragment": tmp_path / "location.conf", "prometheus_snippet": tmp_path / "scrape.yml", } paths["nginx_config"].write_text(NGINX_CONFIG, encoding="utf-8") paths["prometheus_config"].write_text(PROMETHEUS_CONFIG, encoding="utf-8") paths["nginx_fragment"].write_text(NGINX_FRAGMENT, encoding="utf-8") paths["prometheus_snippet"].write_text(PROMETHEUS_SNIPPET, encoding="utf-8") plan = build_metrics_edge_plan( **paths, run_id="sec-p0-001-test", work_item_id="SEC-P0-001", ) assert plan["mode"] == "check" assert plan["nginx"]["changed"] is True assert plan["prometheus"]["changed"] is True assert paths["nginx_config"].read_text(encoding="utf-8") == NGINX_CONFIG def test_prometheus_write_preserves_bind_mount_inode(tmp_path: Path): from services.metrics_edge_controlled_apply_service import _inplace_write config = tmp_path / "prometheus.yml" config.write_text(PROMETHEUS_CONFIG, encoding="utf-8") inode_before = config.stat().st_ino _inplace_write(config, "global:\n scrape_interval: 30s\n") assert config.stat().st_ino == inode_before assert config.read_text(encoding="utf-8") == "global:\n scrape_interval: 30s\n" def test_prometheus_config_sha_detects_stale_container_mount(tmp_path: Path, monkeypatch): from services import metrics_edge_controlled_apply_service as service config = tmp_path / "prometheus.yml" config.write_text("candidate", encoding="utf-8") stale_sha = "0" * 64 monkeypatch.setattr( service, "_run", lambda _command: type("Completed", (), {"stdout": f"{stale_sha} config"})(), ) host_sha, container_sha = service._prometheus_config_sha(config) assert host_sha != container_sha assert container_sha == stale_sha def test_metrics_canary_requires_ewoooc_product_markers(): from services.metrics_edge_controlled_apply_service import _parse_metrics_canary valid = ( "momo_app_info 1\nmomo_app_health 1\nmomo_database_up 1" "\n__EWOOOC_HTTP_STATUS__:200" ) wrong_exporter = "fail2ban_total_failed 0\n__EWOOOC_HTTP_STATUS__:200" assert _parse_metrics_canary(valid) == ("200", True) assert _parse_metrics_canary(wrong_exporter) == ("200", False) def test_metrics_canary_waits_for_new_nginx_worker(monkeypatch): from services import metrics_edge_controlled_apply_service as service outputs = iter([ "forbidden\n__EWOOOC_HTTP_STATUS__:403", ( "momo_app_info 1\nmomo_app_health 1\nmomo_database_up 1" "\n__EWOOOC_HTTP_STATUS__:200" ), ]) monkeypatch.setattr( service, "_run", lambda _command: type("Completed", (), {"stdout": next(outputs)})(), ) monkeypatch.setattr(service.time, "sleep", lambda _seconds: None) assert service._wait_metrics_canary(["curl"], 10) == ("200", True, 2) def test_target_health_rejects_stale_scrape_url(): from services.metrics_edge_controlled_apply_service import _target_health_from_payload payload = { "data": { "activeTargets": [ { "labels": {"job": "ewoooc-app"}, "scrapeUrl": "http://172.20.0.1:9191/metrics", "health": "up", }, { "labels": {"job": "ewoooc-app"}, "scrapeUrl": "http://172.20.0.1:19191/metrics", "health": "down", }, ] } } health = _target_health_from_payload( payload, "http://172.20.0.1:19191/metrics", ) assert health == "down" def test_prometheus_identity_verifier_requires_same_image_and_data_volume(): from services.metrics_edge_controlled_apply_service import ( _prometheus_identity_preserved, ) before = {"image_id": "image-a", "data_volume": "volume-a"} assert _prometheus_identity_preserved(before, dict(before)) is True assert _prometheus_identity_preserved( before, {"image_id": "image-b", "data_volume": "volume-a"}, ) is False assert _prometheus_identity_preserved( before, {"image_id": "image-a", "data_volume": "volume-b"}, ) is False def test_render_rejects_incomplete_templates(): from services.metrics_edge_controlled_apply_service import ( render_nginx_config, render_prometheus_config, ) with pytest.raises(ValueError, match="incomplete"): render_nginx_config(NGINX_CONFIG, "location = /metrics {}") with pytest.raises(ValueError, match="incomplete"): render_prometheus_config(PROMETHEUS_CONFIG, "job_name: other")