reuse-surface/tests/test_stats.py

175 lines
5.7 KiB
Python
Raw Normal View History

from __future__ import annotations
from pathlib import Path
from reuse_surface.stats import (
collect_roster_stats,
collect_stats,
format_roster_stats_markdown,
format_stats_markdown,
)
def test_collect_stats_on_repo_root():
root = Path(__file__).resolve().parent.parent
stats = collect_stats(root)
assert stats["capability_count"] == 2
assert stats["index_present"] is True
assert "discovery" in stats["histograms"]
def test_format_stats_markdown_contains_count():
root = Path(__file__).resolve().parent.parent
text = format_stats_markdown(collect_stats(root))
assert "Capabilities:" in text
assert "2" in text
def test_collect_roster_stats_federation_ready():
root = Path(__file__).resolve().parent.parent
roster = root / "registry/federation/local-repo-roster.yaml"
stats = collect_roster_stats(roster, federation_ready=True)
assert stats["counts"]["total"] == 62
assert stats["counts"]["established"] == 62
assert "federation_readiness" in stats
text = format_roster_stats_markdown(stats)
REUSE-WP-0019-T06: hub freshness monitoring, docs, close workplan reuse_surface/stats.py: _hub_summary() now reports composed_at, stale, age_days, freshness_threshold_days (REUSE_SURFACE_FRESHNESS_DAYS env, default 7), and a computed stale_warning. New hub_client.hub_federated() backs it. format_stats_markdown surfaces a STALE marker when triggered. .forgejo/workflows/ci.yml: new informational (non-failing) hub freshness check against the live production hub on every push -- prints a ::warning:: annotation when stale, never fails the build. docs/RegistryFederation.md: new section tying together the webhook (T02), scheduled fallback (T03), and freshness visibility (T06) into one explanation. docs/deploy/reuse-kubernetes.md: updated for the T03 Forgejo migration and the now-automated image.yaml build; image promotion checklist updated for the known /health ingress bug (verify via /v1/repos or /v1/federated instead). 14 new pytest cases, 173 total pass. Live-verified against production: reuse-surface stats correctly showed composed_at/age_days for the real federated index. Separately discovered and confirmed (via a live signed webhook test) that reuse-surface-env moving to ExternalSecret/OpenBao custody (railiance-apps commit 706f6c7, found while updating these docs) did not break the T02/T03 webhook -- the synced value still matches what the hub actually uses. REUSE-WP-0019 is now fully complete (T01-T06). SCOPE.md and docs/IntentScopeGapAnalysis.md updated to reflect closure. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-08 00:09:58 +02:00
assert "publish pass ratio" in text
# --- T06: hub freshness (composed_at age + stale flag) ---
from datetime import datetime, timedelta, timezone
from reuse_surface.stats import _composed_at_age_days, _freshness_days, _hub_summary
def test_hub_summary_includes_freshness_fields(monkeypatch):
monkeypatch.setenv("REUSE_SURFACE_URL", "http://example.invalid")
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
monkeypatch.setattr(
"reuse_surface.hub_client.hub_list",
lambda base_url=None: (200, {"count": 3, "repos": [{"enabled": True}] * 3}),
)
monkeypatch.setattr(
"reuse_surface.hub_client.hub_federated",
lambda base_url=None: (200, {"composed_at": now, "stale": False}),
)
summary = _hub_summary(None)
assert summary["composed_at"] == now
assert summary["stale"] is False
assert summary["age_days"] is not None
assert summary["age_days"] < 1
assert summary["stale_warning"] is False
def test_hub_summary_stale_warning_from_age(monkeypatch):
monkeypatch.setenv("REUSE_SURFACE_URL", "http://example.invalid")
old = (datetime.now(timezone.utc) - timedelta(days=10)).strftime("%Y-%m-%dT%H:%M:%SZ")
monkeypatch.setattr(
"reuse_surface.hub_client.hub_list",
lambda base_url=None: (200, {"count": 1, "repos": [{"enabled": True}]}),
)
monkeypatch.setattr(
"reuse_surface.hub_client.hub_federated",
lambda base_url=None: (200, {"composed_at": old, "stale": False}),
)
summary = _hub_summary(None)
assert summary["age_days"] > 7
assert summary["stale_warning"] is True
def test_hub_summary_stale_warning_from_flag(monkeypatch):
monkeypatch.setenv("REUSE_SURFACE_URL", "http://example.invalid")
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
monkeypatch.setattr(
"reuse_surface.hub_client.hub_list",
lambda base_url=None: (200, {"count": 1, "repos": [{"enabled": True}]}),
)
monkeypatch.setattr(
"reuse_surface.hub_client.hub_federated",
lambda base_url=None: (200, {"composed_at": now, "stale": True}),
)
summary = _hub_summary(None)
assert summary["stale_warning"] is True
def test_hub_summary_handles_null_composed_at(monkeypatch):
monkeypatch.setenv("REUSE_SURFACE_URL", "http://example.invalid")
monkeypatch.setattr(
"reuse_surface.hub_client.hub_list",
lambda base_url=None: (200, {"count": 0, "repos": []}),
)
monkeypatch.setattr(
"reuse_surface.hub_client.hub_federated",
lambda base_url=None: (200, {"composed_at": None, "stale": False}),
)
summary = _hub_summary(None)
assert summary["age_days"] is None
assert summary["stale_warning"] is False
def test_hub_summary_degrades_when_federated_unreachable(monkeypatch):
monkeypatch.setenv("REUSE_SURFACE_URL", "http://example.invalid")
monkeypatch.setattr(
"reuse_surface.hub_client.hub_list",
lambda base_url=None: (200, {"count": 1, "repos": [{"enabled": True}]}),
)
def _raise(base_url=None):
import urllib.error
raise urllib.error.URLError("no route")
monkeypatch.setattr("reuse_surface.hub_client.hub_federated", _raise)
summary = _hub_summary(None)
assert summary["configured"] is True
assert "composed_at" not in summary
def test_composed_at_age_days_none_when_missing():
assert _composed_at_age_days(None) is None
def test_composed_at_age_days_none_when_malformed():
assert _composed_at_age_days("not-a-timestamp") is None
def test_freshness_days_default():
assert _freshness_days() == 7
def test_freshness_days_env_override(monkeypatch):
monkeypatch.setenv("REUSE_SURFACE_FRESHNESS_DAYS", "3")
assert _freshness_days() == 3
def test_freshness_days_env_invalid_falls_back(monkeypatch):
monkeypatch.setenv("REUSE_SURFACE_FRESHNESS_DAYS", "not-a-number")
assert _freshness_days() == 7
def test_format_stats_markdown_shows_stale_warning():
from reuse_surface.stats import format_stats_markdown
stats = {
"repo_root": "/tmp/x",
"capability_count": 0,
"registry_present": True,
"index_present": True,
"sources_present": True,
"reliability": {"r0_r2": 0, "r3_plus": 0},
"histograms": {},
"vector_drift": [],
"hub": {
"configured": True,
"registration_count": 1,
"enabled_count": 1,
"composed_at": "2020-01-01T00:00:00Z",
"stale": False,
"age_days": 100.0,
"freshness_threshold_days": 7,
"stale_warning": True,
},
}
text = format_stats_markdown(stats)
assert "STALE" in text