Migrate all repos into monorepo context folders
Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)
Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
"""Unit tests for the Summary Reporter module."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from scripts.pat_manager.models import CheckResult, PatEntry, PatStatus, RotationResult
|
||||
from scripts.pat_manager.reporter import SummaryReporter
|
||||
|
||||
|
||||
def make_entry(service: str = "GitLab", token_name: str = "ci-token") -> PatEntry:
|
||||
"""Helper to create a PatEntry for testing."""
|
||||
return PatEntry(
|
||||
service=service,
|
||||
token_name=token_name,
|
||||
expiry_date="2025-08-15",
|
||||
renewal_method="auto" if service == "GitLab" else "manual",
|
||||
)
|
||||
|
||||
|
||||
def make_result(
|
||||
service: str = "GitLab",
|
||||
token_name: str = "ci-token",
|
||||
status: PatStatus = PatStatus.HEALTHY,
|
||||
days_remaining: int | None = 45,
|
||||
error_message: str | None = None,
|
||||
) -> CheckResult:
|
||||
"""Helper to create a CheckResult for testing."""
|
||||
entry = make_entry(service, token_name)
|
||||
return CheckResult(
|
||||
entry=entry,
|
||||
status=status,
|
||||
days_remaining=days_remaining,
|
||||
error_message=error_message,
|
||||
)
|
||||
|
||||
|
||||
class TestSummaryReporter:
|
||||
"""Tests for SummaryReporter.report()."""
|
||||
|
||||
def test_report_header(self) -> None:
|
||||
"""Report starts with the expected header."""
|
||||
reporter = SummaryReporter()
|
||||
report = reporter.report([], [])
|
||||
assert "=== PAT Lifecycle Check Summary ===" in report
|
||||
|
||||
def test_report_contains_table_headers(self) -> None:
|
||||
"""Report contains column headers."""
|
||||
reporter = SummaryReporter()
|
||||
results = [make_result()]
|
||||
report = reporter.report(results, [])
|
||||
assert "Service" in report
|
||||
assert "Token Name" in report
|
||||
assert "Status" in report
|
||||
assert "Details" in report
|
||||
|
||||
def test_report_one_healthy_pat(self) -> None:
|
||||
"""Report shows healthy PAT with days remaining."""
|
||||
reporter = SummaryReporter()
|
||||
results = [make_result(days_remaining=45)]
|
||||
report = reporter.report(results, [])
|
||||
assert "GitLab" in report
|
||||
assert "ci-token" in report
|
||||
assert "healthy" in report
|
||||
assert "45 days remaining" in report
|
||||
|
||||
def test_report_expiring_soon_pat(self) -> None:
|
||||
"""Report shows expiring soon PAT with days remaining."""
|
||||
reporter = SummaryReporter()
|
||||
results = [
|
||||
make_result(
|
||||
service="Jira",
|
||||
token_name="jira-api",
|
||||
status=PatStatus.EXPIRING_SOON,
|
||||
days_remaining=7,
|
||||
)
|
||||
]
|
||||
report = reporter.report(results, [])
|
||||
assert "Jira" in report
|
||||
assert "jira-api" in report
|
||||
assert "expiring soon" in report
|
||||
assert "7 days remaining" in report
|
||||
|
||||
def test_report_expired_pat(self) -> None:
|
||||
"""Report shows expired PAT with 0 days remaining."""
|
||||
reporter = SummaryReporter()
|
||||
results = [
|
||||
make_result(
|
||||
service="Confluence",
|
||||
token_name="confluence-bot",
|
||||
status=PatStatus.EXPIRED,
|
||||
days_remaining=0,
|
||||
)
|
||||
]
|
||||
report = reporter.report(results, [])
|
||||
assert "Confluence" in report
|
||||
assert "confluence-bot" in report
|
||||
assert "expired" in report
|
||||
assert "0 days remaining" in report
|
||||
|
||||
def test_report_check_failed_pat(self) -> None:
|
||||
"""Report shows check failed PAT with error message."""
|
||||
reporter = SummaryReporter()
|
||||
results = [
|
||||
make_result(
|
||||
service="OrgMyLife",
|
||||
token_name="orchestrator-key",
|
||||
status=PatStatus.CHECK_FAILED,
|
||||
days_remaining=None,
|
||||
error_message="Connection timeout",
|
||||
)
|
||||
]
|
||||
report = reporter.report(results, [])
|
||||
assert "OrgMyLife" in report
|
||||
assert "orchestrator-key" in report
|
||||
assert "check failed" in report
|
||||
assert "Connection timeout" in report
|
||||
|
||||
def test_report_multiple_pats(self) -> None:
|
||||
"""Report contains one line per PAT."""
|
||||
reporter = SummaryReporter()
|
||||
results = [
|
||||
make_result(service="GitLab", token_name="token-a", days_remaining=45),
|
||||
make_result(
|
||||
service="Jira",
|
||||
token_name="token-b",
|
||||
status=PatStatus.EXPIRING_SOON,
|
||||
days_remaining=7,
|
||||
),
|
||||
make_result(
|
||||
service="Confluence",
|
||||
token_name="token-c",
|
||||
status=PatStatus.EXPIRED,
|
||||
days_remaining=0,
|
||||
),
|
||||
]
|
||||
report = reporter.report(results, [])
|
||||
assert "token-a" in report
|
||||
assert "token-b" in report
|
||||
assert "token-c" in report
|
||||
|
||||
def test_report_no_rotation_section_when_empty(self) -> None:
|
||||
"""Report omits rotation section when no rotations occurred."""
|
||||
reporter = SummaryReporter()
|
||||
results = [make_result()]
|
||||
report = reporter.report(results, [])
|
||||
assert "Rotation Results" not in report
|
||||
|
||||
def test_report_includes_rotation_section(self) -> None:
|
||||
"""Report includes rotation section with successful rotations."""
|
||||
reporter = SummaryReporter()
|
||||
entry = make_entry("GitLab", "ci-pipeline-token")
|
||||
results = [make_result()]
|
||||
rotations = [
|
||||
RotationResult(
|
||||
success=True,
|
||||
new_token="glpat-new-value",
|
||||
new_expiry_date="2025-08-01",
|
||||
error_message=None,
|
||||
entry=entry,
|
||||
old_expiry_date="2025-07-01",
|
||||
)
|
||||
]
|
||||
report = reporter.report(results, rotations)
|
||||
assert "--- Rotation Results ---" in report
|
||||
assert "GitLab/ci-pipeline-token" in report
|
||||
assert "Rotated successfully" in report
|
||||
assert "old: 2025-07-01" in report
|
||||
assert "new: 2025-08-01" in report
|
||||
|
||||
def test_report_excludes_failed_rotations(self) -> None:
|
||||
"""Report rotation section only shows successful rotations."""
|
||||
reporter = SummaryReporter()
|
||||
results = [make_result()]
|
||||
rotations = [
|
||||
RotationResult(
|
||||
success=False,
|
||||
new_token=None,
|
||||
new_expiry_date=None,
|
||||
error_message="Rotation failed",
|
||||
entry=make_entry("GitLab", "failed-token"),
|
||||
old_expiry_date="2025-07-01",
|
||||
)
|
||||
]
|
||||
report = reporter.report(results, rotations)
|
||||
assert "Rotation Results" not in report
|
||||
|
||||
def test_report_empty_results(self) -> None:
|
||||
"""Report handles empty results list gracefully."""
|
||||
reporter = SummaryReporter()
|
||||
report = reporter.report([], [])
|
||||
assert "=== PAT Lifecycle Check Summary ===" in report
|
||||
Reference in New Issue
Block a user