gabriel / muse public

test_cmd_snapshot.py file-level

at sha256:8 · View file ↗ · Intel ↗

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