Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions collector/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ addopts = "-q --doctest-modules"
# Coverage column reports against, and it is deliberately narrower than
# jq_local_code_lines, which counts every tracked source file in the repo.
source = ["jq_collector"]
# Both arms of every branch, not just every line: an `if` whose false side
# never runs is 100% line-covered and still untested. fail_under below then
# holds lines and branches to the same floor.
branch = true

[tool.coverage.report]
# The package is fully covered; this keeps it that way. pytest-cov reads it, so
Expand Down
15 changes: 15 additions & 0 deletions collector/tests/test_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ def test_the_newest_default_branch_artifact_wins_not_the_newest_overall(make_cli
assert client.coverage_artifact("o/r", "main") == 2


def test_an_older_artifact_listed_after_a_newer_one_does_not_win(make_client):
"""Newest wins by created_at, not by where it sits in the listing."""
client = make_client(
{
ARTIFACTS: {
"artifacts": [
artifact(2, "main", "2026-08-27T04:07:41Z"), # newest on main
artifact(1, "main", "2026-08-26T04:07:41Z"), # older, listed after
]
}
}
)
assert client.coverage_artifact("o/r", "main") == 2


def test_expired_and_unrelated_artifacts_are_ignored(make_client):
client = make_client(
{
Expand Down
17 changes: 17 additions & 0 deletions collector/tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,23 @@ def test_main_warns_when_there_is_no_token(monkeypatch, caplog):
assert "no GITHUB_TOKEN" in caplog.text


def test_main_does_not_warn_when_a_token_is_set(monkeypatch, caplog):
"""The warning is for the deployment that needs it; a set token is silent."""
monkeypatch.setattr(entry, "_refresh_remote", lambda *_: None)
monkeypatch.setattr(entry, "_tick_local", lambda *_: None)
monkeypatch.setattr(entry, "start_http_server", lambda _port: None)
monkeypatch.setattr(entry.REGISTRY, "register", lambda _c: None)
monkeypatch.setattr(entry.signal, "signal", lambda _sig, handler: handler(_sig, None))

cfg = Config()
object.__setattr__(cfg, "token", "ghp_test")
monkeypatch.setattr(entry, "Config", lambda: cfg)

entry.main()

assert "no GITHUB_TOKEN" not in caplog.text


def test_main_starts_a_loop_per_source_and_shuts_them_down(monkeypatch):
started: list[str] = []
real_thread = threading.Thread
Expand Down
38 changes: 38 additions & 0 deletions collector/tests/test_workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,23 @@ def test_latest_is_by_completion_not_feed_order(make_client):
assert c.latest_runs("o/r", "main")[0]["conclusion"] == "failure"


def test_an_older_run_later_in_the_feed_does_not_replace_a_newer_one(make_client):
"""The mirror of the case above: when the feed does happen to put the newer
run first, the older one after it must not win just by coming last."""
c = make_client(
{
WFS: {"workflows": [workflow(1, "CI")]},
RUNS: {
"workflow_runs": [
run(1, "CI", "failure", "2026-08-01T05:39:00Z"),
run(1, "CI", "success", "2026-08-01T04:09:00Z"),
]
},
}
)
assert c.latest_runs("o/r", "main")[0]["conclusion"] == "failure"


def test_workflow_missing_from_the_feed_is_fetched_directly(make_client):
"""The feed's first page is dominated by frequent workflows. cvxgrp/simulator
has 2406 runs on main and only 6 of its 23 workflows appear in the first 100;
Expand Down Expand Up @@ -145,6 +162,27 @@ def test_two_active_workflows_sharing_a_name_get_distinct_labels(make_client):
assert len(names) == len(set(names)), f"labels collide: {names}"


def test_a_shared_name_with_no_path_to_fall_back_on_keeps_its_name(make_client):
"""Only a workflow that has a path can be relabelled by it. One without
keeps its display name rather than being blanked, and the other still
moves to its path, so the labels stay distinct."""
pathless = workflow(1, "CI")
del pathless["path"]
c = make_client(
{
WFS: {"workflows": [pathless, workflow(2, "CI", path=".github/workflows/b.yml")]},
RUNS: {
"workflow_runs": [
run(1, "CI", "success", "2026-08-01T00:00:00Z"),
run(2, "CI", "failure", "2026-08-01T00:00:00Z"),
]
},
}
)
got = {r["_name"]: r["conclusion"] for r in c.latest_runs("o/r", "main")}
assert got == {"CI": "success", ".github/workflows/b.yml": "failure"}


def test_cancelled_run_falls_back_to_the_last_real_verdict(make_client):
"""Stopping a job by hand, or a concurrency group killing it when the next
push lands, is not a failure. The workflow keeps its last conclusive run."""
Expand Down
Loading