blob: 035e96b7f2050d3ff8b4f25bad236548e139178a [file] [log] [blame]
Alexandre Ramesb78f1392016-07-01 14:22:22 +01001# Copyright 2015, VIXL authors
armvixldb644342015-07-21 11:37:10 +01002# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are met:
6#
7# * Redistributions of source code must retain the above copyright notice,
8# this list of conditions and the following disclaimer.
9# * Redistributions in binary form must reproduce the above copyright notice,
10# this list of conditions and the following disclaimer in the documentation
11# and/or other materials provided with the distribution.
12# * Neither the name of ARM Limited nor the names of its contributors may be
13# used to endorse or promote products derived from this software without
14# specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27import multiprocessing
28import re
29import signal
30import subprocess
31import sys
32import time
33
Anton Kirilov88a33762016-08-26 15:46:33 +010034from known_test_failures import FilterKnownTestFailures
armvixldb644342015-07-21 11:37:10 +010035import printer
36import util
37
38# Catch SIGINT to gracefully exit when ctrl+C is pressed.
39def SigIntHandler(signal, frame):
40 sys.exit(1)
41
42signal.signal(signal.SIGINT, SigIntHandler)
43
armvixldb644342015-07-21 11:37:10 +010044# Scan matching tests and return a test manifest.
45def GetTests(runner, filters = []):
46 rc, output = util.getstatusoutput(runner + ' --list')
47 if rc != 0: util.abort('Failed to list all tests')
48
49 tests = output.split()
50 for f in filters:
51 print f
52 tests = filter(re.compile(f).search, tests)
53
54 return tests
55
armvixldb644342015-07-21 11:37:10 +010056def RunTest(test):
Anthony Barbierb5f72392019-02-15 15:33:48 +000057 p = subprocess.Popen(test.command,
armvixldb644342015-07-21 11:37:10 +010058 stdout=subprocess.PIPE,
59 stderr=subprocess.STDOUT)
60 p_out, p_err = p.communicate()
61 rc = p.poll()
62
63 if rc == 0:
Anthony Barbierb5f72392019-02-15 15:33:48 +000064 with Test.n_tests_passed.get_lock(): Test.n_tests_passed.value += 1
armvixldb644342015-07-21 11:37:10 +010065 else:
Anthony Barbierb5f72392019-02-15 15:33:48 +000066 with Test.n_tests_failed.get_lock(): Test.n_tests_failed.value += 1
armvixldb644342015-07-21 11:37:10 +010067
68 printer.__print_lock__.acquire()
69
Anthony Barbierb5f72392019-02-15 15:33:48 +000070 printer.UpdateProgress(test.shared.start_time,
71 Test.n_tests_passed.value,
72 Test.n_tests_failed.value,
73 test.shared.n_tests,
74 test.name,
armvixldb644342015-07-21 11:37:10 +010075 prevent_next_overwrite = (rc != 0),
76 has_lock = True,
Anthony Barbierb5f72392019-02-15 15:33:48 +000077 prefix = test.shared.progress_prefix)
armvixldb644342015-07-21 11:37:10 +010078
79 if rc != 0:
Anthony Barbierb5f72392019-02-15 15:33:48 +000080 printer.Print('FAILED: ' + test.name, has_lock = True)
81 printer.Print(printer.COLOUR_RED + ' '.join(test.command) + printer.NO_COLOUR,
armvixldb644342015-07-21 11:37:10 +010082 has_lock = True)
83 printer.Print(p_out, has_lock = True)
84
85 printer.__print_lock__.release()
86
Anthony Barbierb5f72392019-02-15 15:33:48 +000087class Test(object):
88 # Shared state for multiprocessing. Ideally the context should be passed with
89 # arguments, but constraints from the multiprocessing module prevent us from
90 # doing so: the shared variables (multiprocessing.Value) must be either global
91 # or static, or no work is started.
92 n_tests_passed = multiprocessing.Value('i', 0)
93 n_tests_failed = multiprocessing.Value('i', 0)
armvixldb644342015-07-21 11:37:10 +010094
Anthony Barbierb5f72392019-02-15 15:33:48 +000095 def __init__(self, test_runner, test, runtime_options, use_valgrind, shared):
96 self.command = [test_runner, test] + runtime_options
97 self.name = test
98 self.shared = shared
99 if use_valgrind:
100 self.command = ['valgrind'] + self.command
armvixldb644342015-07-21 11:37:10 +0100101
Anthony Barbierb5f72392019-02-15 15:33:48 +0000102class TestQueue(object):
103 def __init__(self, under_valgrind = False, prefix = ''):
104 self.progress_prefix = prefix
105 self.under_valgrind = under_valgrind
106 self.queue = []
armvixldb644342015-07-21 11:37:10 +0100107
Anthony Barbierb5f72392019-02-15 15:33:48 +0000108 def Add(self, test_runner_command, filters, runtime_options):
109 tests = GetTests(test_runner_command, filters)
110 tests = FilterKnownTestFailures(tests, under_valgrind = self.under_valgrind)
armvixldb644342015-07-21 11:37:10 +0100111
Anthony Barbierb5f72392019-02-15 15:33:48 +0000112 if len(tests) == 0:
113 printer.Print('No tests to run.')
114 return
armvixldb644342015-07-21 11:37:10 +0100115
Anthony Barbierb5f72392019-02-15 15:33:48 +0000116 for test in tests:
117 self.queue.append(Test(test_runner_command, test,
118 runtime_options, self.under_valgrind, self))
armvixldb644342015-07-21 11:37:10 +0100119
Anthony Barbierb5f72392019-02-15 15:33:48 +0000120 # Run the specified tests.
121 # This function won't run in parallel due to constraints from the
122 # multiprocessing module.
123 __run_tests_lock__ = multiprocessing.Lock()
124 def Run(self, jobs):
125 with TestQueue.__run_tests_lock__:
126 # Initialisation.
127 self.start_time = time.time()
128 self.n_tests = len(self.queue)
129 if self.n_tests == 0:
130 printer.Print('No tests to run.')
131 return 0
132 Test.n_tests_passed.value = 0
133 Test.n_tests_failed.value = 0
armvixldb644342015-07-21 11:37:10 +0100134
Anthony Barbierb5f72392019-02-15 15:33:48 +0000135 pool = multiprocessing.Pool(jobs)
136 # The '.get(9999999)' is a workaround to allow killing the test script with
137 # ctrl+C from the shell. This bug is documented at
138 # http://bugs.python.org/issue8296.
139 work = pool.map_async(RunTest, self.queue).get(9999999)
140 pool.close()
141 pool.join()
armvixldb644342015-07-21 11:37:10 +0100142
Anthony Barbierb5f72392019-02-15 15:33:48 +0000143 printer.UpdateProgress(self.start_time,
144 Test.n_tests_passed.value,
145 Test.n_tests_failed.value,
146 self.n_tests,
147 '== Done ==',
148 prevent_next_overwrite = True,
149 prefix = self.progress_prefix)
150
151 # Empty the queue now that the tests have been run.
152 self.queue = []
153 # `0` indicates success
154 return Test.n_tests_failed.value
155