gabriel / musehub public
test_generic_domain.py python
167 lines 5.4 KB
Raw
sha256:fc04e4cae9e1774d6a21b65c45daeed0e6787eb581d13aa1b03bfe9384a34226 Merge branch 'fix/two-column-scroll-layout' into dev Human 9 days ago
1 """TDD tests for the 'generic' domain as a first-class explicit value.
2
3 Design decision: repos without a recognised domain plugin must resolve to
4 'generic' — a named, intentional domain — rather than an empty string or None.
5
6 This covers four surfaces:
7 1. GENERIC_DOMAIN constant exported from musehub.services.musehub_repository
8 2. RepoResponse.domain field resolves to 'generic' when domain_id is None
9 3. _build_repos_out — domain key is 'generic', never '' or None
10 4. profile.html chip — 'generic' renders a distinct icon (not gray #94a3b8)
11 5. POST /api/repos API — omitting or empty domain returns domain='generic'
12
13 Tests are RED-first. Each assertion drives one concrete implementation decision.
14 """
15 from __future__ import annotations
16
17 import pytest
18 from httpx import AsyncClient, ASGITransport
19 from sqlalchemy.ext.asyncio import AsyncSession
20
21 from muse.core.types import long_id
22 from musehub.main import app
23
24
25 # ---------------------------------------------------------------------------
26 # Helpers
27 # ---------------------------------------------------------------------------
28
29 _OWNER = "testuser"
30
31
32 # ---------------------------------------------------------------------------
33 # 1. GENERIC_DOMAIN constant
34 # ---------------------------------------------------------------------------
35
36
37 def test_generic_domain_constant_exported() -> None:
38 from musehub.services.musehub_repository import GENERIC_DOMAIN
39 assert GENERIC_DOMAIN == "generic"
40
41
42 # ---------------------------------------------------------------------------
43 # 2. RepoResponse.domain field is present and defaults to 'generic'
44 # ---------------------------------------------------------------------------
45
46
47 def test_repo_response_has_domain_field() -> None:
48 from musehub.models.musehub import RepoResponse
49 from datetime import datetime, timezone
50
51 now = datetime.now(timezone.utc)
52 resp = RepoResponse(
53 repo_id=long_id("a" * 64),
54 name="test",
55 owner="testuser",
56 slug="test",
57 visibility="public",
58 owner_user_id=long_id("b" * 64),
59 clone_url="https://localhost:1337/api/repos/test",
60 description="",
61 tags=[],
62 domain_id=None,
63 default_branch="main",
64 created_at=now,
65 updated_at=now,
66 pushed_at=None,
67 )
68 assert resp.domain == "generic"
69
70
71 def test_repo_response_domain_set_explicitly() -> None:
72 from musehub.models.musehub import RepoResponse
73 from datetime import datetime, timezone
74
75 now = datetime.now(timezone.utc)
76 resp = RepoResponse(
77 repo_id=long_id("a" * 64),
78 name="test",
79 owner="testuser",
80 slug="test",
81 visibility="public",
82 owner_user_id=long_id("b" * 64),
83 clone_url="https://localhost:1337/api/repos/test",
84 description="",
85 tags=[],
86 domain_id=None,
87 domain="code",
88 default_branch="main",
89 created_at=now,
90 updated_at=now,
91 pushed_at=None,
92 )
93 assert resp.domain == "code"
94
95
96 # ---------------------------------------------------------------------------
97 # 3. create_repo service — returns domain='generic' when no domain specified
98 # ---------------------------------------------------------------------------
99
100
101 @pytest.mark.asyncio
102 async def test_create_repo_no_domain_returns_generic(db_session: AsyncSession) -> None:
103 from musehub.services.musehub_repository import create_repo, GENERIC_DOMAIN
104
105 resp = await create_repo(
106 db_session,
107 name="no-domain-repo",
108 owner=_OWNER,
109 visibility="public",
110 owner_user_id=long_id("a" * 64),
111 owner_identity_id=long_id("a" * 64),
112 )
113 await db_session.commit()
114
115 assert resp.domain == GENERIC_DOMAIN
116
117
118 @pytest.mark.asyncio
119 async def test_create_repo_empty_domain_returns_generic(db_session: AsyncSession) -> None:
120 from musehub.services.musehub_repository import create_repo, GENERIC_DOMAIN
121
122 resp = await create_repo(
123 db_session,
124 name="empty-domain-repo",
125 owner=_OWNER,
126 visibility="public",
127 owner_user_id=long_id("a" * 64),
128 owner_identity_id=long_id("a" * 64),
129 domain="",
130 )
131 await db_session.commit()
132
133 assert resp.domain == GENERIC_DOMAIN
134
135
136 # ---------------------------------------------------------------------------
137 # 4. _build_repos_out — domain key is never '' or None
138 # ---------------------------------------------------------------------------
139
140
141
142
143 # ---------------------------------------------------------------------------
144 # 6. API — POST /api/repos without domain returns domain='generic'
145 # ---------------------------------------------------------------------------
146
147
148 @pytest.mark.asyncio
149 async def test_create_repo_api_omitting_domain_returns_generic(
150 client: AsyncClient,
151 auth_headers: dict[str, str],
152 ) -> None:
153 payload = {"name": "no-domain-api-repo", "owner": "testuser", "visibility": "public"}
154 resp = await client.post("/api/repos", json=payload, headers=auth_headers)
155 assert resp.status_code == 201, resp.text
156 assert resp.json()["domain"] == "generic"
157
158
159 @pytest.mark.asyncio
160 async def test_create_repo_api_empty_domain_returns_generic(
161 client: AsyncClient,
162 auth_headers: dict[str, str],
163 ) -> None:
164 payload = {"name": "empty-domain-api-repo", "owner": "testuser", "visibility": "public", "domain": ""}
165 resp = await client.post("/api/repos", json=payload, headers=auth_headers)
166 assert resp.status_code == 201, resp.text
167 assert resp.json()["domain"] == "generic"
File History 13 commits
sha256:fc04e4cae9e1774d6a21b65c45daeed0e6787eb581d13aa1b03bfe9384a34226 Merge branch 'fix/two-column-scroll-layout' into dev Human 9 days ago
sha256:408916fc5973ba59c6e4eebaa80ebdcc801c0a63205651e25009d11548f79454 chore: bump version to 0.2.0.dev2 — nightly.2, matching muse Sonnet 4.6 patch 12 days ago
sha256:d035733f21ccff27735fddebfbbe0ed24565a32a22db8de5885402262671ecd2 chore: bump version to 0.2.0rc15 for musehub#113 fix release Sonnet 4.6 patch 15 days ago
sha256:0032d6cfa33bc3c8367436ad768e7dd0e339b4332153160247da8266cb5fa352 Merge branch 'task/version-tags-phase3-server' into dev Human 17 days ago
sha256:4669620efda9ff41c55bdefd1f7bfe1c239d468428744c84ead9957e5a003a53 merge: rescue snapshot-recovery hardening (c00aa21d) into d… Opus 4.8 minor 30 days ago
sha256:a59da49c4611b970fc4b6ae48678ce4943261c213a07ddbd73ce9201df869b4a fix: remove false-positive proposal_comments index drop fro… Sonnet 4.6 patch 34 days ago
sha256:0a240d6dbff234f07d98a28a4a9a68db702f3f9ff9260196f24219bdb1c0b6f3 feat: render markdown mists as HTML with heading anchor links Sonnet 4.6 patch 35 days ago
sha256:24a7d47486ebc4ebd1832830580e177ec6f877b48dced8c000e198cdec4ce9d6 Merge 'task/bump-version-rc12' into 'dev' — proposal: Bump … Human 36 days ago
sha256:b9ff931d147e0114a1f17060f415b89ed551c170a91ff226c70437aa5c85f9ee Merge 'task/bump-version-rc12' into 'dev' — proposal: Bump … Human 36 days ago
sha256:d1122d21e73471879b460037b22c0b50fded7c423444a176f248428f75dac39c Merge 'task/fix-issue-pagination-cursor' into 'dev' — propo… Human 36 days ago
sha256:01e18975e73d2b3cd5b6db7929c895bef9aa6e0d4391dc5b2adfc548b41318dd Merge 'feat/adding-debug-logs-to-staging' into 'dev' — prop… Human 36 days ago
sha256:6b1949fc2797ca4c1936a637a4cbfec828ef56cf52398a2e74ca3c4f494e728f fix: use wire_bytes not mpack_bytes_raw in compute_object_b… Sonnet 4.6 patch 48 days ago
sha256:b99f2455dc346966d040133f5203297e6e3ef5803a93728a2c30568d0a0f7583 rename: delta_add → delta_upsert across wire format, models… Sonnet 4.6 patch 50 days ago