"""Tests for muse annotate — CRDT-backed commit annotations. Tiers: 1. Unit — validators and helpers in isolation (no repo, no CLI) 2. Integration — store round-trip: write → annotate → read_commit 3. End-to-End — full CLI invocations via CliRunner 4. Security — injection, control chars, oversized inputs, path traversal 5. Stress — many sequential annotations, large inputs at limits 6. Performance — timing assertions on hot paths 7. Data Integrity — CRDT semantics (ORSet idempotency, GCounter monotone, LWW last-write, append-only notes, roundtrip fidelity) """ from __future__ import annotations import datetime import json import pathlib import time import pytest from tests.cli_test_helper import CliRunner cli = None # argparse migration — CliRunner ignores this arg from muse.cli.commands.annotate import ( _MAX_LABEL_LEN, _MAX_NOTE_LEN, _MAX_REVIEWER_LEN, _STATUS_VALUES, _validate_label, _validate_note, _validate_reviewer, _validate_score, _validate_status, ) from muse.core.ids import hash_commit, hash_snapshot from muse.core.commits import ( CommitRecord, read_commit, write_commit, ) from muse.core.paths import heads_dir, muse_dir runner = CliRunner() # --------------------------------------------------------------------------- # Shared fixtures # --------------------------------------------------------------------------- @pytest.fixture def repo(tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch) -> pathlib.Path: """Minimal Muse repo with a single commit on main.""" monkeypatch.chdir(tmp_path) dot_muse = muse_dir(tmp_path) dot_muse.mkdir() (dot_muse / "repo.json").write_text('{"repo_id":"test-repo"}') (dot_muse / "HEAD").write_text("ref: refs/heads/main") (dot_muse / "commits").mkdir() (dot_muse / "snapshots").mkdir() (dot_muse / "refs" / "heads").mkdir(parents=True) return tmp_path def _write_commit( root: pathlib.Path, message: str = "test commit", *, parent: str | None = None, ) -> CommitRecord: """Write a content-addressed CommitRecord and update the branch ref.""" committed_at = datetime.datetime(2026, 3, 1, tzinfo=datetime.timezone.utc) snap_id = hash_snapshot({}) parents = [parent] if parent else [] cid = hash_commit( parent_ids=parents, snapshot_id=snap_id, message=message, committed_at_iso=committed_at.isoformat(), author="test-author", ) record = CommitRecord( commit_id=cid, branch="main", snapshot_id=snap_id, message=message, committed_at=committed_at, author="test-author", parent_commit_id=parent, ) write_commit(root, record) (heads_dir(root) / "main").write_text(cid) return record # =========================================================================== # 1. Unit tests — validators only, no repo, no I/O # =========================================================================== class TestValidateReviewer: def test_valid_name_passes(self) -> None: assert _validate_reviewer("alice") == "alice" def test_valid_agent_id_passes(self) -> None: assert _validate_reviewer("claude-opus-4") == "claude-opus-4" def test_empty_name_exits(self) -> None: with pytest.raises(SystemExit): _validate_reviewer("") def test_name_at_max_len_passes(self) -> None: name = "a" * _MAX_REVIEWER_LEN assert _validate_reviewer(name) == name def test_name_over_max_len_exits(self) -> None: with pytest.raises(SystemExit): _validate_reviewer("a" * (_MAX_REVIEWER_LEN + 1)) def test_control_char_exits(self) -> None: with pytest.raises(SystemExit): _validate_reviewer("alice\x00") def test_ansi_escape_exits(self) -> None: with pytest.raises(SystemExit): _validate_reviewer("alice\x1b[31m") def test_newline_exits(self) -> None: with pytest.raises(SystemExit): _validate_reviewer("alice\nbob") class TestValidateLabel: def test_valid_label_passes(self) -> None: assert _validate_label("hotfix") == "hotfix" def test_label_at_max_len_passes(self) -> None: lbl = "x" * _MAX_LABEL_LEN assert _validate_label(lbl) == lbl def test_label_over_max_len_exits(self) -> None: with pytest.raises(SystemExit): _validate_label("x" * (_MAX_LABEL_LEN + 1)) def test_empty_label_exits(self) -> None: with pytest.raises(SystemExit): _validate_label("") def test_control_char_exits(self) -> None: with pytest.raises(SystemExit): _validate_label("hot\x01fix") class TestValidateStatus: def test_all_valid_statuses_pass(self) -> None: for s in _STATUS_VALUES: assert _validate_status(s) == s def test_empty_string_clears(self) -> None: assert _validate_status("") == "" def test_unknown_status_exits(self) -> None: with pytest.raises(SystemExit): _validate_status("unknown-state") def test_case_sensitive(self) -> None: with pytest.raises(SystemExit): _validate_status("Approved") class TestValidateScore: def test_zero_passes(self) -> None: assert _validate_score("0.0") == 0.0 def test_one_passes(self) -> None: assert _validate_score("1.0") == 1.0 def test_midpoint_passes(self) -> None: assert _validate_score("0.5") == pytest.approx(0.5) def test_below_zero_exits(self) -> None: with pytest.raises(SystemExit): _validate_score("-0.1") def test_above_one_exits(self) -> None: with pytest.raises(SystemExit): _validate_score("1.1") def test_non_numeric_exits(self) -> None: with pytest.raises(SystemExit): _validate_score("high") def test_integer_string_passes(self) -> None: assert _validate_score("1") == 1.0 class TestValidateNote: def test_valid_note_passes(self) -> None: assert _validate_note("all good") == "all good" def test_empty_exits(self) -> None: with pytest.raises(SystemExit): _validate_note("") def test_whitespace_only_exits(self) -> None: with pytest.raises(SystemExit): _validate_note(" ") def test_note_at_max_len_passes(self) -> None: note = "a" * _MAX_NOTE_LEN assert _validate_note(note) == note def test_note_over_max_len_exits(self) -> None: with pytest.raises(SystemExit): _validate_note("a" * (_MAX_NOTE_LEN + 1)) # =========================================================================== # 2. Integration tests — store round-trip # =========================================================================== class TestStoreRoundTrip: def test_reviewed_by_persisted(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke( cli, ["annotate", "--reviewed-by", "alice", c.commit_id], catch_exceptions=False, ) stored = read_commit(repo, c.commit_id) assert stored is not None assert "alice" in stored.reviewed_by def test_test_runs_persisted(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--test-run", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.test_runs == 1 def test_labels_persisted(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--label", "hotfix", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert "hotfix" in stored.labels def test_status_persisted(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--status", "approved", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.status == "approved" def test_notes_persisted(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke( cli, ["annotate", "--note", "looks good", c.commit_id], catch_exceptions=False, ) stored = read_commit(repo, c.commit_id) assert stored is not None assert "looks good" in stored.notes def test_score_persisted(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--score", "0.9", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.score == pytest.approx(0.9) def test_all_fields_in_one_call(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke( cli, [ "annotate", "--reviewed-by", "alice", "--test-run", "--label", "perf", "--status", "pending", "--note", "first review", "--score", "0.75", c.commit_id, ], catch_exceptions=False, ) stored = read_commit(repo, c.commit_id) assert stored is not None assert "alice" in stored.reviewed_by assert stored.test_runs == 1 assert "perf" in stored.labels assert stored.status == "pending" assert "first review" in stored.notes assert stored.score == pytest.approx(0.75) def test_dry_run_does_not_write(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke( cli, ["annotate", "--dry-run", "--reviewed-by", "agent-x", c.commit_id], catch_exceptions=False, ) stored = read_commit(repo, c.commit_id) assert stored is not None assert "agent-x" not in stored.reviewed_by # =========================================================================== # 3. End-to-End tests — CLI invocations # =========================================================================== class TestShowMode: def test_show_no_flags_exits_0(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", c.commit_id], catch_exceptions=False) assert result.exit_code == 0 def test_show_includes_reviewed_by_header(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", c.commit_id], catch_exceptions=False) assert "reviewed-by" in result.output def test_show_includes_test_runs_header(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", c.commit_id], catch_exceptions=False) assert "test-runs" in result.output def test_show_includes_labels_header(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", c.commit_id], catch_exceptions=False) assert "labels" in result.output def test_show_includes_status_header(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", c.commit_id], catch_exceptions=False) assert "status" in result.output def test_show_includes_notes_header(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", c.commit_id], catch_exceptions=False) assert "notes" in result.output def test_show_includes_score_header(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", c.commit_id], catch_exceptions=False) assert "score" in result.output def test_show_head_when_no_commit_arg(self, repo: pathlib.Path) -> None: _write_commit(repo) result = runner.invoke(cli, ["annotate"], catch_exceptions=False) assert result.exit_code == 0 class TestJsonOutput: def test_json_flag_exits_0(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--json", c.commit_id], catch_exceptions=False ) assert result.exit_code == 0 def test_json_is_valid(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--json", c.commit_id], catch_exceptions=False ) data = json.loads(result.output) assert isinstance(data, dict) def test_json_has_all_keys(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--json", c.commit_id], catch_exceptions=False ) data = json.loads(result.output) required = { "commit_id", "parent_commit_id", "snapshot_id", "message", "branch", "author", "agent_id", "model_id", "committed_at", "reviewed_by", "test_runs", "labels", "status", "notes", "score", "changed", "dry_run", } assert required <= data.keys() def test_json_commit_id_matches(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--json", c.commit_id], catch_exceptions=False ) data = json.loads(result.output) assert data["commit_id"] == c.commit_id def test_json_mutation_reflects_new_values(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--json", "--reviewed-by", "bob", "--score", "0.8", c.commit_id], catch_exceptions=False, ) data = json.loads(result.output) assert "bob" in data["reviewed_by"] assert data["score"] == pytest.approx(0.8) assert data["changed"] is True assert data["dry_run"] is False def test_json_dry_run_flag(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--json", "--dry-run", "--reviewed-by", "alice", c.commit_id], catch_exceptions=False, ) data = json.loads(result.output) assert data["dry_run"] is True assert "alice" in data["reviewed_by"] def test_json_snapshot_id_present(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--json", c.commit_id], catch_exceptions=False ) data = json.loads(result.output) assert data["snapshot_id"] == c.snapshot_id def test_json_parent_commit_id_null_for_root(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--json", c.commit_id], catch_exceptions=False ) data = json.loads(result.output) assert data["parent_commit_id"] is None class TestReviewerFlags: def test_add_single_reviewer(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--reviewed-by", "agent-x", c.commit_id], catch_exceptions=False, ) assert result.exit_code == 0 assert "agent-x" in result.output def test_add_comma_separated_reviewers(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke( cli, ["annotate", "--reviewed-by", "alice,bob", c.commit_id], catch_exceptions=False, ) stored = read_commit(repo, c.commit_id) assert stored is not None assert "alice" in stored.reviewed_by assert "bob" in stored.reviewed_by def test_add_multi_flag_reviewers(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke( cli, ["annotate", "--reviewed-by", "alice", "--reviewed-by", "bob", c.commit_id], catch_exceptions=False, ) stored = read_commit(repo, c.commit_id) assert stored is not None assert "alice" in stored.reviewed_by assert "bob" in stored.reviewed_by def test_remove_reviewer(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--reviewed-by", "alice", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--remove-reviewer", "alice", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert "alice" not in stored.reviewed_by def test_remove_nonexistent_reviewer_warns(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--remove-reviewer", "nobody", c.commit_id], catch_exceptions=False, ) assert result.exit_code == 0 class TestLabelFlags: def test_add_single_label(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--label", "hotfix", c.commit_id], catch_exceptions=False, ) assert result.exit_code == 0 assert "hotfix" in result.output def test_add_comma_separated_labels(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke( cli, ["annotate", "--label", "hotfix,perf", c.commit_id], catch_exceptions=False, ) stored = read_commit(repo, c.commit_id) assert stored is not None assert "hotfix" in stored.labels assert "perf" in stored.labels def test_remove_label(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--label", "hotfix", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--remove-label", "hotfix", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert "hotfix" not in stored.labels def test_remove_nonexistent_label_warns(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--remove-label", "nosuchlabel", c.commit_id], catch_exceptions=False, ) assert result.exit_code == 0 class TestStatusFlag: def test_set_approved(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--status", "approved", c.commit_id], catch_exceptions=False, ) assert result.exit_code == 0 assert "approved" in result.output def test_set_all_valid_statuses(self, repo: pathlib.Path) -> None: c = _write_commit(repo) for status in ("pending", "approved", "rejected", "needs-review", "wip"): result = runner.invoke( cli, ["annotate", "--status", status, c.commit_id], catch_exceptions=False, ) assert result.exit_code == 0 def test_invalid_status_exits_1(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", "--status", "flying", c.commit_id]) assert result.exit_code != 0 def test_status_overwrite(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--status", "pending", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--status", "approved", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.status == "approved" class TestNoteFlag: def test_append_note(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--note", "looks good", c.commit_id], catch_exceptions=False, ) assert result.exit_code == 0 assert "looks good" in result.output def test_multiple_notes_accumulate(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--note", "first", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--note", "second", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert "first" in stored.notes assert "second" in stored.notes assert len(stored.notes) == 2 def test_empty_note_exits_1(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", "--note", " ", c.commit_id]) assert result.exit_code != 0 class TestScoreFlag: def test_set_score(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--score", "0.95", c.commit_id], catch_exceptions=False, ) assert result.exit_code == 0 assert "0.9500" in result.output def test_score_overwrite(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--score", "0.5", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--score", "0.9", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.score == pytest.approx(0.9) def test_invalid_score_exits_1(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", "--score", "2.0", c.commit_id]) assert result.exit_code != 0 def test_score_zero_boundary(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--score", "0.0", c.commit_id], catch_exceptions=False ) assert result.exit_code == 0 def test_score_one_boundary(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke( cli, ["annotate", "--score", "1.0", c.commit_id], catch_exceptions=False ) assert result.exit_code == 0 class TestCommitResolution: def test_full_commit_id(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", c.commit_id], catch_exceptions=False) assert result.exit_code == 0 def test_short_prefix(self, repo: pathlib.Path) -> None: c = _write_commit(repo) # commit_id may have sha256: prefix — use first 8 hex chars after stripping short = c.commit_id[len("sha256:"):len("sha256:") + 8] result = runner.invoke(cli, ["annotate", short], catch_exceptions=False) assert result.exit_code == 0 def test_unknown_commit_exits_error(self, repo: pathlib.Path) -> None: (heads_dir(repo) / "main").write_text("nosuchcommit") result = runner.invoke(cli, ["annotate", "nosuchcommit"]) assert result.exit_code != 0 def test_head_implicit(self, repo: pathlib.Path) -> None: _write_commit(repo) result = runner.invoke(cli, ["annotate"], catch_exceptions=False) assert result.exit_code == 0 # =========================================================================== # 4. Security tests # =========================================================================== class TestSecurity: def test_control_char_in_reviewer_rejected(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", "--reviewed-by", "alice\x00", c.commit_id]) assert result.exit_code != 0 def test_ansi_escape_in_reviewer_rejected(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", "--reviewed-by", "x\x1b[31my", c.commit_id]) assert result.exit_code != 0 def test_control_char_in_label_rejected(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", "--label", "hot\x01fix", c.commit_id]) assert result.exit_code != 0 def test_oversized_reviewer_rejected(self, repo: pathlib.Path) -> None: c = _write_commit(repo) big = "a" * (_MAX_REVIEWER_LEN + 1) result = runner.invoke(cli, ["annotate", "--reviewed-by", big, c.commit_id]) assert result.exit_code != 0 def test_oversized_label_rejected(self, repo: pathlib.Path) -> None: c = _write_commit(repo) big = "x" * (_MAX_LABEL_LEN + 1) result = runner.invoke(cli, ["annotate", "--label", big, c.commit_id]) assert result.exit_code != 0 def test_oversized_note_rejected(self, repo: pathlib.Path) -> None: c = _write_commit(repo) big = "z" * (_MAX_NOTE_LEN + 1) result = runner.invoke(cli, ["annotate", "--note", big, c.commit_id]) assert result.exit_code != 0 def test_invalid_status_value_rejected(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", "--status", "APPROVED", c.commit_id]) assert result.exit_code != 0 def test_score_out_of_range_rejected(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", "--score", "-1", c.commit_id]) assert result.exit_code != 0 def test_score_nan_rejected(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", "--score", "nan", c.commit_id]) assert result.exit_code != 0 def test_error_goes_to_stderr_not_stdout(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", "--reviewed-by", "a\x00b", c.commit_id]) assert result.exit_code != 0 # error detail appears on stderr; stdout carries no diagnostic text assert "❌" in result.stderr def test_commit_ref_glob_metachar_safe(self, repo: pathlib.Path) -> None: """A glob metacharacter in the commit ref must not escape path scanning.""" _write_commit(repo) result = runner.invoke(cli, ["annotate", "../../../etc/passwd"]) assert result.exit_code != 0 # =========================================================================== # 5. Stress tests # =========================================================================== class TestStress: def test_100_sequential_reviewer_adds(self, repo: pathlib.Path) -> None: c = _write_commit(repo) for i in range(100): runner.invoke( cli, ["annotate", "--reviewed-by", f"agent-{i:03d}", c.commit_id], catch_exceptions=False, ) stored = read_commit(repo, c.commit_id) assert stored is not None assert len(stored.reviewed_by) == 100 def test_50_sequential_test_runs(self, repo: pathlib.Path) -> None: c = _write_commit(repo) for _ in range(50): runner.invoke(cli, ["annotate", "--test-run", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.test_runs == 50 def test_200_notes_appended(self, repo: pathlib.Path) -> None: c = _write_commit(repo) for i in range(200): runner.invoke( cli, ["annotate", "--note", f"note {i}", c.commit_id], catch_exceptions=False, ) stored = read_commit(repo, c.commit_id) assert stored is not None assert len(stored.notes) == 200 def test_note_at_max_len_accepted(self, repo: pathlib.Path) -> None: c = _write_commit(repo) big_note = "a" * _MAX_NOTE_LEN result = runner.invoke( cli, ["annotate", "--note", big_note, c.commit_id], catch_exceptions=False, ) assert result.exit_code == 0 def test_reviewer_at_max_len_accepted(self, repo: pathlib.Path) -> None: c = _write_commit(repo) big_name = "a" * _MAX_REVIEWER_LEN result = runner.invoke( cli, ["annotate", "--reviewed-by", big_name, c.commit_id], catch_exceptions=False, ) assert result.exit_code == 0 def test_20_labels_added(self, repo: pathlib.Path) -> None: c = _write_commit(repo) for i in range(20): runner.invoke( cli, ["annotate", "--label", f"label-{i}", c.commit_id], catch_exceptions=False, ) stored = read_commit(repo, c.commit_id) assert stored is not None assert len(stored.labels) == 20 def test_status_updated_many_times(self, repo: pathlib.Path) -> None: c = _write_commit(repo) statuses = ["pending", "wip", "needs-review", "approved", "rejected", "approved"] for s in statuses: runner.invoke(cli, ["annotate", "--status", s, c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.status == "approved" # =========================================================================== # 6. Performance tests # =========================================================================== class TestPerformance: def test_show_annotation_under_200ms(self, repo: pathlib.Path) -> None: c = _write_commit(repo) start = time.monotonic() runner.invoke(cli, ["annotate", c.commit_id], catch_exceptions=False) elapsed = time.monotonic() - start assert elapsed < 0.2, f"show took {elapsed:.3f}s — too slow" def test_single_mutation_under_200ms(self, repo: pathlib.Path) -> None: c = _write_commit(repo) start = time.monotonic() runner.invoke( cli, ["annotate", "--reviewed-by", "perf-agent", c.commit_id], catch_exceptions=False, ) elapsed = time.monotonic() - start assert elapsed < 0.2, f"mutation took {elapsed:.3f}s — too slow" def test_json_output_under_200ms(self, repo: pathlib.Path) -> None: c = _write_commit(repo) start = time.monotonic() runner.invoke(cli, ["annotate", "--json", c.commit_id], catch_exceptions=False) elapsed = time.monotonic() - start assert elapsed < 0.2, f"json output took {elapsed:.3f}s — too slow" def test_combined_mutation_under_300ms(self, repo: pathlib.Path) -> None: c = _write_commit(repo) start = time.monotonic() runner.invoke( cli, [ "annotate", "--reviewed-by", "alice", "--test-run", "--label", "hotfix", "--status", "pending", "--note", "perf test", "--score", "0.8", c.commit_id, ], catch_exceptions=False, ) elapsed = time.monotonic() - start assert elapsed < 0.3, f"combined mutation took {elapsed:.3f}s — too slow" # =========================================================================== # 7. Data Integrity tests — CRDT semantics # =========================================================================== class TestDataIntegrity: # ORSet: reviewed_by def test_orset_reviewer_idempotent(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--reviewed-by", "alice", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--reviewed-by", "alice", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.reviewed_by.count("alice") == 1 def test_orset_reviewer_union(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--reviewed-by", "alice", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--reviewed-by", "bob", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert "alice" in stored.reviewed_by assert "bob" in stored.reviewed_by # ORSet: labels def test_orset_label_idempotent(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--label", "hotfix", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--label", "hotfix", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.labels.count("hotfix") == 1 def test_orset_label_union(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--label", "hotfix", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--label", "perf", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert "hotfix" in stored.labels assert "perf" in stored.labels # GCounter: test_runs def test_gcounter_monotone(self, repo: pathlib.Path) -> None: c = _write_commit(repo) for expected in range(1, 6): runner.invoke(cli, ["annotate", "--test-run", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.test_runs == expected def test_gcounter_never_decrements(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--test-run", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--test-run", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.test_runs >= 2 # LWW: status def test_lww_status_last_write_wins(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--status", "pending", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--status", "rejected", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--status", "approved", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.status == "approved" # LWW: score def test_lww_score_last_write_wins(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--score", "0.3", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--score", "0.7", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--score", "0.1", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.score == pytest.approx(0.1) # Append-only: notes def test_notes_append_only_preserves_order(self, repo: pathlib.Path) -> None: c = _write_commit(repo) notes = ["alpha", "beta", "gamma"] for note in notes: runner.invoke(cli, ["annotate", "--note", note, c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.notes == notes def test_notes_allow_duplicates(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--note", "dup", c.commit_id], catch_exceptions=False) runner.invoke(cli, ["annotate", "--note", "dup", c.commit_id], catch_exceptions=False) stored = read_commit(repo, c.commit_id) assert stored is not None assert stored.notes.count("dup") == 2 # Roundtrip fidelity def test_json_roundtrip_reviewed_by(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--reviewed-by", "carol", c.commit_id], catch_exceptions=False) result = runner.invoke(cli, ["annotate", "--json", c.commit_id], catch_exceptions=False) data = json.loads(result.output) assert "carol" in data["reviewed_by"] def test_json_roundtrip_score(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--score", "0.42", c.commit_id], catch_exceptions=False) result = runner.invoke(cli, ["annotate", "--json", c.commit_id], catch_exceptions=False) data = json.loads(result.output) assert data["score"] == pytest.approx(0.42) def test_json_roundtrip_labels(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--label", "wip-label", c.commit_id], catch_exceptions=False) result = runner.invoke(cli, ["annotate", "--json", c.commit_id], catch_exceptions=False) data = json.loads(result.output) assert "wip-label" in data["labels"] def test_json_changed_false_when_no_mutation(self, repo: pathlib.Path) -> None: c = _write_commit(repo) result = runner.invoke(cli, ["annotate", "--json", c.commit_id], catch_exceptions=False) data = json.loads(result.output) assert data["changed"] is False def test_no_changes_message_when_idempotent(self, repo: pathlib.Path) -> None: c = _write_commit(repo) runner.invoke(cli, ["annotate", "--reviewed-by", "alice", c.commit_id], catch_exceptions=False) result = runner.invoke( cli, ["annotate", "--reviewed-by", "alice", c.commit_id], catch_exceptions=False, ) assert "no changes" in result.output