- Create StepTracker context manager in new report.py module - Track each step of lifecycle operations (install, update, start, stop, enable, disable, status, remove) with begin/done markers - On success: report lists all completed steps with ✓ icons - On failure: report shows failed step (✗), completed steps before failure (✓), and pending steps that never started (○) - Add translations for report header, status labels, and registry step names in all 5 supported languages (EN/BG/DE/RU/ZH) - 105 tests, 100% coverage, pyright clean, ruff clean
103 lines
3.3 KiB
Python
103 lines
3.3 KiB
Python
"""Unit tests for the operation report tracker."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from gitea_runner_manager.exceptions import AnsibleError
|
|
from gitea_runner_manager.report import Step, StepTracker, track_steps
|
|
|
|
|
|
class TestStep:
|
|
def test_init(self) -> None:
|
|
step = Step("test")
|
|
assert step.name == "test"
|
|
assert step.status == "pending"
|
|
|
|
|
|
class TestStepTracker:
|
|
def test_begin(self) -> None:
|
|
tracker = StepTracker()
|
|
tracker.begin("step1")
|
|
assert len(tracker.steps) == 1
|
|
assert tracker.steps[0].name == "step1"
|
|
assert tracker.steps[0].status == "in_progress"
|
|
|
|
def test_done(self) -> None:
|
|
tracker = StepTracker()
|
|
tracker.begin("step1")
|
|
tracker.done()
|
|
assert tracker.steps[0].status == "completed"
|
|
|
|
def test_done_no_steps(self) -> None:
|
|
tracker = StepTracker()
|
|
tracker.done() # should not raise
|
|
assert tracker.steps == []
|
|
|
|
def test_done_last_not_in_progress(self) -> None:
|
|
tracker = StepTracker()
|
|
tracker.begin("step1")
|
|
tracker.done()
|
|
tracker.done() # second done is a no-op
|
|
assert tracker.steps[0].status == "completed"
|
|
|
|
|
|
class TestTrackSteps:
|
|
def test_success(self, capsys: pytest.CaptureFixture[str]) -> None:
|
|
with track_steps() as tracker:
|
|
tracker.begin("step1")
|
|
tracker.done()
|
|
tracker.begin("step2")
|
|
tracker.done()
|
|
|
|
captured = capsys.readouterr()
|
|
assert "Operation Report" in captured.out
|
|
assert "step1" in captured.out
|
|
assert "step2" in captured.out
|
|
assert "✓" in captured.out
|
|
assert "completed" in captured.out
|
|
|
|
def test_failure_marks_step(self, capsys: pytest.CaptureFixture[str]) -> None:
|
|
with pytest.raises(AnsibleError, match="fail"):
|
|
with track_steps() as tracker:
|
|
tracker.begin("step1")
|
|
tracker.done()
|
|
tracker.begin("step2")
|
|
raise AnsibleError("fail")
|
|
|
|
captured = capsys.readouterr()
|
|
assert "Operation Report" in captured.out
|
|
assert "step1" in captured.out
|
|
assert "step2" in captured.out
|
|
assert "✓" in captured.out
|
|
assert "✗" in captured.out
|
|
assert "completed" in captured.out
|
|
assert "failed" in captured.out
|
|
|
|
def test_pending_shown_on_failure(self, capsys: pytest.CaptureFixture[str]) -> None:
|
|
with pytest.raises(AnsibleError, match="fail"):
|
|
with track_steps() as tracker:
|
|
tracker.begin("step1")
|
|
raise AnsibleError("fail")
|
|
|
|
captured = capsys.readouterr()
|
|
assert "✗" in captured.out
|
|
assert "failed" in captured.out
|
|
|
|
def test_empty_report(self, capsys: pytest.CaptureFixture[str]) -> None:
|
|
with track_steps():
|
|
pass
|
|
|
|
captured = capsys.readouterr()
|
|
assert "Operation Report" in captured.out
|
|
|
|
def test_translated_report(self, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]) -> None:
|
|
monkeypatch.setenv("GRM_LANG", "bg")
|
|
with track_steps() as tracker:
|
|
tracker.begin("step1")
|
|
tracker.done()
|
|
|
|
captured = capsys.readouterr()
|
|
assert "Отчет за операцията" in captured.out
|
|
assert "завършено" in captured.out
|