forked from linkong/planet
135 lines
7.0 KiB
Python
135 lines
7.0 KiB
Python
"""Mirror routing regressions without pulling images or editing daemon configuration."""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from test_database_startup import run_shell
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
sys.path.insert(0, str(ROOT / "scripts"))
|
|
import docker_mirror as mirror
|
|
import docker_proxy as proxy
|
|
|
|
DIGEST = "sha256:" + "a" * 64
|
|
|
|
|
|
class MirrorTests(unittest.TestCase):
|
|
def test_recoverable_uv_failure_does_not_freeze_status_before_tuna_fallback(self) -> None:
|
|
result = run_shell(["run_uv_sync_with_mirror_fallback", "run_with_retry"], """
|
|
DEPENDENCY_INSTALL_MAX_RETRIES=1
|
|
DEPENDENCY_INSTALL_RETRY_INTERVAL=0
|
|
WAIT_FAILURE_REPORTED=0
|
|
uv_lock_digest() { echo stable; }
|
|
assert_uv_lock_unchanged() { :; }
|
|
run_command_with_spinner() { shift; "$@"; }
|
|
run_command_quiet_unless_verbose() { return 1; }
|
|
configure_uv_tuna_index() { echo MIRROR_READY; }
|
|
run_uv_sync_with_tuna_config() { echo RECOVERED; }
|
|
set_wait_detail() { :; }
|
|
log_error() { echo FATAL; WAIT_FAILURE_REPORTED=1; }
|
|
""", "run_uv_sync_with_mirror_fallback /dev/null\n[ $WAIT_FAILURE_REPORTED -eq 0 ]")
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
self.assertEqual(result.stdout.splitlines(), ["MIRROR_READY", "RECOVERED"])
|
|
|
|
def test_build_network_failure_retries_once_with_temporary_args(self) -> None:
|
|
with tempfile.TemporaryDirectory() as folder:
|
|
result = run_shell(["run_ai_provider_build_command"], f"""
|
|
AI_PROVIDER_BUILD_LOG_FILE={folder}/build.log
|
|
attempts=0
|
|
DOCKER_BUILD_USE_MIRROR=0
|
|
PYTHON_IMAGE=python:3.14-slim
|
|
run_docker_observed() {{
|
|
attempts=$((attempts + 1))
|
|
echo "$*" >&2
|
|
echo failure > "$3"
|
|
[ $attempts -eq 2 ]
|
|
}}
|
|
docker_failure_allows_mirror() {{ return 0; }}
|
|
prepare_docker_build_proxy() {{ DOCKER_BUILD_USE_MIRROR=1; }}
|
|
resolve_build_mirror_args() {{ DOCKER_MIRROR_BUILD_ARGS=(--build-arg PYTHON_IMAGE=mirror/python@{DIGEST}); }}
|
|
""", 'run_ai_provider_build_command "docker compose"\n'
|
|
'[ $attempts -eq 2 ] && [ "$PYTHON_IMAGE" = python:3.14-slim ]')
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
self.assertIn("--build-arg PYTHON_IMAGE=mirror/python@", result.stderr)
|
|
self.assertTrue((Path(folder) / "build.primary.log").exists())
|
|
|
|
def test_mapping_retains_original_repository_and_digest(self) -> None:
|
|
for image, expected in (
|
|
("python:3.14-slim", "docker.io/library/python:3.14-slim"),
|
|
("docker.io/postgres:15", "docker.io/library/postgres:15"),
|
|
("ghcr.io/astral-sh/uv:latest", "ghcr.io/astral-sh/uv:latest"),
|
|
("redis@" + DIGEST, "docker.io/library/redis@" + DIGEST),
|
|
):
|
|
self.assertEqual(mirror.mirror_image(image, {}), "m.daocloud.io/" + expected)
|
|
|
|
def test_private_repository_and_credentials_are_not_sent_to_public_mirror(self) -> None:
|
|
for image in ("private.example/team/python:3", "docker.io/private/app:latest"):
|
|
with self.assertRaises(mirror.MirrorError):
|
|
mirror.mirror_image(image, {})
|
|
with self.assertRaises(mirror.MirrorError):
|
|
mirror.mirror_prefix({"PLANET_DOCKER_MIRROR_PREFIX": "user:secret@mirror.test"})
|
|
|
|
def test_manifest_is_required_and_pinned_even_for_mutable_tags(self) -> None:
|
|
with patch.object(mirror, "run", return_value=json.dumps({"digest": DIGEST})):
|
|
self.assertEqual(mirror.resolve_image("python:3.14-slim", {}),
|
|
"m.daocloud.io/docker.io/library/python@" + DIGEST)
|
|
self.assertEqual(mirror.resolve_image("redis@" + DIGEST, {}),
|
|
"m.daocloud.io/docker.io/library/redis@" + DIGEST)
|
|
for manifest in ([], {}, {"digest": None}, {"digest": "invalid"}, {"digest": "sha256:" + "b" * 64}):
|
|
with patch.object(mirror, "run", return_value=json.dumps(manifest)):
|
|
with self.assertRaises(mirror.MirrorError):
|
|
mirror.resolve_image("redis@" + DIGEST, {})
|
|
|
|
def test_primary_route_is_preferred_and_fallback_can_be_disabled(self) -> None:
|
|
for reachable, disabled, calls in ((True, False, 1), (False, True, 1), (False, False, 2)):
|
|
with patch.object(proxy, "select_route", side_effect=[
|
|
{"reachable": reachable}, {"reachable": True}
|
|
]) as select:
|
|
plan = proxy.plan_routes({"PLANET_DOCKER_MIRROR_FALLBACK": "0"} if disabled else {})
|
|
self.assertEqual(select.call_count, calls)
|
|
self.assertEqual(plan["mirror"], calls == 2)
|
|
|
|
def test_database_pull_keeps_canonical_tag_and_does_not_replace_cached_images(self) -> None:
|
|
for cached in (True, False):
|
|
calls = []
|
|
def run(command, timeout=30):
|
|
calls.append(command)
|
|
return json.dumps({"services": {"postgres": {"image": "postgres:15"}}})
|
|
with patch.object(mirror, "run", side_effect=run), \
|
|
patch.object(mirror, "resolve_image", return_value="mirror/pg@" + DIGEST), \
|
|
patch.object(mirror.subprocess, "run", return_value=subprocess.CompletedProcess([], 0 if cached else 1)):
|
|
mirror.pull_services(["postgres"], {})
|
|
self.assertEqual(len(calls), 1 if cached else 3)
|
|
if not cached:
|
|
self.assertEqual(calls[-1], ["docker", "tag", "mirror/pg@" + DIGEST, "postgres:15"])
|
|
|
|
def test_only_registry_network_errors_allow_fallback(self) -> None:
|
|
cases = (
|
|
('Head "https://registry-1.docker.io/v2/python": i/o timeout', True),
|
|
('#3 [internal] load metadata for python\nPLANET_DOCKER_COMMAND_TIMEOUT', True),
|
|
('Head "https://registry-1.docker.io/v2/python": 429 Too Many Requests', False),
|
|
('Head "https://registry-1.docker.io/v2/python": unauthorized:', False),
|
|
('Head "https://registry-1.docker.io/v2/python": x509: unknown authority', False),
|
|
('#3 load metadata for python\nno such host\nprocess "/bin/sh -c uv sync" failed', False),
|
|
('Bind for 127.0.0.1:5432 failed: port is already allocated', False),
|
|
)
|
|
with tempfile.TemporaryDirectory() as folder:
|
|
log = Path(folder) / "failure.log"
|
|
for evidence, expected in cases:
|
|
log.write_text(evidence)
|
|
result = run_shell([], f"""
|
|
SCRIPT_DIR={ROOT}
|
|
source {ROOT}/scripts/lib/error-diagnostics.zsh
|
|
source {ROOT}/scripts/lib/docker-mirror.zsh
|
|
""", f"docker_failure_allows_mirror {log}")
|
|
self.assertEqual(result.returncode == 0, expected, evidence + result.stderr)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|