blob: 917e0dc0057bafada8a34a7df8cbda03cf86825f [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 Sekera545be522018-02-16 19:25:06 +01008import time
juraj.linkes184870a2018-07-16 14:22:01 +02009import threading
Klement Sekerab23ffd72021-05-31 16:08:53 +020010import traceback
juraj.linkes184870a2018-07-16 14:22:01 +020011import 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
Klement Sekerab23ffd72021-05-31 16:08:53 +020016from config import config, num_cpus, available_cpus, max_vpp_cpus
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020017from framework import (
18 VppTestRunner,
19 VppTestCase,
20 get_testcase_doc_name,
21 get_test_description,
22 PASS,
23 FAIL,
24 ERROR,
25 SKIP,
26 TEST_RUN,
27 SKIP_CPU_SHORTAGE,
28)
Klement Sekera152a9b62022-05-13 18:01:36 +020029from debug import spawn_gdb
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020030from log import (
31 get_parallel_logger,
32 double_line_delim,
33 RED,
34 YELLOW,
35 GREEN,
36 colorize,
37 single_line_delim,
38)
Klement Sekerafcbf4442017-08-17 07:38:42 +020039from discover_tests import discover_tests
Klement Sekerab23ffd72021-05-31 16:08:53 +020040import sanity_run_vpp
Klement Sekera9b6ece72018-03-23 10:50:11 +010041from subprocess import check_output, CalledProcessError
juraj.linkes40dd73b2018-09-21 13:55:16 +020042from util import check_core_path, get_core_path, is_core_present
Klement Sekera993e0ed2017-03-16 09:14:59 +010043
Klement Sekera05742262018-03-14 18:14:49 +010044# timeout which controls how long the child has to finish after seeing
45# a core dump in test temporary directory. If this is exceeded, parent assumes
Klement Sekeraeb506be2021-03-16 12:52:29 +010046# that child process is stuck (e.g. waiting for event from vpp) and kill
47# the child
Klement Sekera05742262018-03-14 18:14:49 +010048core_timeout = 3
49
Klement Sekera909a6a12017-08-08 04:33:53 +020050
juraj.linkes184870a2018-07-16 14:22:01 +020051class StreamQueue(Queue):
52 def write(self, msg):
53 self.put(msg)
54
55 def flush(self):
56 sys.__stdout__.flush()
57 sys.__stderr__.flush()
58
59 def fileno(self):
60 return self._writer.fileno()
61
62
63class StreamQueueManager(BaseManager):
64 pass
65
66
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020067StreamQueueManager.register("StreamQueue", StreamQueue)
juraj.linkes184870a2018-07-16 14:22:01 +020068
69
juraj.linkescae64f82018-09-19 15:01:47 +020070class TestResult(dict):
juraj.linkes40dd73b2018-09-21 13:55:16 +020071 def __init__(self, testcase_suite, testcases_by_id=None):
juraj.linkescae64f82018-09-19 15:01:47 +020072 super(TestResult, self).__init__()
73 self[PASS] = []
74 self[FAIL] = []
75 self[ERROR] = []
76 self[SKIP] = []
Klement Sekera558ceab2021-04-08 19:37:41 +020077 self[SKIP_CPU_SHORTAGE] = []
juraj.linkescae64f82018-09-19 15:01:47 +020078 self[TEST_RUN] = []
juraj.linkes40dd73b2018-09-21 13:55:16 +020079 self.crashed = False
juraj.linkescae64f82018-09-19 15:01:47 +020080 self.testcase_suite = testcase_suite
81 self.testcases = [testcase for testcase in testcase_suite]
juraj.linkes40dd73b2018-09-21 13:55:16 +020082 self.testcases_by_id = testcases_by_id
juraj.linkescae64f82018-09-19 15:01:47 +020083
84 def was_successful(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020085 return (
86 0 == len(self[FAIL]) == len(self[ERROR])
87 and len(self[PASS] + self[SKIP] + self[SKIP_CPU_SHORTAGE])
Klement Sekera558ceab2021-04-08 19:37:41 +020088 == self.testcase_suite.countTestCases()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020089 )
juraj.linkescae64f82018-09-19 15:01:47 +020090
91 def no_tests_run(self):
92 return 0 == len(self[TEST_RUN])
93
94 def process_result(self, test_id, result):
95 self[result].append(test_id)
juraj.linkescae64f82018-09-19 15:01:47 +020096
97 def suite_from_failed(self):
98 rerun_ids = set([])
99 for testcase in self.testcase_suite:
100 tc_id = testcase.id()
Klement Sekera558ceab2021-04-08 19:37:41 +0200101 if tc_id not in self[PASS] + self[SKIP] + self[SKIP_CPU_SHORTAGE]:
juraj.linkescae64f82018-09-19 15:01:47 +0200102 rerun_ids.add(tc_id)
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800103 if rerun_ids:
juraj.linkescae64f82018-09-19 15:01:47 +0200104 return suite_from_failed(self.testcase_suite, rerun_ids)
105
106 def get_testcase_names(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +0100107 # could be tearDownClass (test_ipsec_esp.TestIpsecEsp1)
108 setup_teardown_match = re.match(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200109 r"((tearDownClass)|(setUpClass)) \((.+\..+)\)", test_id
110 )
juraj.linkes2eca70d2018-12-13 11:10:47 +0100111 if setup_teardown_match:
112 test_name, _, _, testcase_name = setup_teardown_match.groups()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200113 if len(testcase_name.split(".")) == 2:
juraj.linkes2eca70d2018-12-13 11:10:47 +0100114 for key in self.testcases_by_id.keys():
115 if key.startswith(testcase_name):
116 testcase_name = key
117 break
118 testcase_name = self._get_testcase_doc_name(testcase_name)
119 else:
Ole Trøan5ba91592018-11-22 10:01:09 +0000120 test_name = self._get_test_description(test_id)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200121 testcase_name = self._get_testcase_doc_name(test_id)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200122
123 return testcase_name, test_name
juraj.linkescae64f82018-09-19 15:01:47 +0200124
Ole Trøan5ba91592018-11-22 10:01:09 +0000125 def _get_test_description(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +0100126 if test_id in self.testcases_by_id:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200127 desc = get_test_description(descriptions, self.testcases_by_id[test_id])
juraj.linkes2eca70d2018-12-13 11:10:47 +0100128 else:
129 desc = test_id
130 return desc
Ole Trøan5ba91592018-11-22 10:01:09 +0000131
juraj.linkes40dd73b2018-09-21 13:55:16 +0200132 def _get_testcase_doc_name(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +0100133 if test_id in self.testcases_by_id:
134 doc_name = get_testcase_doc_name(self.testcases_by_id[test_id])
135 else:
136 doc_name = test_id
137 return doc_name
juraj.linkescae64f82018-09-19 15:01:47 +0200138
139
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200140def test_runner_wrapper(
141 suite, keep_alive_pipe, stdouterr_queue, finished_pipe, result_pipe, logger
142):
juraj.linkes184870a2018-07-16 14:22:01 +0200143 sys.stdout = stdouterr_queue
144 sys.stderr = stdouterr_queue
juraj.linkesdfb5f2a2018-11-09 11:58:54 +0100145 VppTestCase.parallel_handler = logger.handlers[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200146 result = VppTestRunner(
147 keep_alive_pipe=keep_alive_pipe,
148 descriptions=descriptions,
149 verbosity=config.verbose,
150 result_pipe=result_pipe,
151 failfast=config.failfast,
152 print_summary=False,
153 ).run(suite)
juraj.linkescae64f82018-09-19 15:01:47 +0200154 finished_pipe.send(result.wasSuccessful())
155 finished_pipe.close()
Klement Sekera909a6a12017-08-08 04:33:53 +0200156 keep_alive_pipe.close()
157
158
juraj.linkes184870a2018-07-16 14:22:01 +0200159class TestCaseWrapper(object):
160 def __init__(self, testcase_suite, manager):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200161 self.keep_alive_parent_end, self.keep_alive_child_end = Pipe(duplex=False)
juraj.linkescae64f82018-09-19 15:01:47 +0200162 self.finished_parent_end, self.finished_child_end = Pipe(duplex=False)
juraj.linkes184870a2018-07-16 14:22:01 +0200163 self.result_parent_end, self.result_child_end = Pipe(duplex=False)
164 self.testcase_suite = testcase_suite
Klement Sekera558ceab2021-04-08 19:37:41 +0200165 self.stdouterr_queue = manager.StreamQueue(ctx=get_context())
juraj.linkes184870a2018-07-16 14:22:01 +0200166 self.logger = get_parallel_logger(self.stdouterr_queue)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200167 self.child = Process(
168 target=test_runner_wrapper,
169 args=(
170 testcase_suite,
171 self.keep_alive_child_end,
172 self.stdouterr_queue,
173 self.finished_child_end,
174 self.result_child_end,
175 self.logger,
176 ),
177 )
juraj.linkes184870a2018-07-16 14:22:01 +0200178 self.child.start()
juraj.linkes184870a2018-07-16 14:22:01 +0200179 self.last_test_temp_dir = None
180 self.last_test_vpp_binary = None
juraj.linkes40dd73b2018-09-21 13:55:16 +0200181 self._last_test = None
182 self.last_test_id = None
juraj.linkes721872e2018-09-05 18:13:45 +0200183 self.vpp_pid = None
juraj.linkes184870a2018-07-16 14:22:01 +0200184 self.last_heard = time.time()
185 self.core_detected_at = None
juraj.linkes40dd73b2018-09-21 13:55:16 +0200186 self.testcases_by_id = {}
187 self.testclasess_with_core = {}
188 for testcase in self.testcase_suite:
189 self.testcases_by_id[testcase.id()] = testcase
190 self.result = TestResult(testcase_suite, self.testcases_by_id)
191
192 @property
193 def last_test(self):
194 return self._last_test
195
196 @last_test.setter
197 def last_test(self, test_id):
198 self.last_test_id = test_id
199 if test_id in self.testcases_by_id:
200 testcase = self.testcases_by_id[test_id]
201 self._last_test = testcase.shortDescription()
202 if not self._last_test:
203 self._last_test = str(testcase)
204 else:
205 self._last_test = test_id
206
207 def add_testclass_with_core(self):
208 if self.last_test_id in self.testcases_by_id:
209 test = self.testcases_by_id[self.last_test_id]
210 class_name = unittest.util.strclass(test.__class__)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200211 test_name = "'{}' ({})".format(
212 get_test_description(descriptions, test), self.last_test_id
213 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200214 else:
215 test_name = self.last_test_id
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200216 class_name = re.match(
217 r"((tearDownClass)|(setUpClass)) " r"\((.+\..+)\)", test_name
218 ).groups()[3]
juraj.linkes40dd73b2018-09-21 13:55:16 +0200219 if class_name not in self.testclasess_with_core:
220 self.testclasess_with_core[class_name] = (
221 test_name,
222 self.last_test_vpp_binary,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200223 self.last_test_temp_dir,
224 )
juraj.linkes184870a2018-07-16 14:22:01 +0200225
226 def close_pipes(self):
227 self.keep_alive_child_end.close()
juraj.linkescae64f82018-09-19 15:01:47 +0200228 self.finished_child_end.close()
juraj.linkes184870a2018-07-16 14:22:01 +0200229 self.result_child_end.close()
230 self.keep_alive_parent_end.close()
juraj.linkescae64f82018-09-19 15:01:47 +0200231 self.finished_parent_end.close()
juraj.linkes184870a2018-07-16 14:22:01 +0200232 self.result_parent_end.close()
233
juraj.linkes40dd73b2018-09-21 13:55:16 +0200234 def was_successful(self):
235 return self.result.was_successful()
236
Klement Sekera558ceab2021-04-08 19:37:41 +0200237 @property
238 def cpus_used(self):
239 return self.testcase_suite.cpus_used
240
241 def get_assigned_cpus(self):
242 return self.testcase_suite.get_assigned_cpus()
243
juraj.linkes184870a2018-07-16 14:22:01 +0200244
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200245def stdouterr_reader_wrapper(
246 unread_testcases, finished_unread_testcases, read_testcases
247):
juraj.linkes184870a2018-07-16 14:22:01 +0200248 read_testcase = None
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800249 while read_testcases.is_set() or unread_testcases:
250 if finished_unread_testcases:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100251 read_testcase = finished_unread_testcases.pop()
252 unread_testcases.remove(read_testcase)
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800253 elif unread_testcases:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100254 read_testcase = unread_testcases.pop()
juraj.linkes184870a2018-07-16 14:22:01 +0200255 if read_testcase:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200256 data = ""
juraj.linkes184870a2018-07-16 14:22:01 +0200257 while data is not None:
258 sys.stdout.write(data)
259 data = read_testcase.stdouterr_queue.get()
260
261 read_testcase.stdouterr_queue.close()
262 finished_unread_testcases.discard(read_testcase)
263 read_testcase = None
264
265
Dmitry Valter3ace4d62022-03-26 15:43:14 +0000266def handle_failed_suite(logger, last_test_temp_dir, vpp_pid, vpp_binary):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200267 if last_test_temp_dir:
268 # Need to create link in case of a timeout or core dump without failure
269 lttd = os.path.basename(last_test_temp_dir)
Klement Sekera152a9b62022-05-13 18:01:36 +0200270 link_path = os.path.join(config.failed_dir, f"{lttd}-FAILED")
juraj.linkes40dd73b2018-09-21 13:55:16 +0200271 if not os.path.exists(link_path):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200272 os.symlink(last_test_temp_dir, link_path)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200273 logger.error(
274 "Symlink to failed testcase directory: %s -> %s" % (link_path, lttd)
275 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200276
277 # Report core existence
278 core_path = get_core_path(last_test_temp_dir)
279 if os.path.exists(core_path):
280 logger.error(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200281 "Core-file exists in test temporary directory: %s!" % core_path
282 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200283 check_core_path(logger, core_path)
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800284 logger.debug("Running 'file %s':" % core_path)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200285 try:
286 info = check_output(["file", core_path])
287 logger.debug(info)
288 except CalledProcessError as e:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200289 logger.error(
290 "Subprocess returned with return code "
291 "while running `file' utility on core-file "
292 "returned: "
293 "rc=%s",
294 e.returncode,
295 )
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800296 except OSError as e:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200297 logger.error(
298 "Subprocess returned with OS error while "
299 "running 'file' utility "
300 "on core-file: "
301 "(%s) %s",
302 e.errno,
303 e.strerror,
304 )
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800305 except Exception as e:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200306 logger.exception("Unexpected error running `file' utility on core-file")
Dmitry Valter3ace4d62022-03-26 15:43:14 +0000307 logger.error(f"gdb {vpp_binary} {core_path}")
juraj.linkes40dd73b2018-09-21 13:55:16 +0200308
309 if vpp_pid:
310 # Copy api post mortem
311 api_post_mortem_path = "/tmp/api_post_mortem.%d" % vpp_pid
312 if os.path.isfile(api_post_mortem_path):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200313 logger.error(
314 "Copying api_post_mortem.%d to %s" % (vpp_pid, last_test_temp_dir)
315 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200316 shutil.copy2(api_post_mortem_path, last_test_temp_dir)
317
318
319def check_and_handle_core(vpp_binary, tempdir, core_crash_test):
320 if is_core_present(tempdir):
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200321 if debug_core:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200322 print(
323 "VPP core detected in %s. Last test running was %s"
324 % (tempdir, core_crash_test)
325 )
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200326 print(single_line_delim)
327 spawn_gdb(vpp_binary, get_core_path(tempdir))
328 print(single_line_delim)
Klement Sekerab23ffd72021-05-31 16:08:53 +0200329 elif config.compress_core:
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200330 print("Compressing core-file in test directory `%s'" % tempdir)
331 os.system("gzip %s" % get_core_path(tempdir))
juraj.linkes40dd73b2018-09-21 13:55:16 +0200332
333
334def handle_cores(failed_testcases):
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200335 for failed_testcase in failed_testcases:
336 tcs_with_core = failed_testcase.testclasess_with_core
337 if tcs_with_core:
338 for test, vpp_binary, tempdir in tcs_with_core.values():
339 check_and_handle_core(vpp_binary, tempdir, test)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200340
341
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200342def process_finished_testsuite(
343 wrapped_testcase_suite, finished_testcase_suites, failed_wrapped_testcases, results
344):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200345 results.append(wrapped_testcase_suite.result)
346 finished_testcase_suites.add(wrapped_testcase_suite)
347 stop_run = False
Klement Sekerab23ffd72021-05-31 16:08:53 +0200348 if config.failfast and not wrapped_testcase_suite.was_successful():
juraj.linkes40dd73b2018-09-21 13:55:16 +0200349 stop_run = True
350
351 if not wrapped_testcase_suite.was_successful():
352 failed_wrapped_testcases.add(wrapped_testcase_suite)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200353 handle_failed_suite(
354 wrapped_testcase_suite.logger,
355 wrapped_testcase_suite.last_test_temp_dir,
356 wrapped_testcase_suite.vpp_pid,
357 wrapped_testcase_suite.last_test_vpp_binary,
358 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200359
360 return stop_run
361
362
juraj.linkes721872e2018-09-05 18:13:45 +0200363def run_forked(testcase_suites):
juraj.linkes184870a2018-07-16 14:22:01 +0200364 wrapped_testcase_suites = set()
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000365 solo_testcase_suites = []
juraj.linkes184870a2018-07-16 14:22:01 +0200366
367 # suites are unhashable, need to use list
368 results = []
juraj.linkes184870a2018-07-16 14:22:01 +0200369 unread_testcases = set()
370 finished_unread_testcases = set()
371 manager = StreamQueueManager()
372 manager.start()
Klement Sekera558ceab2021-04-08 19:37:41 +0200373 tests_running = 0
374 free_cpus = list(available_cpus)
375
376 def on_suite_start(tc):
377 nonlocal tests_running
378 nonlocal free_cpus
379 tests_running = tests_running + 1
380
381 def on_suite_finish(tc):
382 nonlocal tests_running
383 nonlocal free_cpus
384 tests_running = tests_running - 1
385 assert tests_running >= 0
386 free_cpus.extend(tc.get_assigned_cpus())
387
388 def run_suite(suite):
389 nonlocal manager
390 nonlocal wrapped_testcase_suites
391 nonlocal unread_testcases
392 nonlocal free_cpus
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200393 suite.assign_cpus(free_cpus[: suite.cpus_used])
394 free_cpus = free_cpus[suite.cpus_used :]
Klement Sekera558ceab2021-04-08 19:37:41 +0200395 wrapper = TestCaseWrapper(suite, manager)
396 wrapped_testcase_suites.add(wrapper)
397 unread_testcases.add(wrapper)
398 on_suite_start(suite)
399
400 def can_run_suite(suite):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200401 return tests_running < max_concurrent_tests and (
402 suite.cpus_used <= len(free_cpus) or suite.cpus_used > max_vpp_cpus
403 )
Klement Sekera558ceab2021-04-08 19:37:41 +0200404
405 while free_cpus and testcase_suites:
406 a_suite = testcase_suites[0]
407 if a_suite.is_tagged_run_solo:
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000408 a_suite = testcase_suites.pop(0)
Klement Sekera558ceab2021-04-08 19:37:41 +0200409 solo_testcase_suites.append(a_suite)
410 continue
411 if can_run_suite(a_suite):
412 a_suite = testcase_suites.pop(0)
413 run_suite(a_suite)
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000414 else:
415 break
416
Klement Sekera558ceab2021-04-08 19:37:41 +0200417 if tests_running == 0 and solo_testcase_suites:
418 a_suite = solo_testcase_suites.pop(0)
419 run_suite(a_suite)
juraj.linkes184870a2018-07-16 14:22:01 +0200420
421 read_from_testcases = threading.Event()
422 read_from_testcases.set()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200423 stdouterr_thread = threading.Thread(
424 target=stdouterr_reader_wrapper,
425 args=(unread_testcases, finished_unread_testcases, read_from_testcases),
426 )
juraj.linkes184870a2018-07-16 14:22:01 +0200427 stdouterr_thread.start()
428
juraj.linkes40dd73b2018-09-21 13:55:16 +0200429 failed_wrapped_testcases = set()
430 stop_run = False
juraj.linkese6b58cf2018-11-29 09:56:35 +0100431
432 try:
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800433 while wrapped_testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100434 finished_testcase_suites = set()
435 for wrapped_testcase_suite in wrapped_testcase_suites:
436 while wrapped_testcase_suite.result_parent_end.poll():
437 wrapped_testcase_suite.result.process_result(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200438 *wrapped_testcase_suite.result_parent_end.recv()
439 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100440 wrapped_testcase_suite.last_heard = time.time()
441
442 while wrapped_testcase_suite.keep_alive_parent_end.poll():
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200443 (
444 wrapped_testcase_suite.last_test,
445 wrapped_testcase_suite.last_test_vpp_binary,
446 wrapped_testcase_suite.last_test_temp_dir,
447 wrapped_testcase_suite.vpp_pid,
448 ) = wrapped_testcase_suite.keep_alive_parent_end.recv()
juraj.linkese6b58cf2018-11-29 09:56:35 +0100449 wrapped_testcase_suite.last_heard = time.time()
450
451 if wrapped_testcase_suite.finished_parent_end.poll():
452 wrapped_testcase_suite.finished_parent_end.recv()
453 wrapped_testcase_suite.last_heard = time.time()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200454 stop_run = (
455 process_finished_testsuite(
456 wrapped_testcase_suite,
457 finished_testcase_suites,
458 failed_wrapped_testcases,
459 results,
460 )
461 or stop_run
462 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100463 continue
464
465 fail = False
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200466 if wrapped_testcase_suite.last_heard + config.timeout < time.time():
juraj.linkese6b58cf2018-11-29 09:56:35 +0100467 fail = True
468 wrapped_testcase_suite.logger.critical(
469 "Child test runner process timed out "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200470 "(last test running was `%s' in `%s')!"
471 % (
472 wrapped_testcase_suite.last_test,
473 wrapped_testcase_suite.last_test_temp_dir,
474 )
475 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100476 elif not wrapped_testcase_suite.child.is_alive():
477 fail = True
478 wrapped_testcase_suite.logger.critical(
479 "Child test runner process unexpectedly died "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200480 "(last test running was `%s' in `%s')!"
481 % (
482 wrapped_testcase_suite.last_test,
483 wrapped_testcase_suite.last_test_temp_dir,
484 )
485 )
486 elif (
487 wrapped_testcase_suite.last_test_temp_dir
488 and wrapped_testcase_suite.last_test_vpp_binary
489 ):
490 if is_core_present(wrapped_testcase_suite.last_test_temp_dir):
juraj.linkese6b58cf2018-11-29 09:56:35 +0100491 wrapped_testcase_suite.add_testclass_with_core()
492 if wrapped_testcase_suite.core_detected_at is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200493 wrapped_testcase_suite.core_detected_at = time.time()
494 elif (
495 wrapped_testcase_suite.core_detected_at + core_timeout
496 < time.time()
497 ):
juraj.linkese6b58cf2018-11-29 09:56:35 +0100498 wrapped_testcase_suite.logger.critical(
499 "Child test runner process unresponsive and "
500 "core-file exists in test temporary directory "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200501 "(last test running was `%s' in `%s')!"
502 % (
503 wrapped_testcase_suite.last_test,
504 wrapped_testcase_suite.last_test_temp_dir,
505 )
506 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100507 fail = True
508
509 if fail:
510 wrapped_testcase_suite.child.terminate()
511 try:
512 # terminating the child process tends to leave orphan
513 # VPP process around
514 if wrapped_testcase_suite.vpp_pid:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200515 os.kill(wrapped_testcase_suite.vpp_pid, signal.SIGTERM)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100516 except OSError:
517 # already dead
518 pass
519 wrapped_testcase_suite.result.crashed = True
520 wrapped_testcase_suite.result.process_result(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200521 wrapped_testcase_suite.last_test_id, ERROR
522 )
523 stop_run = (
524 process_finished_testsuite(
525 wrapped_testcase_suite,
526 finished_testcase_suites,
527 failed_wrapped_testcases,
528 results,
529 )
530 or stop_run
531 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100532
533 for finished_testcase in finished_testcase_suites:
Andrew Yourtchenko42693522019-11-05 01:08:26 +0100534 # Somewhat surprisingly, the join below may
535 # timeout, even if client signaled that
536 # it finished - so we note it just in case.
537 join_start = time.time()
538 finished_testcase.child.join(test_finished_join_timeout)
539 join_end = time.time()
540 if join_end - join_start >= test_finished_join_timeout:
541 finished_testcase.logger.error(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200542 "Timeout joining finished test: %s (pid %d)"
543 % (finished_testcase.last_test, finished_testcase.child.pid)
544 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100545 finished_testcase.close_pipes()
546 wrapped_testcase_suites.remove(finished_testcase)
547 finished_unread_testcases.add(finished_testcase)
548 finished_testcase.stdouterr_queue.put(None)
Klement Sekera558ceab2021-04-08 19:37:41 +0200549 on_suite_finish(finished_testcase)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100550 if stop_run:
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800551 while testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100552 results.append(TestResult(testcase_suites.pop(0)))
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800553 elif testcase_suites:
Klement Sekera558ceab2021-04-08 19:37:41 +0200554 a_suite = testcase_suites.pop(0)
555 while a_suite and a_suite.is_tagged_run_solo:
556 solo_testcase_suites.append(a_suite)
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000557 if testcase_suites:
Klement Sekera558ceab2021-04-08 19:37:41 +0200558 a_suite = testcase_suites.pop(0)
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000559 else:
Klement Sekera558ceab2021-04-08 19:37:41 +0200560 a_suite = None
561 if a_suite and can_run_suite(a_suite):
562 run_suite(a_suite)
563 if solo_testcase_suites and tests_running == 0:
564 a_suite = solo_testcase_suites.pop(0)
565 run_suite(a_suite)
Paul Vinciguerrac0692a42019-03-15 19:16:50 -0700566 time.sleep(0.1)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100567 except Exception:
juraj.linkes184870a2018-07-16 14:22:01 +0200568 for wrapped_testcase_suite in wrapped_testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100569 wrapped_testcase_suite.child.terminate()
570 wrapped_testcase_suite.stdouterr_queue.put(None)
571 raise
572 finally:
573 read_from_testcases.clear()
Klement Sekerab23ffd72021-05-31 16:08:53 +0200574 stdouterr_thread.join(config.timeout)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100575 manager.shutdown()
juraj.linkescae64f82018-09-19 15:01:47 +0200576
juraj.linkes40dd73b2018-09-21 13:55:16 +0200577 handle_cores(failed_wrapped_testcases)
juraj.linkes184870a2018-07-16 14:22:01 +0200578 return results
579
580
Klement Sekera558ceab2021-04-08 19:37:41 +0200581class TestSuiteWrapper(unittest.TestSuite):
582 cpus_used = 0
583
584 def __init__(self):
585 return super().__init__()
586
587 def addTest(self, test):
588 self.cpus_used = max(self.cpus_used, test.get_cpus_required())
589 super().addTest(test)
590
591 def assign_cpus(self, cpus):
592 self.cpus = cpus
593
594 def _handleClassSetUp(self, test, result):
595 if not test.__class__.skipped_due_to_cpu_lack:
596 test.assign_cpus(self.cpus)
597 super()._handleClassSetUp(test, result)
598
599 def get_assigned_cpus(self):
600 return self.cpus
601
602
juraj.linkes184870a2018-07-16 14:22:01 +0200603class SplitToSuitesCallback:
604 def __init__(self, filter_callback):
605 self.suites = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200606 self.suite_name = "default"
juraj.linkes184870a2018-07-16 14:22:01 +0200607 self.filter_callback = filter_callback
Klement Sekera558ceab2021-04-08 19:37:41 +0200608 self.filtered = TestSuiteWrapper()
Klement Sekerafcbf4442017-08-17 07:38:42 +0200609
610 def __call__(self, file_name, cls, method):
juraj.linkes184870a2018-07-16 14:22:01 +0200611 test_method = cls(method)
612 if self.filter_callback(file_name, cls.__name__, method):
613 self.suite_name = file_name + cls.__name__
614 if self.suite_name not in self.suites:
Klement Sekera558ceab2021-04-08 19:37:41 +0200615 self.suites[self.suite_name] = TestSuiteWrapper()
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000616 self.suites[self.suite_name].is_tagged_run_solo = False
juraj.linkes184870a2018-07-16 14:22:01 +0200617 self.suites[self.suite_name].addTest(test_method)
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000618 if test_method.is_tagged_run_solo():
619 self.suites[self.suite_name].is_tagged_run_solo = True
juraj.linkes184870a2018-07-16 14:22:01 +0200620
621 else:
622 self.filtered.addTest(test_method)
Klement Sekerafcbf4442017-08-17 07:38:42 +0200623
624
Klement Sekerab23ffd72021-05-31 16:08:53 +0200625def parse_test_filter(test_filter):
626 f = test_filter
juraj.linkes184870a2018-07-16 14:22:01 +0200627 filter_file_name = None
628 filter_class_name = None
629 filter_func_name = None
630 if f:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200631 if "." in f:
632 parts = f.split(".")
juraj.linkes184870a2018-07-16 14:22:01 +0200633 if len(parts) > 3:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200634 raise Exception("Unrecognized %s option: %s" % (test_option, f))
juraj.linkes184870a2018-07-16 14:22:01 +0200635 if len(parts) > 2:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200636 if parts[2] not in ("*", ""):
juraj.linkes184870a2018-07-16 14:22:01 +0200637 filter_func_name = parts[2]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200638 if parts[1] not in ("*", ""):
juraj.linkes184870a2018-07-16 14:22:01 +0200639 filter_class_name = parts[1]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200640 if parts[0] not in ("*", ""):
641 if parts[0].startswith("test_"):
juraj.linkes184870a2018-07-16 14:22:01 +0200642 filter_file_name = parts[0]
643 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200644 filter_file_name = "test_%s" % parts[0]
juraj.linkes184870a2018-07-16 14:22:01 +0200645 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200646 if f.startswith("test_"):
juraj.linkes184870a2018-07-16 14:22:01 +0200647 filter_file_name = f
648 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200649 filter_file_name = "test_%s" % f
juraj.linkes184870a2018-07-16 14:22:01 +0200650 if filter_file_name:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200651 filter_file_name = "%s.py" % filter_file_name
juraj.linkes184870a2018-07-16 14:22:01 +0200652 return filter_file_name, filter_class_name, filter_func_name
653
654
655def filter_tests(tests, filter_cb):
Klement Sekera558ceab2021-04-08 19:37:41 +0200656 result = TestSuiteWrapper()
juraj.linkes184870a2018-07-16 14:22:01 +0200657 for t in tests:
658 if isinstance(t, unittest.suite.TestSuite):
659 # this is a bunch of tests, recursively filter...
660 x = filter_tests(t, filter_cb)
661 if x.countTestCases() > 0:
662 result.addTest(x)
663 elif isinstance(t, unittest.TestCase):
664 # this is a single test
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200665 parts = t.id().split(".")
juraj.linkes184870a2018-07-16 14:22:01 +0200666 # t.id() for common cases like this:
667 # test_classifier.TestClassifier.test_acl_ip
668 # apply filtering only if it is so
669 if len(parts) == 3:
670 if not filter_cb(parts[0], parts[1], parts[2]):
671 continue
672 result.addTest(t)
673 else:
674 # unexpected object, don't touch it
675 result.addTest(t)
676 return result
677
678
679class FilterByTestOption:
680 def __init__(self, filter_file_name, filter_class_name, filter_func_name):
681 self.filter_file_name = filter_file_name
682 self.filter_class_name = filter_class_name
683 self.filter_func_name = filter_func_name
684
685 def __call__(self, file_name, class_name, func_name):
Andrew Yourtchenkod760f792018-10-03 11:38:31 +0200686 if self.filter_file_name:
687 fn_match = fnmatch.fnmatch(file_name, self.filter_file_name)
688 if not fn_match:
689 return False
juraj.linkes184870a2018-07-16 14:22:01 +0200690 if self.filter_class_name and class_name != self.filter_class_name:
691 return False
692 if self.filter_func_name and func_name != self.filter_func_name:
693 return False
694 return True
695
696
697class FilterByClassList:
juraj.linkes721872e2018-09-05 18:13:45 +0200698 def __init__(self, classes_with_filenames):
699 self.classes_with_filenames = classes_with_filenames
Klement Sekeradf2b9802017-10-05 10:26:03 +0200700
701 def __call__(self, file_name, class_name, func_name):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200702 return ".".join([file_name, class_name]) in self.classes_with_filenames
Klement Sekeradf2b9802017-10-05 10:26:03 +0200703
704
705def suite_from_failed(suite, failed):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200706 failed = {x.rsplit(".", 1)[0] for x in failed}
juraj.linkes184870a2018-07-16 14:22:01 +0200707 filter_cb = FilterByClassList(failed)
708 suite = filter_tests(suite, filter_cb)
Klement Sekera4c5422e2018-06-22 13:19:45 +0200709 return suite
Klement Sekeradf2b9802017-10-05 10:26:03 +0200710
711
juraj.linkescae64f82018-09-19 15:01:47 +0200712class AllResults(dict):
juraj.linkes184870a2018-07-16 14:22:01 +0200713 def __init__(self):
juraj.linkescae64f82018-09-19 15:01:47 +0200714 super(AllResults, self).__init__()
juraj.linkes184870a2018-07-16 14:22:01 +0200715 self.all_testcases = 0
juraj.linkescae64f82018-09-19 15:01:47 +0200716 self.results_per_suite = []
717 self[PASS] = 0
718 self[FAIL] = 0
719 self[ERROR] = 0
720 self[SKIP] = 0
Klement Sekera558ceab2021-04-08 19:37:41 +0200721 self[SKIP_CPU_SHORTAGE] = 0
juraj.linkescae64f82018-09-19 15:01:47 +0200722 self[TEST_RUN] = 0
juraj.linkes184870a2018-07-16 14:22:01 +0200723 self.rerun = []
juraj.linkescae64f82018-09-19 15:01:47 +0200724 self.testsuites_no_tests_run = []
Klement Sekera909a6a12017-08-08 04:33:53 +0200725
juraj.linkescae64f82018-09-19 15:01:47 +0200726 def add_results(self, result):
727 self.results_per_suite.append(result)
Klement Sekera558ceab2021-04-08 19:37:41 +0200728 result_types = [PASS, FAIL, ERROR, SKIP, TEST_RUN, SKIP_CPU_SHORTAGE]
juraj.linkescae64f82018-09-19 15:01:47 +0200729 for result_type in result_types:
730 self[result_type] += len(result[result_type])
Klement Sekera05742262018-03-14 18:14:49 +0100731
juraj.linkescae64f82018-09-19 15:01:47 +0200732 def add_result(self, result):
juraj.linkes184870a2018-07-16 14:22:01 +0200733 retval = 0
juraj.linkescae64f82018-09-19 15:01:47 +0200734 self.all_testcases += result.testcase_suite.countTestCases()
juraj.linkes40dd73b2018-09-21 13:55:16 +0200735 self.add_results(result)
juraj.linkes184870a2018-07-16 14:22:01 +0200736
juraj.linkes40dd73b2018-09-21 13:55:16 +0200737 if result.no_tests_run():
juraj.linkescae64f82018-09-19 15:01:47 +0200738 self.testsuites_no_tests_run.append(result.testcase_suite)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200739 if result.crashed:
740 retval = -1
741 else:
742 retval = 1
743 elif not result.was_successful():
744 retval = 1
juraj.linkes184870a2018-07-16 14:22:01 +0200745
juraj.linkes184870a2018-07-16 14:22:01 +0200746 if retval != 0:
juraj.linkesabec0122018-11-16 17:28:56 +0100747 self.rerun.append(result.testcase_suite)
juraj.linkes184870a2018-07-16 14:22:01 +0200748
749 return retval
750
751 def print_results(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200752 print("")
juraj.linkes184870a2018-07-16 14:22:01 +0200753 print(double_line_delim)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200754 print("TEST RESULTS:")
Klement Sekera558ceab2021-04-08 19:37:41 +0200755
756 def indent_results(lines):
757 lines = list(filter(None, lines))
758 maximum = max(lines, key=lambda x: x.index(":"))
759 maximum = 4 + maximum.index(":")
760 for l in lines:
761 padding = " " * (maximum - l.index(":"))
762 print(f"{padding}{l}")
763
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200764 indent_results(
765 [
766 f"Scheduled tests: {self.all_testcases}",
767 f"Executed tests: {self[TEST_RUN]}",
768 f"Passed tests: {colorize(self[PASS], GREEN)}",
769 f"Skipped tests: {colorize(self[SKIP], YELLOW)}"
770 if self[SKIP]
771 else None,
772 f"Not Executed tests: {colorize(self.not_executed, RED)}"
773 if self.not_executed
774 else None,
775 f"Failures: {colorize(self[FAIL], RED)}" if self[FAIL] else None,
776 f"Errors: {colorize(self[ERROR], RED)}" if self[ERROR] else None,
777 "Tests skipped due to lack of CPUS: "
778 f"{colorize(self[SKIP_CPU_SHORTAGE], YELLOW)}"
779 if self[SKIP_CPU_SHORTAGE]
780 else None,
781 ]
782 )
juraj.linkes184870a2018-07-16 14:22:01 +0200783
784 if self.all_failed > 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200785 print("FAILURES AND ERRORS IN TESTS:")
juraj.linkescae64f82018-09-19 15:01:47 +0200786 for result in self.results_per_suite:
787 failed_testcase_ids = result[FAIL]
788 errored_testcase_ids = result[ERROR]
789 old_testcase_name = None
Paul Vinciguerra67a77492019-12-10 23:36:05 -0500790 if failed_testcase_ids:
juraj.linkescae64f82018-09-19 15:01:47 +0200791 for failed_test_id in failed_testcase_ids:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200792 new_testcase_name, test_name = result.get_testcase_names(
793 failed_test_id
794 )
juraj.linkescae64f82018-09-19 15:01:47 +0200795 if new_testcase_name != old_testcase_name:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200796 print(
797 " Testcase name: {}".format(
798 colorize(new_testcase_name, RED)
799 )
800 )
juraj.linkescae64f82018-09-19 15:01:47 +0200801 old_testcase_name = new_testcase_name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200802 print(
803 " FAILURE: {} [{}]".format(
804 colorize(test_name, RED), failed_test_id
805 )
806 )
Paul Vinciguerra67a77492019-12-10 23:36:05 -0500807 if errored_testcase_ids:
808 for errored_test_id in errored_testcase_ids:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200809 new_testcase_name, test_name = result.get_testcase_names(
810 errored_test_id
811 )
juraj.linkescae64f82018-09-19 15:01:47 +0200812 if new_testcase_name != old_testcase_name:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200813 print(
814 " Testcase name: {}".format(
815 colorize(new_testcase_name, RED)
816 )
817 )
juraj.linkescae64f82018-09-19 15:01:47 +0200818 old_testcase_name = new_testcase_name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200819 print(
820 " ERROR: {} [{}]".format(
821 colorize(test_name, RED), errored_test_id
822 )
823 )
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800824 if self.testsuites_no_tests_run:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200825 print("TESTCASES WHERE NO TESTS WERE SUCCESSFULLY EXECUTED:")
juraj.linkes40dd73b2018-09-21 13:55:16 +0200826 tc_classes = set()
juraj.linkescae64f82018-09-19 15:01:47 +0200827 for testsuite in self.testsuites_no_tests_run:
828 for testcase in testsuite:
829 tc_classes.add(get_testcase_doc_name(testcase))
830 for tc_class in tc_classes:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200831 print(" {}".format(colorize(tc_class, RED)))
juraj.linkes184870a2018-07-16 14:22:01 +0200832
Klement Sekera558ceab2021-04-08 19:37:41 +0200833 if self[SKIP_CPU_SHORTAGE]:
834 print()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200835 print(
836 colorize(
837 " SOME TESTS WERE SKIPPED BECAUSE THERE ARE NOT"
838 " ENOUGH CPUS AVAILABLE",
839 YELLOW,
840 )
841 )
juraj.linkes184870a2018-07-16 14:22:01 +0200842 print(double_line_delim)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200843 print("")
juraj.linkes184870a2018-07-16 14:22:01 +0200844
845 @property
juraj.linkescae64f82018-09-19 15:01:47 +0200846 def not_executed(self):
847 return self.all_testcases - self[TEST_RUN]
848
849 @property
juraj.linkes184870a2018-07-16 14:22:01 +0200850 def all_failed(self):
juraj.linkescae64f82018-09-19 15:01:47 +0200851 return self[FAIL] + self[ERROR]
juraj.linkes184870a2018-07-16 14:22:01 +0200852
853
854def parse_results(results):
855 """
juraj.linkescae64f82018-09-19 15:01:47 +0200856 Prints the number of scheduled, executed, not executed, passed, failed,
857 errored and skipped tests and details about failed and errored tests.
juraj.linkes184870a2018-07-16 14:22:01 +0200858
juraj.linkescae64f82018-09-19 15:01:47 +0200859 Also returns all suites where any test failed.
juraj.linkes184870a2018-07-16 14:22:01 +0200860
861 :param results:
862 :return:
863 """
864
juraj.linkescae64f82018-09-19 15:01:47 +0200865 results_per_suite = AllResults()
juraj.linkes184870a2018-07-16 14:22:01 +0200866 crashed = False
867 failed = False
juraj.linkescae64f82018-09-19 15:01:47 +0200868 for result in results:
869 result_code = results_per_suite.add_result(result)
juraj.linkes184870a2018-07-16 14:22:01 +0200870 if result_code == 1:
871 failed = True
872 elif result_code == -1:
873 crashed = True
874
875 results_per_suite.print_results()
876
877 if crashed:
878 return_code = -1
879 elif failed:
880 return_code = 1
881 else:
882 return_code = 0
883 return return_code, results_per_suite.rerun
884
885
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200886if __name__ == "__main__":
Klement Sekera3f6ff192017-08-11 06:56:05 +0200887
Klement Sekerab23ffd72021-05-31 16:08:53 +0200888 print(f"Config is: {config}")
Klement Sekera3f6ff192017-08-11 06:56:05 +0200889
Klement Sekerab23ffd72021-05-31 16:08:53 +0200890 if config.sanity:
891 print("Running sanity test case.")
892 try:
893 rc = sanity_run_vpp.main()
894 if rc != 0:
895 sys.exit(rc)
896 except Exception as e:
897 print(traceback.format_exc())
898 print("Couldn't run sanity test case.")
899 sys.exit(-1)
Klement Sekera3f6ff192017-08-11 06:56:05 +0200900
Andrew Yourtchenko42693522019-11-05 01:08:26 +0100901 test_finished_join_timeout = 15
902
Klement Sekerab23ffd72021-05-31 16:08:53 +0200903 debug_gdb = config.debug in ["gdb", "gdbserver", "attach"]
904 debug_core = config.debug == "core"
Klement Sekera3f6ff192017-08-11 06:56:05 +0200905
Klement Sekerab23ffd72021-05-31 16:08:53 +0200906 run_interactive = debug_gdb or config.step or config.force_foreground
juraj.linkes184870a2018-07-16 14:22:01 +0200907
Klement Sekera558ceab2021-04-08 19:37:41 +0200908 max_concurrent_tests = 0
909 print(f"OS reports {num_cpus} available cpu(s).")
Paul Vinciguerra025cd9c2019-07-08 14:14:22 -0400910
Klement Sekerab23ffd72021-05-31 16:08:53 +0200911 test_jobs = config.jobs
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200912 if test_jobs == "auto":
juraj.linkes184870a2018-07-16 14:22:01 +0200913 if run_interactive:
Klement Sekera558ceab2021-04-08 19:37:41 +0200914 max_concurrent_tests = 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200915 print("Interactive mode required, running tests consecutively.")
juraj.linkes184870a2018-07-16 14:22:01 +0200916 else:
Klement Sekera558ceab2021-04-08 19:37:41 +0200917 max_concurrent_tests = num_cpus
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200918 print(
919 f"Running at most {max_concurrent_tests} python test "
920 "processes concurrently."
921 )
juraj.linkes184870a2018-07-16 14:22:01 +0200922 else:
Klement Sekerab23ffd72021-05-31 16:08:53 +0200923 max_concurrent_tests = test_jobs
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200924 print(
925 f"Running at most {max_concurrent_tests} python test processes "
926 "concurrently as set by 'TEST_JOBS'."
927 )
juraj.linkes184870a2018-07-16 14:22:01 +0200928
Klement Sekera558ceab2021-04-08 19:37:41 +0200929 print(f"Using at most {max_vpp_cpus} cpus for VPP threads.")
930
931 if run_interactive and max_concurrent_tests > 1:
juraj.linkes184870a2018-07-16 14:22:01 +0200932 raise NotImplementedError(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200933 "Running tests interactively (DEBUG is gdb[server] or ATTACH or "
934 "STEP is set) in parallel (TEST_JOBS is more than 1) is not "
935 "supported"
936 )
Klement Sekera13a83ef2018-03-21 12:35:51 +0100937
juraj.linkes184870a2018-07-16 14:22:01 +0200938 descriptions = True
Klement Sekera3f6ff192017-08-11 06:56:05 +0200939
Klement Sekera558ceab2021-04-08 19:37:41 +0200940 print("Running tests using custom test runner.")
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200941 filter_file, filter_class, filter_func = parse_test_filter(config.filter)
juraj.linkes184870a2018-07-16 14:22:01 +0200942
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200943 print(
944 "Selected filters: file=%s, class=%s, function=%s"
945 % (filter_file, filter_class, filter_func)
946 )
juraj.linkes184870a2018-07-16 14:22:01 +0200947
948 filter_cb = FilterByTestOption(filter_file, filter_class, filter_func)
949
Klement Sekerab23ffd72021-05-31 16:08:53 +0200950 ignore_path = config.venv_dir
juraj.linkes184870a2018-07-16 14:22:01 +0200951 cb = SplitToSuitesCallback(filter_cb)
Klement Sekerab23ffd72021-05-31 16:08:53 +0200952 for d in config.test_src_dir:
Klement Sekeradf2b9802017-10-05 10:26:03 +0200953 print("Adding tests from directory tree %s" % d)
Klement Sekerab8c72a42018-11-08 11:21:39 +0100954 discover_tests(d, cb, ignore_path)
Klement Sekera3f6ff192017-08-11 06:56:05 +0200955
juraj.linkes184870a2018-07-16 14:22:01 +0200956 # suites are not hashable, need to use list
957 suites = []
958 tests_amount = 0
959 for testcase_suite in cb.suites.values():
960 tests_amount += testcase_suite.countTestCases()
Klement Sekera558ceab2021-04-08 19:37:41 +0200961 if testcase_suite.cpus_used > max_vpp_cpus:
962 # here we replace test functions with lambdas to just skip them
963 # but we also replace setUp/tearDown functions to do nothing
964 # so that the test can be "started" and "stopped", so that we can
965 # still keep those prints (test description - SKIP), which are done
966 # in stopTest() (for that to trigger, test function must run)
967 for t in testcase_suite:
968 for m in dir(t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200969 if m.startswith("test_"):
Klement Sekera558ceab2021-04-08 19:37:41 +0200970 setattr(t, m, lambda: t.skipTest("not enough cpus"))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200971 setattr(t.__class__, "setUpClass", lambda: None)
972 setattr(t.__class__, "tearDownClass", lambda: None)
973 setattr(t, "setUp", lambda: None)
974 setattr(t, "tearDown", lambda: None)
Klement Sekera558ceab2021-04-08 19:37:41 +0200975 t.__class__.skipped_due_to_cpu_lack = True
juraj.linkes184870a2018-07-16 14:22:01 +0200976 suites.append(testcase_suite)
Klement Sekerabbfa5fd2018-06-27 13:54:32 +0200977
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200978 print(
979 "%s out of %s tests match specified filters"
980 % (tests_amount, tests_amount + cb.filtered.countTestCases())
981 )
juraj.linkes184870a2018-07-16 14:22:01 +0200982
Klement Sekerab23ffd72021-05-31 16:08:53 +0200983 if not config.extended:
juraj.linkes184870a2018-07-16 14:22:01 +0200984 print("Not running extended tests (some tests will be skipped)")
985
Klement Sekerab23ffd72021-05-31 16:08:53 +0200986 attempts = config.retries + 1
Klement Sekeradf2b9802017-10-05 10:26:03 +0200987 if attempts > 1:
988 print("Perform %s attempts to pass the suite..." % attempts)
juraj.linkes184870a2018-07-16 14:22:01 +0200989
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800990 if run_interactive and suites:
juraj.linkes184870a2018-07-16 14:22:01 +0200991 # don't fork if requiring interactive terminal
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200992 print("Running tests in foreground in the current process")
juraj.linkes46e8e912019-01-10 12:13:07 +0100993 full_suite = unittest.TestSuite()
Klement Sekera558ceab2021-04-08 19:37:41 +0200994 free_cpus = list(available_cpus)
995 cpu_shortage = False
996 for suite in suites:
997 if suite.cpus_used <= max_vpp_cpus:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200998 suite.assign_cpus(free_cpus[: suite.cpus_used])
Klement Sekera558ceab2021-04-08 19:37:41 +0200999 else:
1000 suite.assign_cpus([])
1001 cpu_shortage = True
Klement Sekerad743dff2019-10-29 11:03:47 +00001002 full_suite.addTests(suites)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001003 result = VppTestRunner(
1004 verbosity=config.verbose, failfast=config.failfast, print_summary=True
1005 ).run(full_suite)
juraj.linkes40dd73b2018-09-21 13:55:16 +02001006 was_successful = result.wasSuccessful()
1007 if not was_successful:
1008 for test_case_info in result.failed_test_cases_info:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001009 handle_failed_suite(
1010 test_case_info.logger,
1011 test_case_info.tempdir,
1012 test_case_info.vpp_pid,
1013 config.vpp,
1014 )
Klement Sekeraf40ee3a2019-05-06 19:11:25 +02001015 if test_case_info in result.core_crash_test_cases_info:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001016 check_and_handle_core(
1017 test_case_info.vpp_bin_path,
1018 test_case_info.tempdir,
1019 test_case_info.core_crash_test,
1020 )
juraj.linkes40dd73b2018-09-21 13:55:16 +02001021
Klement Sekera558ceab2021-04-08 19:37:41 +02001022 if cpu_shortage:
1023 print()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001024 print(
1025 colorize(
1026 "SOME TESTS WERE SKIPPED BECAUSE THERE ARE NOT"
1027 " ENOUGH CPUS AVAILABLE",
1028 YELLOW,
1029 )
1030 )
Klement Sekera558ceab2021-04-08 19:37:41 +02001031 print()
juraj.linkes40dd73b2018-09-21 13:55:16 +02001032 sys.exit(not was_successful)
Klement Sekera13a83ef2018-03-21 12:35:51 +01001033 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001034 print(
1035 "Running each VPPTestCase in a separate background process"
1036 f" with at most {max_concurrent_tests} parallel python test "
1037 "process(es)"
1038 )
juraj.linkes184870a2018-07-16 14:22:01 +02001039 exit_code = 0
Naveen Joy2cbf2fb2019-03-06 10:41:06 -08001040 while suites and attempts > 0:
juraj.linkes184870a2018-07-16 14:22:01 +02001041 results = run_forked(suites)
1042 exit_code, suites = parse_results(results)
1043 attempts -= 1
1044 if exit_code == 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001045 print("Test run was successful")
juraj.linkes184870a2018-07-16 14:22:01 +02001046 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001047 print("%s attempt(s) left." % attempts)
juraj.linkes184870a2018-07-16 14:22:01 +02001048 sys.exit(exit_code)