-
Notifications
You must be signed in to change notification settings - Fork 17
/
run_tests.py
93 lines (80 loc) · 2.9 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
import glob
import itertools
import logging
import os
import subprocess
import sys
log = logging.getLogger( __name__ )
# A "keyword" is an argument to pytest's -k option. It acts as a selector for tests. Each of the
# keywords in the list below will be run concurrently. Once they are done, everything else will
# be run sequentially. Please note that keywords are match as substrings: Foo will match Foo,
# FooBar and BarFoo.
#
try:
if not os.getcwd( ) in sys.path:
sys.path.append( os.getcwd( ) )
from tests import parallelizable_keywords
except ImportError:
parallelizable_keywords = [ ]
def run_tests( index, keywords=None, args=None ):
cmd = [ sys.executable, '-m', 'pytest', '-vv',
'--junitxml', 'nosetests-%s.xml' % index ]
if keywords:
cmd.extend( [ '-k', keywords ] )
if args:
cmd.extend( args )
log.info( 'Running %r', cmd )
return subprocess.Popen( cmd )
def main( args ):
for name in glob.glob( 'nosetests-*.xml' ):
os.unlink( name )
num_failures = 0
index = itertools.count( )
pids = set( )
# PyTest thinks that absence of tests constitutes an error.
# Luckily it has a distinct status code (5) for that.
ok_statuses = (0, 5)
try:
for keyword in parallelizable_keywords:
process = run_tests( index=str( next( index ) ),
keywords=keyword,
args=args )
pids.add( process.pid )
while pids:
pid, status = os.wait( )
pids.remove( pid )
if os.WIFEXITED( status ):
status = os.WEXITSTATUS( status )
if status not in ok_statuses:
num_failures += 1
else:
num_failures += 1
except:
for pid in pids:
os.kill( pid, 15 )
raise
if parallelizable_keywords:
everything_else = ' and '.join( 'not ' + keyword for keyword in parallelizable_keywords )
else:
everything_else = None
process = run_tests( index=str( next( index ) ),
keywords=everything_else,
args=args )
if process.wait( ) not in ok_statuses:
num_failures += 1
import xml.etree.ElementTree as ET
testsuites = ET.Element( 'testsuites' )
for name in glob.glob( 'nosetests-*.xml' ):
log.info( "Reading test report %s", name )
tree = ET.parse( name )
testsuites.append( tree.getroot( ) )
os.unlink( name )
name = 'nosetests.xml'
log.info( 'Writing aggregate test report %s', name )
ET.ElementTree( testsuites ).write( name, xml_declaration=True )
if num_failures:
log.error( '%i out %i child processes failed', num_failures, next( index ) )
return num_failures
if __name__ == '__main__':
logging.basicConfig( level=logging.INFO )
sys.exit( main( sys.argv[ 1: ] ) )