diff --git a/tests/test_jenkins_build_weather.py b/tests/test_jenkins_build_weather.py index 8b9c0ab..2e3eb5f 100644 --- a/tests/test_jenkins_build_weather.py +++ b/tests/test_jenkins_build_weather.py @@ -4,6 +4,7 @@ from datetime import datetime, timezone import types import httpx +import pytest from prometheus_client import REGISTRY from ariadne.services import jenkins_build_weather as weather_module @@ -225,3 +226,100 @@ def test_fetch_jobs_flattens_folder_jobs(monkeypatch) -> None: assert jobs[0].status == "success" assert jobs[0].last_duration_seconds == 1.0 assert datetime.fromtimestamp(jobs[0].last_run_ts, tz=timezone.utc).year == 2024 + + +def test_weather_helper_edges(monkeypatch) -> None: + assert weather_module._metric_number(True) == 0.0 + assert weather_module._metric_number(object()) == 0.0 + assert weather_module._millis_to_seconds(0) == 0.0 + + monkeypatch.setattr( + weather_module, + "settings", + types.SimpleNamespace(jenkins_api_user=" user ", jenkins_api_token=" token "), + ) + assert weather_module._jenkins_auth() == ("user", "token") + + assert weather_module._jenkins_status({"color": "blue_anime"}) == "running" + assert weather_module._jenkins_status({"color": "green"}) == "success" + assert weather_module._jenkins_status({"color": "yellow"}) == "failure" + assert weather_module._jenkins_status({}) == "unknown" + + assert weather_module._health_score({"healthReport": ["bad"]}, "success") == 100.0 + assert weather_module._health_score({}, "running") == 60.0 + assert weather_module._health_score({}, "failure") == 10.0 + assert weather_module._health_score({}, "unknown") == -1.0 + + assert weather_module._weather_icon(-1) == "❔" + assert weather_module._weather_icon(60) == "⛅" + assert weather_module._weather_icon(20) == "🌧️" + + +def test_flatten_parse_and_fetch_edges(monkeypatch) -> None: + flattened = weather_module._flatten_jobs( + [ + "bad", + {"name": ""}, + {"name": "folder", "jobs": [{"name": "child", "url": "https://ci/job/child/", "lastBuild": {"result": "SUCCESS"}}]}, + {"name": "folder-without-build", "jobs": []}, + ] + ) + assert [job["name"] for job in flattened] == ["folder/child", "folder-without-build"] + assert weather_module._parse_job({"name": "missing-url"}) is None + + monkeypatch.setattr(weather_module, "settings", _dummy_settings(base_url="")) + assert weather_module._fetch_jobs() == [] + + captured = {} + + class CapturingClient(_DummyClient): + def __init__(self, **kwargs): + captured.update(kwargs) + super().__init__({"jobs": [{"name": "bad"}]}) + + monkeypatch.setattr( + weather_module, + "settings", + types.SimpleNamespace( + jenkins_base_url="https://ci.bstein.dev/", + jenkins_api_user="user", + jenkins_api_token="token", + jenkins_api_timeout_sec=7.0, + ), + ) + monkeypatch.setattr(weather_module.httpx, "Client", CapturingClient) + assert weather_module._fetch_jobs() == [] + assert captured["auth"] == ("user", "token") + assert captured["timeout"] == 7.0 + + class NonObjectClient(_DummyClient): + def __init__(self, **kwargs): + super().__init__(["bad"]) + + monkeypatch.setattr(weather_module.httpx, "Client", NonObjectClient) + with pytest.raises(ValueError, match="non-object"): + weather_module._fetch_jobs() + + +def test_remove_missing_series_ignores_missing_metric_labels(monkeypatch) -> None: + class MissingMetric: + def remove(self, *labels): + raise KeyError(labels) + + weather_module._JOB_SERIES = {("old", "https://ci/job/old/", "☀️")} + monkeypatch.setattr(weather_module, "_JOB_METRICS", (MissingMetric(),)) + + weather_module._remove_missing_series(set()) + + assert weather_module._JOB_SERIES == set() + + +def test_collect_jenkins_build_weather_records_error(monkeypatch) -> None: + monkeypatch.setattr(weather_module, "settings", _dummy_settings()) + before = _metric_value("ariadne_jenkins_build_weather_runs_total", {"status": "error"}) or 0.0 + monkeypatch.setattr(weather_module, "_fetch_jobs", lambda: (_ for _ in ()).throw(RuntimeError("jenkins down"))) + + with pytest.raises(RuntimeError, match="jenkins down"): + weather_module.collect_jenkins_build_weather() + + assert (_metric_value("ariadne_jenkins_build_weather_runs_total", {"status": "error"}) or 0.0) == before + 1