Files
pebrel/scripts/tests/test_xplat.py
T

177 lines
8.3 KiB
Python

"""Exercise metadata-check isolation; the Cargo recorder performs no compilation."""
import json
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
import unittest
ROOT = Path(__file__).resolve().parents[2]
MAC_TARGET = "aarch64-apple-darwin"
@unittest.skipUnless(os.name == "posix" and shutil.which("bash"), "requires a POSIX Bash host")
class XplatIsolationTests(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory(prefix="nebula-xplat-test-")
self.addCleanup(self.temp.cleanup)
self.root = Path(self.temp.name).resolve()
self.repo = self.root / "repo with spaces"
self.scripts = self.repo / "scripts/xplat"
shutil.copytree(ROOT / "scripts/xplat", self.scripts)
self.output = self.repo / ".target-xplat/metadata-only-v1"
self.native = self.root / "native target"
self.native.mkdir()
self.native_sentinel = self.native / "keep.txt"
self.native_sentinel.write_text("native cache", encoding="utf-8")
self.calls = self.root / "cargo-calls.jsonl"
self.bin = self.root / "bin"
self.bin.mkdir()
rustc = self.bin / "rustc"
rustc.write_text(
'#!/usr/bin/env bash\nprintf "rustc test\\nhost: %s\\n" "$XPLAT_TEST_HOST"\n',
encoding="utf-8",
)
cargo = self.bin / "cargo"
cargo.write_text(
"#!/usr/bin/env python3\n"
"import json, os, sys\n"
"from pathlib import Path\n"
"record = {'args': sys.argv[1:], 'target': os.environ['CARGO_TARGET_DIR'], "
"'build_dir': os.environ['CARGO_BUILD_BUILD_DIR'], "
"'cc': os.environ.get('CC_aarch64_apple_darwin')}\n"
"with Path(os.environ['XPLAT_TEST_LOG']).open('a', encoding='utf-8') as log:\n"
" log.write(json.dumps(record) + '\\n')\n"
"raise SystemExit(int(os.environ.get('XPLAT_TEST_EXIT', '0')))\n",
encoding="utf-8",
)
rustc.chmod(0o755)
cargo.chmod(0o755)
def run_check(self, *args, host="x86_64-pc-windows-msvc", exit_code=0):
env = {
**os.environ,
"PATH": str(self.bin) + os.pathsep + os.environ["PATH"],
"RUSTC": str(self.bin / "rustc"),
"CARGO_TARGET_DIR": str(self.native),
"CARGO_BUILD_BUILD_DIR": str(self.native / "intermediate"),
"XPLAT_TEST_HOST": host,
"XPLAT_TEST_LOG": str(self.calls),
"XPLAT_TEST_EXIT": str(exit_code),
}
return subprocess.run(
[str(self.scripts / "check.sh"), *(args or ("macos",))],
cwd=self.root, env=env, text=True, capture_output=True, timeout=10,
)
def recordings(self):
if not self.calls.exists():
return []
return [json.loads(line) for line in self.calls.read_text(encoding="utf-8").splitlines()]
def build_out(self, base, package):
result = base / MAC_TARGET / "debug/build" / package / "out"
result.mkdir(parents=True)
return result
def test_inherited_native_output_is_preserved_and_cargo_is_locked(self):
native_out = self.build_out(self.native, "media-native")
result = self.run_check("macos", "--features", "gpui-shell", "-p", "nebula")
self.assertEqual(result.returncode, 0, result.stderr)
call, = self.recordings()
self.assertEqual(call["target"], str(self.output))
self.assertEqual(call["build_dir"], str(self.output))
args = call["args"]
self.assertIn("--locked", args)
self.assertEqual(args[args.index("--target-dir") + 1], str(self.output))
self.assertEqual(args[-4:], ["--features", "gpui-shell", "-p", "nebula"])
self.assertEqual(list(native_out.iterdir()), [])
self.assertEqual(self.native_sentinel.read_text(encoding="utf-8"), "native cache")
self.assertIn("not a native build/test", result.stdout)
def test_native_target_is_rejected_before_any_output_or_cargo_call(self):
for selector, host in [("macos", MAC_TARGET), ("linux", "x86_64-unknown-linux-gnu"), ("all", MAC_TARGET)]:
with self.subTest(selector=selector):
result = self.run_check(selector, host=host)
self.assertEqual(result.returncode, 2, result.stderr)
self.assertIn("refusing native target", result.stderr)
self.assertEqual(self.recordings(), [])
self.assertFalse(self.output.exists())
def test_cargo_target_and_configuration_overrides_are_rejected(self):
for options in [
["--target-dir", str(self.native)], [f"--target-dir={self.native}"],
["--target-d", str(self.native)], ["--config", "build.target-dir='target'"],
["--config=build.target-dir='target'"], ["--target", "x86_64-unknown-linux-gnu"],
["--manifest-path", "elsewhere/Cargo.toml"], ["--release"],
]:
with self.subTest(options=options):
result = self.run_check("macos", *options)
self.assertEqual(result.returncode, 2, result.stderr)
self.assertEqual(self.recordings(), [])
self.assertFalse(self.output.exists())
def test_unmarked_existing_metadata_directory_is_not_repurposed(self):
self.output.mkdir(parents=True)
sentinel = self.output / "user-data"
sentinel.write_text("keep", encoding="utf-8")
result = self.run_check()
self.assertEqual(result.returncode, 2, result.stderr)
self.assertEqual(sentinel.read_text(encoding="utf-8"), "keep")
self.assertEqual(self.recordings(), [])
def test_stubs_are_seeded_only_in_owned_metadata_output(self):
self.assertEqual(self.run_check().returncode, 0)
media = self.build_out(self.output, "media-check")
shaders = self.build_out(self.output, "gpui_macos-check")
native_media = self.build_out(self.native, "media-native")
native_shaders = self.build_out(self.native, "gpui_macos-native")
result = self.run_check()
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual((media / "bindings.rs").read_bytes(), (self.scripts / "media-bindings-stub.rs").read_bytes())
self.assertEqual((shaders / "shaders.metallib").read_bytes(), b"")
self.assertEqual(list(native_media.iterdir()), [])
self.assertEqual(list(native_shaders.iterdir()), [])
def test_symlinked_output_root_is_rejected(self):
(self.repo / ".target-xplat").symlink_to(self.native, target_is_directory=True)
result = self.run_check()
self.assertEqual(result.returncode, 2, result.stderr)
self.assertEqual(self.recordings(), [])
self.assertEqual([path.name for path in self.native.iterdir()], ["keep.txt"])
def test_symlinked_stub_directory_cannot_escape_owned_output(self):
self.assertEqual(self.run_check().returncode, 0)
package = self.output / MAC_TARGET / "debug/build/media-escape"
package.mkdir(parents=True)
(package / "out").symlink_to(self.native, target_is_directory=True)
result = self.run_check()
self.assertEqual(result.returncode, 2, result.stderr)
self.assertIn("escapes metadata directory", result.stderr)
self.assertEqual(len(self.recordings()), 1)
self.assertFalse((self.native / "bindings.rs").exists())
def test_symlinked_stub_file_cannot_overwrite_native_file(self):
self.assertEqual(self.run_check().returncode, 0)
media = self.build_out(self.output, "media-escape")
(media / "bindings.rs").symlink_to(self.native_sentinel)
result = self.run_check()
self.assertEqual(result.returncode, 2, result.stderr)
self.assertEqual(self.native_sentinel.read_text(encoding="utf-8"), "native cache")
def test_cargo_failure_is_reported_unchanged(self):
result = self.run_check(exit_code=17)
self.assertEqual(result.returncode, 17)
self.assertEqual(len(self.recordings()), 1)
def test_posix_compiler_can_be_invoked_directly(self):
result = subprocess.run(
[str(self.scripts / "fake-cc.sh"), "--version"],
text=True, capture_output=True, timeout=10,
)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertIn("cross-check stub", result.stdout)