blob: 70608af391dfb2b7a9710d047cc3a74e73fc4938 [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,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020022)
Klement Sekera47f35272023-03-29 16:04:58 +020023from test_result_code import TestResultCode
Klement Sekera152a9b62022-05-13 18:01:36 +020024from debug import spawn_gdb
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020025from log import (
26 get_parallel_logger,
27 double_line_delim,
28 RED,
29 YELLOW,
30 GREEN,
31 colorize,
32 single_line_delim,
33)
Klement Sekerafcbf4442017-08-17 07:38:42 +020034from discover_tests import discover_tests
Klement Sekerab23ffd72021-05-31 16:08:53 +020035import sanity_run_vpp
Klement Sekera9b6ece72018-03-23 10:50:11 +010036from subprocess import check_output, CalledProcessError
juraj.linkes40dd73b2018-09-21 13:55:16 +020037from util import check_core_path, get_core_path, is_core_present
Klement Sekera993e0ed2017-03-16 09:14:59 +010038
Klement Sekera05742262018-03-14 18:14:49 +010039# timeout which controls how long the child has to finish after seeing
40# a core dump in test temporary directory. If this is exceeded, parent assumes
Klement Sekeraeb506be2021-03-16 12:52:29 +010041# that child process is stuck (e.g. waiting for event from vpp) and kill
42# the child
Klement Sekera05742262018-03-14 18:14:49 +010043core_timeout = 3
44
Klement Sekera909a6a12017-08-08 04:33:53 +020045
juraj.linkes184870a2018-07-16 14:22:01 +020046class StreamQueue(Queue):
47 def write(self, msg):
48 self.put(msg)
49
50 def flush(self):
51 sys.__stdout__.flush()
52 sys.__stderr__.flush()
53
54 def fileno(self):
55 return self._writer.fileno()
56
57
58class StreamQueueManager(BaseManager):
59 pass
60
61
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020062StreamQueueManager.register("StreamQueue", StreamQueue)
juraj.linkes184870a2018-07-16 14:22:01 +020063
64
juraj.linkescae64f82018-09-19 15:01:47 +020065class TestResult(dict):
juraj.linkes40dd73b2018-09-21 13:55:16 +020066 def __init__(self, testcase_suite, testcases_by_id=None):
juraj.linkescae64f82018-09-19 15:01:47 +020067 super(TestResult, self).__init__()
Klement Sekera47f35272023-03-29 16:04:58 +020068 for trc in list(TestResultCode):
69 self[trc] = []
juraj.linkes40dd73b2018-09-21 13:55:16 +020070 self.crashed = False
juraj.linkescae64f82018-09-19 15:01:47 +020071 self.testcase_suite = testcase_suite
72 self.testcases = [testcase for testcase in testcase_suite]
juraj.linkes40dd73b2018-09-21 13:55:16 +020073 self.testcases_by_id = testcases_by_id
juraj.linkescae64f82018-09-19 15:01:47 +020074
75 def was_successful(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020076 return (
Klement Sekera47f35272023-03-29 16:04:58 +020077 0
78 == len(self[TestResultCode.FAIL])
79 == len(self[TestResultCode.ERROR])
80 == len(self[TestResultCode.UNEXPECTED_PASS])
81 and len(self[TestResultCode.PASS])
82 + len(self[TestResultCode.SKIP])
83 + len(self[TestResultCode.SKIP_CPU_SHORTAGE])
84 + len(self[TestResultCode.EXPECTED_FAIL])
Klement Sekera558ceab2021-04-08 19:37:41 +020085 == self.testcase_suite.countTestCases()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020086 )
juraj.linkescae64f82018-09-19 15:01:47 +020087
88 def no_tests_run(self):
Klement Sekera47f35272023-03-29 16:04:58 +020089 return 0 == len(self[TestResultCode.TEST_RUN])
juraj.linkescae64f82018-09-19 15:01:47 +020090
91 def process_result(self, test_id, result):
92 self[result].append(test_id)
juraj.linkescae64f82018-09-19 15:01:47 +020093
94 def suite_from_failed(self):
95 rerun_ids = set([])
96 for testcase in self.testcase_suite:
97 tc_id = testcase.id()
Klement Sekera47f35272023-03-29 16:04:58 +020098 if (
99 tc_id
100 not in self[TestResultCode.PASS]
101 + self[TestResultCode.SKIP]
102 + self[TestResultCode.SKIP_CPU_SHORTAGE]
103 + self[TestResultCode.EXPECTED_FAIL]
104 ):
juraj.linkescae64f82018-09-19 15:01:47 +0200105 rerun_ids.add(tc_id)
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800106 if rerun_ids:
juraj.linkescae64f82018-09-19 15:01:47 +0200107 return suite_from_failed(self.testcase_suite, rerun_ids)
108
109 def get_testcase_names(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +0100110 # could be tearDownClass (test_ipsec_esp.TestIpsecEsp1)
111 setup_teardown_match = re.match(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200112 r"((tearDownClass)|(setUpClass)) \((.+\..+)\)", test_id
113 )
juraj.linkes2eca70d2018-12-13 11:10:47 +0100114 if setup_teardown_match:
115 test_name, _, _, testcase_name = setup_teardown_match.groups()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200116 if len(testcase_name.split(".")) == 2:
juraj.linkes2eca70d2018-12-13 11:10:47 +0100117 for key in self.testcases_by_id.keys():
118 if key.startswith(testcase_name):
119 testcase_name = key
120 break
121 testcase_name = self._get_testcase_doc_name(testcase_name)
122 else:
Ole Trøan5ba91592018-11-22 10:01:09 +0000123 test_name = self._get_test_description(test_id)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200124 testcase_name = self._get_testcase_doc_name(test_id)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200125
126 return testcase_name, test_name
juraj.linkescae64f82018-09-19 15:01:47 +0200127
Ole Trøan5ba91592018-11-22 10:01:09 +0000128 def _get_test_description(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +0100129 if test_id in self.testcases_by_id:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200130 desc = get_test_description(descriptions, self.testcases_by_id[test_id])
juraj.linkes2eca70d2018-12-13 11:10:47 +0100131 else:
132 desc = test_id
133 return desc
Ole Trøan5ba91592018-11-22 10:01:09 +0000134
juraj.linkes40dd73b2018-09-21 13:55:16 +0200135 def _get_testcase_doc_name(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +0100136 if test_id in self.testcases_by_id:
137 doc_name = get_testcase_doc_name(self.testcases_by_id[test_id])
138 else:
139 doc_name = test_id
140 return doc_name
juraj.linkescae64f82018-09-19 15:01:47 +0200141
142
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200143def test_runner_wrapper(
144 suite, keep_alive_pipe, stdouterr_queue, finished_pipe, result_pipe, logger
145):
juraj.linkes184870a2018-07-16 14:22:01 +0200146 sys.stdout = stdouterr_queue
147 sys.stderr = stdouterr_queue
juraj.linkesdfb5f2a2018-11-09 11:58:54 +0100148 VppTestCase.parallel_handler = logger.handlers[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200149 result = VppTestRunner(
150 keep_alive_pipe=keep_alive_pipe,
151 descriptions=descriptions,
152 verbosity=config.verbose,
153 result_pipe=result_pipe,
154 failfast=config.failfast,
155 print_summary=False,
156 ).run(suite)
juraj.linkescae64f82018-09-19 15:01:47 +0200157 finished_pipe.send(result.wasSuccessful())
158 finished_pipe.close()
Klement Sekera909a6a12017-08-08 04:33:53 +0200159 keep_alive_pipe.close()
160
161
juraj.linkes184870a2018-07-16 14:22:01 +0200162class TestCaseWrapper(object):
163 def __init__(self, testcase_suite, manager):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200164 self.keep_alive_parent_end, self.keep_alive_child_end = Pipe(duplex=False)
juraj.linkescae64f82018-09-19 15:01:47 +0200165 self.finished_parent_end, self.finished_child_end = Pipe(duplex=False)
juraj.linkes184870a2018-07-16 14:22:01 +0200166 self.result_parent_end, self.result_child_end = Pipe(duplex=False)
167 self.testcase_suite = testcase_suite
Klement Sekera558ceab2021-04-08 19:37:41 +0200168 self.stdouterr_queue = manager.StreamQueue(ctx=get_context())
juraj.linkes184870a2018-07-16 14:22:01 +0200169 self.logger = get_parallel_logger(self.stdouterr_queue)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200170 self.child = Process(
171 target=test_runner_wrapper,
172 args=(
173 testcase_suite,
174 self.keep_alive_child_end,
175 self.stdouterr_queue,
176 self.finished_child_end,
177 self.result_child_end,
178 self.logger,
179 ),
180 )
juraj.linkes184870a2018-07-16 14:22:01 +0200181 self.child.start()
juraj.linkes184870a2018-07-16 14:22:01 +0200182 self.last_test_temp_dir = None
183 self.last_test_vpp_binary = None
juraj.linkes40dd73b2018-09-21 13:55:16 +0200184 self._last_test = None
185 self.last_test_id = None
juraj.linkes721872e2018-09-05 18:13:45 +0200186 self.vpp_pid = None
juraj.linkes184870a2018-07-16 14:22:01 +0200187 self.last_heard = time.time()
188 self.core_detected_at = None
juraj.linkes40dd73b2018-09-21 13:55:16 +0200189 self.testcases_by_id = {}
190 self.testclasess_with_core = {}
191 for testcase in self.testcase_suite:
192 self.testcases_by_id[testcase.id()] = testcase
193 self.result = TestResult(testcase_suite, self.testcases_by_id)
194
195 @property
196 def last_test(self):
197 return self._last_test
198
199 @last_test.setter
200 def last_test(self, test_id):
201 self.last_test_id = test_id
202 if test_id in self.testcases_by_id:
203 testcase = self.testcases_by_id[test_id]
204 self._last_test = testcase.shortDescription()
205 if not self._last_test:
206 self._last_test = str(testcase)
207 else:
208 self._last_test = test_id
209
210 def add_testclass_with_core(self):
211 if self.last_test_id in self.testcases_by_id:
212 test = self.testcases_by_id[self.last_test_id]
213 class_name = unittest.util.strclass(test.__class__)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200214 test_name = "'{}' ({})".format(
215 get_test_description(descriptions, test), self.last_test_id
216 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200217 else:
218 test_name = self.last_test_id
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200219 class_name = re.match(
220 r"((tearDownClass)|(setUpClass)) " r"\((.+\..+)\)", test_name
221 ).groups()[3]
juraj.linkes40dd73b2018-09-21 13:55:16 +0200222 if class_name not in self.testclasess_with_core:
223 self.testclasess_with_core[class_name] = (
224 test_name,
225 self.last_test_vpp_binary,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200226 self.last_test_temp_dir,
227 )
juraj.linkes184870a2018-07-16 14:22:01 +0200228
229 def close_pipes(self):
230 self.keep_alive_child_end.close()
juraj.linkescae64f82018-09-19 15:01:47 +0200231 self.finished_child_end.close()
juraj.linkes184870a2018-07-16 14:22:01 +0200232 self.result_child_end.close()
233 self.keep_alive_parent_end.close()
juraj.linkescae64f82018-09-19 15:01:47 +0200234 self.finished_parent_end.close()
juraj.linkes184870a2018-07-16 14:22:01 +0200235 self.result_parent_end.close()
236
juraj.linkes40dd73b2018-09-21 13:55:16 +0200237 def was_successful(self):
238 return self.result.was_successful()
239
Klement Sekera558ceab2021-04-08 19:37:41 +0200240 @property
241 def cpus_used(self):
242 return self.testcase_suite.cpus_used
243
244 def get_assigned_cpus(self):
245 return self.testcase_suite.get_assigned_cpus()
246
juraj.linkes184870a2018-07-16 14:22:01 +0200247
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200248def stdouterr_reader_wrapper(
249 unread_testcases, finished_unread_testcases, read_testcases
250):
juraj.linkes184870a2018-07-16 14:22:01 +0200251 read_testcase = None
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800252 while read_testcases.is_set() or unread_testcases:
253 if finished_unread_testcases:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100254 read_testcase = finished_unread_testcases.pop()
255 unread_testcases.remove(read_testcase)
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800256 elif unread_testcases:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100257 read_testcase = unread_testcases.pop()
juraj.linkes184870a2018-07-16 14:22:01 +0200258 if read_testcase:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200259 data = ""
juraj.linkes184870a2018-07-16 14:22:01 +0200260 while data is not None:
261 sys.stdout.write(data)
262 data = read_testcase.stdouterr_queue.get()
263
264 read_testcase.stdouterr_queue.close()
265 finished_unread_testcases.discard(read_testcase)
266 read_testcase = None
267
268
Dmitry Valter3ace4d62022-03-26 15:43:14 +0000269def handle_failed_suite(logger, last_test_temp_dir, vpp_pid, vpp_binary):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200270 if last_test_temp_dir:
271 # Need to create link in case of a timeout or core dump without failure
272 lttd = os.path.basename(last_test_temp_dir)
Klement Sekera152a9b62022-05-13 18:01:36 +0200273 link_path = os.path.join(config.failed_dir, f"{lttd}-FAILED")
juraj.linkes40dd73b2018-09-21 13:55:16 +0200274 if not os.path.exists(link_path):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200275 os.symlink(last_test_temp_dir, link_path)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200276 logger.error(
277 "Symlink to failed testcase directory: %s -> %s" % (link_path, lttd)
278 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200279
280 # Report core existence
281 core_path = get_core_path(last_test_temp_dir)
282 if os.path.exists(core_path):
283 logger.error(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200284 "Core-file exists in test temporary directory: %s!" % core_path
285 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200286 check_core_path(logger, core_path)
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800287 logger.debug("Running 'file %s':" % core_path)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200288 try:
289 info = check_output(["file", core_path])
290 logger.debug(info)
291 except CalledProcessError as e:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200292 logger.error(
293 "Subprocess returned with return code "
294 "while running `file' utility on core-file "
295 "returned: "
296 "rc=%s",
297 e.returncode,
298 )
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800299 except OSError as e:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200300 logger.error(
301 "Subprocess returned with OS error while "
302 "running 'file' utility "
303 "on core-file: "
304 "(%s) %s",
305 e.errno,
306 e.strerror,
307 )
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800308 except Exception as e:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200309 logger.exception("Unexpected error running `file' utility on core-file")
Dmitry Valter3ace4d62022-03-26 15:43:14 +0000310 logger.error(f"gdb {vpp_binary} {core_path}")
juraj.linkes40dd73b2018-09-21 13:55:16 +0200311
312 if vpp_pid:
313 # Copy api post mortem
314 api_post_mortem_path = "/tmp/api_post_mortem.%d" % vpp_pid
315 if os.path.isfile(api_post_mortem_path):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200316 logger.error(
317 "Copying api_post_mortem.%d to %s" % (vpp_pid, last_test_temp_dir)
318 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200319 shutil.copy2(api_post_mortem_path, last_test_temp_dir)
320
321
322def check_and_handle_core(vpp_binary, tempdir, core_crash_test):
323 if is_core_present(tempdir):
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200324 if debug_core:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200325 print(
326 "VPP core detected in %s. Last test running was %s"
327 % (tempdir, core_crash_test)
328 )
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200329 print(single_line_delim)
330 spawn_gdb(vpp_binary, get_core_path(tempdir))
331 print(single_line_delim)
Klement Sekerab23ffd72021-05-31 16:08:53 +0200332 elif config.compress_core:
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200333 print("Compressing core-file in test directory `%s'" % tempdir)
334 os.system("gzip %s" % get_core_path(tempdir))
juraj.linkes40dd73b2018-09-21 13:55:16 +0200335
336
337def handle_cores(failed_testcases):
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200338 for failed_testcase in failed_testcases:
339 tcs_with_core = failed_testcase.testclasess_with_core
340 if tcs_with_core:
341 for test, vpp_binary, tempdir in tcs_with_core.values():
342 check_and_handle_core(vpp_binary, tempdir, test)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200343
344
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200345def process_finished_testsuite(
346 wrapped_testcase_suite, finished_testcase_suites, failed_wrapped_testcases, results
347):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200348 results.append(wrapped_testcase_suite.result)
349 finished_testcase_suites.add(wrapped_testcase_suite)
350 stop_run = False
Klement Sekerab23ffd72021-05-31 16:08:53 +0200351 if config.failfast and not wrapped_testcase_suite.was_successful():
juraj.linkes40dd73b2018-09-21 13:55:16 +0200352 stop_run = True
353
354 if not wrapped_testcase_suite.was_successful():
355 failed_wrapped_testcases.add(wrapped_testcase_suite)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200356 handle_failed_suite(
357 wrapped_testcase_suite.logger,
358 wrapped_testcase_suite.last_test_temp_dir,
359 wrapped_testcase_suite.vpp_pid,
360 wrapped_testcase_suite.last_test_vpp_binary,
361 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200362
363 return stop_run
364
365
juraj.linkes721872e2018-09-05 18:13:45 +0200366def run_forked(testcase_suites):
juraj.linkes184870a2018-07-16 14:22:01 +0200367 wrapped_testcase_suites = set()
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000368 solo_testcase_suites = []
juraj.linkes184870a2018-07-16 14:22:01 +0200369
370 # suites are unhashable, need to use list
371 results = []
juraj.linkes184870a2018-07-16 14:22:01 +0200372 unread_testcases = set()
373 finished_unread_testcases = set()
374 manager = StreamQueueManager()
375 manager.start()
Klement Sekera558ceab2021-04-08 19:37:41 +0200376 tests_running = 0
377 free_cpus = list(available_cpus)
378
379 def on_suite_start(tc):
380 nonlocal tests_running
381 nonlocal free_cpus
382 tests_running = tests_running + 1
383
384 def on_suite_finish(tc):
385 nonlocal tests_running
386 nonlocal free_cpus
387 tests_running = tests_running - 1
388 assert tests_running >= 0
389 free_cpus.extend(tc.get_assigned_cpus())
390
391 def run_suite(suite):
392 nonlocal manager
393 nonlocal wrapped_testcase_suites
394 nonlocal unread_testcases
395 nonlocal free_cpus
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200396 suite.assign_cpus(free_cpus[: suite.cpus_used])
397 free_cpus = free_cpus[suite.cpus_used :]
Klement Sekera558ceab2021-04-08 19:37:41 +0200398 wrapper = TestCaseWrapper(suite, manager)
399 wrapped_testcase_suites.add(wrapper)
400 unread_testcases.add(wrapper)
401 on_suite_start(suite)
402
403 def can_run_suite(suite):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200404 return tests_running < max_concurrent_tests and (
405 suite.cpus_used <= len(free_cpus) or suite.cpus_used > max_vpp_cpus
406 )
Klement Sekera558ceab2021-04-08 19:37:41 +0200407
408 while free_cpus and testcase_suites:
409 a_suite = testcase_suites[0]
410 if a_suite.is_tagged_run_solo:
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000411 a_suite = testcase_suites.pop(0)
Klement Sekera558ceab2021-04-08 19:37:41 +0200412 solo_testcase_suites.append(a_suite)
413 continue
414 if can_run_suite(a_suite):
415 a_suite = testcase_suites.pop(0)
416 run_suite(a_suite)
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000417 else:
418 break
419
Klement Sekera558ceab2021-04-08 19:37:41 +0200420 if tests_running == 0 and solo_testcase_suites:
421 a_suite = solo_testcase_suites.pop(0)
422 run_suite(a_suite)
juraj.linkes184870a2018-07-16 14:22:01 +0200423
424 read_from_testcases = threading.Event()
425 read_from_testcases.set()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200426 stdouterr_thread = threading.Thread(
427 target=stdouterr_reader_wrapper,
428 args=(unread_testcases, finished_unread_testcases, read_from_testcases),
429 )
juraj.linkes184870a2018-07-16 14:22:01 +0200430 stdouterr_thread.start()
431
juraj.linkes40dd73b2018-09-21 13:55:16 +0200432 failed_wrapped_testcases = set()
433 stop_run = False
juraj.linkese6b58cf2018-11-29 09:56:35 +0100434
435 try:
Klement Sekerac7d50472023-04-14 17:43:35 +0200436 while wrapped_testcase_suites or testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100437 finished_testcase_suites = set()
438 for wrapped_testcase_suite in wrapped_testcase_suites:
439 while wrapped_testcase_suite.result_parent_end.poll():
440 wrapped_testcase_suite.result.process_result(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200441 *wrapped_testcase_suite.result_parent_end.recv()
442 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100443 wrapped_testcase_suite.last_heard = time.time()
444
445 while wrapped_testcase_suite.keep_alive_parent_end.poll():
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200446 (
447 wrapped_testcase_suite.last_test,
448 wrapped_testcase_suite.last_test_vpp_binary,
449 wrapped_testcase_suite.last_test_temp_dir,
450 wrapped_testcase_suite.vpp_pid,
451 ) = wrapped_testcase_suite.keep_alive_parent_end.recv()
juraj.linkese6b58cf2018-11-29 09:56:35 +0100452 wrapped_testcase_suite.last_heard = time.time()
453
454 if wrapped_testcase_suite.finished_parent_end.poll():
455 wrapped_testcase_suite.finished_parent_end.recv()
456 wrapped_testcase_suite.last_heard = time.time()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200457 stop_run = (
458 process_finished_testsuite(
459 wrapped_testcase_suite,
460 finished_testcase_suites,
461 failed_wrapped_testcases,
462 results,
463 )
464 or stop_run
465 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100466 continue
467
468 fail = False
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200469 if wrapped_testcase_suite.last_heard + config.timeout < time.time():
juraj.linkese6b58cf2018-11-29 09:56:35 +0100470 fail = True
471 wrapped_testcase_suite.logger.critical(
472 "Child test runner process timed out "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200473 "(last test running was `%s' in `%s')!"
474 % (
475 wrapped_testcase_suite.last_test,
476 wrapped_testcase_suite.last_test_temp_dir,
477 )
478 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100479 elif not wrapped_testcase_suite.child.is_alive():
480 fail = True
481 wrapped_testcase_suite.logger.critical(
482 "Child test runner process unexpectedly died "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200483 "(last test running was `%s' in `%s')!"
484 % (
485 wrapped_testcase_suite.last_test,
486 wrapped_testcase_suite.last_test_temp_dir,
487 )
488 )
489 elif (
490 wrapped_testcase_suite.last_test_temp_dir
491 and wrapped_testcase_suite.last_test_vpp_binary
492 ):
493 if is_core_present(wrapped_testcase_suite.last_test_temp_dir):
juraj.linkese6b58cf2018-11-29 09:56:35 +0100494 wrapped_testcase_suite.add_testclass_with_core()
495 if wrapped_testcase_suite.core_detected_at is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200496 wrapped_testcase_suite.core_detected_at = time.time()
497 elif (
498 wrapped_testcase_suite.core_detected_at + core_timeout
499 < time.time()
500 ):
juraj.linkese6b58cf2018-11-29 09:56:35 +0100501 wrapped_testcase_suite.logger.critical(
502 "Child test runner process unresponsive and "
503 "core-file exists in test temporary directory "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200504 "(last test running was `%s' in `%s')!"
505 % (
506 wrapped_testcase_suite.last_test,
507 wrapped_testcase_suite.last_test_temp_dir,
508 )
509 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100510 fail = True
511
512 if fail:
513 wrapped_testcase_suite.child.terminate()
514 try:
515 # terminating the child process tends to leave orphan
516 # VPP process around
517 if wrapped_testcase_suite.vpp_pid:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200518 os.kill(wrapped_testcase_suite.vpp_pid, signal.SIGTERM)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100519 except OSError:
520 # already dead
521 pass
522 wrapped_testcase_suite.result.crashed = True
523 wrapped_testcase_suite.result.process_result(
Klement Sekera47f35272023-03-29 16:04:58 +0200524 wrapped_testcase_suite.last_test_id, TestResultCode.ERROR
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200525 )
526 stop_run = (
527 process_finished_testsuite(
528 wrapped_testcase_suite,
529 finished_testcase_suites,
530 failed_wrapped_testcases,
531 results,
532 )
533 or stop_run
534 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100535
536 for finished_testcase in finished_testcase_suites:
Andrew Yourtchenko42693522019-11-05 01:08:26 +0100537 # Somewhat surprisingly, the join below may
538 # timeout, even if client signaled that
539 # it finished - so we note it just in case.
540 join_start = time.time()
541 finished_testcase.child.join(test_finished_join_timeout)
542 join_end = time.time()
543 if join_end - join_start >= test_finished_join_timeout:
544 finished_testcase.logger.error(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200545 "Timeout joining finished test: %s (pid %d)"
546 % (finished_testcase.last_test, finished_testcase.child.pid)
547 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100548 finished_testcase.close_pipes()
549 wrapped_testcase_suites.remove(finished_testcase)
550 finished_unread_testcases.add(finished_testcase)
551 finished_testcase.stdouterr_queue.put(None)
Klement Sekera558ceab2021-04-08 19:37:41 +0200552 on_suite_finish(finished_testcase)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100553 if stop_run:
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800554 while testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100555 results.append(TestResult(testcase_suites.pop(0)))
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800556 elif testcase_suites:
Klement Sekerac7d50472023-04-14 17:43:35 +0200557 a_suite = testcase_suites[0]
Klement Sekera558ceab2021-04-08 19:37:41 +0200558 while a_suite and a_suite.is_tagged_run_solo:
Klement Sekerac7d50472023-04-14 17:43:35 +0200559 testcase_suites.pop(0)
Klement Sekera558ceab2021-04-08 19:37:41 +0200560 solo_testcase_suites.append(a_suite)
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000561 if testcase_suites:
Klement Sekerac7d50472023-04-14 17:43:35 +0200562 a_suite = testcase_suites[0]
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000563 else:
Klement Sekera558ceab2021-04-08 19:37:41 +0200564 a_suite = None
565 if a_suite and can_run_suite(a_suite):
Klement Sekerac7d50472023-04-14 17:43:35 +0200566 testcase_suites.pop(0)
Klement Sekera558ceab2021-04-08 19:37:41 +0200567 run_suite(a_suite)
568 if solo_testcase_suites and tests_running == 0:
569 a_suite = solo_testcase_suites.pop(0)
570 run_suite(a_suite)
Paul Vinciguerrac0692a42019-03-15 19:16:50 -0700571 time.sleep(0.1)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100572 except Exception:
juraj.linkes184870a2018-07-16 14:22:01 +0200573 for wrapped_testcase_suite in wrapped_testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100574 wrapped_testcase_suite.child.terminate()
575 wrapped_testcase_suite.stdouterr_queue.put(None)
576 raise
577 finally:
578 read_from_testcases.clear()
Klement Sekerab23ffd72021-05-31 16:08:53 +0200579 stdouterr_thread.join(config.timeout)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100580 manager.shutdown()
juraj.linkescae64f82018-09-19 15:01:47 +0200581
juraj.linkes40dd73b2018-09-21 13:55:16 +0200582 handle_cores(failed_wrapped_testcases)
juraj.linkes184870a2018-07-16 14:22:01 +0200583 return results
584
585
Klement Sekera558ceab2021-04-08 19:37:41 +0200586class TestSuiteWrapper(unittest.TestSuite):
587 cpus_used = 0
588
589 def __init__(self):
590 return super().__init__()
591
592 def addTest(self, test):
593 self.cpus_used = max(self.cpus_used, test.get_cpus_required())
594 super().addTest(test)
595
596 def assign_cpus(self, cpus):
597 self.cpus = cpus
598
599 def _handleClassSetUp(self, test, result):
600 if not test.__class__.skipped_due_to_cpu_lack:
601 test.assign_cpus(self.cpus)
602 super()._handleClassSetUp(test, result)
603
604 def get_assigned_cpus(self):
605 return self.cpus
606
607
juraj.linkes184870a2018-07-16 14:22:01 +0200608class SplitToSuitesCallback:
609 def __init__(self, filter_callback):
610 self.suites = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200611 self.suite_name = "default"
juraj.linkes184870a2018-07-16 14:22:01 +0200612 self.filter_callback = filter_callback
Klement Sekera558ceab2021-04-08 19:37:41 +0200613 self.filtered = TestSuiteWrapper()
Klement Sekerafcbf4442017-08-17 07:38:42 +0200614
615 def __call__(self, file_name, cls, method):
juraj.linkes184870a2018-07-16 14:22:01 +0200616 test_method = cls(method)
617 if self.filter_callback(file_name, cls.__name__, method):
618 self.suite_name = file_name + cls.__name__
619 if self.suite_name not in self.suites:
Klement Sekera558ceab2021-04-08 19:37:41 +0200620 self.suites[self.suite_name] = TestSuiteWrapper()
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000621 self.suites[self.suite_name].is_tagged_run_solo = False
juraj.linkes184870a2018-07-16 14:22:01 +0200622 self.suites[self.suite_name].addTest(test_method)
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000623 if test_method.is_tagged_run_solo():
624 self.suites[self.suite_name].is_tagged_run_solo = True
juraj.linkes184870a2018-07-16 14:22:01 +0200625
626 else:
627 self.filtered.addTest(test_method)
Klement Sekerafcbf4442017-08-17 07:38:42 +0200628
629
Klement Sekerab23ffd72021-05-31 16:08:53 +0200630def parse_test_filter(test_filter):
631 f = test_filter
juraj.linkes184870a2018-07-16 14:22:01 +0200632 filter_file_name = None
633 filter_class_name = None
634 filter_func_name = None
635 if f:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200636 if "." in f:
637 parts = f.split(".")
juraj.linkes184870a2018-07-16 14:22:01 +0200638 if len(parts) > 3:
Klement Sekera08c50e32023-04-14 17:44:04 +0200639 raise Exception(f"Invalid test filter: {test_filter}")
juraj.linkes184870a2018-07-16 14:22:01 +0200640 if len(parts) > 2:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200641 if parts[2] not in ("*", ""):
juraj.linkes184870a2018-07-16 14:22:01 +0200642 filter_func_name = parts[2]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200643 if parts[1] not in ("*", ""):
juraj.linkes184870a2018-07-16 14:22:01 +0200644 filter_class_name = parts[1]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200645 if parts[0] not in ("*", ""):
646 if parts[0].startswith("test_"):
juraj.linkes184870a2018-07-16 14:22:01 +0200647 filter_file_name = parts[0]
648 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200649 filter_file_name = "test_%s" % parts[0]
juraj.linkes184870a2018-07-16 14:22:01 +0200650 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200651 if f.startswith("test_"):
juraj.linkes184870a2018-07-16 14:22:01 +0200652 filter_file_name = f
653 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200654 filter_file_name = "test_%s" % f
juraj.linkes184870a2018-07-16 14:22:01 +0200655 if filter_file_name:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200656 filter_file_name = "%s.py" % filter_file_name
juraj.linkes184870a2018-07-16 14:22:01 +0200657 return filter_file_name, filter_class_name, filter_func_name
658
659
660def filter_tests(tests, filter_cb):
Klement Sekera558ceab2021-04-08 19:37:41 +0200661 result = TestSuiteWrapper()
juraj.linkes184870a2018-07-16 14:22:01 +0200662 for t in tests:
663 if isinstance(t, unittest.suite.TestSuite):
664 # this is a bunch of tests, recursively filter...
665 x = filter_tests(t, filter_cb)
666 if x.countTestCases() > 0:
667 result.addTest(x)
668 elif isinstance(t, unittest.TestCase):
669 # this is a single test
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200670 parts = t.id().split(".")
juraj.linkes184870a2018-07-16 14:22:01 +0200671 # t.id() for common cases like this:
672 # test_classifier.TestClassifier.test_acl_ip
673 # apply filtering only if it is so
674 if len(parts) == 3:
675 if not filter_cb(parts[0], parts[1], parts[2]):
676 continue
677 result.addTest(t)
678 else:
679 # unexpected object, don't touch it
680 result.addTest(t)
681 return result
682
683
684class FilterByTestOption:
Klement Sekera08c50e32023-04-14 17:44:04 +0200685 def __init__(self, filters):
686 self.filters = filters
juraj.linkes184870a2018-07-16 14:22:01 +0200687
688 def __call__(self, file_name, class_name, func_name):
Klement Sekera08c50e32023-04-14 17:44:04 +0200689 def test_one(
690 filter_file_name,
691 filter_class_name,
692 filter_func_name,
693 file_name,
694 class_name,
695 func_name,
696 ):
697 if filter_file_name:
698 fn_match = fnmatch.fnmatch(file_name, filter_file_name)
699 if not fn_match:
700 return False
701 if filter_class_name and class_name != filter_class_name:
Andrew Yourtchenkod760f792018-10-03 11:38:31 +0200702 return False
Klement Sekera08c50e32023-04-14 17:44:04 +0200703 if filter_func_name and func_name != filter_func_name:
704 return False
705 return True
706
707 for filter_file_name, filter_class_name, filter_func_name in self.filters:
708 if test_one(
709 filter_file_name,
710 filter_class_name,
711 filter_func_name,
712 file_name,
713 class_name,
714 func_name,
715 ):
716 return True
717
718 return False
juraj.linkes184870a2018-07-16 14:22:01 +0200719
720
721class FilterByClassList:
juraj.linkes721872e2018-09-05 18:13:45 +0200722 def __init__(self, classes_with_filenames):
723 self.classes_with_filenames = classes_with_filenames
Klement Sekeradf2b9802017-10-05 10:26:03 +0200724
725 def __call__(self, file_name, class_name, func_name):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200726 return ".".join([file_name, class_name]) in self.classes_with_filenames
Klement Sekeradf2b9802017-10-05 10:26:03 +0200727
728
729def suite_from_failed(suite, failed):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200730 failed = {x.rsplit(".", 1)[0] for x in failed}
juraj.linkes184870a2018-07-16 14:22:01 +0200731 filter_cb = FilterByClassList(failed)
732 suite = filter_tests(suite, filter_cb)
Klement Sekera4c5422e2018-06-22 13:19:45 +0200733 return suite
Klement Sekeradf2b9802017-10-05 10:26:03 +0200734
735
juraj.linkescae64f82018-09-19 15:01:47 +0200736class AllResults(dict):
juraj.linkes184870a2018-07-16 14:22:01 +0200737 def __init__(self):
juraj.linkescae64f82018-09-19 15:01:47 +0200738 super(AllResults, self).__init__()
juraj.linkes184870a2018-07-16 14:22:01 +0200739 self.all_testcases = 0
juraj.linkescae64f82018-09-19 15:01:47 +0200740 self.results_per_suite = []
Klement Sekera47f35272023-03-29 16:04:58 +0200741 for trc in list(TestResultCode):
742 self[trc] = 0
juraj.linkes184870a2018-07-16 14:22:01 +0200743 self.rerun = []
juraj.linkescae64f82018-09-19 15:01:47 +0200744 self.testsuites_no_tests_run = []
Klement Sekera909a6a12017-08-08 04:33:53 +0200745
juraj.linkescae64f82018-09-19 15:01:47 +0200746 def add_results(self, result):
747 self.results_per_suite.append(result)
Klement Sekera47f35272023-03-29 16:04:58 +0200748 for trc in list(TestResultCode):
749 self[trc] += len(result[trc])
Klement Sekera05742262018-03-14 18:14:49 +0100750
juraj.linkescae64f82018-09-19 15:01:47 +0200751 def add_result(self, result):
juraj.linkes184870a2018-07-16 14:22:01 +0200752 retval = 0
juraj.linkescae64f82018-09-19 15:01:47 +0200753 self.all_testcases += result.testcase_suite.countTestCases()
juraj.linkes40dd73b2018-09-21 13:55:16 +0200754 self.add_results(result)
juraj.linkes184870a2018-07-16 14:22:01 +0200755
juraj.linkes40dd73b2018-09-21 13:55:16 +0200756 if result.no_tests_run():
juraj.linkescae64f82018-09-19 15:01:47 +0200757 self.testsuites_no_tests_run.append(result.testcase_suite)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200758 if result.crashed:
759 retval = -1
760 else:
761 retval = 1
762 elif not result.was_successful():
763 retval = 1
juraj.linkes184870a2018-07-16 14:22:01 +0200764
juraj.linkes184870a2018-07-16 14:22:01 +0200765 if retval != 0:
juraj.linkesabec0122018-11-16 17:28:56 +0100766 self.rerun.append(result.testcase_suite)
juraj.linkes184870a2018-07-16 14:22:01 +0200767
768 return retval
769
770 def print_results(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200771 print("")
juraj.linkes184870a2018-07-16 14:22:01 +0200772 print(double_line_delim)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200773 print("TEST RESULTS:")
Klement Sekera558ceab2021-04-08 19:37:41 +0200774
775 def indent_results(lines):
776 lines = list(filter(None, lines))
777 maximum = max(lines, key=lambda x: x.index(":"))
778 maximum = 4 + maximum.index(":")
779 for l in lines:
780 padding = " " * (maximum - l.index(":"))
781 print(f"{padding}{l}")
782
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200783 indent_results(
784 [
785 f"Scheduled tests: {self.all_testcases}",
Klement Sekera47f35272023-03-29 16:04:58 +0200786 f"Executed tests: {self[TestResultCode.TEST_RUN]}",
787 f"Passed tests: {colorize(self[TestResultCode.PASS], GREEN)}",
788 f"Expected failures: {colorize(self[TestResultCode.EXPECTED_FAIL], GREEN)}"
789 if self[TestResultCode.EXPECTED_FAIL]
790 else None,
791 f"Skipped tests: {colorize(self[TestResultCode.SKIP], YELLOW)}"
792 if self[TestResultCode.SKIP]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200793 else None,
794 f"Not Executed tests: {colorize(self.not_executed, RED)}"
795 if self.not_executed
796 else None,
Klement Sekera47f35272023-03-29 16:04:58 +0200797 f"Failures: {colorize(self[TestResultCode.FAIL], RED)}"
798 if self[TestResultCode.FAIL]
799 else None,
800 f"Unexpected passes: {colorize(self[TestResultCode.UNEXPECTED_PASS], RED)}"
801 if self[TestResultCode.UNEXPECTED_PASS]
802 else None,
803 f"Errors: {colorize(self[TestResultCode.ERROR], RED)}"
804 if self[TestResultCode.ERROR]
805 else None,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200806 "Tests skipped due to lack of CPUS: "
Klement Sekera47f35272023-03-29 16:04:58 +0200807 f"{colorize(self[TestResultCode.SKIP_CPU_SHORTAGE], YELLOW)}"
808 if self[TestResultCode.SKIP_CPU_SHORTAGE]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200809 else None,
810 ]
811 )
juraj.linkes184870a2018-07-16 14:22:01 +0200812
813 if self.all_failed > 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200814 print("FAILURES AND ERRORS IN TESTS:")
juraj.linkescae64f82018-09-19 15:01:47 +0200815 for result in self.results_per_suite:
juraj.linkescae64f82018-09-19 15:01:47 +0200816 old_testcase_name = None
Klement Sekera47f35272023-03-29 16:04:58 +0200817 for tr_code, headline in (
818 (TestResultCode.FAIL, "FAILURE"),
819 (TestResultCode.ERROR, "ERROR"),
820 (TestResultCode.UNEXPECTED_PASS, "UNEXPECTED PASS"),
821 ):
822 if not result[tr_code]:
823 continue
824
825 for failed_test_id in result[tr_code]:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200826 new_testcase_name, test_name = result.get_testcase_names(
827 failed_test_id
828 )
juraj.linkescae64f82018-09-19 15:01:47 +0200829 if new_testcase_name != old_testcase_name:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200830 print(
Klement Sekera47f35272023-03-29 16:04:58 +0200831 f" Testcase name: {colorize(new_testcase_name, RED)}"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200832 )
juraj.linkescae64f82018-09-19 15:01:47 +0200833 old_testcase_name = new_testcase_name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200834 print(
Klement Sekera47f35272023-03-29 16:04:58 +0200835 f" {headline}: {colorize(test_name, RED)} [{failed_test_id}]"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200836 )
Klement Sekera47f35272023-03-29 16:04:58 +0200837
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800838 if self.testsuites_no_tests_run:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200839 print("TESTCASES WHERE NO TESTS WERE SUCCESSFULLY EXECUTED:")
juraj.linkes40dd73b2018-09-21 13:55:16 +0200840 tc_classes = set()
juraj.linkescae64f82018-09-19 15:01:47 +0200841 for testsuite in self.testsuites_no_tests_run:
842 for testcase in testsuite:
843 tc_classes.add(get_testcase_doc_name(testcase))
844 for tc_class in tc_classes:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200845 print(" {}".format(colorize(tc_class, RED)))
juraj.linkes184870a2018-07-16 14:22:01 +0200846
Klement Sekera47f35272023-03-29 16:04:58 +0200847 if self[TestResultCode.SKIP_CPU_SHORTAGE]:
Klement Sekera558ceab2021-04-08 19:37:41 +0200848 print()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200849 print(
850 colorize(
851 " SOME TESTS WERE SKIPPED BECAUSE THERE ARE NOT"
852 " ENOUGH CPUS AVAILABLE",
853 YELLOW,
854 )
855 )
juraj.linkes184870a2018-07-16 14:22:01 +0200856 print(double_line_delim)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200857 print("")
juraj.linkes184870a2018-07-16 14:22:01 +0200858
859 @property
juraj.linkescae64f82018-09-19 15:01:47 +0200860 def not_executed(self):
Klement Sekera47f35272023-03-29 16:04:58 +0200861 return self.all_testcases - self[TestResultCode.TEST_RUN]
juraj.linkescae64f82018-09-19 15:01:47 +0200862
863 @property
juraj.linkes184870a2018-07-16 14:22:01 +0200864 def all_failed(self):
Klement Sekera47f35272023-03-29 16:04:58 +0200865 return (
866 self[TestResultCode.FAIL]
867 + self[TestResultCode.ERROR]
868 + self[TestResultCode.UNEXPECTED_PASS]
869 )
juraj.linkes184870a2018-07-16 14:22:01 +0200870
871
872def parse_results(results):
873 """
juraj.linkescae64f82018-09-19 15:01:47 +0200874 Prints the number of scheduled, executed, not executed, passed, failed,
875 errored and skipped tests and details about failed and errored tests.
juraj.linkes184870a2018-07-16 14:22:01 +0200876
juraj.linkescae64f82018-09-19 15:01:47 +0200877 Also returns all suites where any test failed.
juraj.linkes184870a2018-07-16 14:22:01 +0200878
879 :param results:
880 :return:
881 """
882
juraj.linkescae64f82018-09-19 15:01:47 +0200883 results_per_suite = AllResults()
juraj.linkes184870a2018-07-16 14:22:01 +0200884 crashed = False
885 failed = False
juraj.linkescae64f82018-09-19 15:01:47 +0200886 for result in results:
887 result_code = results_per_suite.add_result(result)
juraj.linkes184870a2018-07-16 14:22:01 +0200888 if result_code == 1:
889 failed = True
890 elif result_code == -1:
891 crashed = True
892
893 results_per_suite.print_results()
894
895 if crashed:
896 return_code = -1
897 elif failed:
898 return_code = 1
899 else:
900 return_code = 0
901 return return_code, results_per_suite.rerun
902
903
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200904if __name__ == "__main__":
Klement Sekerab23ffd72021-05-31 16:08:53 +0200905 print(f"Config is: {config}")
Klement Sekera3f6ff192017-08-11 06:56:05 +0200906
Klement Sekerab23ffd72021-05-31 16:08:53 +0200907 if config.sanity:
908 print("Running sanity test case.")
909 try:
910 rc = sanity_run_vpp.main()
911 if rc != 0:
912 sys.exit(rc)
913 except Exception as e:
914 print(traceback.format_exc())
915 print("Couldn't run sanity test case.")
916 sys.exit(-1)
Klement Sekera3f6ff192017-08-11 06:56:05 +0200917
Andrew Yourtchenko42693522019-11-05 01:08:26 +0100918 test_finished_join_timeout = 15
919
Klement Sekerab23ffd72021-05-31 16:08:53 +0200920 debug_gdb = config.debug in ["gdb", "gdbserver", "attach"]
921 debug_core = config.debug == "core"
Klement Sekera3f6ff192017-08-11 06:56:05 +0200922
Klement Sekerab23ffd72021-05-31 16:08:53 +0200923 run_interactive = debug_gdb or config.step or config.force_foreground
juraj.linkes184870a2018-07-16 14:22:01 +0200924
Klement Sekera558ceab2021-04-08 19:37:41 +0200925 max_concurrent_tests = 0
926 print(f"OS reports {num_cpus} available cpu(s).")
Paul Vinciguerra025cd9c2019-07-08 14:14:22 -0400927
Klement Sekerab23ffd72021-05-31 16:08:53 +0200928 test_jobs = config.jobs
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200929 if test_jobs == "auto":
juraj.linkes184870a2018-07-16 14:22:01 +0200930 if run_interactive:
Klement Sekera558ceab2021-04-08 19:37:41 +0200931 max_concurrent_tests = 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200932 print("Interactive mode required, running tests consecutively.")
juraj.linkes184870a2018-07-16 14:22:01 +0200933 else:
Klement Sekera558ceab2021-04-08 19:37:41 +0200934 max_concurrent_tests = num_cpus
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200935 print(
936 f"Running at most {max_concurrent_tests} python test "
937 "processes concurrently."
938 )
juraj.linkes184870a2018-07-16 14:22:01 +0200939 else:
Klement Sekerab23ffd72021-05-31 16:08:53 +0200940 max_concurrent_tests = test_jobs
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200941 print(
942 f"Running at most {max_concurrent_tests} python test processes "
943 "concurrently as set by 'TEST_JOBS'."
944 )
juraj.linkes184870a2018-07-16 14:22:01 +0200945
Klement Sekera558ceab2021-04-08 19:37:41 +0200946 print(f"Using at most {max_vpp_cpus} cpus for VPP threads.")
947
948 if run_interactive and max_concurrent_tests > 1:
juraj.linkes184870a2018-07-16 14:22:01 +0200949 raise NotImplementedError(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200950 "Running tests interactively (DEBUG is gdb[server] or ATTACH or "
951 "STEP is set) in parallel (TEST_JOBS is more than 1) is not "
952 "supported"
953 )
Klement Sekera13a83ef2018-03-21 12:35:51 +0100954
juraj.linkes184870a2018-07-16 14:22:01 +0200955 descriptions = True
Klement Sekera3f6ff192017-08-11 06:56:05 +0200956
Klement Sekera558ceab2021-04-08 19:37:41 +0200957 print("Running tests using custom test runner.")
Klement Sekera08c50e32023-04-14 17:44:04 +0200958 filters = [(parse_test_filter(f)) for f in config.filter.split(",")]
juraj.linkes184870a2018-07-16 14:22:01 +0200959
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200960 print(
Klement Sekera08c50e32023-04-14 17:44:04 +0200961 "Selected filters: ",
962 "|".join(
963 f"file={filter_file}, class={filter_class}, function={filter_func}"
964 for filter_file, filter_class, filter_func in filters
965 ),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200966 )
juraj.linkes184870a2018-07-16 14:22:01 +0200967
Klement Sekera08c50e32023-04-14 17:44:04 +0200968 filter_cb = FilterByTestOption(filters)
juraj.linkes184870a2018-07-16 14:22:01 +0200969
970 cb = SplitToSuitesCallback(filter_cb)
Klement Sekerab23ffd72021-05-31 16:08:53 +0200971 for d in config.test_src_dir:
Klement Sekeradf2b9802017-10-05 10:26:03 +0200972 print("Adding tests from directory tree %s" % d)
Saima Yunusc7f93b32022-08-10 03:25:31 -0400973 discover_tests(d, cb)
Klement Sekera3f6ff192017-08-11 06:56:05 +0200974
juraj.linkes184870a2018-07-16 14:22:01 +0200975 # suites are not hashable, need to use list
976 suites = []
977 tests_amount = 0
978 for testcase_suite in cb.suites.values():
979 tests_amount += testcase_suite.countTestCases()
Klement Sekera558ceab2021-04-08 19:37:41 +0200980 if testcase_suite.cpus_used > max_vpp_cpus:
981 # here we replace test functions with lambdas to just skip them
982 # but we also replace setUp/tearDown functions to do nothing
983 # so that the test can be "started" and "stopped", so that we can
984 # still keep those prints (test description - SKIP), which are done
985 # in stopTest() (for that to trigger, test function must run)
986 for t in testcase_suite:
987 for m in dir(t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200988 if m.startswith("test_"):
Klement Sekera558ceab2021-04-08 19:37:41 +0200989 setattr(t, m, lambda: t.skipTest("not enough cpus"))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200990 setattr(t.__class__, "setUpClass", lambda: None)
991 setattr(t.__class__, "tearDownClass", lambda: None)
992 setattr(t, "setUp", lambda: None)
993 setattr(t, "tearDown", lambda: None)
Klement Sekera558ceab2021-04-08 19:37:41 +0200994 t.__class__.skipped_due_to_cpu_lack = True
juraj.linkes184870a2018-07-16 14:22:01 +0200995 suites.append(testcase_suite)
Klement Sekerabbfa5fd2018-06-27 13:54:32 +0200996
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200997 print(
998 "%s out of %s tests match specified filters"
999 % (tests_amount, tests_amount + cb.filtered.countTestCases())
1000 )
juraj.linkes184870a2018-07-16 14:22:01 +02001001
Klement Sekerab23ffd72021-05-31 16:08:53 +02001002 if not config.extended:
juraj.linkes184870a2018-07-16 14:22:01 +02001003 print("Not running extended tests (some tests will be skipped)")
1004
Klement Sekerab23ffd72021-05-31 16:08:53 +02001005 attempts = config.retries + 1
Klement Sekeradf2b9802017-10-05 10:26:03 +02001006 if attempts > 1:
1007 print("Perform %s attempts to pass the suite..." % attempts)
juraj.linkes184870a2018-07-16 14:22:01 +02001008
Naveen Joy2cbf2fb2019-03-06 10:41:06 -08001009 if run_interactive and suites:
juraj.linkes184870a2018-07-16 14:22:01 +02001010 # don't fork if requiring interactive terminal
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001011 print("Running tests in foreground in the current process")
juraj.linkes46e8e912019-01-10 12:13:07 +01001012 full_suite = unittest.TestSuite()
Klement Sekera558ceab2021-04-08 19:37:41 +02001013 free_cpus = list(available_cpus)
1014 cpu_shortage = False
1015 for suite in suites:
1016 if suite.cpus_used <= max_vpp_cpus:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001017 suite.assign_cpus(free_cpus[: suite.cpus_used])
Klement Sekera558ceab2021-04-08 19:37:41 +02001018 else:
1019 suite.assign_cpus([])
1020 cpu_shortage = True
Klement Sekerad743dff2019-10-29 11:03:47 +00001021 full_suite.addTests(suites)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001022 result = VppTestRunner(
1023 verbosity=config.verbose, failfast=config.failfast, print_summary=True
1024 ).run(full_suite)
juraj.linkes40dd73b2018-09-21 13:55:16 +02001025 was_successful = result.wasSuccessful()
1026 if not was_successful:
1027 for test_case_info in result.failed_test_cases_info:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001028 handle_failed_suite(
1029 test_case_info.logger,
1030 test_case_info.tempdir,
1031 test_case_info.vpp_pid,
1032 config.vpp,
1033 )
Klement Sekeraf40ee3a2019-05-06 19:11:25 +02001034 if test_case_info in result.core_crash_test_cases_info:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001035 check_and_handle_core(
1036 test_case_info.vpp_bin_path,
1037 test_case_info.tempdir,
1038 test_case_info.core_crash_test,
1039 )
juraj.linkes40dd73b2018-09-21 13:55:16 +02001040
Klement Sekera558ceab2021-04-08 19:37:41 +02001041 if cpu_shortage:
1042 print()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001043 print(
1044 colorize(
1045 "SOME TESTS WERE SKIPPED BECAUSE THERE ARE NOT"
1046 " ENOUGH CPUS AVAILABLE",
1047 YELLOW,
1048 )
1049 )
Klement Sekera558ceab2021-04-08 19:37:41 +02001050 print()
juraj.linkes40dd73b2018-09-21 13:55:16 +02001051 sys.exit(not was_successful)
Klement Sekera13a83ef2018-03-21 12:35:51 +01001052 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001053 print(
1054 "Running each VPPTestCase in a separate background process"
1055 f" with at most {max_concurrent_tests} parallel python test "
1056 "process(es)"
1057 )
juraj.linkes184870a2018-07-16 14:22:01 +02001058 exit_code = 0
Naveen Joy2cbf2fb2019-03-06 10:41:06 -08001059 while suites and attempts > 0:
juraj.linkes184870a2018-07-16 14:22:01 +02001060 results = run_forked(suites)
1061 exit_code, suites = parse_results(results)
1062 attempts -= 1
1063 if exit_code == 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001064 print("Test run was successful")
juraj.linkes184870a2018-07-16 14:22:01 +02001065 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001066 print("%s attempt(s) left." % attempts)
juraj.linkes184870a2018-07-16 14:22:01 +02001067 sys.exit(exit_code)