Latest merge from Hunter. Also a couple files I forgot to add yesterday.
This commit is contained in:
1 parent
4da61465b0
commit
0a3d946ffa
4 files changed
+237
-3
No files matched your search
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Exercise build/toolchain boundaries without network access or a reader."""
|
||||
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
|
||||
MOCK_TOOL = r'''#!/usr/bin/env python3
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
tool = Path(sys.argv[0]).name
|
||||
args = sys.argv[1:]
|
||||
with open(os.environ["BUILD_LOG"], "a") as stream:
|
||||
stream.write(json.dumps([tool, args, os.getcwd(), {
|
||||
name: os.environ.get(name) for name in
|
||||
("GOTOOLCHAIN", "GOFLAGS", "CGO_ENABLED", "CGO_CFLAGS", "GOMODCACHE")
|
||||
}]) + "\n")
|
||||
if tool == "uname":
|
||||
print("Linux" if args == ["-s"] else "x86_64")
|
||||
elif tool == "pkg-config":
|
||||
sys.exit(1 if args[-1] == os.environ.get("MISSING_LIBRARY") else 0)
|
||||
elif tool == "curl":
|
||||
if args[-1].endswith(".sha256"):
|
||||
print(os.environ["ARCHIVE_SHA"])
|
||||
else:
|
||||
shutil.copyfile(os.environ["ARCHIVE_PATH"], args[args.index("--output") + 1])
|
||||
elif tool in ("go", "bootstrap-go"):
|
||||
if args == ["version"]:
|
||||
version = "1.24.0" if tool == "bootstrap-go" else os.environ["INSTALLED_GO"]
|
||||
print("go version go" + version + " linux/amd64")
|
||||
elif args[0] == "build":
|
||||
if args[-1].endswith("cthulhu-braille") and os.environ.get("FAIL_BRAILLE"):
|
||||
sys.exit(2)
|
||||
Path(args[args.index("-o") + 1]).touch()
|
||||
'''
|
||||
|
||||
|
||||
class BuildScriptTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tempDir = tempfile.TemporaryDirectory(prefix="cthulhu-build-test-")
|
||||
self.addCleanup(self.tempDir.cleanup)
|
||||
self.root = Path(self.tempDir.name)
|
||||
self.project = self.root / "checkout"
|
||||
self.project.mkdir()
|
||||
source = Path(__file__).resolve().parents[1] / "build-cthulhu.sh"
|
||||
self.script = self.project / source.name
|
||||
shutil.copyfile(source, self.script)
|
||||
(self.project / "go.mod").write_text("module example.invalid/reader\n\ngo 1.24.0\n")
|
||||
self.caller = self.root / "caller directory"
|
||||
self.caller.mkdir()
|
||||
self.binDir = self.root / "bin"
|
||||
self.binDir.mkdir()
|
||||
for name in ("go", "curl", "pkg-config", "uname"):
|
||||
toolPath = self.binDir / name
|
||||
toolPath.write_text(MOCK_TOOL)
|
||||
toolPath.chmod(0o755)
|
||||
# Give the downloaded Go its own name for log assertions.
|
||||
bootstrap = MOCK_TOOL.replace('Path(sys.argv[0]).name', '"bootstrap-go"')
|
||||
self.archive = self.root / "go.tar.gz"
|
||||
with tarfile.open(self.archive, "w:gz") as archive:
|
||||
data = bootstrap.encode()
|
||||
entry = tarfile.TarInfo("go/bin/go")
|
||||
entry.size = len(data)
|
||||
entry.mode = 0o755
|
||||
archive.addfile(entry, io.BytesIO(data))
|
||||
self.logPath = self.root / "calls.jsonl"
|
||||
self.env = dict(os.environ, PATH=f"{self.binDir}:/usr/bin:/bin",
|
||||
INSTALLED_GO="1.24.0", BUILD_LOG=str(self.logPath),
|
||||
XDG_CACHE_HOME=str(self.root / "cache"),
|
||||
ARCHIVE_PATH=str(self.archive),
|
||||
ARCHIVE_SHA=hashlib.sha256(self.archive.read_bytes()).hexdigest(),
|
||||
GOTOOLCHAIN="auto", CGO_ENABLED="1", GOFLAGS="-mod=readonly",
|
||||
CGO_CFLAGS="-O2", GOMODCACHE=str(self.root / "modules"))
|
||||
|
||||
def run_build(self, *args):
|
||||
return subprocess.run(["/bin/bash", str(self.script), *args], cwd=self.caller,
|
||||
env=self.env, text=True, capture_output=True, check=False)
|
||||
|
||||
def calls(self, name):
|
||||
if not self.logPath.exists():
|
||||
return []
|
||||
return [call for line in self.logPath.read_text().splitlines()
|
||||
if (call := json.loads(line))[0] == name]
|
||||
|
||||
def test_local_build_paths_flags_and_environment(self):
|
||||
self.env["GOTOOLCHAIN"] = "local"
|
||||
result = self.run_build("--output-dir", "output directory", "--", "-trimpath")
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
for binary in ("cthulhu", "cthulhu-braille"):
|
||||
self.assertTrue((self.caller / "output directory" / binary).is_file())
|
||||
builds = [call for call in self.calls("go") if call[1][0] == "build"]
|
||||
self.assertEqual(len(builds), 2)
|
||||
for call in builds:
|
||||
self.assertIn("-trimpath", call[1])
|
||||
self.assertEqual(call[2], str(self.project))
|
||||
for name in ("GOTOOLCHAIN", "GOFLAGS", "CGO_CFLAGS", "GOMODCACHE"):
|
||||
self.assertEqual(call[3][name], self.env[name])
|
||||
self.assertIn("brlapi", builds[1][1])
|
||||
self.assertFalse(self.calls("curl"))
|
||||
|
||||
def test_old_go_bootstrap_and_cache_reuse(self):
|
||||
self.env["INSTALLED_GO"] = "1.20.14"
|
||||
result = self.run_build()
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertTrue((self.project / "cthulhu-braille").is_file())
|
||||
self.assertEqual(len(self.calls("curl")), 2)
|
||||
result = self.run_build()
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertEqual(len(self.calls("curl")), 2)
|
||||
self.assertEqual(len([c for c in self.calls("bootstrap-go") if c[1][0] == "build"]), 4)
|
||||
|
||||
def test_checksum_failure_never_executes_download(self):
|
||||
self.env.update(INSTALLED_GO="1.20.14", ARCHIVE_SHA="0" * 64)
|
||||
result = self.run_build()
|
||||
self.assertNotEqual(result.returncode, 0)
|
||||
self.assertIn("checksum mismatch", result.stderr)
|
||||
self.assertFalse(self.calls("bootstrap-go"))
|
||||
self.assertFalse(list((self.root / "cache").rglob("*.download.*")))
|
||||
|
||||
def test_bootstrap_without_installed_go(self):
|
||||
(self.binDir / "go").unlink()
|
||||
for name in ("python3", "dirname", "awk", "mkdir", "mktemp", "tar",
|
||||
"gzip", "sha256sum", "mv", "rm"):
|
||||
toolPath = sys.executable if name == "python3" else shutil.which(name)
|
||||
(self.binDir / name).symlink_to(toolPath)
|
||||
self.env["PATH"] = str(self.binDir)
|
||||
result = self.run_build()
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertEqual(len(self.calls("curl")), 2)
|
||||
self.assertTrue((self.project / "cthulhu").is_file())
|
||||
|
||||
def test_local_old_go_does_not_download(self):
|
||||
self.env.update(INSTALLED_GO="1.20.14", GOTOOLCHAIN="local")
|
||||
result = self.run_build()
|
||||
self.assertNotEqual(result.returncode, 0)
|
||||
self.assertIn("Install Go 1.24.0", result.stderr)
|
||||
self.assertFalse(self.calls("curl"))
|
||||
|
||||
def test_preflight_and_arguments_do_not_download(self):
|
||||
for args in (("--output-dir",), ("--unknown",)):
|
||||
with self.subTest(args=args):
|
||||
self.assertNotEqual(self.run_build(*args).returncode, 0)
|
||||
self.assertEqual(self.run_build("--help").returncode, 0)
|
||||
self.assertFalse(self.logPath.exists())
|
||||
self.env.update(INSTALLED_GO="1.20.14", MISSING_LIBRARY="xres")
|
||||
result = self.run_build()
|
||||
self.assertIn("xres", result.stderr)
|
||||
self.assertNotEqual(result.returncode, 0)
|
||||
self.assertFalse(self.calls("curl"))
|
||||
|
||||
def test_braille_failure_is_not_reported_as_success(self):
|
||||
self.env["FAIL_BRAILLE"] = "1"
|
||||
result = self.run_build()
|
||||
self.assertNotEqual(result.returncode, 0)
|
||||
self.assertNotIn("Cthulhu has been built", result.stdout)
|
||||
|
||||
def test_disabled_cgo_and_output_conflicts_fail_before_building(self):
|
||||
self.env["CGO_ENABLED"] = "0"
|
||||
result = self.run_build()
|
||||
self.assertNotEqual(result.returncode, 0)
|
||||
self.assertIn("CGO_ENABLED=1", result.stderr)
|
||||
self.env["CGO_ENABLED"] = "1"
|
||||
(self.caller / "output").write_text("existing file")
|
||||
self.assertNotEqual(self.run_build("-o", "output").returncode, 0)
|
||||
(self.project / "cthulhu-braille").mkdir()
|
||||
self.assertNotEqual(self.run_build().returncode, 0)
|
||||
self.assertFalse(self.calls("go"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user