blob: 5d091ad253fb3ceb9b65465dcbd360e551c6cd37 [file] [log] [blame]
Renato Botelho do Coutoead1e532019-10-31 13:31:07 -05001#!/usr/bin/env python3
Damjan Marionf56b77a2016-10-03 19:44:57 +02002
Klement Sekera993e0ed2017-03-16 09:14:59 +01003import sys
Dave Wallacee2efd122017-09-30 22:04:21 -04004import shutil
Damjan Marionf56b77a2016-10-03 19:44:57 +02005import os
Andrew Yourtchenkod760f792018-10-03 11:38:31 +02006import fnmatch
Damjan Marionf56b77a2016-10-03 19:44:57 +02007import unittest
Klement Sekera993e0ed2017-03-16 09:14:59 +01008import argparse
Klement Sekera545be522018-02-16 19:25:06 +01009import time
juraj.linkes184870a2018-07-16 14:22:01 +020010import threading
11import signal
juraj.linkes40dd73b2018-09-21 13:55:16 +020012import re
Klement Sekera558ceab2021-04-08 19:37:41 +020013from multiprocessing import Process, Pipe, get_context
juraj.linkes184870a2018-07-16 14:22:01 +020014from multiprocessing.queues import Queue
15from multiprocessing.managers import BaseManager
Paul Vinciguerra0cbc71d2019-07-03 08:38:38 -040016import framework
juraj.linkes184870a2018-07-16 14:22:01 +020017from framework import VppTestRunner, running_extended_tests, VppTestCase, \
Ole Trøan5ba91592018-11-22 10:01:09 +000018 get_testcase_doc_name, get_test_description, PASS, FAIL, ERROR, SKIP, \
Klement Sekera558ceab2021-04-08 19:37:41 +020019 TEST_RUN, SKIP_CPU_SHORTAGE
Klement Sekerae2636852021-03-16 12:52:12 +010020from debug import spawn_gdb, start_vpp_in_gdb
juraj.linkes184870a2018-07-16 14:22:01 +020021from log import get_parallel_logger, double_line_delim, RED, YELLOW, GREEN, \
juraj.linkes40dd73b2018-09-21 13:55:16 +020022 colorize, single_line_delim
Klement Sekerafcbf4442017-08-17 07:38:42 +020023from discover_tests import discover_tests
Klement Sekera9b6ece72018-03-23 10:50:11 +010024from subprocess import check_output, CalledProcessError
juraj.linkes40dd73b2018-09-21 13:55:16 +020025from util import check_core_path, get_core_path, is_core_present
Klement Sekera558ceab2021-04-08 19:37:41 +020026from cpu_config import num_cpus, max_vpp_cpus, available_cpus
Klement Sekera993e0ed2017-03-16 09:14:59 +010027
Klement Sekera05742262018-03-14 18:14:49 +010028# timeout which controls how long the child has to finish after seeing
29# a core dump in test temporary directory. If this is exceeded, parent assumes
Klement Sekeraeb506be2021-03-16 12:52:29 +010030# that child process is stuck (e.g. waiting for event from vpp) and kill
31# the child
Klement Sekera05742262018-03-14 18:14:49 +010032core_timeout = 3
33
Klement Sekera909a6a12017-08-08 04:33:53 +020034
juraj.linkes184870a2018-07-16 14:22:01 +020035class StreamQueue(Queue):
36 def write(self, msg):
37 self.put(msg)
38
39 def flush(self):
40 sys.__stdout__.flush()
41 sys.__stderr__.flush()
42
43 def fileno(self):
44 return self._writer.fileno()
45
46
47class StreamQueueManager(BaseManager):
48 pass
49
50
juraj.linkescae64f82018-09-19 15:01:47 +020051StreamQueueManager.register('StreamQueue', StreamQueue)
juraj.linkes184870a2018-07-16 14:22:01 +020052
53
juraj.linkescae64f82018-09-19 15:01:47 +020054class TestResult(dict):
juraj.linkes40dd73b2018-09-21 13:55:16 +020055 def __init__(self, testcase_suite, testcases_by_id=None):
juraj.linkescae64f82018-09-19 15:01:47 +020056 super(TestResult, self).__init__()
57 self[PASS] = []
58 self[FAIL] = []
59 self[ERROR] = []
60 self[SKIP] = []
Klement Sekera558ceab2021-04-08 19:37:41 +020061 self[SKIP_CPU_SHORTAGE] = []
juraj.linkescae64f82018-09-19 15:01:47 +020062 self[TEST_RUN] = []
juraj.linkes40dd73b2018-09-21 13:55:16 +020063 self.crashed = False
juraj.linkescae64f82018-09-19 15:01:47 +020064 self.testcase_suite = testcase_suite
65 self.testcases = [testcase for testcase in testcase_suite]
juraj.linkes40dd73b2018-09-21 13:55:16 +020066 self.testcases_by_id = testcases_by_id
juraj.linkescae64f82018-09-19 15:01:47 +020067
68 def was_successful(self):
juraj.linkes40dd73b2018-09-21 13:55:16 +020069 return 0 == len(self[FAIL]) == len(self[ERROR]) \
Klement Sekera558ceab2021-04-08 19:37:41 +020070 and len(self[PASS] + self[SKIP] + self[SKIP_CPU_SHORTAGE]) \
71 == self.testcase_suite.countTestCases()
juraj.linkescae64f82018-09-19 15:01:47 +020072
73 def no_tests_run(self):
74 return 0 == len(self[TEST_RUN])
75
76 def process_result(self, test_id, result):
77 self[result].append(test_id)
juraj.linkescae64f82018-09-19 15:01:47 +020078
79 def suite_from_failed(self):
80 rerun_ids = set([])
81 for testcase in self.testcase_suite:
82 tc_id = testcase.id()
Klement Sekera558ceab2021-04-08 19:37:41 +020083 if tc_id not in self[PASS] + self[SKIP] + self[SKIP_CPU_SHORTAGE]:
juraj.linkescae64f82018-09-19 15:01:47 +020084 rerun_ids.add(tc_id)
Naveen Joy2cbf2fb2019-03-06 10:41:06 -080085 if rerun_ids:
juraj.linkescae64f82018-09-19 15:01:47 +020086 return suite_from_failed(self.testcase_suite, rerun_ids)
87
88 def get_testcase_names(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +010089 # could be tearDownClass (test_ipsec_esp.TestIpsecEsp1)
90 setup_teardown_match = re.match(
91 r'((tearDownClass)|(setUpClass)) \((.+\..+)\)', test_id)
92 if setup_teardown_match:
93 test_name, _, _, testcase_name = setup_teardown_match.groups()
94 if len(testcase_name.split('.')) == 2:
95 for key in self.testcases_by_id.keys():
96 if key.startswith(testcase_name):
97 testcase_name = key
98 break
99 testcase_name = self._get_testcase_doc_name(testcase_name)
100 else:
Ole Trøan5ba91592018-11-22 10:01:09 +0000101 test_name = self._get_test_description(test_id)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200102 testcase_name = self._get_testcase_doc_name(test_id)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200103
104 return testcase_name, test_name
juraj.linkescae64f82018-09-19 15:01:47 +0200105
Ole Trøan5ba91592018-11-22 10:01:09 +0000106 def _get_test_description(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +0100107 if test_id in self.testcases_by_id:
108 desc = get_test_description(descriptions,
109 self.testcases_by_id[test_id])
110 else:
111 desc = test_id
112 return desc
Ole Trøan5ba91592018-11-22 10:01:09 +0000113
juraj.linkes40dd73b2018-09-21 13:55:16 +0200114 def _get_testcase_doc_name(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +0100115 if test_id in self.testcases_by_id:
116 doc_name = get_testcase_doc_name(self.testcases_by_id[test_id])
117 else:
118 doc_name = test_id
119 return doc_name
juraj.linkescae64f82018-09-19 15:01:47 +0200120
121
122def test_runner_wrapper(suite, keep_alive_pipe, stdouterr_queue,
123 finished_pipe, result_pipe, logger):
juraj.linkes184870a2018-07-16 14:22:01 +0200124 sys.stdout = stdouterr_queue
125 sys.stderr = stdouterr_queue
juraj.linkesdfb5f2a2018-11-09 11:58:54 +0100126 VppTestCase.parallel_handler = logger.handlers[0]
juraj.linkes184870a2018-07-16 14:22:01 +0200127 result = VppTestRunner(keep_alive_pipe=keep_alive_pipe,
128 descriptions=descriptions,
129 verbosity=verbose,
juraj.linkescae64f82018-09-19 15:01:47 +0200130 result_pipe=result_pipe,
juraj.linkesabec0122018-11-16 17:28:56 +0100131 failfast=failfast,
132 print_summary=False).run(suite)
juraj.linkescae64f82018-09-19 15:01:47 +0200133 finished_pipe.send(result.wasSuccessful())
134 finished_pipe.close()
Klement Sekera909a6a12017-08-08 04:33:53 +0200135 keep_alive_pipe.close()
136
137
juraj.linkes184870a2018-07-16 14:22:01 +0200138class TestCaseWrapper(object):
139 def __init__(self, testcase_suite, manager):
140 self.keep_alive_parent_end, self.keep_alive_child_end = Pipe(
141 duplex=False)
juraj.linkescae64f82018-09-19 15:01:47 +0200142 self.finished_parent_end, self.finished_child_end = Pipe(duplex=False)
juraj.linkes184870a2018-07-16 14:22:01 +0200143 self.result_parent_end, self.result_child_end = Pipe(duplex=False)
144 self.testcase_suite = testcase_suite
Klement Sekera558ceab2021-04-08 19:37:41 +0200145 self.stdouterr_queue = manager.StreamQueue(ctx=get_context())
juraj.linkes184870a2018-07-16 14:22:01 +0200146 self.logger = get_parallel_logger(self.stdouterr_queue)
147 self.child = Process(target=test_runner_wrapper,
juraj.linkescae64f82018-09-19 15:01:47 +0200148 args=(testcase_suite,
149 self.keep_alive_child_end,
150 self.stdouterr_queue,
151 self.finished_child_end,
152 self.result_child_end,
153 self.logger)
juraj.linkes184870a2018-07-16 14:22:01 +0200154 )
155 self.child.start()
juraj.linkes184870a2018-07-16 14:22:01 +0200156 self.last_test_temp_dir = None
157 self.last_test_vpp_binary = None
juraj.linkes40dd73b2018-09-21 13:55:16 +0200158 self._last_test = None
159 self.last_test_id = None
juraj.linkes721872e2018-09-05 18:13:45 +0200160 self.vpp_pid = None
juraj.linkes184870a2018-07-16 14:22:01 +0200161 self.last_heard = time.time()
162 self.core_detected_at = None
juraj.linkes40dd73b2018-09-21 13:55:16 +0200163 self.testcases_by_id = {}
164 self.testclasess_with_core = {}
165 for testcase in self.testcase_suite:
166 self.testcases_by_id[testcase.id()] = testcase
167 self.result = TestResult(testcase_suite, self.testcases_by_id)
168
169 @property
170 def last_test(self):
171 return self._last_test
172
173 @last_test.setter
174 def last_test(self, test_id):
175 self.last_test_id = test_id
176 if test_id in self.testcases_by_id:
177 testcase = self.testcases_by_id[test_id]
178 self._last_test = testcase.shortDescription()
179 if not self._last_test:
180 self._last_test = str(testcase)
181 else:
182 self._last_test = test_id
183
184 def add_testclass_with_core(self):
185 if self.last_test_id in self.testcases_by_id:
186 test = self.testcases_by_id[self.last_test_id]
187 class_name = unittest.util.strclass(test.__class__)
188 test_name = "'{}' ({})".format(get_test_description(descriptions,
189 test),
190 self.last_test_id)
191 else:
192 test_name = self.last_test_id
193 class_name = re.match(r'((tearDownClass)|(setUpClass)) '
194 r'\((.+\..+)\)', test_name).groups()[3]
195 if class_name not in self.testclasess_with_core:
196 self.testclasess_with_core[class_name] = (
197 test_name,
198 self.last_test_vpp_binary,
199 self.last_test_temp_dir)
juraj.linkes184870a2018-07-16 14:22:01 +0200200
201 def close_pipes(self):
202 self.keep_alive_child_end.close()
juraj.linkescae64f82018-09-19 15:01:47 +0200203 self.finished_child_end.close()
juraj.linkes184870a2018-07-16 14:22:01 +0200204 self.result_child_end.close()
205 self.keep_alive_parent_end.close()
juraj.linkescae64f82018-09-19 15:01:47 +0200206 self.finished_parent_end.close()
juraj.linkes184870a2018-07-16 14:22:01 +0200207 self.result_parent_end.close()
208
juraj.linkes40dd73b2018-09-21 13:55:16 +0200209 def was_successful(self):
210 return self.result.was_successful()
211
Klement Sekera558ceab2021-04-08 19:37:41 +0200212 @property
213 def cpus_used(self):
214 return self.testcase_suite.cpus_used
215
216 def get_assigned_cpus(self):
217 return self.testcase_suite.get_assigned_cpus()
218
juraj.linkes184870a2018-07-16 14:22:01 +0200219
220def stdouterr_reader_wrapper(unread_testcases, finished_unread_testcases,
221 read_testcases):
222 read_testcase = None
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800223 while read_testcases.is_set() or unread_testcases:
224 if finished_unread_testcases:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100225 read_testcase = finished_unread_testcases.pop()
226 unread_testcases.remove(read_testcase)
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800227 elif unread_testcases:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100228 read_testcase = unread_testcases.pop()
juraj.linkes184870a2018-07-16 14:22:01 +0200229 if read_testcase:
230 data = ''
231 while data is not None:
232 sys.stdout.write(data)
233 data = read_testcase.stdouterr_queue.get()
234
235 read_testcase.stdouterr_queue.close()
236 finished_unread_testcases.discard(read_testcase)
237 read_testcase = None
238
239
juraj.linkes40dd73b2018-09-21 13:55:16 +0200240def handle_failed_suite(logger, last_test_temp_dir, vpp_pid):
241 if last_test_temp_dir:
242 # Need to create link in case of a timeout or core dump without failure
243 lttd = os.path.basename(last_test_temp_dir)
Klement Sekerab8c72a42018-11-08 11:21:39 +0100244 failed_dir = os.getenv('FAILED_DIR')
juraj.linkes40dd73b2018-09-21 13:55:16 +0200245 link_path = '%s%s-FAILED' % (failed_dir, lttd)
246 if not os.path.exists(link_path):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200247 os.symlink(last_test_temp_dir, link_path)
juraj.linkesabec0122018-11-16 17:28:56 +0100248 logger.error("Symlink to failed testcase directory: %s -> %s"
249 % (link_path, lttd))
juraj.linkes40dd73b2018-09-21 13:55:16 +0200250
251 # Report core existence
252 core_path = get_core_path(last_test_temp_dir)
253 if os.path.exists(core_path):
254 logger.error(
255 "Core-file exists in test temporary directory: %s!" %
256 core_path)
257 check_core_path(logger, core_path)
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800258 logger.debug("Running 'file %s':" % core_path)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200259 try:
260 info = check_output(["file", core_path])
261 logger.debug(info)
262 except CalledProcessError as e:
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800263 logger.error("Subprocess returned with return code "
264 "while running `file' utility on core-file "
265 "returned: "
266 "rc=%s", e.returncode)
267 except OSError as e:
268 logger.error("Subprocess returned with OS error while "
269 "running 'file' utility "
270 "on core-file: "
271 "(%s) %s", e.errno, e.strerror)
272 except Exception as e:
273 logger.exception("Unexpected error running `file' utility "
274 "on core-file")
Klement Sekera98d82ca2021-02-02 13:25:40 +0100275 logger.error("gdb %s %s" %
276 (os.getenv('VPP_BIN', 'vpp'), core_path))
juraj.linkes40dd73b2018-09-21 13:55:16 +0200277
278 if vpp_pid:
279 # Copy api post mortem
280 api_post_mortem_path = "/tmp/api_post_mortem.%d" % vpp_pid
281 if os.path.isfile(api_post_mortem_path):
282 logger.error("Copying api_post_mortem.%d to %s" %
283 (vpp_pid, last_test_temp_dir))
284 shutil.copy2(api_post_mortem_path, last_test_temp_dir)
285
286
287def check_and_handle_core(vpp_binary, tempdir, core_crash_test):
288 if is_core_present(tempdir):
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200289 if debug_core:
290 print('VPP core detected in %s. Last test running was %s' %
291 (tempdir, core_crash_test))
292 print(single_line_delim)
293 spawn_gdb(vpp_binary, get_core_path(tempdir))
294 print(single_line_delim)
295 elif compress_core:
296 print("Compressing core-file in test directory `%s'" % tempdir)
297 os.system("gzip %s" % get_core_path(tempdir))
juraj.linkes40dd73b2018-09-21 13:55:16 +0200298
299
300def handle_cores(failed_testcases):
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200301 for failed_testcase in failed_testcases:
302 tcs_with_core = failed_testcase.testclasess_with_core
303 if tcs_with_core:
304 for test, vpp_binary, tempdir in tcs_with_core.values():
305 check_and_handle_core(vpp_binary, tempdir, test)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200306
307
308def process_finished_testsuite(wrapped_testcase_suite,
309 finished_testcase_suites,
310 failed_wrapped_testcases,
311 results):
312 results.append(wrapped_testcase_suite.result)
313 finished_testcase_suites.add(wrapped_testcase_suite)
314 stop_run = False
315 if failfast and not wrapped_testcase_suite.was_successful():
316 stop_run = True
317
318 if not wrapped_testcase_suite.was_successful():
319 failed_wrapped_testcases.add(wrapped_testcase_suite)
320 handle_failed_suite(wrapped_testcase_suite.logger,
321 wrapped_testcase_suite.last_test_temp_dir,
322 wrapped_testcase_suite.vpp_pid)
323
324 return stop_run
325
326
juraj.linkes721872e2018-09-05 18:13:45 +0200327def run_forked(testcase_suites):
juraj.linkes184870a2018-07-16 14:22:01 +0200328 wrapped_testcase_suites = set()
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000329 solo_testcase_suites = []
juraj.linkes184870a2018-07-16 14:22:01 +0200330
331 # suites are unhashable, need to use list
332 results = []
juraj.linkes184870a2018-07-16 14:22:01 +0200333 unread_testcases = set()
334 finished_unread_testcases = set()
335 manager = StreamQueueManager()
336 manager.start()
Klement Sekera558ceab2021-04-08 19:37:41 +0200337 tests_running = 0
338 free_cpus = list(available_cpus)
339
340 def on_suite_start(tc):
341 nonlocal tests_running
342 nonlocal free_cpus
343 tests_running = tests_running + 1
344
345 def on_suite_finish(tc):
346 nonlocal tests_running
347 nonlocal free_cpus
348 tests_running = tests_running - 1
349 assert tests_running >= 0
350 free_cpus.extend(tc.get_assigned_cpus())
351
352 def run_suite(suite):
353 nonlocal manager
354 nonlocal wrapped_testcase_suites
355 nonlocal unread_testcases
356 nonlocal free_cpus
357 suite.assign_cpus(free_cpus[:suite.cpus_used])
358 free_cpus = free_cpus[suite.cpus_used:]
359 wrapper = TestCaseWrapper(suite, manager)
360 wrapped_testcase_suites.add(wrapper)
361 unread_testcases.add(wrapper)
362 on_suite_start(suite)
363
364 def can_run_suite(suite):
365 return (tests_running < max_concurrent_tests and
366 (suite.cpus_used <= len(free_cpus) or
367 suite.cpus_used > max_vpp_cpus))
368
369 while free_cpus and testcase_suites:
370 a_suite = testcase_suites[0]
371 if a_suite.is_tagged_run_solo:
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000372 a_suite = testcase_suites.pop(0)
Klement Sekera558ceab2021-04-08 19:37:41 +0200373 solo_testcase_suites.append(a_suite)
374 continue
375 if can_run_suite(a_suite):
376 a_suite = testcase_suites.pop(0)
377 run_suite(a_suite)
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000378 else:
379 break
380
Klement Sekera558ceab2021-04-08 19:37:41 +0200381 if tests_running == 0 and solo_testcase_suites:
382 a_suite = solo_testcase_suites.pop(0)
383 run_suite(a_suite)
juraj.linkes184870a2018-07-16 14:22:01 +0200384
385 read_from_testcases = threading.Event()
386 read_from_testcases.set()
387 stdouterr_thread = threading.Thread(target=stdouterr_reader_wrapper,
388 args=(unread_testcases,
389 finished_unread_testcases,
390 read_from_testcases))
391 stdouterr_thread.start()
392
juraj.linkes40dd73b2018-09-21 13:55:16 +0200393 failed_wrapped_testcases = set()
394 stop_run = False
juraj.linkese6b58cf2018-11-29 09:56:35 +0100395
396 try:
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800397 while wrapped_testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100398 finished_testcase_suites = set()
399 for wrapped_testcase_suite in wrapped_testcase_suites:
400 while wrapped_testcase_suite.result_parent_end.poll():
401 wrapped_testcase_suite.result.process_result(
402 *wrapped_testcase_suite.result_parent_end.recv())
403 wrapped_testcase_suite.last_heard = time.time()
404
405 while wrapped_testcase_suite.keep_alive_parent_end.poll():
406 wrapped_testcase_suite.last_test, \
407 wrapped_testcase_suite.last_test_vpp_binary, \
408 wrapped_testcase_suite.last_test_temp_dir, \
409 wrapped_testcase_suite.vpp_pid = \
410 wrapped_testcase_suite.keep_alive_parent_end.recv()
411 wrapped_testcase_suite.last_heard = time.time()
412
413 if wrapped_testcase_suite.finished_parent_end.poll():
414 wrapped_testcase_suite.finished_parent_end.recv()
415 wrapped_testcase_suite.last_heard = time.time()
416 stop_run = process_finished_testsuite(
417 wrapped_testcase_suite,
418 finished_testcase_suites,
419 failed_wrapped_testcases,
420 results) or stop_run
421 continue
422
423 fail = False
424 if wrapped_testcase_suite.last_heard + test_timeout < \
425 time.time():
426 fail = True
427 wrapped_testcase_suite.logger.critical(
428 "Child test runner process timed out "
429 "(last test running was `%s' in `%s')!" %
430 (wrapped_testcase_suite.last_test,
431 wrapped_testcase_suite.last_test_temp_dir))
432 elif not wrapped_testcase_suite.child.is_alive():
433 fail = True
434 wrapped_testcase_suite.logger.critical(
435 "Child test runner process unexpectedly died "
436 "(last test running was `%s' in `%s')!" %
437 (wrapped_testcase_suite.last_test,
438 wrapped_testcase_suite.last_test_temp_dir))
439 elif wrapped_testcase_suite.last_test_temp_dir and \
440 wrapped_testcase_suite.last_test_vpp_binary:
441 if is_core_present(
442 wrapped_testcase_suite.last_test_temp_dir):
443 wrapped_testcase_suite.add_testclass_with_core()
444 if wrapped_testcase_suite.core_detected_at is None:
445 wrapped_testcase_suite.core_detected_at = \
446 time.time()
447 elif wrapped_testcase_suite.core_detected_at + \
448 core_timeout < time.time():
449 wrapped_testcase_suite.logger.critical(
450 "Child test runner process unresponsive and "
451 "core-file exists in test temporary directory "
452 "(last test running was `%s' in `%s')!" %
453 (wrapped_testcase_suite.last_test,
454 wrapped_testcase_suite.last_test_temp_dir))
455 fail = True
456
457 if fail:
458 wrapped_testcase_suite.child.terminate()
459 try:
460 # terminating the child process tends to leave orphan
461 # VPP process around
462 if wrapped_testcase_suite.vpp_pid:
463 os.kill(wrapped_testcase_suite.vpp_pid,
464 signal.SIGTERM)
465 except OSError:
466 # already dead
467 pass
468 wrapped_testcase_suite.result.crashed = True
469 wrapped_testcase_suite.result.process_result(
470 wrapped_testcase_suite.last_test_id, ERROR)
471 stop_run = process_finished_testsuite(
472 wrapped_testcase_suite,
473 finished_testcase_suites,
474 failed_wrapped_testcases,
475 results) or stop_run
476
477 for finished_testcase in finished_testcase_suites:
Andrew Yourtchenko42693522019-11-05 01:08:26 +0100478 # Somewhat surprisingly, the join below may
479 # timeout, even if client signaled that
480 # it finished - so we note it just in case.
481 join_start = time.time()
482 finished_testcase.child.join(test_finished_join_timeout)
483 join_end = time.time()
484 if join_end - join_start >= test_finished_join_timeout:
485 finished_testcase.logger.error(
486 "Timeout joining finished test: %s (pid %d)" %
487 (finished_testcase.last_test,
488 finished_testcase.child.pid))
juraj.linkese6b58cf2018-11-29 09:56:35 +0100489 finished_testcase.close_pipes()
490 wrapped_testcase_suites.remove(finished_testcase)
491 finished_unread_testcases.add(finished_testcase)
492 finished_testcase.stdouterr_queue.put(None)
Klement Sekera558ceab2021-04-08 19:37:41 +0200493 on_suite_finish(finished_testcase)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100494 if stop_run:
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800495 while testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100496 results.append(TestResult(testcase_suites.pop(0)))
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800497 elif testcase_suites:
Klement Sekera558ceab2021-04-08 19:37:41 +0200498 a_suite = testcase_suites.pop(0)
499 while a_suite and a_suite.is_tagged_run_solo:
500 solo_testcase_suites.append(a_suite)
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000501 if testcase_suites:
Klement Sekera558ceab2021-04-08 19:37:41 +0200502 a_suite = testcase_suites.pop(0)
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000503 else:
Klement Sekera558ceab2021-04-08 19:37:41 +0200504 a_suite = None
505 if a_suite and can_run_suite(a_suite):
506 run_suite(a_suite)
507 if solo_testcase_suites and tests_running == 0:
508 a_suite = solo_testcase_suites.pop(0)
509 run_suite(a_suite)
Paul Vinciguerrac0692a42019-03-15 19:16:50 -0700510 time.sleep(0.1)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100511 except Exception:
juraj.linkes184870a2018-07-16 14:22:01 +0200512 for wrapped_testcase_suite in wrapped_testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100513 wrapped_testcase_suite.child.terminate()
514 wrapped_testcase_suite.stdouterr_queue.put(None)
515 raise
516 finally:
517 read_from_testcases.clear()
518 stdouterr_thread.join(test_timeout)
519 manager.shutdown()
juraj.linkescae64f82018-09-19 15:01:47 +0200520
juraj.linkes40dd73b2018-09-21 13:55:16 +0200521 handle_cores(failed_wrapped_testcases)
juraj.linkes184870a2018-07-16 14:22:01 +0200522 return results
523
524
Klement Sekera558ceab2021-04-08 19:37:41 +0200525class TestSuiteWrapper(unittest.TestSuite):
526 cpus_used = 0
527
528 def __init__(self):
529 return super().__init__()
530
531 def addTest(self, test):
532 self.cpus_used = max(self.cpus_used, test.get_cpus_required())
533 super().addTest(test)
534
535 def assign_cpus(self, cpus):
536 self.cpus = cpus
537
538 def _handleClassSetUp(self, test, result):
539 if not test.__class__.skipped_due_to_cpu_lack:
540 test.assign_cpus(self.cpus)
541 super()._handleClassSetUp(test, result)
542
543 def get_assigned_cpus(self):
544 return self.cpus
545
546
juraj.linkes184870a2018-07-16 14:22:01 +0200547class SplitToSuitesCallback:
548 def __init__(self, filter_callback):
549 self.suites = {}
550 self.suite_name = 'default'
551 self.filter_callback = filter_callback
Klement Sekera558ceab2021-04-08 19:37:41 +0200552 self.filtered = TestSuiteWrapper()
Klement Sekerafcbf4442017-08-17 07:38:42 +0200553
554 def __call__(self, file_name, cls, method):
juraj.linkes184870a2018-07-16 14:22:01 +0200555 test_method = cls(method)
556 if self.filter_callback(file_name, cls.__name__, method):
557 self.suite_name = file_name + cls.__name__
558 if self.suite_name not in self.suites:
Klement Sekera558ceab2021-04-08 19:37:41 +0200559 self.suites[self.suite_name] = TestSuiteWrapper()
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000560 self.suites[self.suite_name].is_tagged_run_solo = False
juraj.linkes184870a2018-07-16 14:22:01 +0200561 self.suites[self.suite_name].addTest(test_method)
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000562 if test_method.is_tagged_run_solo():
563 self.suites[self.suite_name].is_tagged_run_solo = True
juraj.linkes184870a2018-07-16 14:22:01 +0200564
565 else:
566 self.filtered.addTest(test_method)
Klement Sekerafcbf4442017-08-17 07:38:42 +0200567
568
juraj.linkes184870a2018-07-16 14:22:01 +0200569test_option = "TEST"
570
571
572def parse_test_option():
573 f = os.getenv(test_option, None)
574 filter_file_name = None
575 filter_class_name = None
576 filter_func_name = None
577 if f:
578 if '.' in f:
579 parts = f.split('.')
580 if len(parts) > 3:
581 raise Exception("Unrecognized %s option: %s" %
582 (test_option, f))
583 if len(parts) > 2:
584 if parts[2] not in ('*', ''):
585 filter_func_name = parts[2]
586 if parts[1] not in ('*', ''):
587 filter_class_name = parts[1]
588 if parts[0] not in ('*', ''):
589 if parts[0].startswith('test_'):
590 filter_file_name = parts[0]
591 else:
592 filter_file_name = 'test_%s' % parts[0]
593 else:
594 if f.startswith('test_'):
595 filter_file_name = f
596 else:
597 filter_file_name = 'test_%s' % f
598 if filter_file_name:
599 filter_file_name = '%s.py' % filter_file_name
600 return filter_file_name, filter_class_name, filter_func_name
601
602
603def filter_tests(tests, filter_cb):
Klement Sekera558ceab2021-04-08 19:37:41 +0200604 result = TestSuiteWrapper()
juraj.linkes184870a2018-07-16 14:22:01 +0200605 for t in tests:
606 if isinstance(t, unittest.suite.TestSuite):
607 # this is a bunch of tests, recursively filter...
608 x = filter_tests(t, filter_cb)
609 if x.countTestCases() > 0:
610 result.addTest(x)
611 elif isinstance(t, unittest.TestCase):
612 # this is a single test
613 parts = t.id().split('.')
614 # t.id() for common cases like this:
615 # test_classifier.TestClassifier.test_acl_ip
616 # apply filtering only if it is so
617 if len(parts) == 3:
618 if not filter_cb(parts[0], parts[1], parts[2]):
619 continue
620 result.addTest(t)
621 else:
622 # unexpected object, don't touch it
623 result.addTest(t)
624 return result
625
626
627class FilterByTestOption:
628 def __init__(self, filter_file_name, filter_class_name, filter_func_name):
629 self.filter_file_name = filter_file_name
630 self.filter_class_name = filter_class_name
631 self.filter_func_name = filter_func_name
632
633 def __call__(self, file_name, class_name, func_name):
Andrew Yourtchenkod760f792018-10-03 11:38:31 +0200634 if self.filter_file_name:
635 fn_match = fnmatch.fnmatch(file_name, self.filter_file_name)
636 if not fn_match:
637 return False
juraj.linkes184870a2018-07-16 14:22:01 +0200638 if self.filter_class_name and class_name != self.filter_class_name:
639 return False
640 if self.filter_func_name and func_name != self.filter_func_name:
641 return False
642 return True
643
644
645class FilterByClassList:
juraj.linkes721872e2018-09-05 18:13:45 +0200646 def __init__(self, classes_with_filenames):
647 self.classes_with_filenames = classes_with_filenames
Klement Sekeradf2b9802017-10-05 10:26:03 +0200648
649 def __call__(self, file_name, class_name, func_name):
juraj.linkes721872e2018-09-05 18:13:45 +0200650 return '.'.join([file_name, class_name]) in self.classes_with_filenames
Klement Sekeradf2b9802017-10-05 10:26:03 +0200651
652
653def suite_from_failed(suite, failed):
juraj.linkes721872e2018-09-05 18:13:45 +0200654 failed = {x.rsplit('.', 1)[0] for x in failed}
juraj.linkes184870a2018-07-16 14:22:01 +0200655 filter_cb = FilterByClassList(failed)
656 suite = filter_tests(suite, filter_cb)
Klement Sekera4c5422e2018-06-22 13:19:45 +0200657 return suite
Klement Sekeradf2b9802017-10-05 10:26:03 +0200658
659
juraj.linkescae64f82018-09-19 15:01:47 +0200660class AllResults(dict):
juraj.linkes184870a2018-07-16 14:22:01 +0200661 def __init__(self):
juraj.linkescae64f82018-09-19 15:01:47 +0200662 super(AllResults, self).__init__()
juraj.linkes184870a2018-07-16 14:22:01 +0200663 self.all_testcases = 0
juraj.linkescae64f82018-09-19 15:01:47 +0200664 self.results_per_suite = []
665 self[PASS] = 0
666 self[FAIL] = 0
667 self[ERROR] = 0
668 self[SKIP] = 0
Klement Sekera558ceab2021-04-08 19:37:41 +0200669 self[SKIP_CPU_SHORTAGE] = 0
juraj.linkescae64f82018-09-19 15:01:47 +0200670 self[TEST_RUN] = 0
juraj.linkes184870a2018-07-16 14:22:01 +0200671 self.rerun = []
juraj.linkescae64f82018-09-19 15:01:47 +0200672 self.testsuites_no_tests_run = []
Klement Sekera909a6a12017-08-08 04:33:53 +0200673
juraj.linkescae64f82018-09-19 15:01:47 +0200674 def add_results(self, result):
675 self.results_per_suite.append(result)
Klement Sekera558ceab2021-04-08 19:37:41 +0200676 result_types = [PASS, FAIL, ERROR, SKIP, TEST_RUN, SKIP_CPU_SHORTAGE]
juraj.linkescae64f82018-09-19 15:01:47 +0200677 for result_type in result_types:
678 self[result_type] += len(result[result_type])
Klement Sekera05742262018-03-14 18:14:49 +0100679
juraj.linkescae64f82018-09-19 15:01:47 +0200680 def add_result(self, result):
juraj.linkes184870a2018-07-16 14:22:01 +0200681 retval = 0
juraj.linkescae64f82018-09-19 15:01:47 +0200682 self.all_testcases += result.testcase_suite.countTestCases()
juraj.linkes40dd73b2018-09-21 13:55:16 +0200683 self.add_results(result)
juraj.linkes184870a2018-07-16 14:22:01 +0200684
juraj.linkes40dd73b2018-09-21 13:55:16 +0200685 if result.no_tests_run():
juraj.linkescae64f82018-09-19 15:01:47 +0200686 self.testsuites_no_tests_run.append(result.testcase_suite)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200687 if result.crashed:
688 retval = -1
689 else:
690 retval = 1
691 elif not result.was_successful():
692 retval = 1
juraj.linkes184870a2018-07-16 14:22:01 +0200693
juraj.linkes184870a2018-07-16 14:22:01 +0200694 if retval != 0:
juraj.linkesabec0122018-11-16 17:28:56 +0100695 self.rerun.append(result.testcase_suite)
juraj.linkes184870a2018-07-16 14:22:01 +0200696
697 return retval
698
699 def print_results(self):
700 print('')
701 print(double_line_delim)
702 print('TEST RESULTS:')
Klement Sekera558ceab2021-04-08 19:37:41 +0200703
704 def indent_results(lines):
705 lines = list(filter(None, lines))
706 maximum = max(lines, key=lambda x: x.index(":"))
707 maximum = 4 + maximum.index(":")
708 for l in lines:
709 padding = " " * (maximum - l.index(":"))
710 print(f"{padding}{l}")
711
712 indent_results([
713 f'Scheduled tests: {self.all_testcases}',
714 f'Executed tests: {self[TEST_RUN]}',
715 f'Passed tests: {colorize(self[PASS], GREEN)}',
716 f'Skipped tests: {colorize(self[SKIP], YELLOW)}'
717 if self[SKIP] else None,
718 f'Not Executed tests: {colorize(self.not_executed, RED)}'
719 if self.not_executed else None,
720 f'Failures: {colorize(self[FAIL], RED)}' if self[FAIL] else None,
721 f'Errors: {colorize(self[ERROR], RED)}' if self[ERROR] else None,
722 'Tests skipped due to lack of CPUS: '
723 f'{colorize(self[SKIP_CPU_SHORTAGE], YELLOW)}'
724 if self[SKIP_CPU_SHORTAGE] else None
725 ])
juraj.linkes184870a2018-07-16 14:22:01 +0200726
727 if self.all_failed > 0:
juraj.linkes40dd73b2018-09-21 13:55:16 +0200728 print('FAILURES AND ERRORS IN TESTS:')
juraj.linkescae64f82018-09-19 15:01:47 +0200729 for result in self.results_per_suite:
730 failed_testcase_ids = result[FAIL]
731 errored_testcase_ids = result[ERROR]
732 old_testcase_name = None
Paul Vinciguerra67a77492019-12-10 23:36:05 -0500733 if failed_testcase_ids:
juraj.linkescae64f82018-09-19 15:01:47 +0200734 for failed_test_id in failed_testcase_ids:
735 new_testcase_name, test_name = \
736 result.get_testcase_names(failed_test_id)
737 if new_testcase_name != old_testcase_name:
738 print(' Testcase name: {}'.format(
739 colorize(new_testcase_name, RED)))
740 old_testcase_name = new_testcase_name
Klement Sekera33177d62018-11-30 14:17:20 +0100741 print(' FAILURE: {} [{}]'.format(
742 colorize(test_name, RED), failed_test_id))
Paul Vinciguerra67a77492019-12-10 23:36:05 -0500743 if errored_testcase_ids:
744 for errored_test_id in errored_testcase_ids:
juraj.linkescae64f82018-09-19 15:01:47 +0200745 new_testcase_name, test_name = \
Paul Vinciguerra67a77492019-12-10 23:36:05 -0500746 result.get_testcase_names(errored_test_id)
juraj.linkescae64f82018-09-19 15:01:47 +0200747 if new_testcase_name != old_testcase_name:
748 print(' Testcase name: {}'.format(
749 colorize(new_testcase_name, RED)))
750 old_testcase_name = new_testcase_name
Klement Sekera33177d62018-11-30 14:17:20 +0100751 print(' ERROR: {} [{}]'.format(
Paul Vinciguerra67a77492019-12-10 23:36:05 -0500752 colorize(test_name, RED), errored_test_id))
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800753 if self.testsuites_no_tests_run:
juraj.linkescae64f82018-09-19 15:01:47 +0200754 print('TESTCASES WHERE NO TESTS WERE SUCCESSFULLY EXECUTED:')
juraj.linkes40dd73b2018-09-21 13:55:16 +0200755 tc_classes = set()
juraj.linkescae64f82018-09-19 15:01:47 +0200756 for testsuite in self.testsuites_no_tests_run:
757 for testcase in testsuite:
758 tc_classes.add(get_testcase_doc_name(testcase))
759 for tc_class in tc_classes:
760 print(' {}'.format(colorize(tc_class, RED)))
juraj.linkes184870a2018-07-16 14:22:01 +0200761
Klement Sekera558ceab2021-04-08 19:37:41 +0200762 if self[SKIP_CPU_SHORTAGE]:
763 print()
764 print(colorize(' SOME TESTS WERE SKIPPED BECAUSE THERE ARE NOT'
765 ' ENOUGH CPUS AVAILABLE', YELLOW))
juraj.linkes184870a2018-07-16 14:22:01 +0200766 print(double_line_delim)
767 print('')
768
769 @property
juraj.linkescae64f82018-09-19 15:01:47 +0200770 def not_executed(self):
771 return self.all_testcases - self[TEST_RUN]
772
773 @property
juraj.linkes184870a2018-07-16 14:22:01 +0200774 def all_failed(self):
juraj.linkescae64f82018-09-19 15:01:47 +0200775 return self[FAIL] + self[ERROR]
juraj.linkes184870a2018-07-16 14:22:01 +0200776
777
778def parse_results(results):
779 """
juraj.linkescae64f82018-09-19 15:01:47 +0200780 Prints the number of scheduled, executed, not executed, passed, failed,
781 errored and skipped tests and details about failed and errored tests.
juraj.linkes184870a2018-07-16 14:22:01 +0200782
juraj.linkescae64f82018-09-19 15:01:47 +0200783 Also returns all suites where any test failed.
juraj.linkes184870a2018-07-16 14:22:01 +0200784
785 :param results:
786 :return:
787 """
788
juraj.linkescae64f82018-09-19 15:01:47 +0200789 results_per_suite = AllResults()
juraj.linkes184870a2018-07-16 14:22:01 +0200790 crashed = False
791 failed = False
juraj.linkescae64f82018-09-19 15:01:47 +0200792 for result in results:
793 result_code = results_per_suite.add_result(result)
juraj.linkes184870a2018-07-16 14:22:01 +0200794 if result_code == 1:
795 failed = True
796 elif result_code == -1:
797 crashed = True
798
799 results_per_suite.print_results()
800
801 if crashed:
802 return_code = -1
803 elif failed:
804 return_code = 1
805 else:
806 return_code = 0
807 return return_code, results_per_suite.rerun
808
809
810def parse_digit_env(env_var, default):
811 value = os.getenv(env_var, default)
812 if value != default:
813 if value.isdigit():
814 value = int(value)
815 else:
816 print('WARNING: unsupported value "%s" for env var "%s",'
817 'defaulting to %s' % (value, env_var, default))
818 value = default
819 return value
Klement Sekera3f6ff192017-08-11 06:56:05 +0200820
821
822if __name__ == '__main__':
823
juraj.linkes184870a2018-07-16 14:22:01 +0200824 verbose = parse_digit_env("V", 0)
Klement Sekera3f6ff192017-08-11 06:56:05 +0200825
juraj.linkes184870a2018-07-16 14:22:01 +0200826 test_timeout = parse_digit_env("TIMEOUT", 600) # default = 10 minutes
Klement Sekera3f6ff192017-08-11 06:56:05 +0200827
Andrew Yourtchenko42693522019-11-05 01:08:26 +0100828 test_finished_join_timeout = 15
829
juraj.linkes184870a2018-07-16 14:22:01 +0200830 retries = parse_digit_env("RETRIES", 0)
Klement Sekera3f6ff192017-08-11 06:56:05 +0200831
Klement Sekerae2636852021-03-16 12:52:12 +0100832 debug = os.getenv("DEBUG", "n").lower() in ["gdb", "gdbserver", "attach"]
juraj.linkes184870a2018-07-16 14:22:01 +0200833
juraj.linkes40dd73b2018-09-21 13:55:16 +0200834 debug_core = os.getenv("DEBUG", "").lower() == "core"
Paul Vinciguerra0cbc71d2019-07-03 08:38:38 -0400835 compress_core = framework.BoolEnvironmentVariable("CORE_COMPRESS")
juraj.linkes40dd73b2018-09-21 13:55:16 +0200836
Klement Sekerae2636852021-03-16 12:52:12 +0100837 if os.getenv("VPP_IN_GDB", "n").lower() in ["1", "y", "yes"]:
838 start_vpp_in_gdb()
839 exit()
840
Paul Vinciguerra0cbc71d2019-07-03 08:38:38 -0400841 step = framework.BoolEnvironmentVariable("STEP")
842 force_foreground = framework.BoolEnvironmentVariable("FORCE_FOREGROUND")
juraj.linkesb5ef26d2019-07-03 10:42:40 +0200843
844 run_interactive = debug or step or force_foreground
juraj.linkes184870a2018-07-16 14:22:01 +0200845
Klement Sekera558ceab2021-04-08 19:37:41 +0200846 max_concurrent_tests = 0
847 print(f"OS reports {num_cpus} available cpu(s).")
Paul Vinciguerra025cd9c2019-07-08 14:14:22 -0400848
juraj.linkes184870a2018-07-16 14:22:01 +0200849 test_jobs = os.getenv("TEST_JOBS", "1").lower() # default = 1 process
850 if test_jobs == 'auto':
851 if run_interactive:
Klement Sekera558ceab2021-04-08 19:37:41 +0200852 max_concurrent_tests = 1
853 print('Interactive mode required, running tests consecutively.')
juraj.linkes184870a2018-07-16 14:22:01 +0200854 else:
Klement Sekera558ceab2021-04-08 19:37:41 +0200855 max_concurrent_tests = num_cpus
856 print(f"Running at most {max_concurrent_tests} python test "
857 "processes concurrently.")
juraj.linkes184870a2018-07-16 14:22:01 +0200858 else:
Klement Sekera558ceab2021-04-08 19:37:41 +0200859 try:
860 test_jobs = int(test_jobs)
861 except ValueError as e:
862 raise ValueError("Invalid TEST_JOBS value specified, valid "
863 "values are a positive integer or 'auto'") from e
864 if test_jobs <= 0:
865 raise ValueError("Invalid TEST_JOBS value specified, valid "
866 "values are a positive integer or 'auto'")
867 max_concurrent_tests = int(test_jobs)
868 print(f"Running at most {max_concurrent_tests} python test processes "
869 "concurrently as set by 'TEST_JOBS'.")
juraj.linkes184870a2018-07-16 14:22:01 +0200870
Klement Sekera558ceab2021-04-08 19:37:41 +0200871 print(f"Using at most {max_vpp_cpus} cpus for VPP threads.")
872
873 if run_interactive and max_concurrent_tests > 1:
juraj.linkes184870a2018-07-16 14:22:01 +0200874 raise NotImplementedError(
Klement Sekerae2636852021-03-16 12:52:12 +0100875 'Running tests interactively (DEBUG is gdb[server] or ATTACH or '
876 'STEP is set) in parallel (TEST_JOBS is more than 1) is not '
877 'supported')
Klement Sekera13a83ef2018-03-21 12:35:51 +0100878
Klement Sekera3f6ff192017-08-11 06:56:05 +0200879 parser = argparse.ArgumentParser(description="VPP unit tests")
juraj.linkes184870a2018-07-16 14:22:01 +0200880 parser.add_argument("-f", "--failfast", action='store_true',
Klement Sekera3f6ff192017-08-11 06:56:05 +0200881 help="fast failure flag")
882 parser.add_argument("-d", "--dir", action='append', type=str,
883 help="directory containing test files "
884 "(may be specified multiple times)")
885 args = parser.parse_args()
juraj.linkes184870a2018-07-16 14:22:01 +0200886 failfast = args.failfast
887 descriptions = True
Klement Sekera3f6ff192017-08-11 06:56:05 +0200888
Klement Sekera558ceab2021-04-08 19:37:41 +0200889 print("Running tests using custom test runner.")
juraj.linkes184870a2018-07-16 14:22:01 +0200890 filter_file, filter_class, filter_func = parse_test_option()
891
892 print("Active filters: file=%s, class=%s, function=%s" % (
893 filter_file, filter_class, filter_func))
894
895 filter_cb = FilterByTestOption(filter_file, filter_class, filter_func)
896
Klement Sekerab8c72a42018-11-08 11:21:39 +0100897 ignore_path = os.getenv("VENV_PATH", None)
juraj.linkes184870a2018-07-16 14:22:01 +0200898 cb = SplitToSuitesCallback(filter_cb)
Klement Sekera3f6ff192017-08-11 06:56:05 +0200899 for d in args.dir:
Klement Sekeradf2b9802017-10-05 10:26:03 +0200900 print("Adding tests from directory tree %s" % d)
Klement Sekerab8c72a42018-11-08 11:21:39 +0100901 discover_tests(d, cb, ignore_path)
Klement Sekera3f6ff192017-08-11 06:56:05 +0200902
juraj.linkes184870a2018-07-16 14:22:01 +0200903 # suites are not hashable, need to use list
904 suites = []
905 tests_amount = 0
906 for testcase_suite in cb.suites.values():
907 tests_amount += testcase_suite.countTestCases()
Klement Sekera558ceab2021-04-08 19:37:41 +0200908 if testcase_suite.cpus_used > max_vpp_cpus:
909 # here we replace test functions with lambdas to just skip them
910 # but we also replace setUp/tearDown functions to do nothing
911 # so that the test can be "started" and "stopped", so that we can
912 # still keep those prints (test description - SKIP), which are done
913 # in stopTest() (for that to trigger, test function must run)
914 for t in testcase_suite:
915 for m in dir(t):
916 if m.startswith('test_'):
917 setattr(t, m, lambda: t.skipTest("not enough cpus"))
918 setattr(t.__class__, 'setUpClass', lambda: None)
919 setattr(t.__class__, 'tearDownClass', lambda: None)
920 setattr(t, 'setUp', lambda: None)
921 setattr(t, 'tearDown', lambda: None)
922 t.__class__.skipped_due_to_cpu_lack = True
juraj.linkes184870a2018-07-16 14:22:01 +0200923 suites.append(testcase_suite)
Klement Sekerabbfa5fd2018-06-27 13:54:32 +0200924
juraj.linkes184870a2018-07-16 14:22:01 +0200925 print("%s out of %s tests match specified filters" % (
926 tests_amount, tests_amount + cb.filtered.countTestCases()))
927
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800928 if not running_extended_tests:
juraj.linkes184870a2018-07-16 14:22:01 +0200929 print("Not running extended tests (some tests will be skipped)")
930
Klement Sekeradf2b9802017-10-05 10:26:03 +0200931 attempts = retries + 1
932 if attempts > 1:
933 print("Perform %s attempts to pass the suite..." % attempts)
juraj.linkes184870a2018-07-16 14:22:01 +0200934
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800935 if run_interactive and suites:
juraj.linkes184870a2018-07-16 14:22:01 +0200936 # don't fork if requiring interactive terminal
juraj.linkesb5ef26d2019-07-03 10:42:40 +0200937 print('Running tests in foreground in the current process')
juraj.linkes46e8e912019-01-10 12:13:07 +0100938 full_suite = unittest.TestSuite()
Klement Sekera558ceab2021-04-08 19:37:41 +0200939 free_cpus = list(available_cpus)
940 cpu_shortage = False
941 for suite in suites:
942 if suite.cpus_used <= max_vpp_cpus:
943 suite.assign_cpus(free_cpus[:suite.cpus_used])
944 else:
945 suite.assign_cpus([])
946 cpu_shortage = True
Klement Sekerad743dff2019-10-29 11:03:47 +0000947 full_suite.addTests(suites)
juraj.linkesabec0122018-11-16 17:28:56 +0100948 result = VppTestRunner(verbosity=verbose,
949 failfast=failfast,
juraj.linkes46e8e912019-01-10 12:13:07 +0100950 print_summary=True).run(full_suite)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200951 was_successful = result.wasSuccessful()
952 if not was_successful:
953 for test_case_info in result.failed_test_cases_info:
954 handle_failed_suite(test_case_info.logger,
955 test_case_info.tempdir,
956 test_case_info.vpp_pid)
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200957 if test_case_info in result.core_crash_test_cases_info:
juraj.linkes40dd73b2018-09-21 13:55:16 +0200958 check_and_handle_core(test_case_info.vpp_bin_path,
959 test_case_info.tempdir,
960 test_case_info.core_crash_test)
961
Klement Sekera558ceab2021-04-08 19:37:41 +0200962 if cpu_shortage:
963 print()
964 print(colorize('SOME TESTS WERE SKIPPED BECAUSE THERE ARE NOT'
965 ' ENOUGH CPUS AVAILABLE', YELLOW))
966 print()
juraj.linkes40dd73b2018-09-21 13:55:16 +0200967 sys.exit(not was_successful)
Klement Sekera13a83ef2018-03-21 12:35:51 +0100968 else:
juraj.linkesb5ef26d2019-07-03 10:42:40 +0200969 print('Running each VPPTestCase in a separate background process'
Klement Sekera558ceab2021-04-08 19:37:41 +0200970 f' with at most {max_concurrent_tests} parallel python test '
971 'process(es)')
juraj.linkes184870a2018-07-16 14:22:01 +0200972 exit_code = 0
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800973 while suites and attempts > 0:
juraj.linkes184870a2018-07-16 14:22:01 +0200974 results = run_forked(suites)
975 exit_code, suites = parse_results(results)
976 attempts -= 1
977 if exit_code == 0:
978 print('Test run was successful')
979 else:
980 print('%s attempt(s) left.' % attempts)
981 sys.exit(exit_code)