gabriel / muse public
test_transport_push_mpack_presign.py python
119 lines 5.2 KB
Raw
sha256:79ffe87f5fe2ec146e35f05521218bbf54dffdb0440c07f970bad05f16efb89f chore: merge main — carry all urllib/typing/test fixes from dev Sonnet 4.6 minor ⚠ breaking 20 days ago
1 """TDD — HttpTransport.push_mpack_presign: client-side Step 1 of the mpack push protocol.
2
3 PP-1 Happy path: POST returns {upload_url, mpack_key} — both echoed back correctly.
4 PP-2 The POST body contains mpack_key == blob_id(mpack_bytes) and correct size_bytes.
5 PP-3 The POST is sent to /{owner}/{slug}/push/mpack-presign.
6 PP-4 Non-200 response raises TransportError.
7 PP-5 Response missing upload_url raises TransportError.
8 """
9 from __future__ import annotations
10
11 from unittest.mock import MagicMock, patch
12
13 import msgpack
14 import pytest
15
16 from muse.core.transport import HttpTransport, TransportError
17 from muse.core.types import blob_id
18
19 _URL = "https://staging.musehub.ai/gabriel/muse"
20 _UPLOAD_URL = "https://minio.example.com/mpacks/sha256:abc?sig=fake"
21
22
23 def _presign_response(mpack_key: str, upload_url: str = _UPLOAD_URL) -> bytes:
24 return msgpack.packb(
25 {"upload_url": upload_url, "mpack_key": mpack_key},
26 use_bin_type=True,
27 )
28
29
30 class _Resp:
31 def __init__(self, body: bytes, status: int = 200) -> None:
32 self.status_code = status
33 self.content = body
34
35
36 def _mock_client(resp: _Resp) -> MagicMock:
37 mock = MagicMock()
38 mock.__enter__ = MagicMock(return_value=mock)
39 mock.__exit__ = MagicMock(return_value=False)
40 mock.post = MagicMock(return_value=resp)
41 return mock
42
43
44 # ── PP-1 ──────────────────────────────────────────────────────────────────────
45
46 def test_pp1_happy_path_returns_upload_url_and_mpack_key() -> None:
47 """Server 200 → dict with upload_url and mpack_key returned to caller."""
48 mpack_bytes = b"fake mpack content"
49 mpack_key = blob_id(mpack_bytes)
50 mock_client = _mock_client(_Resp(_presign_response(mpack_key)))
51
52 transport = HttpTransport()
53 with patch("muse.core.transport._httpx_mod.Client", return_value=mock_client):
54 result = transport.push_mpack_presign(_URL, None, mpack_bytes)
55
56 assert result["upload_url"] == _UPLOAD_URL
57 assert result["mpack_key"] == mpack_key
58
59
60 # ── PP-2 ──────────────────────────────────────────────────────────────────────
61
62 def test_pp2_post_body_contains_correct_key_and_size() -> None:
63 """The POST body must encode mpack_key = blob_id(bytes) and size_bytes = len(bytes)."""
64 mpack_bytes = b"x" * 512
65 mpack_key = blob_id(mpack_bytes)
66 mock_client = _mock_client(_Resp(_presign_response(mpack_key)))
67
68 transport = HttpTransport()
69 with patch("muse.core.transport._httpx_mod.Client", return_value=mock_client):
70 transport.push_mpack_presign(_URL, None, mpack_bytes)
71
72 call_kwargs = mock_client.post.call_args
73 sent_body: bytes = call_kwargs[1].get("content") or call_kwargs[0][1]
74 payload = msgpack.unpackb(sent_body, raw=False)
75 assert payload["mpack_key"] == mpack_key
76 assert payload["size_bytes"] == 512
77
78
79 # ── PP-3 ──────────────────────────────────────────────────────────────────────
80
81 def test_pp3_posts_to_correct_endpoint() -> None:
82 """POST must go to /{owner}/{slug}/push/mpack-presign."""
83 mpack_bytes = b"data"
84 mpack_key = blob_id(mpack_bytes)
85 mock_client = _mock_client(_Resp(_presign_response(mpack_key)))
86
87 transport = HttpTransport()
88 with patch("muse.core.transport._httpx_mod.Client", return_value=mock_client):
89 transport.push_mpack_presign(_URL, None, mpack_bytes)
90
91 posted_url: str = mock_client.post.call_args[0][0]
92 assert posted_url.endswith("/push/mpack-presign")
93
94
95 # ── PP-4 ──────────────────────────────────────────────────────────────────────
96
97 def test_pp4_non_200_raises_transport_error() -> None:
98 """A 4xx/5xx response must raise TransportError."""
99 mock_client = _mock_client(_Resp(b"quota exceeded", status=429))
100
101 transport = HttpTransport()
102 with patch("muse.core.transport._httpx_mod.Client", return_value=mock_client):
103 with pytest.raises(TransportError):
104 transport.push_mpack_presign(_URL, None, b"bytes")
105
106
107 # ── PP-5 ──────────────────────────────────────────────────────────────────────
108
109 def test_pp5_missing_upload_url_raises_transport_error() -> None:
110 """If the server omits upload_url, TransportError must be raised."""
111 mpack_bytes = b"data"
112 mpack_key = blob_id(mpack_bytes)
113 bad_resp = msgpack.packb({"mpack_key": mpack_key}, use_bin_type=True)
114 mock_client = _mock_client(_Resp(bad_resp))
115
116 transport = HttpTransport()
117 with patch("muse.core.transport._httpx_mod.Client", return_value=mock_client):
118 with pytest.raises(TransportError, match="upload_url"):
119 transport.push_mpack_presign(_URL, None, mpack_bytes)
File History 2 commits
sha256:79ffe87f5fe2ec146e35f05521218bbf54dffdb0440c07f970bad05f16efb89f chore: merge main — carry all urllib/typing/test fixes from dev Sonnet 4.6 minor 20 days ago
sha256:0bea7600d1eee83e87950be49933b1006fa9dc2c71e7c4ee748d324f61138156 chore: bump version to 0.2.0rc11; fix typing audit violatio… Sonnet 4.6 minor 20 days ago