Repository navigation
Expand file tree
/
Copy pathlocal_test.py
More file actions
111 lines (88 loc) · 3.03 KB
/
Copy pathlocal_test.py
File metadata and controls
111 lines (88 loc) · 3.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
"""Run the pull-request product tests in the current local environment."""
from __future__ import annotations
import os
import subprocess
import sys
from dataclasses import dataclass
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import Callable, Mapping
from test.ci.shards import SHARDS
REPOSITORY_ROOT = Path(__file__).resolve().parent
XDG_DIRECTORIES = {
"XDG_STATE_HOME": "state",
"XDG_CONFIG_HOME": "config",
"XDG_DATA_HOME": "data",
"XDG_CACHE_HOME": "cache",
}
@dataclass(frozen=True)
class TestCommand:
"""A named child process in the local test sequence."""
label: str
argv: tuple[str, ...]
ProcessRunner = Callable[..., subprocess.CompletedProcess[bytes]]
def test_commands(python: str = sys.executable) -> tuple[TestCommand, ...]:
"""Build the contract command followed by every registered test domain."""
commands = [
TestCommand(
"Test contract",
(python, "-m", "unittest", "-v", "test.ci.test_pr_workflow"),
)
]
commands.extend(
TestCommand(
f"Domain: {shard.id} ({shard.name})",
(python, "-m", "test.ci.run_test_shard", "--domain", shard.id),
)
for shard in SHARDS
)
return tuple(commands)
def isolated_environment(
root: Path, base: Mapping[str, str] | None = None
) -> dict[str, str]:
"""Copy an environment and add writable, isolated Qt/XDG test settings."""
environment = dict(os.environ if base is None else base)
environment.update(
{
"PYTHONUTF8": "1",
"QT_QPA_PLATFORM": "offscreen",
"QT_OPENGL": "software",
"LIBGL_ALWAYS_SOFTWARE": "1",
}
)
for variable, directory_name in XDG_DIRECTORIES.items():
directory = root / directory_name
directory.mkdir(parents=True, exist_ok=True)
environment[variable] = str(directory)
return environment
def run_local_tests(
runner: ProcessRunner | None = None,
*,
python: str = sys.executable,
) -> int:
"""Run all local CI commands and return the first non-zero exit status."""
process_runner = runner or subprocess.run
commands = test_commands(python)
with TemporaryDirectory(prefix="xjtu-local-test-") as temporary_root:
environment = isolated_environment(Path(temporary_root))
for command in commands:
print(f"==> {command.label}", flush=True)
result = process_runner(
command.argv,
cwd=REPOSITORY_ROOT,
env=environment,
check=False,
)
if result.returncode:
print(
f"FAILED: {command.label} (exit {result.returncode})",
file=sys.stderr,
flush=True,
)
return result.returncode
print(f"PASS: {len(commands)} local test commands succeeded.", flush=True)
return 0
def main() -> int:
return run_local_tests()
if __name__ == "__main__":
raise SystemExit(main())