Files
seaweedfs/docker/test_apt_install.py
T
Chris Lu 6c473433c5 vector: bound request buffering before authentication and document installation (#12537)
* s3vectors: bound body buffering before authentication

* docs: include vector engine installation and source builds

* s3vectors: prevent MIME sniffing of JSON error responses

* docs: load vector Cargo configuration when building from source

* docs: note the native protoc requirement for Windows vector builds

* docs: make vector source checkout and working directory explicit

* ci: handle deb822 sources during Ubuntu mirror failover

* ci: bound Ubuntu mirror attempts and reject partial index updates
2026-11-10 04:21:56 -08:00

111 lines
6.1 KiB
Python

import json
import os
from pathlib import Path
import subprocess
import tempfile
import unittest
class AptInstallTests(unittest.TestCase):
def run_helper(self, sources, fail_action="update", timeout_azure=False):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
apt = root / "apt"
(apt / "sources.list.d").mkdir(parents=True)
(apt / "sources.list").write_text("")
for name, content in sources.items():
(apt / name).write_text(content)
helper = root / "apt-install"
helper.write_text(Path(__file__).with_name("apt-install").read_text()
.replace("/etc/apt", str(apt))
.replace("/var/lib/apt", str(root / "state")))
commands = root / "bin"
commands.mkdir()
fake_apt = commands / "apt-get"
fake_apt.write_text(r"""#!/usr/bin/env python3
import json, os, pathlib, sys
root = pathlib.Path(os.environ["VECTOR_APT_TEST_ROOT"])
apt = root / "apt"
sources = [apt / "sources.list", *apt.glob("sources.list.d/*.list"), *apt.glob("sources.list.d/*.sources")]
content = "".join(p.read_text() for p in sources)
action = next(a for a in sys.argv[1:] if a in ("update", "install", "clean"))
with (root / "calls").open("a") as output:
output.write(json.dumps({"action": action, "sources": content, "args": sys.argv[1:]}) + "\n")
if "azure.archive.ubuntu.com" in content and action == "update" and os.environ["VECTOR_APT_FAIL_ACTION"] == "partial":
sys.exit(100 if "APT::Update::Error-Mode=any" in sys.argv else 0)
if "azure.archive.ubuntu.com" in content and action == os.environ["VECTOR_APT_FAIL_ACTION"]:
sys.exit(100)
""")
fake_apt.chmod(0o755)
fake_timeout = commands / "timeout"
fake_timeout.write_text(r"""#!/usr/bin/env python3
import json, os, pathlib, sys
root = pathlib.Path(os.environ["VECTOR_APT_TEST_ROOT"])
apt = root / "apt"
sources = [apt / "sources.list", *apt.glob("sources.list.d/*.list"), *apt.glob("sources.list.d/*.sources")]
content = "".join(p.read_text() for p in sources)
with (root / "calls").open("a") as output:
output.write(json.dumps({"action": "timeout", "args": sys.argv[1:]}) + "\n")
if os.environ["VECTOR_APT_TIMEOUT_AZURE"] and "azure.archive.ubuntu.com" in content:
sys.exit(124)
os.execvp(sys.argv[3], sys.argv[3:])
""")
fake_timeout.chmod(0o755)
result = subprocess.run(["/bin/sh", str(helper), "fuse"],
env={**os.environ, "PATH": str(commands) + os.pathsep + os.environ["PATH"],
"VECTOR_APT_TEST_ROOT": str(root), "VECTOR_APT_FAIL_ACTION": fail_action,
"VECTOR_APT_TIMEOUT_AZURE": "1" if timeout_azure else ""},
text=True, capture_output=True, timeout=5)
calls = [json.loads(line) for line in (root / "calls").read_text().splitlines()] if (root / "calls").exists() else []
return result, calls
def test_fallback_rewrites_all_source_formats(self):
for protocol in ("http", "https"):
for layout in ("legacy", "deb822", "mixed"):
with self.subTest(protocol=protocol, layout=layout):
sources = {}
if layout in ("legacy", "mixed"):
sources["sources.list"] = f"deb {protocol}://azure.archive.ubuntu.com/ubuntu noble main\n"
if layout in ("deb822", "mixed"):
sources["sources.list.d/ubuntu.sources"] = f"Types: deb\nURIs: {protocol}://azure.archive.ubuntu.com/ubuntu\nSuites: noble\nComponents: main\n"
result, calls = self.run_helper(sources)
self.assertEqual(result.returncode, 0, result.stderr)
installs = [call for call in calls if call["action"] == "install"]
self.assertEqual(len(installs), 1)
self.assertNotIn("azure.archive.ubuntu.com", installs[0]["sources"])
self.assertIn(protocol + "://archive.ubuntu.com", installs[0]["sources"])
def test_install_failure_also_tries_the_next_mirror(self):
result, calls = self.run_helper({"sources.list.d/ubuntu.sources":
"Types: deb\nURIs: http://security.ubuntu.com/ubuntu\nSuites: noble-security\nComponents: main\n"},
fail_action="install")
self.assertEqual(result.returncode, 0, result.stderr)
installs = [call for call in calls if call["action"] == "install"]
self.assertEqual(len(installs), 2)
self.assertIn("azure.archive.ubuntu.com", installs[0]["sources"])
self.assertNotIn("azure.archive.ubuntu.com", installs[1]["sources"])
def test_partial_update_does_not_install_stale_indexes(self):
result, calls = self.run_helper({"sources.list": "deb http://azure.archive.ubuntu.com/ubuntu noble main\n"},
fail_action="partial")
self.assertEqual(result.returncode, 0, result.stderr)
installs = [call for call in calls if call["action"] == "install"]
self.assertEqual(len(installs), 1)
self.assertNotIn("azure.archive.ubuntu.com", installs[0]["sources"])
def test_timeout_advances_to_the_next_mirror(self):
result, calls = self.run_helper({"sources.list": "deb http://azure.archive.ubuntu.com/ubuntu noble main\n"},
fail_action="none", timeout_azure=True)
self.assertEqual(result.returncode, 0, result.stderr)
timeouts = [call for call in calls if call["action"] == "timeout"]
self.assertEqual(len(timeouts), 3)
for call in timeouts:
self.assertEqual(call["args"][0], "--kill-after=5s")
self.assertLessEqual(int(call["args"][1].removesuffix("s")), 180)
installs = [call for call in calls if call["action"] == "install"]
self.assertNotIn("azure.archive.ubuntu.com", installs[0]["sources"])
if __name__ == "__main__":
unittest.main()