test_transport_push_mpack_presign.py
python
sha256:79ffe87f5fe2ec146e35f05521218bbf54dffdb0440c07f970bad05f16efb89f
chore: merge main — carry all urllib/typing/test fixes from dev
Sonnet 4.6
minor
⚠ breaking
19 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 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 | def _mock_urllib_do(body: bytes, status: int = 200) -> "Callable[..., bytes]": |
| 31 | calls: list[tuple[str, str, dict, bytes | None]] = [] |
| 32 | |
| 33 | def _side_effect(method: str, url: str, headers: "dict[str, str]", data: "bytes | None" = None, **kwargs: "str | int | bool") -> bytes: |
| 34 | calls.append((method, url, headers, data)) |
| 35 | if status >= 400: |
| 36 | raise TransportError(f"HTTP {status}", status) |
| 37 | return body |
| 38 | |
| 39 | _side_effect.calls = calls |
| 40 | return _side_effect |
| 41 | |
| 42 | |
| 43 | # ── PP-1 ────────────────────────────────────────────────────────────────────── |
| 44 | |
| 45 | def test_pp1_happy_path_returns_upload_url_and_mpack_key() -> None: |
| 46 | mpack_bytes = b"fake mpack content" |
| 47 | mpack_key = blob_id(mpack_bytes) |
| 48 | do = _mock_urllib_do(_presign_response(mpack_key)) |
| 49 | |
| 50 | with patch("muse.core.transport._urllib_do", side_effect=do): |
| 51 | result = HttpTransport().push_mpack_presign(_URL, None, mpack_bytes) |
| 52 | |
| 53 | assert result["upload_url"] == _UPLOAD_URL |
| 54 | assert result["mpack_key"] == mpack_key |
| 55 | |
| 56 | |
| 57 | # ── PP-2 ────────────────────────────────────────────────────────────────────── |
| 58 | |
| 59 | def test_pp2_post_body_contains_correct_key_and_size() -> None: |
| 60 | mpack_bytes = b"x" * 512 |
| 61 | mpack_key = blob_id(mpack_bytes) |
| 62 | do = _mock_urllib_do(_presign_response(mpack_key)) |
| 63 | |
| 64 | with patch("muse.core.transport._urllib_do", side_effect=do): |
| 65 | HttpTransport().push_mpack_presign(_URL, None, mpack_bytes) |
| 66 | |
| 67 | _, _, _, sent_data = do.calls[0] |
| 68 | payload = msgpack.unpackb(sent_data, raw=False) |
| 69 | assert payload["mpack_key"] == mpack_key |
| 70 | assert payload["size_bytes"] == 512 |
| 71 | |
| 72 | |
| 73 | # ── PP-3 ────────────────────────────────────────────────────────────────────── |
| 74 | |
| 75 | def test_pp3_posts_to_correct_endpoint() -> None: |
| 76 | mpack_bytes = b"data" |
| 77 | mpack_key = blob_id(mpack_bytes) |
| 78 | do = _mock_urllib_do(_presign_response(mpack_key)) |
| 79 | |
| 80 | with patch("muse.core.transport._urllib_do", side_effect=do): |
| 81 | HttpTransport().push_mpack_presign(_URL, None, mpack_bytes) |
| 82 | |
| 83 | _, url, _, _ = do.calls[0] |
| 84 | assert url.endswith("/push/mpack-presign") |
| 85 | |
| 86 | |
| 87 | # ── PP-4 ────────────────────────────────────────────────────────────────────── |
| 88 | |
| 89 | def test_pp4_non_200_raises_transport_error() -> None: |
| 90 | do = _mock_urllib_do(b"quota exceeded", status=429) |
| 91 | |
| 92 | with patch("muse.core.transport._urllib_do", side_effect=do): |
| 93 | with pytest.raises(TransportError): |
| 94 | HttpTransport().push_mpack_presign(_URL, None, b"bytes") |
| 95 | |
| 96 | |
| 97 | # ── PP-5 ────────────────────────────────────────────────────────────────────── |
| 98 | |
| 99 | def test_pp5_missing_upload_url_raises_transport_error() -> None: |
| 100 | mpack_bytes = b"data" |
| 101 | mpack_key = blob_id(mpack_bytes) |
| 102 | bad_resp = msgpack.packb({"mpack_key": mpack_key}, use_bin_type=True) |
| 103 | do = _mock_urllib_do(bad_resp) |
| 104 | |
| 105 | with patch("muse.core.transport._urllib_do", side_effect=do): |
| 106 | with pytest.raises(TransportError, match="upload_url"): |
| 107 | HttpTransport().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
⚠
19 days ago
sha256:0bea7600d1eee83e87950be49933b1006fa9dc2c71e7c4ee748d324f61138156
chore: bump version to 0.2.0rc11; fix typing audit violatio…
Sonnet 4.6
minor
⚠
19 days ago