gabriel / musehub public
test_model_defaults.py python
391 lines 12.8 KB
Raw
sha256:4992098130166d191cefed0a2821d19cd3cdd3cf50867a4e715c2b30636826c7 fix: repair syntax errors from typing annotation cleanup Sonnet 4.6 21 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_identity_models import MusehubIdentity
19 from musehub.db.musehub_intel_models import MusehubSymbolIntel
20 from musehub.db.musehub_release_models import MusehubRelease
21 from musehub.db.musehub_repo_models import (
22 MusehubBranch,
23 MusehubCommit,
24 MusehubMist,
25 MusehubRepo,
26 MusehubSession,
27 MusehubSnapshot,
28 )
29 from musehub.db.musehub_social_models import (
30 MusehubIssue,
31 MusehubIssueEvent,
32 MusehubProposal,
33 MusehubProposalComment,
34 )
35 from musehub.db.musehub_webhook_models import MusehubWebhook
36
37 _REPO_ID = fake_id("repo")
38 _OWNER_ID = fake_id("owner")
39 _BRANCH_ID = fake_id("branch")
40 _COMMIT_ID = fake_id("commit")
41 _SNAP_ID = fake_id("snapshot")
42 _IDENTITY_ID = fake_id("identity")
43 _ISSUE_ID = fake_id("issue")
44 _PROPOSAL_ID = fake_id("proposal")
45 _KEY_ID = fake_id("key")
46 _COLLAB_ID = fake_id("collab")
47
48
49 def test_musehub_repo_scalar_defaults_at_construction() -> None:
50 repo = MusehubRepo(
51 repo_id=_REPO_ID,
52 name="test",
53 owner="gabriel",
54 slug="test",
55 owner_user_id=_OWNER_ID,
56 )
57 assert repo.default_branch == "main"
58 assert repo.visibility == "public"
59 assert repo.description == ""
60 assert repo.domain_id == "code"
61 assert repo.training_opt_out is False
62 assert repo.settings is None
63 assert repo.pushed_at is None
64
65
66 def test_musehub_repo_mutable_defaults_are_isolated() -> None:
67 """Each instance must get its own list/dict, not a shared mutable object."""
68 r1 = MusehubRepo(repo_id=_REPO_ID, name="t", owner="x", slug="t", owner_user_id=_OWNER_ID)
69 r2 = MusehubRepo(repo_id=_REPO_ID, name="t", owner="x", slug="t", owner_user_id=_OWNER_ID)
70 assert r1.tags == []
71 assert r1.domain_meta == {}
72 r1.tags.append("jazz")
73 assert r2.tags == [], "mutable default must not be shared between instances"
74
75
76 def test_musehub_repo_timestamps_set_at_construction() -> None:
77 repo = MusehubRepo(
78 repo_id=_REPO_ID,
79 name="t",
80 owner="x",
81 slug="t",
82 owner_user_id=_OWNER_ID,
83 )
84 assert isinstance(repo.created_at, datetime)
85 assert isinstance(repo.updated_at, datetime)
86
87
88 def test_musehub_snapshot_defaults_at_construction() -> None:
89 snap = MusehubSnapshot(
90 snapshot_id=_SNAP_ID,
91 manifest_blob=b"\x80",
92 )
93 assert snap.directories == []
94 assert snap.entry_count == 0
95 assert isinstance(snap.created_at, datetime)
96
97
98 def test_musehub_identity_defaults_at_construction() -> None:
99 identity = MusehubIdentity(
100 identity_id=_IDENTITY_ID,
101 handle="gabriel",
102 )
103 assert identity.identity_type == "human"
104 assert identity.agent_capabilities == []
105 assert identity.is_verified is False
106 assert identity.pinned_repo_ids == []
107 assert isinstance(identity.created_at, datetime)
108 assert isinstance(identity.updated_at, datetime)
109
110
111 def test_musehub_issue_defaults_at_construction() -> None:
112 issue = MusehubIssue(
113 issue_id=_ISSUE_ID,
114 repo_id=_REPO_ID,
115 number=1,
116 title="bug: something broken",
117 )
118 assert issue.body == ""
119 assert issue.state == "open"
120 assert issue.labels == []
121 assert issue.symbol_anchors == []
122 assert issue.commit_anchors == []
123 assert issue.author == ""
124 assert issue.assignee is None
125 assert issue.agent_id == ""
126 assert issue.model_id == ""
127 assert isinstance(issue.created_at, datetime)
128 assert isinstance(issue.updated_at, datetime)
129
130
131 def test_musehub_proposal_defaults_at_construction() -> None:
132 proposal = MusehubProposal(
133 proposal_id=_PROPOSAL_ID,
134 repo_id=_REPO_ID,
135 proposal_number=1,
136 title="feat: new thing",
137 from_branch="feat/new-thing",
138 to_branch="main",
139 )
140 assert proposal.body == ""
141 assert proposal.state == "open"
142 assert proposal.merge_commit_id is None
143 assert proposal.merged_at is None
144 assert proposal.author == ""
145 assert isinstance(proposal.created_at, datetime)
146 assert isinstance(proposal.updated_at, datetime)
147 assert proposal.domain_diff is None
148 assert proposal.risk_score is None
149 assert proposal.blast_delta is None
150 assert proposal.breakage_count == 0
151 assert proposal.test_gap_count == 0
152 assert proposal.symbols_changed == 0
153 assert proposal.touched_symbols == []
154
155
156 def test_musehub_auth_key_defaults_at_construction() -> None:
157 key = MusehubAuthKey(
158 key_id=_KEY_ID,
159 identity_id=_IDENTITY_ID,
160 public_key_b64="ed25519:AAAA",
161 fingerprint=fake_id("fp"),
162 )
163 assert key.algorithm == "ed25519"
164 assert key.label == ""
165 assert isinstance(key.created_at, datetime)
166 assert key.last_used_at is None
167
168
169 def test_musehub_collaborator_defaults_at_construction() -> None:
170 collab = MusehubCollaborator(
171 id=_COLLAB_ID,
172 repo_id=_REPO_ID,
173 identity_handle="alice",
174 )
175 assert collab.permission == "write"
176 assert isinstance(collab.invited_at, datetime)
177 assert collab.invited_by_handle is None
178 assert collab.accepted_at is None
179
180
181 def test_musehub_branch_defaults_at_construction() -> None:
182 branch = MusehubBranch(
183 branch_id=_BRANCH_ID,
184 repo_id=_REPO_ID,
185 name="main",
186 )
187 assert branch.head_commit_id is None
188
189
190 def test_musehub_label_defaults_at_construction() -> None:
191 from musehub.db.musehub_label_models import MusehubLabel
192
193 label = MusehubLabel(
194 id=fake_id("label"),
195 repo_id=_REPO_ID,
196 name="bug",
197 color="#d73a4a",
198 )
199 assert label.description is None
200 assert isinstance(label.created_at, datetime)
201
202
203 def test_musehub_commit_defaults_at_construction() -> None:
204 commit = MusehubCommit(
205 commit_id=_COMMIT_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 2 commits
sha256:4992098130166d191cefed0a2821d19cd3cdd3cf50867a4e715c2b30636826c7 fix: repair syntax errors from typing annotation cleanup Sonnet 4.6 21 days ago
sha256:ef10830ce231e0a20efcb0e2586cb879471247e916616e6fdd0d51df459e2595 fix: typing audit — 0 violations, 0 untyped defs across all… Sonnet 4.6 minor 21 days ago