Skip to content

Commit 460efa0

Browse files
committed
Crash test script WIP
1 parent 1b44603 commit 460efa0

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

tools/crash_test.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#!/usr/bin/env python3
2+
3+
import os
4+
import subprocess
5+
import sys
6+
import traceback
7+
8+
DAEMON_DIR = '/unv/Unvanquished/daemon'
9+
BREAKPAD_DIR = '/unv/Unvanquished/daemon/libs/breakpad'
10+
GAME_BUILD_DIR = '.'
11+
ARCH = 'amd64'
12+
13+
SYMBOLIZE = os.path.join(BREAKPAD_DIR, "symbolize.py")
14+
STACKWALK = os.path.join(BREAKPAD_DIR, "src/processor/minidump_stackwalk")
15+
16+
DAEMON_TTYCLIENT = os.path.join(GAME_BUILD_DIR, 'daemon-tty')
17+
DAEMON_SERVER = os.path.join(GAME_BUILD_DIR, 'daemonded')
18+
TEMP_DIR = os.path.join(GAME_BUILD_DIR, "crashtest-tmp")
19+
os.makedirs(TEMP_DIR, exist_ok=True)
20+
SYMBOL_DIR = os.path.join(TEMP_DIR, "symbols")
21+
os.makedirs(SYMBOL_DIR, exist_ok=True)
22+
HOMEPATH = os.path.join(TEMP_DIR, "homepath")
23+
24+
dummy = False
25+
if dummy:
26+
GAMELOGIC_NACL = os.path.join(GAME_BUILD_DIR, f"cgame-{ARCH}.nexe")
27+
else:
28+
GAMELOGIC_NACL = os.path.join(GAME_BUILD_DIR, f"sgame-{ARCH}.nexe")
29+
30+
31+
assert os.path.isfile(GAMELOGIC_NACL), GAMELOGIC_NACL
32+
assert os.path.isfile(DAEMON_SERVER)
33+
assert os.path.isfile(STACKWALK)
34+
35+
print(f"Symbolizing '{GAMELOGIC_NACL}'...")
36+
subprocess.check_call([sys.executable, SYMBOLIZE, "--symbol-directory", SYMBOL_DIR, GAMELOGIC_NACL])
37+
38+
class CrashTest:
39+
def __init__(self, name):
40+
self.name = name
41+
42+
def Begin(self):
43+
self.status = "PASSED"
44+
print(f"===RUNNING: {self.name}===")
45+
self.tmpdir = os.path.join(TEMP_DIR, self.name)
46+
os.makedirs(self.tmpdir, exist_ok=True)
47+
48+
def End(self):
49+
print(f"==={self.status}: {self.name}===")
50+
51+
def Verify(self, cond, reason):
52+
if not cond:
53+
print(f"FAILURE: {reason}")
54+
self.status = "FAILED"
55+
56+
def Go(self):
57+
self.Begin()
58+
try:
59+
self.Do()
60+
except Exception as e:
61+
traceback.print_exception(e)
62+
self.status = "FAILED"
63+
self.End()
64+
return self.status == "PASSED"
65+
66+
class NaclCrashTest(CrashTest):
67+
def __init__(self, fault):
68+
super().__init__(f"nacl.{fault}")
69+
self.fault = fault
70+
71+
def Do(self):
72+
print("Running daemon...")
73+
p = subprocess.run([DAEMON_SERVER, "-set", "vm.sgame.type", "1",
74+
#"-set", "logs.level.fs", "warning",
75+
"-set", "sv_fps", "1000",
76+
#"-set", "server.private", "2",
77+
#"-set", "sv_networkScope", "0",
78+
"-set", "net_enabled", "0",
79+
"-set", "common.framerate.max", "0",
80+
#"-homepath", HOMEPATH,
81+
#"-pakpath", os.path.join(DAEMON_DIR, "pkg"),
82+
#"-set", "fs_basepak", "testdata",
83+
"+devmap plat23",
84+
"+delay 20f echo CRASHTEST_BEGIN",
85+
"+delay 20f sgame.injectFault", self.fault,
86+
"+delay 20f echo CRASHTEST_END",
87+
"+delay 40f quit"],
88+
stderr=subprocess.PIPE)
89+
log = [s.strip() for s in p.stderr.decode("utf8").splitlines()]
90+
i = log.index("CRASHTEST_BEGIN")
91+
j = log.index("CRASHTEST_END")
92+
# TODO expected vs. actual Warn's
93+
DUMP_PREFIX = "Wrote crash dump to "
94+
dumps = [l for l in log if l.startswith(DUMP_PREFIX)]
95+
assert len(dumps) == 1, "Daemon log contains 1 crash dump"
96+
dump = dumps[0][len(DUMP_PREFIX):]
97+
sw_out = os.path.join(self.tmpdir, "stackwalk.log")
98+
with open(sw_out, "a+") as sw_f:
99+
print(f"Extracting stack trace to '{sw_out}'...")
100+
sw_f.truncate()
101+
subprocess.run([STACKWALK, dump, SYMBOL_DIR], check=True, stdout=sw_f, stderr=subprocess.STDOUT)
102+
sw_f.seek(0)
103+
sw = sw_f.read()
104+
TRACE_FUNC = "InjectFaultCmd::Run"
105+
self.Verify(TRACE_FUNC in sw, "function names not found in trace (did you build with symbols?)")
106+
107+
passed = (True
108+
& NaclCrashTest("exception").Go()
109+
& NaclCrashTest("throw").Go()
110+
& NaclCrashTest("abort").Go()
111+
& NaclCrashTest("segfault").Go())
112+
sys.exit(1 - passed)
113+

0 commit comments

Comments
 (0)