"""Tests for pack_origin URL rewriting in _push_objects_as_packs. Covers: - URL origin replacement (scheme + host replaced, path preserved) - No-op when pack_origin is absent - Different scheme rewriting (http → https) - Empty object-list produces no pack uploads """ from __future__ import annotations import pathlib import unittest.mock import hashlib import pytest from muse.cli.commands.push import _push_objects_as_packs from muse.core.object_store import write_object from muse.core.pack import ObjectsChunkResponse # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- def _make_transport(captured_urls: list[str]) -> unittest.mock.MagicMock: """Build a mock transport that records the URL passed to push_object_pack.""" transport = unittest.mock.MagicMock() def _push_pack(url: str, signing: object, pack: list[object]) -> ObjectsChunkResponse: captured_urls.append(url) return ObjectsChunkResponse(stored=len(pack), skipped=0) transport.push_object_pack.side_effect = _push_pack return transport def _write_obj(root: pathlib.Path, content: bytes) -> str: """Write content to the object store and return its real SHA-256 OID.""" oid = hashlib.sha256(content).hexdigest() write_object(root, oid, content) return oid # --------------------------------------------------------------------------- # pack_origin URL rewriting # --------------------------------------------------------------------------- class TestPackOriginUrlRewriting: def test_origin_replaced_path_preserved(self, tmp_path: pathlib.Path) -> None: """pack_origin replaces scheme+host; /{owner}/{slug} path is kept intact.""" urls: list[str] = [] transport = _make_transport(urls) oid = _write_obj(tmp_path, b"test-object-a") _push_objects_as_packs( transport, "http://localhost:10003/gabriel/muse", None, [oid], tmp_path, pack_origin="https://worker.example.workers.dev", ) assert len(urls) == 1 assert urls[0] == "https://worker.example.workers.dev/gabriel/muse" def test_https_hub_replaced_with_worker_origin(self, tmp_path: pathlib.Path) -> None: """HTTPS musehub.ai origin is replaced with the worker origin.""" urls: list[str] = [] transport = _make_transport(urls) oid = _write_obj(tmp_path, b"test-object-b") _push_objects_as_packs( transport, "https://musehub.ai/gabriel/muse", None, [oid], tmp_path, pack_origin="https://worker.example.workers.dev", ) assert urls[0] == "https://worker.example.workers.dev/gabriel/muse" def test_no_pack_origin_uses_hub_url_unchanged(self, tmp_path: pathlib.Path) -> None: """Without pack_origin the original URL is passed to push_object_pack.""" urls: list[str] = [] transport = _make_transport(urls) oid = _write_obj(tmp_path, b"test-object-c") _push_objects_as_packs( transport, "https://musehub.ai/gabriel/muse", None, [oid], tmp_path, ) assert urls[0] == "https://musehub.ai/gabriel/muse" def test_http_to_https_scheme_swap(self, tmp_path: pathlib.Path) -> None: """HTTP localhost URL is rewritten to HTTPS worker URL.""" urls: list[str] = [] transport = _make_transport(urls) oid = _write_obj(tmp_path, b"test-object-d") _push_objects_as_packs( transport, "http://localhost:10003/org/repo", None, [oid], tmp_path, pack_origin="https://worker.example.workers.dev", ) assert urls[0] == "https://worker.example.workers.dev/org/repo" def test_empty_object_list_no_pack_calls(self, tmp_path: pathlib.Path) -> None: """Zero objects produces zero push_object_pack calls regardless of pack_origin.""" urls: list[str] = [] transport = _make_transport(urls) stored, skipped = _push_objects_as_packs( transport, "https://musehub.ai/gabriel/muse", None, [], tmp_path, pack_origin="https://worker.example.workers.dev", ) assert urls == [] assert stored == 0 assert skipped == 0 def test_pack_origin_does_not_append_extra_path(self, tmp_path: pathlib.Path) -> None: """The worker origin must not accumulate path segments from both URLs.""" urls: list[str] = [] transport = _make_transport(urls) oid = _write_obj(tmp_path, b"test-object-e") _push_objects_as_packs( transport, "https://musehub.ai/gabriel/muse", None, [oid], tmp_path, pack_origin="https://different-worker.dev", ) # Must be exactly worker origin + hub path, no duplication assert urls[0] == "https://different-worker.dev/gabriel/muse" assert urls[0].count("/gabriel/muse") == 1 def test_multiple_packs_all_use_worker_url(self, tmp_path: pathlib.Path) -> None: """All packs in a multi-pack upload use the worker origin.""" urls: list[str] = [] transport = _make_transport(urls) oids = [] for i in range(5): oid = _write_obj(tmp_path, f"multi-pack-content-{i}".encode()) oids.append(oid) _push_objects_as_packs( transport, "https://musehub.ai/gabriel/muse", None, oids, tmp_path, pack_origin="https://worker.example.workers.dev", ) assert len(urls) >= 1 for url in urls: assert url.startswith("https://worker.example.workers.dev") assert "/gabriel/muse" in url def test_stored_and_skipped_totals_accumulated(self, tmp_path: pathlib.Path) -> None: """Return value is (total_stored, total_skipped) summed across all packs.""" transport = unittest.mock.MagicMock() def _push_pack(url: str, signing: object, pack: list[object]) -> ObjectsChunkResponse: return ObjectsChunkResponse(stored=len(pack), skipped=0) transport.push_object_pack.side_effect = _push_pack oids = [] for i in range(3): oid = _write_obj(tmp_path, f"accumulate-content-{i}".encode()) oids.append(oid) stored, skipped = _push_objects_as_packs( transport, "https://musehub.ai/gabriel/muse", None, oids, tmp_path, ) assert stored == 3 assert skipped == 0