blob: 2aa7b028ffc975a34c823aa5214d366139536041 [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:
Klement Sekerac7d50472023-04-14 17:43:35 +0200433 while wrapped_testcase_suites or 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 Sekerac7d50472023-04-14 17:43:35 +0200554 a_suite = testcase_suites[0]
Klement Sekera558ceab2021-04-08 19:37:41 +0200555 while a_suite and a_suite.is_tagged_run_solo:
Klement Sekerac7d50472023-04-14 17:43:35 +0200556 testcase_suites.pop(0)
Klement Sekera558ceab2021-04-08 19:37:41 +0200557 solo_testcase_suites.append(a_suite)
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000558 if testcase_suites:
Klement Sekerac7d50472023-04-14 17:43:35 +0200559 a_suite = testcase_suites[0]
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000560 else:
Klement Sekera558ceab2021-04-08 19:37:41 +0200561 a_suite = None
562 if a_suite and can_run_suite(a_suite):
Klement Sekerac7d50472023-04-14 17:43:35 +0200563 testcase_suites.pop(0)
Klement Sekera558ceab2021-04-08 19:37:41 +0200564 run_suite(a_suite)
565 if solo_testcase_suites and tests_running == 0:
566 a_suite = solo_testcase_suites.pop(0)
567 run_suite(a_suite)
Paul Vinciguerrac0692a42019-03-15 19:16:50 -0700568 time.sleep(0.1)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100569 except Exception:
juraj.linkes184870a2018-07-16 14:22:01 +0200570 for wrapped_testcase_suite in wrapped_testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100571 wrapped_testcase_suite.child.terminate()
572 wrapped_testcase_suite.stdouterr_queue.put(None)
573 raise
574 finally:
575 read_from_testcases.clear()
Klement Sekerab23ffd72021-05-31 16:08:53 +0200576 stdouterr_thread.join(config.timeout)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100577 manager.shutdown()
juraj.linkescae64f82018-09-19 15:01:47 +0200578
juraj.linkes40dd73b2018-09-21 13:55:16 +0200579 handle_cores(failed_wrapped_testcases)
juraj.linkes184870a2018-07-16 14:22:01 +0200580 return results
581
582
Klement Sekera558ceab2021-04-08 19:37:41 +0200583class TestSuiteWrapper(unittest.TestSuite):
584 cpus_used = 0
585
586 def __init__(self):
587 return super().__init__()
588
589 def addTest(self, test):
590 self.cpus_used = max(self.cpus_used, test.get_cpus_required())
591 super().addTest(test)
592
593 def assign_cpus(self, cpus):
594 self.cpus = cpus
595
596 def _handleClassSetUp(self, test, result):
597 if not test.__class__.skipped_due_to_cpu_lack:
598 test.assign_cpus(self.cpus)
599 super()._handleClassSetUp(test, result)
600
601 def get_assigned_cpus(self):
602 return self.cpus
603
604
juraj.linkes184870a2018-07-16 14:22:01 +0200605class SplitToSuitesCallback:
606 def __init__(self, filter_callback):
607 self.suites = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200608 self.suite_name = "default"
juraj.linkes184870a2018-07-16 14:22:01 +0200609 self.filter_callback = filter_callback
Klement Sekera558ceab2021-04-08 19:37:41 +0200610 self.filtered = TestSuiteWrapper()
Klement Sekerafcbf4442017-08-17 07:38:42 +0200611
612 def __call__(self, file_name, cls, method):
juraj.linkes184870a2018-07-16 14:22:01 +0200613 test_method = cls(method)
614 if self.filter_callback(file_name, cls.__name__, method):
615 self.suite_name = file_name + cls.__name__
616 if self.suite_name not in self.suites:
Klement Sekera558ceab2021-04-08 19:37:41 +0200617 self.suites[self.suite_name] = TestSuiteWrapper()
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000618 self.suites[self.suite_name].is_tagged_run_solo = False
juraj.linkes184870a2018-07-16 14:22:01 +0200619 self.suites[self.suite_name].addTest(test_method)
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000620 if test_method.is_tagged_run_solo():
621 self.suites[self.suite_name].is_tagged_run_solo = True
juraj.linkes184870a2018-07-16 14:22:01 +0200622
623 else:
624 self.filtered.addTest(test_method)
Klement Sekerafcbf4442017-08-17 07:38:42 +0200625
626
Klement Sekerab23ffd72021-05-31 16:08:53 +0200627def parse_test_filter(test_filter):
628 f = test_filter
juraj.linkes184870a2018-07-16 14:22:01 +0200629 filter_file_name = None
630 filter_class_name = None
631 filter_func_name = None
632 if f:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200633 if "." in f:
634 parts = f.split(".")
juraj.linkes184870a2018-07-16 14:22:01 +0200635 if len(parts) > 3:
Klement Sekera08c50e32023-04-14 17:44:04 +0200636 raise Exception(f"Invalid test filter: {test_filter}")
juraj.linkes184870a2018-07-16 14:22:01 +0200637 if len(parts) > 2:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200638 if parts[2] not in ("*", ""):
juraj.linkes184870a2018-07-16 14:22:01 +0200639 filter_func_name = parts[2]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200640 if parts[1] not in ("*", ""):
juraj.linkes184870a2018-07-16 14:22:01 +0200641 filter_class_name = parts[1]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200642 if parts[0] not in ("*", ""):
643 if parts[0].startswith("test_"):
juraj.linkes184870a2018-07-16 14:22:01 +0200644 filter_file_name = parts[0]
645 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200646 filter_file_name = "test_%s" % parts[0]
juraj.linkes184870a2018-07-16 14:22:01 +0200647 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200648 if f.startswith("test_"):
juraj.linkes184870a2018-07-16 14:22:01 +0200649 filter_file_name = f
650 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200651 filter_file_name = "test_%s" % f
juraj.linkes184870a2018-07-16 14:22:01 +0200652 if filter_file_name:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200653 filter_file_name = "%s.py" % filter_file_name
juraj.linkes184870a2018-07-16 14:22:01 +0200654 return filter_file_name, filter_class_name, filter_func_name
655
656
657def filter_tests(tests, filter_cb):
Klement Sekera558ceab2021-04-08 19:37:41 +0200658 result = TestSuiteWrapper()
juraj.linkes184870a2018-07-16 14:22:01 +0200659 for t in tests:
660 if isinstance(t, unittest.suite.TestSuite):
661 # this is a bunch of tests, recursively filter...
662 x = filter_tests(t, filter_cb)
663 if x.countTestCases() > 0:
664 result.addTest(x)
665 elif isinstance(t, unittest.TestCase):
666 # this is a single test
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200667 parts = t.id().split(".")
juraj.linkes184870a2018-07-16 14:22:01 +0200668 # t.id() for common cases like this:
669 # test_classifier.TestClassifier.test_acl_ip
670 # apply filtering only if it is so
671 if len(parts) == 3:
672 if not filter_cb(parts[0], parts[1], parts[2]):
673 continue
674 result.addTest(t)
675 else:
676 # unexpected object, don't touch it
677 result.addTest(t)
678 return result
679
680
681class FilterByTestOption:
Klement Sekera08c50e32023-04-14 17:44:04 +0200682 def __init__(self, filters):
683 self.filters = filters
juraj.linkes184870a2018-07-16 14:22:01 +0200684
685 def __call__(self, file_name, class_name, func_name):
Klement Sekera08c50e32023-04-14 17:44:04 +0200686 def test_one(
687 filter_file_name,
688 filter_class_name,
689 filter_func_name,
690 file_name,
691 class_name,
692 func_name,
693 ):
694 if filter_file_name:
695 fn_match = fnmatch.fnmatch(file_name, filter_file_name)
696 if not fn_match:
697 return False
698 if filter_class_name and class_name != filter_class_name:
Andrew Yourtchenkod760f792018-10-03 11:38:31 +0200699 return False
Klement Sekera08c50e32023-04-14 17:44:04 +0200700 if filter_func_name and func_name != filter_func_name:
701 return False
702 return True
703
704 for filter_file_name, filter_class_name, filter_func_name in self.filters:
705 if test_one(
706 filter_file_name,
707 filter_class_name,
708 filter_func_name,
709 file_name,
710 class_name,
711 func_name,
712 ):
713 return True
714
715 return False
juraj.linkes184870a2018-07-16 14:22:01 +0200716
717
718class FilterByClassList:
juraj.linkes721872e2018-09-05 18:13:45 +0200719 def __init__(self, classes_with_filenames):
720 self.classes_with_filenames = classes_with_filenames
Klement Sekeradf2b9802017-10-05 10:26:03 +0200721
722 def __call__(self, file_name, class_name, func_name):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200723 return ".".join([file_name, class_name]) in self.classes_with_filenames
Klement Sekeradf2b9802017-10-05 10:26:03 +0200724
725
726def suite_from_failed(suite, failed):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200727 failed = {x.rsplit(".", 1)[0] for x in failed}
juraj.linkes184870a2018-07-16 14:22:01 +0200728 filter_cb = FilterByClassList(failed)
729 suite = filter_tests(suite, filter_cb)
Klement Sekera4c5422e2018-06-22 13:19:45 +0200730 return suite
Klement Sekeradf2b9802017-10-05 10:26:03 +0200731
732
juraj.linkescae64f82018-09-19 15:01:47 +0200733class AllResults(dict):
juraj.linkes184870a2018-07-16 14:22:01 +0200734 def __init__(self):
juraj.linkescae64f82018-09-19 15:01:47 +0200735 super(AllResults, self).__init__()
juraj.linkes184870a2018-07-16 14:22:01 +0200736 self.all_testcases = 0
juraj.linkescae64f82018-09-19 15:01:47 +0200737 self.results_per_suite = []
738 self[PASS] = 0
739 self[FAIL] = 0
740 self[ERROR] = 0
741 self[SKIP] = 0
Klement Sekera558ceab2021-04-08 19:37:41 +0200742 self[SKIP_CPU_SHORTAGE] = 0
juraj.linkescae64f82018-09-19 15:01:47 +0200743 self[TEST_RUN] = 0
juraj.linkes184870a2018-07-16 14:22:01 +0200744 self.rerun = []
juraj.linkescae64f82018-09-19 15:01:47 +0200745 self.testsuites_no_tests_run = []
Klement Sekera909a6a12017-08-08 04:33:53 +0200746
juraj.linkescae64f82018-09-19 15:01:47 +0200747 def add_results(self, result):
748 self.results_per_suite.append(result)
Klement Sekera558ceab2021-04-08 19:37:41 +0200749 result_types = [PASS, FAIL, ERROR, SKIP, TEST_RUN, SKIP_CPU_SHORTAGE]
juraj.linkescae64f82018-09-19 15:01:47 +0200750 for result_type in result_types:
751 self[result_type] += len(result[result_type])
Klement Sekera05742262018-03-14 18:14:49 +0100752
juraj.linkescae64f82018-09-19 15:01:47 +0200753 def add_result(self, result):
juraj.linkes184870a2018-07-16 14:22:01 +0200754 retval = 0
juraj.linkescae64f82018-09-19 15:01:47 +0200755 self.all_testcases += result.testcase_suite.countTestCases()
juraj.linkes40dd73b2018-09-21 13:55:16 +0200756 self.add_results(result)
juraj.linkes184870a2018-07-16 14:22:01 +0200757
juraj.linkes40dd73b2018-09-21 13:55:16 +0200758 if result.no_tests_run():
juraj.linkescae64f82018-09-19 15:01:47 +0200759 self.testsuites_no_tests_run.append(result.testcase_suite)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200760 if result.crashed:
761 retval = -1
762 else:
763 retval = 1
764 elif not result.was_successful():
765 retval = 1
juraj.linkes184870a2018-07-16 14:22:01 +0200766
juraj.linkes184870a2018-07-16 14:22:01 +0200767 if retval != 0:
juraj.linkesabec0122018-11-16 17:28:56 +0100768 self.rerun.append(result.testcase_suite)
juraj.linkes184870a2018-07-16 14:22:01 +0200769
770 return retval
771
772 def print_results(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200773 print("")
juraj.linkes184870a2018-07-16 14:22:01 +0200774 print(double_line_delim)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200775 print("TEST RESULTS:")
Klement Sekera558ceab2021-04-08 19:37:41 +0200776
777 def indent_results(lines):
778 lines = list(filter(None, lines))
779 maximum = max(lines, key=lambda x: x.index(":"))
780 maximum = 4 + maximum.index(":")
781 for l in lines:
782 padding = " " * (maximum - l.index(":"))
783 print(f"{padding}{l}")
784
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200785 indent_results(
786 [
787 f"Scheduled tests: {self.all_testcases}",
788 f"Executed tests: {self[TEST_RUN]}",
789 f"Passed tests: {colorize(self[PASS], GREEN)}",
790 f"Skipped tests: {colorize(self[SKIP], YELLOW)}"
791 if self[SKIP]
792 else None,
793 f"Not Executed tests: {colorize(self.not_executed, RED)}"
794 if self.not_executed
795 else None,
796 f"Failures: {colorize(self[FAIL], RED)}" if self[FAIL] else None,
797 f"Errors: {colorize(self[ERROR], RED)}" if self[ERROR] else None,
798 "Tests skipped due to lack of CPUS: "
799 f"{colorize(self[SKIP_CPU_SHORTAGE], YELLOW)}"
800 if self[SKIP_CPU_SHORTAGE]
801 else None,
802 ]
803 )
juraj.linkes184870a2018-07-16 14:22:01 +0200804
805 if self.all_failed > 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200806 print("FAILURES AND ERRORS IN TESTS:")
juraj.linkescae64f82018-09-19 15:01:47 +0200807 for result in self.results_per_suite:
808 failed_testcase_ids = result[FAIL]
809 errored_testcase_ids = result[ERROR]
810 old_testcase_name = None
Paul Vinciguerra67a77492019-12-10 23:36:05 -0500811 if failed_testcase_ids:
juraj.linkescae64f82018-09-19 15:01:47 +0200812 for failed_test_id in failed_testcase_ids:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200813 new_testcase_name, test_name = result.get_testcase_names(
814 failed_test_id
815 )
juraj.linkescae64f82018-09-19 15:01:47 +0200816 if new_testcase_name != old_testcase_name:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200817 print(
818 " Testcase name: {}".format(
819 colorize(new_testcase_name, RED)
820 )
821 )
juraj.linkescae64f82018-09-19 15:01:47 +0200822 old_testcase_name = new_testcase_name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200823 print(
824 " FAILURE: {} [{}]".format(
825 colorize(test_name, RED), failed_test_id
826 )
827 )
Paul Vinciguerra67a77492019-12-10 23:36:05 -0500828 if errored_testcase_ids:
829 for errored_test_id in errored_testcase_ids:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200830 new_testcase_name, test_name = result.get_testcase_names(
831 errored_test_id
832 )
juraj.linkescae64f82018-09-19 15:01:47 +0200833 if new_testcase_name != old_testcase_name:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200834 print(
835 " Testcase name: {}".format(
836 colorize(new_testcase_name, RED)
837 )
838 )
juraj.linkescae64f82018-09-19 15:01:47 +0200839 old_testcase_name = new_testcase_name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200840 print(
841 " ERROR: {} [{}]".format(
842 colorize(test_name, RED), errored_test_id
843 )
844 )
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800845 if self.testsuites_no_tests_run:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200846 print("TESTCASES WHERE NO TESTS WERE SUCCESSFULLY EXECUTED:")
juraj.linkes40dd73b2018-09-21 13:55:16 +0200847 tc_classes = set()
juraj.linkescae64f82018-09-19 15:01:47 +0200848 for testsuite in self.testsuites_no_tests_run:
849 for testcase in testsuite:
850 tc_classes.add(get_testcase_doc_name(testcase))
851 for tc_class in tc_classes:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200852 print(" {}".format(colorize(tc_class, RED)))
juraj.linkes184870a2018-07-16 14:22:01 +0200853
Klement Sekera558ceab2021-04-08 19:37:41 +0200854 if self[SKIP_CPU_SHORTAGE]:
855 print()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200856 print(
857 colorize(
858 " SOME TESTS WERE SKIPPED BECAUSE THERE ARE NOT"
859 " ENOUGH CPUS AVAILABLE",
860 YELLOW,
861 )
862 )
juraj.linkes184870a2018-07-16 14:22:01 +0200863 print(double_line_delim)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200864 print("")
juraj.linkes184870a2018-07-16 14:22:01 +0200865
866 @property
juraj.linkescae64f82018-09-19 15:01:47 +0200867 def not_executed(self):
868 return self.all_testcases - self[TEST_RUN]
869
870 @property
juraj.linkes184870a2018-07-16 14:22:01 +0200871 def all_failed(self):
juraj.linkescae64f82018-09-19 15:01:47 +0200872 return self[FAIL] + self[ERROR]
juraj.linkes184870a2018-07-16 14:22:01 +0200873
874
875def parse_results(results):
876 """
juraj.linkescae64f82018-09-19 15:01:47 +0200877 Prints the number of scheduled, executed, not executed, passed, failed,
878 errored and skipped tests and details about failed and errored tests.
juraj.linkes184870a2018-07-16 14:22:01 +0200879
juraj.linkescae64f82018-09-19 15:01:47 +0200880 Also returns all suites where any test failed.
juraj.linkes184870a2018-07-16 14:22:01 +0200881
882 :param results:
883 :return:
884 """
885
juraj.linkescae64f82018-09-19 15:01:47 +0200886 results_per_suite = AllResults()
juraj.linkes184870a2018-07-16 14:22:01 +0200887 crashed = False
888 failed = False
juraj.linkescae64f82018-09-19 15:01:47 +0200889 for result in results:
890 result_code = results_per_suite.add_result(result)
juraj.linkes184870a2018-07-16 14:22:01 +0200891 if result_code == 1:
892 failed = True
893 elif result_code == -1:
894 crashed = True
895
896 results_per_suite.print_results()
897
898 if crashed:
899 return_code = -1
900 elif failed:
901 return_code = 1
902 else:
903 return_code = 0
904 return return_code, results_per_suite.rerun
905
906
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200907if __name__ == "__main__":
Klement Sekera3f6ff192017-08-11 06:56:05 +0200908
Klement Sekerab23ffd72021-05-31 16:08:53 +0200909 print(f"Config is: {config}")
Klement Sekera3f6ff192017-08-11 06:56:05 +0200910
Klement Sekerab23ffd72021-05-31 16:08:53 +0200911 if config.sanity:
912 print("Running sanity test case.")
913 try:
914 rc = sanity_run_vpp.main()
915 if rc != 0:
916 sys.exit(rc)
917 except Exception as e:
918 print(traceback.format_exc())
919 print("Couldn't run sanity test case.")
920 sys.exit(-1)
Klement Sekera3f6ff192017-08-11 06:56:05 +0200921
Andrew Yourtchenko42693522019-11-05 01:08:26 +0100922 test_finished_join_timeout = 15
923
Klement Sekerab23ffd72021-05-31 16:08:53 +0200924 debug_gdb = config.debug in ["gdb", "gdbserver", "attach"]
925 debug_core = config.debug == "core"
Klement Sekera3f6ff192017-08-11 06:56:05 +0200926
Klement Sekerab23ffd72021-05-31 16:08:53 +0200927 run_interactive = debug_gdb or config.step or config.force_foreground
juraj.linkes184870a2018-07-16 14:22:01 +0200928
Klement Sekera558ceab2021-04-08 19:37:41 +0200929 max_concurrent_tests = 0
930 print(f"OS reports {num_cpus} available cpu(s).")
Paul Vinciguerra025cd9c2019-07-08 14:14:22 -0400931
Klement Sekerab23ffd72021-05-31 16:08:53 +0200932 test_jobs = config.jobs
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200933 if test_jobs == "auto":
juraj.linkes184870a2018-07-16 14:22:01 +0200934 if run_interactive:
Klement Sekera558ceab2021-04-08 19:37:41 +0200935 max_concurrent_tests = 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200936 print("Interactive mode required, running tests consecutively.")
juraj.linkes184870a2018-07-16 14:22:01 +0200937 else:
Klement Sekera558ceab2021-04-08 19:37:41 +0200938 max_concurrent_tests = num_cpus
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200939 print(
940 f"Running at most {max_concurrent_tests} python test "
941 "processes concurrently."
942 )
juraj.linkes184870a2018-07-16 14:22:01 +0200943 else:
Klement Sekerab23ffd72021-05-31 16:08:53 +0200944 max_concurrent_tests = test_jobs
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200945 print(
946 f"Running at most {max_concurrent_tests} python test processes "
947 "concurrently as set by 'TEST_JOBS'."
948 )
juraj.linkes184870a2018-07-16 14:22:01 +0200949
Klement Sekera558ceab2021-04-08 19:37:41 +0200950 print(f"Using at most {max_vpp_cpus} cpus for VPP threads.")
951
952 if run_interactive and max_concurrent_tests > 1:
juraj.linkes184870a2018-07-16 14:22:01 +0200953 raise NotImplementedError(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200954 "Running tests interactively (DEBUG is gdb[server] or ATTACH or "
955 "STEP is set) in parallel (TEST_JOBS is more than 1) is not "
956 "supported"
957 )
Klement Sekera13a83ef2018-03-21 12:35:51 +0100958
juraj.linkes184870a2018-07-16 14:22:01 +0200959 descriptions = True
Klement Sekera3f6ff192017-08-11 06:56:05 +0200960
Klement Sekera558ceab2021-04-08 19:37:41 +0200961 print("Running tests using custom test runner.")
Klement Sekera08c50e32023-04-14 17:44:04 +0200962 filters = [(parse_test_filter(f)) for f in config.filter.split(",")]
juraj.linkes184870a2018-07-16 14:22:01 +0200963
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200964 print(
Klement Sekera08c50e32023-04-14 17:44:04 +0200965 "Selected filters: ",
966 "|".join(
967 f"file={filter_file}, class={filter_class}, function={filter_func}"
968 for filter_file, filter_class, filter_func in filters
969 ),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200970 )
juraj.linkes184870a2018-07-16 14:22:01 +0200971
Klement Sekera08c50e32023-04-14 17:44:04 +0200972 filter_cb = FilterByTestOption(filters)
juraj.linkes184870a2018-07-16 14:22:01 +0200973
974 cb = SplitToSuitesCallback(filter_cb)
Klement Sekerab23ffd72021-05-31 16:08:53 +0200975 for d in config.test_src_dir:
Klement Sekeradf2b9802017-10-05 10:26:03 +0200976 print("Adding tests from directory tree %s" % d)
Saima Yunusc7f93b32022-08-10 03:25:31 -0400977 discover_tests(d, cb)
Klement Sekera3f6ff192017-08-11 06:56:05 +0200978
juraj.linkes184870a2018-07-16 14:22:01 +0200979 # suites are not hashable, need to use list
980 suites = []
981 tests_amount = 0
982 for testcase_suite in cb.suites.values():
983 tests_amount += testcase_suite.countTestCases()
Klement Sekera558ceab2021-04-08 19:37:41 +0200984 if testcase_suite.cpus_used > max_vpp_cpus:
985 # here we replace test functions with lambdas to just skip them
986 # but we also replace setUp/tearDown functions to do nothing
987 # so that the test can be "started" and "stopped", so that we can
988 # still keep those prints (test description - SKIP), which are done
989 # in stopTest() (for that to trigger, test function must run)
990 for t in testcase_suite:
991 for m in dir(t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200992 if m.startswith("test_"):
Klement Sekera558ceab2021-04-08 19:37:41 +0200993 setattr(t, m, lambda: t.skipTest("not enough cpus"))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200994 setattr(t.__class__, "setUpClass", lambda: None)
995 setattr(t.__class__, "tearDownClass", lambda: None)
996 setattr(t, "setUp", lambda: None)
997 setattr(t, "tearDown", lambda: None)
Klement Sekera558ceab2021-04-08 19:37:41 +0200998 t.__class__.skipped_due_to_cpu_lack = True
juraj.linkes184870a2018-07-16 14:22:01 +0200999 suites.append(testcase_suite)
Klement Sekerabbfa5fd2018-06-27 13:54:32 +02001000
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001001 print(
1002 "%s out of %s tests match specified filters"
1003 % (tests_amount, tests_amount + cb.filtered.countTestCases())
1004 )
juraj.linkes184870a2018-07-16 14:22:01 +02001005
Klement Sekerab23ffd72021-05-31 16:08:53 +02001006 if not config.extended:
juraj.linkes184870a2018-07-16 14:22:01 +02001007 print("Not running extended tests (some tests will be skipped)")
1008
Klement Sekerab23ffd72021-05-31 16:08:53 +02001009 attempts = config.retries + 1
Klement Sekeradf2b9802017-10-05 10:26:03 +02001010 if attempts > 1:
1011 print("Perform %s attempts to pass the suite..." % attempts)
juraj.linkes184870a2018-07-16 14:22:01 +02001012
Naveen Joy2cbf2fb2019-03-06 10:41:06 -08001013 if run_interactive and suites:
juraj.linkes184870a2018-07-16 14:22:01 +02001014 # don't fork if requiring interactive terminal
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001015 print("Running tests in foreground in the current process")
juraj.linkes46e8e912019-01-10 12:13:07 +01001016 full_suite = unittest.TestSuite()
Klement Sekera558ceab2021-04-08 19:37:41 +02001017 free_cpus = list(available_cpus)
1018 cpu_shortage = False
1019 for suite in suites:
1020 if suite.cpus_used <= max_vpp_cpus:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001021 suite.assign_cpus(free_cpus[: suite.cpus_used])
Klement Sekera558ceab2021-04-08 19:37:41 +02001022 else:
1023 suite.assign_cpus([])
1024 cpu_shortage = True
Klement Sekerad743dff2019-10-29 11:03:47 +00001025 full_suite.addTests(suites)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001026 result = VppTestRunner(
1027 verbosity=config.verbose, failfast=config.failfast, print_summary=True
1028 ).run(full_suite)
juraj.linkes40dd73b2018-09-21 13:55:16 +02001029 was_successful = result.wasSuccessful()
1030 if not was_successful:
1031 for test_case_info in result.failed_test_cases_info:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001032 handle_failed_suite(
1033 test_case_info.logger,
1034 test_case_info.tempdir,
1035 test_case_info.vpp_pid,
1036 config.vpp,
1037 )
Klement Sekeraf40ee3a2019-05-06 19:11:25 +02001038 if test_case_info in result.core_crash_test_cases_info:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001039 check_and_handle_core(
1040 test_case_info.vpp_bin_path,
1041 test_case_info.tempdir,
1042 test_case_info.core_crash_test,
1043 )
juraj.linkes40dd73b2018-09-21 13:55:16 +02001044
Klement Sekera558ceab2021-04-08 19:37:41 +02001045 if cpu_shortage:
1046 print()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001047 print(
1048 colorize(
1049 "SOME TESTS WERE SKIPPED BECAUSE THERE ARE NOT"
1050 " ENOUGH CPUS AVAILABLE",
1051 YELLOW,
1052 )
1053 )
Klement Sekera558ceab2021-04-08 19:37:41 +02001054 print()
juraj.linkes40dd73b2018-09-21 13:55:16 +02001055 sys.exit(not was_successful)
Klement Sekera13a83ef2018-03-21 12:35:51 +01001056 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001057 print(
1058 "Running each VPPTestCase in a separate background process"
1059 f" with at most {max_concurrent_tests} parallel python test "
1060 "process(es)"
1061 )
juraj.linkes184870a2018-07-16 14:22:01 +02001062 exit_code = 0
Naveen Joy2cbf2fb2019-03-06 10:41:06 -08001063 while suites and attempts > 0:
juraj.linkes184870a2018-07-16 14:22:01 +02001064 results = run_forked(suites)
1065 exit_code, suites = parse_results(results)
1066 attempts -= 1
1067 if exit_code == 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001068 print("Test run was successful")
juraj.linkes184870a2018-07-16 14:22:01 +02001069 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001070 print("%s attempt(s) left." % attempts)
juraj.linkes184870a2018-07-16 14:22:01 +02001071 sys.exit(exit_code)