gabriel / musehub public
test_model_defaults.py python
391 lines 12.6 KB
Raw
sha256:a34090cc4a394a78bd72cbbe34b08cc59525141e19135b6c0ab154f10611b9ef debug(push/stream): instrument O-frame decode path with INF… Sonnet 4.6 patch 121 days ago
1 """ORM model instances must have correct Python-side attribute values at
2 construction time — no DB flush or refresh required.
3
4 This guards against the class of bug where service code calls a Pydantic
5 serialiser (e.g. _to_repo_response) on a freshly constructed ORM object and
6 receives None for columns that have a server_default or column-level default,
7 because SQLAlchemy's ``default=`` only fires at INSERT time in non-dataclass
8 models.
9 """
10 from __future__ import annotations
11
12 from datetime import datetime, timezone
13
14 from muse.core.types import fake_id
15
16 from musehub.db.musehub_auth_models import MusehubAuthKey
17 from musehub.db.musehub_collaborator_models import MusehubCollaborator
18 from musehub.db.musehub_models import (
19 MusehubBranch,
20 MusehubCommit,
21 MusehubIdentity,
22 MusehubIssue,
23 MusehubIssueEvent,
24 MusehubMist,
25 MusehubProposal,
26 MusehubProposalComment,
27 MusehubRelease,
28 MusehubRepo,
29 MusehubSession,
30 MusehubSnapshot,
31 MusehubSymbolIntel,
32 MusehubWebhook,
33 )
34
35 _REPO_ID = fake_id("repo")
36 _OWNER_ID = fake_id("owner")
37 _BRANCH_ID = fake_id("branch")
38 _COMMIT_ID = fake_id("commit")
39 _SNAP_ID = fake_id("snapshot")
40 _IDENTITY_ID = fake_id("identity")
41 _ISSUE_ID = fake_id("issue")
42 _PROPOSAL_ID = fake_id("proposal")
43 _KEY_ID = fake_id("key")
44 _COLLAB_ID = fake_id("collab")
45
46
47 def test_musehub_repo_scalar_defaults_at_construction() -> None:
48 repo = MusehubRepo(
49 repo_id=_REPO_ID,
50 name="test",
51 owner="gabriel",
52 slug="test",
53 owner_user_id=_OWNER_ID,
54 )
55 assert repo.default_branch == "main"
56 assert repo.visibility == "public"
57 assert repo.description == ""
58 assert repo.domain_id == "code"
59 assert repo.training_opt_out is False
60 assert repo.settings is None
61 assert repo.pushed_at is None
62
63
64 def test_musehub_repo_mutable_defaults_are_isolated() -> None:
65 """Each instance must get its own list/dict, not a shared mutable object."""
66 r1 = MusehubRepo(repo_id=_REPO_ID, name="t", owner="x", slug="t", owner_user_id=_OWNER_ID)
67 r2 = MusehubRepo(repo_id=_REPO_ID, name="t", owner="x", slug="t", owner_user_id=_OWNER_ID)
68 assert r1.tags == []
69 assert r1.domain_meta == {}
70 r1.tags.append("jazz")
71 assert r2.tags == [], "mutable default must not be shared between instances"
72
73
74 def test_musehub_repo_timestamps_set_at_construction() -> None:
75 repo = MusehubRepo(
76 repo_id=_REPO_ID,
77 name="t",
78 owner="x",
79 slug="t",
80 owner_user_id=_OWNER_ID,
81 )
82 assert isinstance(repo.created_at, datetime)
83 assert isinstance(repo.updated_at, datetime)
84
85
86 def test_musehub_snapshot_defaults_at_construction() -> None:
87 snap = MusehubSnapshot(
88 snapshot_id=_SNAP_ID,
89 repo_id=_REPO_ID,
90 manifest_blob=b"\x80",
91 )
92 assert snap.directories == []
93 assert snap.entry_count == 0
94 assert isinstance(snap.created_at, datetime)
95
96
97 def test_musehub_identity_defaults_at_construction() -> None:
98 identity = MusehubIdentity(
99 identity_id=_IDENTITY_ID,
100 handle="gabriel",
101 )
102 assert identity.identity_type == "human"
103 assert identity.agent_capabilities == []
104 assert identity.is_verified is False
105 assert identity.pinned_repo_ids == []
106 assert isinstance(identity.created_at, datetime)
107 assert isinstance(identity.updated_at, datetime)
108
109
110 def test_musehub_issue_defaults_at_construction() -> None:
111 issue = MusehubIssue(
112 issue_id=_ISSUE_ID,
113 repo_id=_REPO_ID,
114 number=1,
115 title="bug: something broken",
116 )
117 assert issue.body == ""
118 assert issue.state == "open"
119 assert issue.labels == []
120 assert issue.symbol_anchors == []
121 assert issue.commit_anchors == []
122 assert issue.author == ""
123 assert issue.assignee is None
124 assert issue.agent_id == ""
125 assert issue.model_id == ""
126 assert isinstance(issue.created_at, datetime)
127 assert isinstance(issue.updated_at, datetime)
128
129
130 def test_musehub_proposal_defaults_at_construction() -> None:
131 proposal = MusehubProposal(
132 proposal_id=_PROPOSAL_ID,
133 repo_id=_REPO_ID,
134 proposal_number=1,
135 title="feat: new thing",
136 from_branch="feat/new-thing",
137 to_branch="main",
138 )
139 assert proposal.body == ""
140 assert proposal.state == "open"
141 assert proposal.merge_commit_id is None
142 assert proposal.merged_at is None
143 assert proposal.author == ""
144 assert isinstance(proposal.created_at, datetime)
145 assert isinstance(proposal.updated_at, datetime)
146 assert proposal.domain_diff is None
147 assert proposal.risk_score is None
148 assert proposal.blast_delta is None
149 assert proposal.breakage_count == 0
150 assert proposal.test_gap_count == 0
151 assert proposal.symbols_changed == 0
152 assert proposal.touched_symbols == []
153
154
155 def test_musehub_auth_key_defaults_at_construction() -> None:
156 key = MusehubAuthKey(
157 key_id=_KEY_ID,
158 identity_id=_IDENTITY_ID,
159 public_key_b64="ed25519:AAAA",
160 fingerprint=fake_id("fp"),
161 )
162 assert key.algorithm == "ed25519"
163 assert key.label == ""
164 assert isinstance(key.created_at, datetime)
165 assert key.last_used_at is None
166
167
168 def test_musehub_collaborator_defaults_at_construction() -> None:
169 collab = MusehubCollaborator(
170 id=_COLLAB_ID,
171 repo_id=_REPO_ID,
172 identity_handle="alice",
173 )
174 assert collab.permission == "write"
175 assert isinstance(collab.invited_at, datetime)
176 assert collab.invited_by_handle is None
177 assert collab.accepted_at is None
178
179
180 def test_musehub_branch_defaults_at_construction() -> None:
181 branch = MusehubBranch(
182 branch_id=_BRANCH_ID,
183 repo_id=_REPO_ID,
184 name="main",
185 )
186 assert branch.head_commit_id is None
187
188
189 def test_musehub_label_defaults_at_construction() -> None:
190 from musehub.db.musehub_label_models import MusehubLabel
191
192 label = MusehubLabel(
193 id=fake_id("label"),
194 repo_id=_REPO_ID,
195 name="bug",
196 color="#d73a4a",
197 )
198 assert label.description is None
199 assert isinstance(label.created_at, datetime)
200
201
202 def test_musehub_commit_defaults_at_construction() -> None:
203 commit = MusehubCommit(
204 commit_id=_COMMIT_ID,
205 repo_id=_REPO_ID,
206 branch="main",
207 message="feat: test",
208 author="gabriel",
209 timestamp=datetime.now(tz=timezone.utc),
210 )
211 assert commit.parent_ids == []
212 assert commit.snapshot_id is None
213 assert commit.agent_id == ""
214 assert commit.model_id == ""
215 assert commit.toolchain_id == ""
216 assert commit.commit_branch is None
217 assert commit.signature == ""
218 assert commit.signer_public_key == ""
219 assert commit.signer_key_id == ""
220 assert commit.sem_ver_bump == "none"
221 assert commit.breaking_changes == []
222 assert commit.reviewed_by == []
223 assert commit.test_runs == 0
224 assert commit.prompt_hash == ""
225 assert commit.structured_delta is None
226 assert isinstance(commit.created_at, datetime)
227
228
229 # ---------------------------------------------------------------------------
230 # Phase 3 — classes that need MappedAsDataclass (mutable callable defaults)
231 # ---------------------------------------------------------------------------
232
233 _EVENT_ID = fake_id("event")
234 _WEBHOOK_ID = fake_id("webhook")
235 _SESSION_ID = fake_id("session")
236 _COMMENT_ID = fake_id("pcomment")
237 _RELEASE_ID = fake_id("release")
238 _MIST_ID = fake_id("mist")
239
240
241 def test_musehub_issue_event_defaults_at_construction() -> None:
242 event = MusehubIssueEvent(
243 event_id=_EVENT_ID,
244 issue_id=_ISSUE_ID,
245 repo_id=_REPO_ID,
246 event_type="opened",
247 )
248 assert event.actor == ""
249 assert event.payload == {}
250 assert isinstance(event.created_at, datetime)
251
252
253 def test_musehub_issue_event_payload_is_isolated() -> None:
254 e1 = MusehubIssueEvent(event_id=_EVENT_ID, issue_id=_ISSUE_ID, repo_id=_REPO_ID, event_type="opened")
255 e2 = MusehubIssueEvent(event_id=_EVENT_ID, issue_id=_ISSUE_ID, repo_id=_REPO_ID, event_type="opened")
256 e1.payload["key"] = "value"
257 assert e2.payload == {}, "payload must not be shared between instances"
258
259
260 def test_musehub_webhook_defaults_at_construction() -> None:
261 wh = MusehubWebhook(
262 webhook_id=_WEBHOOK_ID,
263 repo_id=_REPO_ID,
264 url="https://ci.example.com/hook",
265 )
266 assert wh.events == []
267 assert wh.secret == ""
268 assert wh.active is True
269 assert isinstance(wh.created_at, datetime)
270 assert isinstance(wh.updated_at, datetime)
271
272
273 def test_musehub_webhook_events_is_isolated() -> None:
274 w1 = MusehubWebhook(webhook_id=_WEBHOOK_ID, repo_id=_REPO_ID, url="https://a.example.com")
275 w2 = MusehubWebhook(webhook_id=_WEBHOOK_ID, repo_id=_REPO_ID, url="https://b.example.com")
276 w1.events.append("push")
277 assert w2.events == [], "events must not be shared between instances"
278
279
280 def test_musehub_session_defaults_at_construction() -> None:
281 session = MusehubSession(
282 session_id=_SESSION_ID,
283 repo_id=_REPO_ID,
284 started_at=datetime.now(tz=timezone.utc),
285 )
286 assert session.participants == []
287 assert session.commits == []
288 assert session.schema_version == "1"
289 assert session.location == ""
290 assert session.intent == ""
291 assert session.notes == ""
292 assert session.is_active is False
293 assert isinstance(session.created_at, datetime)
294
295
296 def test_musehub_session_lists_are_isolated() -> None:
297 now = datetime.now(tz=timezone.utc)
298 s1 = MusehubSession(session_id=_SESSION_ID, repo_id=_REPO_ID, started_at=now)
299 s2 = MusehubSession(session_id=_SESSION_ID, repo_id=_REPO_ID, started_at=now)
300 s1.participants.append("gabriel")
301 assert s2.participants == [], "participants must not be shared between instances"
302
303
304 def test_musehub_proposal_comment_defaults_at_construction() -> None:
305 comment = MusehubProposalComment(
306 comment_id=_COMMENT_ID,
307 proposal_id=_PROPOSAL_ID,
308 repo_id=_REPO_ID,
309 author="gabriel",
310 body="looks good",
311 )
312 assert comment.dimension_ref == {}
313 assert comment.symbol_address is None
314 assert comment.parent_comment_id is None
315 assert isinstance(comment.created_at, datetime)
316
317
318 def test_musehub_proposal_comment_dimension_ref_is_isolated() -> None:
319 kwargs = dict(comment_id=_COMMENT_ID, proposal_id=_PROPOSAL_ID, repo_id=_REPO_ID, author="x", body="y")
320 c1 = MusehubProposalComment(**kwargs)
321 c2 = MusehubProposalComment(**kwargs)
322 c1.dimension_ref["dim"] = "harmony"
323 assert c2.dimension_ref == {}, "dimension_ref must not be shared between instances"
324
325
326 def test_musehub_release_defaults_at_construction() -> None:
327 release = MusehubRelease(
328 release_id=_RELEASE_ID,
329 repo_id=_REPO_ID,
330 tag="v1.0.0",
331 )
332 assert release.download_urls == {}
333 assert release.title == ""
334 assert release.body == ""
335 assert release.is_draft is False
336 assert release.channel == "stable"
337 assert release.semver_major == 0
338 assert isinstance(release.created_at, datetime)
339 assert isinstance(release.updated_at, datetime)
340
341
342 def test_musehub_release_download_urls_is_isolated() -> None:
343 r1 = MusehubRelease(release_id=_RELEASE_ID, repo_id=_REPO_ID, tag="v1.0.0")
344 r2 = MusehubRelease(release_id=_RELEASE_ID, repo_id=_REPO_ID, tag="v1.0.0")
345 r1.download_urls["linux"] = "https://example.com/linux.tar.gz"
346 assert r2.download_urls == {}, "download_urls must not be shared between instances"
347
348
349 def test_musehub_mist_defaults_at_construction() -> None:
350 mist = MusehubMist(
351 mist_id=_MIST_ID,
352 repo_id=_REPO_ID,
353 owner="gabriel",
354 filename="track.mid",
355 content="<binary>",
356 )
357 assert mist.tags == []
358 assert mist.symbol_anchors == []
359 assert mist.artifact_type == "unknown"
360 assert mist.visibility == "public"
361 assert mist.fork_depth == 0
362 assert mist.view_count == 0
363 assert isinstance(mist.created_at, datetime)
364 assert isinstance(mist.updated_at, datetime)
365
366
367 def test_musehub_mist_lists_are_isolated() -> None:
368 kwargs = dict(mist_id=_MIST_ID, repo_id=_REPO_ID, owner="gabriel", filename="f.mid", content="x")
369 m1 = MusehubMist(**kwargs)
370 m2 = MusehubMist(**kwargs)
371 m1.tags.append("jazz")
372 assert m2.tags == [], "tags must not be shared between instances"
373
374
375 def test_musehub_symbol_intel_defaults_at_construction() -> None:
376 intel = MusehubSymbolIntel(
377 repo_id=_REPO_ID,
378 address="src/engine.py::AudioEngine",
379 )
380 assert intel.blast_top == []
381 assert intel.weekly == []
382 assert intel.churn == 0
383 assert intel.blast == 0
384 assert intel.gravity == 0.0
385
386
387 def test_musehub_symbol_intel_arrays_are_isolated() -> None:
388 i1 = MusehubSymbolIntel(repo_id=_REPO_ID, address="a.py::Foo")
389 i2 = MusehubSymbolIntel(repo_id=_REPO_ID, address="b.py::Bar")
390 i1.blast_top.append("x.py::Dep")
391 assert i2.blast_top == [], "blast_top must not be shared between instances"
File History 1 commit
sha256:a34090cc4a394a78bd72cbbe34b08cc59525141e19135b6c0ab154f10611b9ef debug(push/stream): instrument O-frame decode path with INF… Sonnet 4.6 patch 121 days ago