-
Notifications
You must be signed in to change notification settings - Fork 18
/
run-tests.py
executable file
·156 lines (123 loc) · 3.96 KB
/
run-tests.py
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/env python
import subprocess
from subprocess import Popen
import os
from os import listdir, path
from os.path import isfile, join
import sys
import re
import time
try:
from shutil import which
except ImportError:
def which(cmd):
path = os.getenv('PATH')
for p in path.split(os.path.pathsep):
p = os.path.join(p, cmd)
if os.path.exists(p) and os.access(p, os.X_OK):
return p
if not hasattr(Popen, '__enter__'):
def backported_enter(self):
return self
def backported_exit(self, type, value, traceback):
if self.stdout:
self.stdout.close()
if self.stderr:
self.stderr.close()
try: # Flushing a BufferedWriter may raise an error
if self.stdin:
self.stdin.close()
finally:
# Wait for the process to terminate, to avoid zombies.
return
self.wait()
Popen.__enter__ = backported_enter
Popen.__exit__ = backported_exit
PYTEST = 'pytest'
XVFB = 'Xvfb'
I3_BINARY = 'i3'
MESON = 'meson'
NINJA = 'ninja'
SOCKETDIR = '/tmp/.X11-unix'
FILEDIR = os.path.dirname(os.path.realpath(__file__))
BUILDDIR = os.path.join(FILEDIR, 'mesonbuild-test')
def check_dependencies():
if not which(MESON):
print('Meson is required to run tests')
print('Command "%s" not found in PATH' % XVFB)
sys.exit(127)
if not which(NINJA):
print('Ninja build is required to run tests')
print('Command "%s" not found in PATH' % XVFB)
sys.exit(127)
if not which(XVFB):
print('Xvfb is required to run tests')
print('Command "%s" not found in PATH' % XVFB)
sys.exit(127)
if not which(I3_BINARY):
print('i3 binary is required to run tests')
print('Command "%s" not found in PATH' % I3_BINARY)
sys.exit(127)
if not which(PYTEST):
print('pytest is required to run tests')
print('Command %s not found in PATH' % PYTEST)
sys.exit(127)
def get_open_display():
if not os.path.isdir(SOCKETDIR):
sys.stderr.write(
'warning: could not find the X11 socket directory at {}. Using display 0.\n'
.format(SOCKETDIR))
sys.stderr.flush()
return 0
socket_re = re.compile(r'^X([0-9]+)$')
socket_files = [f for f in listdir(SOCKETDIR) if socket_re.match(f)]
displays = [int(socket_re.search(f).group(1)) for f in socket_files]
open_display = min(
[i for i in range(0,
max(displays or [0]) + 2) if i not in displays])
return open_display
def start_server(display):
xvfb = Popen([XVFB, ':%d' % display])
# wait for the socket to make sure the server is running
socketfile = path.join(SOCKETDIR, 'X%d' % display)
tries = 0
while True:
if path.exists(socketfile):
break
else:
tries += 1
if tries > 100:
print('could not start x server')
xvfb.kill()
sys.exit(1)
time.sleep(0.1)
return xvfb
def run_pytest(display):
env = os.environ.copy()
env['DISPLAY'] = ':%d' % display
env['_I3IPC_TEST'] = '1'
env['GI_TYPELIB_PATH'] = os.path.join(BUILDDIR, 'i3ipc-glib')
env['LD_LIBRARY_PATH'] = os.path.join(BUILDDIR, 'i3ipc-glib')
return subprocess.call(['valgrind', PYTEST], env=env)
def build_project():
ret = subprocess.call([MESON, BUILDDIR])
if ret != 0:
return ret
# TODO make incremental builds work
ret = subprocess.call([NINJA, '-C', BUILDDIR, 'clean'])
if ret != 0:
return ret
ret = subprocess.call([NINJA, '-C', BUILDDIR])
return ret
def main():
check_dependencies()
ret = build_project()
if ret != 0:
sys.exit(ret)
display = get_open_display()
with start_server(display) as server:
ret = run_pytest(display)
server.terminate()
sys.exit(ret)
if __name__ == '__main__':
main()