gabriel / muse public
test_cmd_snapshot.py python
226 lines 7.8 KB
Raw
sha256:b636f72dcba9e190afb980bece906fa5b717fbde014b76ef023df8cb96e01eb9 docs: expand cache plan with all seven testing tiers and do… Sonnet 4.6 131 days ago
1 """Tests for ``muse snapshot`` subcommands.
2
3 Covers: create (text/json), list (empty/populated/limit), show (text/json/prefix),
4 export (tar.gz/zip), short flags, stress: 50 files.
5 """
6
7 from __future__ import annotations
8
9 import json
10 import pathlib
11 import tarfile
12 import zipfile
13
14 import pytest
15
16 from muse.core._types import Manifest, short_id
17 from tests.cli_test_helper import CliRunner
18
19 cli = None # argparse migration — CliRunner ignores this arg
20
21 runner = CliRunner()
22
23
24 # ---------------------------------------------------------------------------
25 # Helpers
26 # ---------------------------------------------------------------------------
27
28
29 def _init_repo(path: pathlib.Path) -> pathlib.Path:
30 muse = path / ".muse"
31 for d in ("commits", "snapshots", "objects", "refs/heads"):
32 (muse / d).mkdir(parents=True, exist_ok=True)
33 (muse / "HEAD").write_text("ref: refs/heads/main", encoding="utf-8")
34 (muse / "repo.json").write_text(
35 json.dumps({"repo_id": "snap-test", "domain": "code"}), encoding="utf-8"
36 )
37 return path
38
39
40 def _env(repo: pathlib.Path) -> Manifest:
41 return {"MUSE_REPO_ROOT": str(repo)}
42
43
44 def _create_files(root: pathlib.Path, count: int = 3) -> list[str]:
45 names: list[str] = []
46 for i in range(count):
47 name = f"file_{i}.txt"
48 (root / name).write_text(f"content {i}", encoding="utf-8")
49 names.append(name)
50 return names
51
52
53 # ---------------------------------------------------------------------------
54 # Unit: snapshot create
55 # ---------------------------------------------------------------------------
56
57
58 def test_snapshot_create_help() -> None:
59 result = runner.invoke(cli, ["snapshot", "--help"])
60 assert result.exit_code == 0
61
62
63 def test_snapshot_create_text(tmp_path: pathlib.Path) -> None:
64 _init_repo(tmp_path)
65 _create_files(tmp_path, 3)
66 result = runner.invoke(cli, ["snapshot", "create"], env=_env(tmp_path))
67 assert result.exit_code == 0
68 assert "file(s)" in result.output
69
70
71 def test_snapshot_create_json(tmp_path: pathlib.Path) -> None:
72 _init_repo(tmp_path)
73 _create_files(tmp_path, 2)
74 result = runner.invoke(cli, ["snapshot", "create", "--json"], env=_env(tmp_path))
75 assert result.exit_code == 0
76 data = json.loads(result.output)
77 assert "snapshot_id" in data
78 assert data["file_count"] >= 1
79
80
81 def test_snapshot_create_with_note(tmp_path: pathlib.Path) -> None:
82 _init_repo(tmp_path)
83 _create_files(tmp_path, 1)
84 result = runner.invoke(cli, ["snapshot", "create", "-m", "WIP note"], env=_env(tmp_path))
85 assert result.exit_code == 0
86 assert "WIP note" in result.output
87
88
89 def test_snapshot_create_short_flags(tmp_path: pathlib.Path) -> None:
90 _init_repo(tmp_path)
91 _create_files(tmp_path, 1)
92 result = runner.invoke(cli, ["snapshot", "create", "-m", "test", "--json"], env=_env(tmp_path))
93 assert result.exit_code == 0
94 data = json.loads(result.output)
95 assert "snapshot_id" in data
96
97
98 # ---------------------------------------------------------------------------
99 # Unit: snapshot list
100 # ---------------------------------------------------------------------------
101
102
103 def test_snapshot_list_empty(tmp_path: pathlib.Path) -> None:
104 _init_repo(tmp_path)
105 result = runner.invoke(cli, ["snapshot", "list"], env=_env(tmp_path))
106 assert result.exit_code == 0
107 assert "no snapshots" in result.output.lower()
108
109
110 def test_snapshot_list_after_create(tmp_path: pathlib.Path) -> None:
111 _init_repo(tmp_path)
112 _create_files(tmp_path, 2)
113 runner.invoke(cli, ["snapshot", "create"], env=_env(tmp_path))
114 result = runner.invoke(cli, ["snapshot", "list"], env=_env(tmp_path))
115 assert result.exit_code == 0
116 lines = [l for l in result.output.strip().split("\n") if l.strip()]
117 assert len(lines) >= 1
118
119
120 def test_snapshot_list_json(tmp_path: pathlib.Path) -> None:
121 _init_repo(tmp_path)
122 _create_files(tmp_path, 2)
123 runner.invoke(cli, ["snapshot", "create"], env=_env(tmp_path))
124 result = runner.invoke(cli, ["snapshot", "list", "--json"], env=_env(tmp_path))
125 assert result.exit_code == 0
126 data = json.loads(result.output)
127 assert "snapshots" in data
128 assert len(data["snapshots"]) >= 1
129 assert "snapshot_id" in data["snapshots"][0]
130
131
132 def test_snapshot_list_limit(tmp_path: pathlib.Path) -> None:
133 _init_repo(tmp_path)
134 _create_files(tmp_path, 1)
135 for _ in range(5):
136 runner.invoke(cli, ["snapshot", "create"], env=_env(tmp_path))
137 result = runner.invoke(cli, ["snapshot", "list", "--limit", "3", "--json"], env=_env(tmp_path))
138 assert result.exit_code == 0
139 data = json.loads(result.output)
140 assert len(data["snapshots"]) <= 3
141
142
143 # ---------------------------------------------------------------------------
144 # Unit: snapshot read
145 # ---------------------------------------------------------------------------
146
147
148 def test_snapshot_read_json(tmp_path: pathlib.Path) -> None:
149 _init_repo(tmp_path)
150 _create_files(tmp_path, 2)
151 create_result = runner.invoke(cli, ["snapshot", "create", "--json"], env=_env(tmp_path))
152 snap_id = json.loads(create_result.output)["snapshot_id"]
153 result = runner.invoke(cli, ["snapshot", "read", snap_id, "--json"], env=_env(tmp_path))
154 assert result.exit_code == 0
155 data = json.loads(result.output)
156 assert data["snapshot_id"] == snap_id
157 assert "manifest" in data
158
159
160 def test_snapshot_read_prefix(tmp_path: pathlib.Path) -> None:
161 _init_repo(tmp_path)
162 _create_files(tmp_path, 1)
163 create_result = runner.invoke(cli, ["snapshot", "create", "--json"], env=_env(tmp_path))
164 snap_id = json.loads(create_result.output)["snapshot_id"]
165 # Short prefix must carry the sha256: type tag — bare hex is never accepted.
166 short_prefixed = short_id(snap_id)
167 result = runner.invoke(cli, ["snapshot", "read", short_prefixed], env=_env(tmp_path))
168 assert result.exit_code == 0
169
170
171 def test_snapshot_read_not_found(tmp_path: pathlib.Path) -> None:
172 _init_repo(tmp_path)
173 result = runner.invoke(cli, ["snapshot", "read", "nonexistent"], env=_env(tmp_path))
174 assert result.exit_code != 0
175
176
177 # ---------------------------------------------------------------------------
178 # Unit: snapshot export
179 # ---------------------------------------------------------------------------
180
181
182 def test_snapshot_export_tar_gz(tmp_path: pathlib.Path) -> None:
183 _init_repo(tmp_path)
184 _create_files(tmp_path, 2)
185 create_result = runner.invoke(cli, ["snapshot", "create", "--json"], env=_env(tmp_path))
186 snap_id = json.loads(create_result.output)["snapshot_id"]
187 out_file = tmp_path / "snap.tar.gz"
188 result = runner.invoke(
189 cli,
190 ["snapshot", "export", snap_id, "--output", str(out_file)],
191 env=_env(tmp_path),
192 )
193 assert result.exit_code == 0
194 assert out_file.exists()
195 assert tarfile.is_tarfile(str(out_file))
196
197
198 def test_snapshot_export_zip(tmp_path: pathlib.Path) -> None:
199 _init_repo(tmp_path)
200 _create_files(tmp_path, 2)
201 create_result = runner.invoke(cli, ["snapshot", "create", "--json"], env=_env(tmp_path))
202 snap_id = json.loads(create_result.output)["snapshot_id"]
203 out_file = tmp_path / "snap.zip"
204 result = runner.invoke(
205 cli,
206 ["snapshot", "export", snap_id, "--format", "zip", "--output", str(out_file)],
207 env=_env(tmp_path),
208 )
209 assert result.exit_code == 0
210 assert out_file.exists()
211 assert zipfile.is_zipfile(str(out_file))
212
213
214 # ---------------------------------------------------------------------------
215 # Stress: 50 files
216 # ---------------------------------------------------------------------------
217
218
219 def test_snapshot_create_stress_50_files(tmp_path: pathlib.Path) -> None:
220 _init_repo(tmp_path)
221 for i in range(50):
222 (tmp_path / f"stress_{i}.txt").write_bytes(b"x" * 1024)
223 result = runner.invoke(cli, ["snapshot", "create", "--json"], env=_env(tmp_path))
224 assert result.exit_code == 0
225 data = json.loads(result.output)
226 assert data["file_count"] >= 50
File History 3 commits
sha256:b636f72dcba9e190afb980bece906fa5b717fbde014b76ef023df8cb96e01eb9 docs: expand cache plan with all seven testing tiers and do… Sonnet 4.6 131 days ago
sha256:7f9e2ef5286aedad9c1e6011b4c46ca27f39dbdad6e3409357e36b26e46b3b7c docs: docstring sprint for-each-ref→hotspots — idiomatic ru… Sonnet 4.6 patch 137 days ago
sha256:a09b1b4f6838754495547f200aa0ce88e2f56ffc5b20b900f6f0cff2c3cdede9 fix(cursorignore): remove git-ism (.git/worktrees) Human minor 140 days ago