mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-10 22:08:48 +01:00
* 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
111 lines
6.1 KiB
Python
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()
|