blob: 19ab9052d5c6c9feccf0612b25c8505cd5ceec32 [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
Dave Wallace8800f732023-08-31 00:47:44 -040017from asfframework import (
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020018 VppTestRunner,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020019 get_testcase_doc_name,
20 get_test_description,
Dave Wallace8800f732023-08-31 00:47:44 -040021 get_failed_testcase_linkname,
22 get_testcase_dirname,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020023)
Dave Wallace8800f732023-08-31 00:47:44 -040024from framework import VppTestCase
Klement Sekera47f35272023-03-29 16:04:58 +020025from test_result_code import TestResultCode
Klement Sekera152a9b62022-05-13 18:01:36 +020026from debug import spawn_gdb
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020027from log import (
28 get_parallel_logger,
29 double_line_delim,
30 RED,
31 YELLOW,
32 GREEN,
33 colorize,
34 single_line_delim,
35)
Klement Sekerafcbf4442017-08-17 07:38:42 +020036from discover_tests import discover_tests
Klement Sekerab23ffd72021-05-31 16:08:53 +020037import sanity_run_vpp
Klement Sekera9b6ece72018-03-23 10:50:11 +010038from subprocess import check_output, CalledProcessError
juraj.linkes40dd73b2018-09-21 13:55:16 +020039from util import check_core_path, get_core_path, is_core_present
Klement Sekera993e0ed2017-03-16 09:14:59 +010040
Klement Sekera05742262018-03-14 18:14:49 +010041# timeout which controls how long the child has to finish after seeing
42# a core dump in test temporary directory. If this is exceeded, parent assumes
Klement Sekeraeb506be2021-03-16 12:52:29 +010043# that child process is stuck (e.g. waiting for event from vpp) and kill
44# the child
Klement Sekera05742262018-03-14 18:14:49 +010045core_timeout = 3
46
Klement Sekera909a6a12017-08-08 04:33:53 +020047
juraj.linkes184870a2018-07-16 14:22:01 +020048class StreamQueue(Queue):
49 def write(self, msg):
50 self.put(msg)
51
52 def flush(self):
53 sys.__stdout__.flush()
54 sys.__stderr__.flush()
55
56 def fileno(self):
57 return self._writer.fileno()
58
59
60class StreamQueueManager(BaseManager):
61 pass
62
63
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020064StreamQueueManager.register("StreamQueue", StreamQueue)
juraj.linkes184870a2018-07-16 14:22:01 +020065
66
juraj.linkescae64f82018-09-19 15:01:47 +020067class TestResult(dict):
juraj.linkes40dd73b2018-09-21 13:55:16 +020068 def __init__(self, testcase_suite, testcases_by_id=None):
juraj.linkescae64f82018-09-19 15:01:47 +020069 super(TestResult, self).__init__()
Klement Sekera47f35272023-03-29 16:04:58 +020070 for trc in list(TestResultCode):
71 self[trc] = []
juraj.linkes40dd73b2018-09-21 13:55:16 +020072 self.crashed = False
juraj.linkescae64f82018-09-19 15:01:47 +020073 self.testcase_suite = testcase_suite
74 self.testcases = [testcase for testcase in testcase_suite]
juraj.linkes40dd73b2018-09-21 13:55:16 +020075 self.testcases_by_id = testcases_by_id
juraj.linkescae64f82018-09-19 15:01:47 +020076
77 def was_successful(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020078 return (
Klement Sekera47f35272023-03-29 16:04:58 +020079 0
80 == len(self[TestResultCode.FAIL])
81 == len(self[TestResultCode.ERROR])
82 == len(self[TestResultCode.UNEXPECTED_PASS])
83 and len(self[TestResultCode.PASS])
84 + len(self[TestResultCode.SKIP])
85 + len(self[TestResultCode.SKIP_CPU_SHORTAGE])
86 + len(self[TestResultCode.EXPECTED_FAIL])
Klement Sekera558ceab2021-04-08 19:37:41 +020087 == self.testcase_suite.countTestCases()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020088 )
juraj.linkescae64f82018-09-19 15:01:47 +020089
90 def no_tests_run(self):
Klement Sekera47f35272023-03-29 16:04:58 +020091 return 0 == len(self[TestResultCode.TEST_RUN])
juraj.linkescae64f82018-09-19 15:01:47 +020092
93 def process_result(self, test_id, result):
94 self[result].append(test_id)
juraj.linkescae64f82018-09-19 15:01:47 +020095
96 def suite_from_failed(self):
97 rerun_ids = set([])
98 for testcase in self.testcase_suite:
99 tc_id = testcase.id()
Klement Sekera47f35272023-03-29 16:04:58 +0200100 if (
101 tc_id
102 not in self[TestResultCode.PASS]
103 + self[TestResultCode.SKIP]
104 + self[TestResultCode.SKIP_CPU_SHORTAGE]
105 + self[TestResultCode.EXPECTED_FAIL]
106 ):
juraj.linkescae64f82018-09-19 15:01:47 +0200107 rerun_ids.add(tc_id)
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800108 if rerun_ids:
juraj.linkescae64f82018-09-19 15:01:47 +0200109 return suite_from_failed(self.testcase_suite, rerun_ids)
110
111 def get_testcase_names(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +0100112 # could be tearDownClass (test_ipsec_esp.TestIpsecEsp1)
113 setup_teardown_match = re.match(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200114 r"((tearDownClass)|(setUpClass)) \((.+\..+)\)", test_id
115 )
juraj.linkes2eca70d2018-12-13 11:10:47 +0100116 if setup_teardown_match:
117 test_name, _, _, testcase_name = setup_teardown_match.groups()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200118 if len(testcase_name.split(".")) == 2:
juraj.linkes2eca70d2018-12-13 11:10:47 +0100119 for key in self.testcases_by_id.keys():
120 if key.startswith(testcase_name):
121 testcase_name = key
122 break
123 testcase_name = self._get_testcase_doc_name(testcase_name)
124 else:
Ole Trøan5ba91592018-11-22 10:01:09 +0000125 test_name = self._get_test_description(test_id)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200126 testcase_name = self._get_testcase_doc_name(test_id)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200127
128 return testcase_name, test_name
juraj.linkescae64f82018-09-19 15:01:47 +0200129
Ole Trøan5ba91592018-11-22 10:01:09 +0000130 def _get_test_description(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +0100131 if test_id in self.testcases_by_id:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200132 desc = get_test_description(descriptions, self.testcases_by_id[test_id])
juraj.linkes2eca70d2018-12-13 11:10:47 +0100133 else:
134 desc = test_id
135 return desc
Ole Trøan5ba91592018-11-22 10:01:09 +0000136
juraj.linkes40dd73b2018-09-21 13:55:16 +0200137 def _get_testcase_doc_name(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +0100138 if test_id in self.testcases_by_id:
139 doc_name = get_testcase_doc_name(self.testcases_by_id[test_id])
140 else:
141 doc_name = test_id
142 return doc_name
juraj.linkescae64f82018-09-19 15:01:47 +0200143
144
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200145def test_runner_wrapper(
146 suite, keep_alive_pipe, stdouterr_queue, finished_pipe, result_pipe, logger
147):
juraj.linkes184870a2018-07-16 14:22:01 +0200148 sys.stdout = stdouterr_queue
149 sys.stderr = stdouterr_queue
juraj.linkesdfb5f2a2018-11-09 11:58:54 +0100150 VppTestCase.parallel_handler = logger.handlers[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200151 result = VppTestRunner(
152 keep_alive_pipe=keep_alive_pipe,
153 descriptions=descriptions,
154 verbosity=config.verbose,
155 result_pipe=result_pipe,
156 failfast=config.failfast,
157 print_summary=False,
158 ).run(suite)
juraj.linkescae64f82018-09-19 15:01:47 +0200159 finished_pipe.send(result.wasSuccessful())
160 finished_pipe.close()
Klement Sekera909a6a12017-08-08 04:33:53 +0200161 keep_alive_pipe.close()
162
163
juraj.linkes184870a2018-07-16 14:22:01 +0200164class TestCaseWrapper(object):
165 def __init__(self, testcase_suite, manager):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200166 self.keep_alive_parent_end, self.keep_alive_child_end = Pipe(duplex=False)
juraj.linkescae64f82018-09-19 15:01:47 +0200167 self.finished_parent_end, self.finished_child_end = Pipe(duplex=False)
juraj.linkes184870a2018-07-16 14:22:01 +0200168 self.result_parent_end, self.result_child_end = Pipe(duplex=False)
169 self.testcase_suite = testcase_suite
Klement Sekera558ceab2021-04-08 19:37:41 +0200170 self.stdouterr_queue = manager.StreamQueue(ctx=get_context())
juraj.linkes184870a2018-07-16 14:22:01 +0200171 self.logger = get_parallel_logger(self.stdouterr_queue)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200172 self.child = Process(
173 target=test_runner_wrapper,
174 args=(
175 testcase_suite,
176 self.keep_alive_child_end,
177 self.stdouterr_queue,
178 self.finished_child_end,
179 self.result_child_end,
180 self.logger,
181 ),
182 )
juraj.linkes184870a2018-07-16 14:22:01 +0200183 self.child.start()
juraj.linkes184870a2018-07-16 14:22:01 +0200184 self.last_test_temp_dir = None
185 self.last_test_vpp_binary = None
juraj.linkes40dd73b2018-09-21 13:55:16 +0200186 self._last_test = None
187 self.last_test_id = None
juraj.linkes721872e2018-09-05 18:13:45 +0200188 self.vpp_pid = None
juraj.linkes184870a2018-07-16 14:22:01 +0200189 self.last_heard = time.time()
190 self.core_detected_at = None
juraj.linkes40dd73b2018-09-21 13:55:16 +0200191 self.testcases_by_id = {}
192 self.testclasess_with_core = {}
193 for testcase in self.testcase_suite:
194 self.testcases_by_id[testcase.id()] = testcase
195 self.result = TestResult(testcase_suite, self.testcases_by_id)
196
197 @property
198 def last_test(self):
199 return self._last_test
200
201 @last_test.setter
202 def last_test(self, test_id):
203 self.last_test_id = test_id
204 if test_id in self.testcases_by_id:
205 testcase = self.testcases_by_id[test_id]
206 self._last_test = testcase.shortDescription()
207 if not self._last_test:
208 self._last_test = str(testcase)
209 else:
210 self._last_test = test_id
211
212 def add_testclass_with_core(self):
213 if self.last_test_id in self.testcases_by_id:
214 test = self.testcases_by_id[self.last_test_id]
215 class_name = unittest.util.strclass(test.__class__)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200216 test_name = "'{}' ({})".format(
217 get_test_description(descriptions, test), self.last_test_id
218 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200219 else:
220 test_name = self.last_test_id
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200221 class_name = re.match(
222 r"((tearDownClass)|(setUpClass)) " r"\((.+\..+)\)", test_name
223 ).groups()[3]
juraj.linkes40dd73b2018-09-21 13:55:16 +0200224 if class_name not in self.testclasess_with_core:
225 self.testclasess_with_core[class_name] = (
226 test_name,
227 self.last_test_vpp_binary,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200228 self.last_test_temp_dir,
229 )
juraj.linkes184870a2018-07-16 14:22:01 +0200230
231 def close_pipes(self):
232 self.keep_alive_child_end.close()
juraj.linkescae64f82018-09-19 15:01:47 +0200233 self.finished_child_end.close()
juraj.linkes184870a2018-07-16 14:22:01 +0200234 self.result_child_end.close()
235 self.keep_alive_parent_end.close()
juraj.linkescae64f82018-09-19 15:01:47 +0200236 self.finished_parent_end.close()
juraj.linkes184870a2018-07-16 14:22:01 +0200237 self.result_parent_end.close()
238
juraj.linkes40dd73b2018-09-21 13:55:16 +0200239 def was_successful(self):
240 return self.result.was_successful()
241
Klement Sekera558ceab2021-04-08 19:37:41 +0200242 @property
243 def cpus_used(self):
244 return self.testcase_suite.cpus_used
245
246 def get_assigned_cpus(self):
247 return self.testcase_suite.get_assigned_cpus()
248
juraj.linkes184870a2018-07-16 14:22:01 +0200249
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200250def stdouterr_reader_wrapper(
251 unread_testcases, finished_unread_testcases, read_testcases
252):
juraj.linkes184870a2018-07-16 14:22:01 +0200253 read_testcase = None
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800254 while read_testcases.is_set() or unread_testcases:
255 if finished_unread_testcases:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100256 read_testcase = finished_unread_testcases.pop()
257 unread_testcases.remove(read_testcase)
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800258 elif unread_testcases:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100259 read_testcase = unread_testcases.pop()
juraj.linkes184870a2018-07-16 14:22:01 +0200260 if read_testcase:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200261 data = ""
juraj.linkes184870a2018-07-16 14:22:01 +0200262 while data is not None:
263 sys.stdout.write(data)
264 data = read_testcase.stdouterr_queue.get()
265
266 read_testcase.stdouterr_queue.close()
267 finished_unread_testcases.discard(read_testcase)
268 read_testcase = None
269
270
Dmitry Valter3ace4d62022-03-26 15:43:14 +0000271def handle_failed_suite(logger, last_test_temp_dir, vpp_pid, vpp_binary):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200272 if last_test_temp_dir:
273 # Need to create link in case of a timeout or core dump without failure
274 lttd = os.path.basename(last_test_temp_dir)
Klement Sekera152a9b62022-05-13 18:01:36 +0200275 link_path = os.path.join(config.failed_dir, f"{lttd}-FAILED")
juraj.linkes40dd73b2018-09-21 13:55:16 +0200276 if not os.path.exists(link_path):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200277 os.symlink(last_test_temp_dir, link_path)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200278 logger.error(
279 "Symlink to failed testcase directory: %s -> %s" % (link_path, lttd)
280 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200281
282 # Report core existence
283 core_path = get_core_path(last_test_temp_dir)
284 if os.path.exists(core_path):
285 logger.error(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200286 "Core-file exists in test temporary directory: %s!" % core_path
287 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200288 check_core_path(logger, core_path)
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800289 logger.debug("Running 'file %s':" % core_path)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200290 try:
291 info = check_output(["file", core_path])
292 logger.debug(info)
293 except CalledProcessError as e:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200294 logger.error(
295 "Subprocess returned with return code "
296 "while running `file' utility on core-file "
297 "returned: "
298 "rc=%s",
299 e.returncode,
300 )
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800301 except OSError as e:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200302 logger.error(
303 "Subprocess returned with OS error while "
304 "running 'file' utility "
305 "on core-file: "
306 "(%s) %s",
307 e.errno,
308 e.strerror,
309 )
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800310 except Exception as e:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200311 logger.exception("Unexpected error running `file' utility on core-file")
Dmitry Valter3ace4d62022-03-26 15:43:14 +0000312 logger.error(f"gdb {vpp_binary} {core_path}")
juraj.linkes40dd73b2018-09-21 13:55:16 +0200313
314 if vpp_pid:
315 # Copy api post mortem
316 api_post_mortem_path = "/tmp/api_post_mortem.%d" % vpp_pid
317 if os.path.isfile(api_post_mortem_path):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200318 logger.error(
319 "Copying api_post_mortem.%d to %s" % (vpp_pid, last_test_temp_dir)
320 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200321 shutil.copy2(api_post_mortem_path, last_test_temp_dir)
322
323
324def check_and_handle_core(vpp_binary, tempdir, core_crash_test):
325 if is_core_present(tempdir):
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200326 if debug_core:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200327 print(
328 "VPP core detected in %s. Last test running was %s"
329 % (tempdir, core_crash_test)
330 )
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200331 print(single_line_delim)
332 spawn_gdb(vpp_binary, get_core_path(tempdir))
333 print(single_line_delim)
Klement Sekerab23ffd72021-05-31 16:08:53 +0200334 elif config.compress_core:
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200335 print("Compressing core-file in test directory `%s'" % tempdir)
336 os.system("gzip %s" % get_core_path(tempdir))
juraj.linkes40dd73b2018-09-21 13:55:16 +0200337
338
339def handle_cores(failed_testcases):
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200340 for failed_testcase in failed_testcases:
341 tcs_with_core = failed_testcase.testclasess_with_core
342 if tcs_with_core:
343 for test, vpp_binary, tempdir in tcs_with_core.values():
344 check_and_handle_core(vpp_binary, tempdir, test)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200345
346
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200347def process_finished_testsuite(
348 wrapped_testcase_suite, finished_testcase_suites, failed_wrapped_testcases, results
349):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200350 results.append(wrapped_testcase_suite.result)
351 finished_testcase_suites.add(wrapped_testcase_suite)
352 stop_run = False
Klement Sekerab23ffd72021-05-31 16:08:53 +0200353 if config.failfast and not wrapped_testcase_suite.was_successful():
juraj.linkes40dd73b2018-09-21 13:55:16 +0200354 stop_run = True
355
356 if not wrapped_testcase_suite.was_successful():
357 failed_wrapped_testcases.add(wrapped_testcase_suite)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200358 handle_failed_suite(
359 wrapped_testcase_suite.logger,
360 wrapped_testcase_suite.last_test_temp_dir,
361 wrapped_testcase_suite.vpp_pid,
362 wrapped_testcase_suite.last_test_vpp_binary,
363 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200364
365 return stop_run
366
367
juraj.linkes721872e2018-09-05 18:13:45 +0200368def run_forked(testcase_suites):
juraj.linkes184870a2018-07-16 14:22:01 +0200369 wrapped_testcase_suites = set()
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000370 solo_testcase_suites = []
juraj.linkes184870a2018-07-16 14:22:01 +0200371
372 # suites are unhashable, need to use list
373 results = []
juraj.linkes184870a2018-07-16 14:22:01 +0200374 unread_testcases = set()
375 finished_unread_testcases = set()
376 manager = StreamQueueManager()
377 manager.start()
Klement Sekera558ceab2021-04-08 19:37:41 +0200378 tests_running = 0
379 free_cpus = list(available_cpus)
380
381 def on_suite_start(tc):
382 nonlocal tests_running
383 nonlocal free_cpus
384 tests_running = tests_running + 1
385
386 def on_suite_finish(tc):
387 nonlocal tests_running
388 nonlocal free_cpus
389 tests_running = tests_running - 1
390 assert tests_running >= 0
391 free_cpus.extend(tc.get_assigned_cpus())
392
393 def run_suite(suite):
394 nonlocal manager
395 nonlocal wrapped_testcase_suites
396 nonlocal unread_testcases
397 nonlocal free_cpus
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200398 suite.assign_cpus(free_cpus[: suite.cpus_used])
399 free_cpus = free_cpus[suite.cpus_used :]
Klement Sekera558ceab2021-04-08 19:37:41 +0200400 wrapper = TestCaseWrapper(suite, manager)
401 wrapped_testcase_suites.add(wrapper)
402 unread_testcases.add(wrapper)
403 on_suite_start(suite)
404
405 def can_run_suite(suite):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200406 return tests_running < max_concurrent_tests and (
407 suite.cpus_used <= len(free_cpus) or suite.cpus_used > max_vpp_cpus
408 )
Klement Sekera558ceab2021-04-08 19:37:41 +0200409
410 while free_cpus and testcase_suites:
411 a_suite = testcase_suites[0]
412 if a_suite.is_tagged_run_solo:
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000413 a_suite = testcase_suites.pop(0)
Klement Sekera558ceab2021-04-08 19:37:41 +0200414 solo_testcase_suites.append(a_suite)
415 continue
416 if can_run_suite(a_suite):
417 a_suite = testcase_suites.pop(0)
418 run_suite(a_suite)
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000419 else:
420 break
421
Klement Sekera558ceab2021-04-08 19:37:41 +0200422 if tests_running == 0 and solo_testcase_suites:
423 a_suite = solo_testcase_suites.pop(0)
424 run_suite(a_suite)
juraj.linkes184870a2018-07-16 14:22:01 +0200425
426 read_from_testcases = threading.Event()
427 read_from_testcases.set()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200428 stdouterr_thread = threading.Thread(
429 target=stdouterr_reader_wrapper,
430 args=(unread_testcases, finished_unread_testcases, read_from_testcases),
431 )
juraj.linkes184870a2018-07-16 14:22:01 +0200432 stdouterr_thread.start()
433
juraj.linkes40dd73b2018-09-21 13:55:16 +0200434 failed_wrapped_testcases = set()
435 stop_run = False
juraj.linkese6b58cf2018-11-29 09:56:35 +0100436
437 try:
Klement Sekerac7d50472023-04-14 17:43:35 +0200438 while wrapped_testcase_suites or testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100439 finished_testcase_suites = set()
440 for wrapped_testcase_suite in wrapped_testcase_suites:
441 while wrapped_testcase_suite.result_parent_end.poll():
442 wrapped_testcase_suite.result.process_result(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200443 *wrapped_testcase_suite.result_parent_end.recv()
444 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100445 wrapped_testcase_suite.last_heard = time.time()
446
447 while wrapped_testcase_suite.keep_alive_parent_end.poll():
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200448 (
449 wrapped_testcase_suite.last_test,
450 wrapped_testcase_suite.last_test_vpp_binary,
451 wrapped_testcase_suite.last_test_temp_dir,
452 wrapped_testcase_suite.vpp_pid,
453 ) = wrapped_testcase_suite.keep_alive_parent_end.recv()
juraj.linkese6b58cf2018-11-29 09:56:35 +0100454 wrapped_testcase_suite.last_heard = time.time()
455
456 if wrapped_testcase_suite.finished_parent_end.poll():
457 wrapped_testcase_suite.finished_parent_end.recv()
458 wrapped_testcase_suite.last_heard = time.time()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200459 stop_run = (
460 process_finished_testsuite(
461 wrapped_testcase_suite,
462 finished_testcase_suites,
463 failed_wrapped_testcases,
464 results,
465 )
466 or stop_run
467 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100468 continue
469
470 fail = False
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200471 if wrapped_testcase_suite.last_heard + config.timeout < time.time():
juraj.linkese6b58cf2018-11-29 09:56:35 +0100472 fail = True
473 wrapped_testcase_suite.logger.critical(
474 "Child test runner process timed out "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200475 "(last test running was `%s' in `%s')!"
476 % (
477 wrapped_testcase_suite.last_test,
478 wrapped_testcase_suite.last_test_temp_dir,
479 )
480 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100481 elif not wrapped_testcase_suite.child.is_alive():
482 fail = True
483 wrapped_testcase_suite.logger.critical(
484 "Child test runner process unexpectedly died "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200485 "(last test running was `%s' in `%s')!"
486 % (
487 wrapped_testcase_suite.last_test,
488 wrapped_testcase_suite.last_test_temp_dir,
489 )
490 )
491 elif (
492 wrapped_testcase_suite.last_test_temp_dir
493 and wrapped_testcase_suite.last_test_vpp_binary
494 ):
495 if is_core_present(wrapped_testcase_suite.last_test_temp_dir):
juraj.linkese6b58cf2018-11-29 09:56:35 +0100496 wrapped_testcase_suite.add_testclass_with_core()
497 if wrapped_testcase_suite.core_detected_at is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200498 wrapped_testcase_suite.core_detected_at = time.time()
499 elif (
500 wrapped_testcase_suite.core_detected_at + core_timeout
501 < time.time()
502 ):
juraj.linkese6b58cf2018-11-29 09:56:35 +0100503 wrapped_testcase_suite.logger.critical(
504 "Child test runner process unresponsive and "
505 "core-file exists in test temporary directory "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200506 "(last test running was `%s' in `%s')!"
507 % (
508 wrapped_testcase_suite.last_test,
509 wrapped_testcase_suite.last_test_temp_dir,
510 )
511 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100512 fail = True
513
514 if fail:
515 wrapped_testcase_suite.child.terminate()
516 try:
517 # terminating the child process tends to leave orphan
518 # VPP process around
519 if wrapped_testcase_suite.vpp_pid:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200520 os.kill(wrapped_testcase_suite.vpp_pid, signal.SIGTERM)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100521 except OSError:
522 # already dead
523 pass
524 wrapped_testcase_suite.result.crashed = True
525 wrapped_testcase_suite.result.process_result(
Klement Sekera47f35272023-03-29 16:04:58 +0200526 wrapped_testcase_suite.last_test_id, TestResultCode.ERROR
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200527 )
528 stop_run = (
529 process_finished_testsuite(
530 wrapped_testcase_suite,
531 finished_testcase_suites,
532 failed_wrapped_testcases,
533 results,
534 )
535 or stop_run
536 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100537
538 for finished_testcase in finished_testcase_suites:
Andrew Yourtchenko42693522019-11-05 01:08:26 +0100539 # Somewhat surprisingly, the join below may
540 # timeout, even if client signaled that
541 # it finished - so we note it just in case.
542 join_start = time.time()
543 finished_testcase.child.join(test_finished_join_timeout)
544 join_end = time.time()
545 if join_end - join_start >= test_finished_join_timeout:
546 finished_testcase.logger.error(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200547 "Timeout joining finished test: %s (pid %d)"
548 % (finished_testcase.last_test, finished_testcase.child.pid)
549 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100550 finished_testcase.close_pipes()
551 wrapped_testcase_suites.remove(finished_testcase)
552 finished_unread_testcases.add(finished_testcase)
553 finished_testcase.stdouterr_queue.put(None)
Klement Sekera558ceab2021-04-08 19:37:41 +0200554 on_suite_finish(finished_testcase)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100555 if stop_run:
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800556 while testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100557 results.append(TestResult(testcase_suites.pop(0)))
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800558 elif testcase_suites:
Klement Sekerac7d50472023-04-14 17:43:35 +0200559 a_suite = testcase_suites[0]
Klement Sekera558ceab2021-04-08 19:37:41 +0200560 while a_suite and a_suite.is_tagged_run_solo:
Klement Sekerac7d50472023-04-14 17:43:35 +0200561 testcase_suites.pop(0)
Klement Sekera558ceab2021-04-08 19:37:41 +0200562 solo_testcase_suites.append(a_suite)
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000563 if testcase_suites:
Klement Sekerac7d50472023-04-14 17:43:35 +0200564 a_suite = testcase_suites[0]
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000565 else:
Klement Sekera558ceab2021-04-08 19:37:41 +0200566 a_suite = None
567 if a_suite and can_run_suite(a_suite):
Klement Sekerac7d50472023-04-14 17:43:35 +0200568 testcase_suites.pop(0)
Klement Sekera558ceab2021-04-08 19:37:41 +0200569 run_suite(a_suite)
570 if solo_testcase_suites and tests_running == 0:
571 a_suite = solo_testcase_suites.pop(0)
572 run_suite(a_suite)
Paul Vinciguerrac0692a42019-03-15 19:16:50 -0700573 time.sleep(0.1)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100574 except Exception:
juraj.linkes184870a2018-07-16 14:22:01 +0200575 for wrapped_testcase_suite in wrapped_testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100576 wrapped_testcase_suite.child.terminate()
577 wrapped_testcase_suite.stdouterr_queue.put(None)
578 raise
579 finally:
580 read_from_testcases.clear()
Klement Sekerab23ffd72021-05-31 16:08:53 +0200581 stdouterr_thread.join(config.timeout)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100582 manager.shutdown()
juraj.linkescae64f82018-09-19 15:01:47 +0200583
juraj.linkes40dd73b2018-09-21 13:55:16 +0200584 handle_cores(failed_wrapped_testcases)
juraj.linkes184870a2018-07-16 14:22:01 +0200585 return results
586
587
Klement Sekera558ceab2021-04-08 19:37:41 +0200588class TestSuiteWrapper(unittest.TestSuite):
589 cpus_used = 0
590
591 def __init__(self):
592 return super().__init__()
593
594 def addTest(self, test):
595 self.cpus_used = max(self.cpus_used, test.get_cpus_required())
596 super().addTest(test)
597
598 def assign_cpus(self, cpus):
599 self.cpus = cpus
600
601 def _handleClassSetUp(self, test, result):
602 if not test.__class__.skipped_due_to_cpu_lack:
603 test.assign_cpus(self.cpus)
604 super()._handleClassSetUp(test, result)
605
606 def get_assigned_cpus(self):
607 return self.cpus
608
609
juraj.linkes184870a2018-07-16 14:22:01 +0200610class SplitToSuitesCallback:
611 def __init__(self, filter_callback):
612 self.suites = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200613 self.suite_name = "default"
juraj.linkes184870a2018-07-16 14:22:01 +0200614 self.filter_callback = filter_callback
Klement Sekera558ceab2021-04-08 19:37:41 +0200615 self.filtered = TestSuiteWrapper()
Klement Sekerafcbf4442017-08-17 07:38:42 +0200616
617 def __call__(self, file_name, cls, method):
juraj.linkes184870a2018-07-16 14:22:01 +0200618 test_method = cls(method)
619 if self.filter_callback(file_name, cls.__name__, method):
620 self.suite_name = file_name + cls.__name__
621 if self.suite_name not in self.suites:
Klement Sekera558ceab2021-04-08 19:37:41 +0200622 self.suites[self.suite_name] = TestSuiteWrapper()
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000623 self.suites[self.suite_name].is_tagged_run_solo = False
juraj.linkes184870a2018-07-16 14:22:01 +0200624 self.suites[self.suite_name].addTest(test_method)
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000625 if test_method.is_tagged_run_solo():
626 self.suites[self.suite_name].is_tagged_run_solo = True
juraj.linkes184870a2018-07-16 14:22:01 +0200627
628 else:
629 self.filtered.addTest(test_method)
Klement Sekerafcbf4442017-08-17 07:38:42 +0200630
631
Klement Sekerab23ffd72021-05-31 16:08:53 +0200632def parse_test_filter(test_filter):
633 f = test_filter
juraj.linkes184870a2018-07-16 14:22:01 +0200634 filter_file_name = None
635 filter_class_name = None
636 filter_func_name = None
637 if f:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200638 if "." in f:
639 parts = f.split(".")
juraj.linkes184870a2018-07-16 14:22:01 +0200640 if len(parts) > 3:
Klement Sekera08c50e32023-04-14 17:44:04 +0200641 raise Exception(f"Invalid test filter: {test_filter}")
juraj.linkes184870a2018-07-16 14:22:01 +0200642 if len(parts) > 2:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200643 if parts[2] not in ("*", ""):
juraj.linkes184870a2018-07-16 14:22:01 +0200644 filter_func_name = parts[2]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200645 if parts[1] not in ("*", ""):
juraj.linkes184870a2018-07-16 14:22:01 +0200646 filter_class_name = parts[1]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200647 if parts[0] not in ("*", ""):
648 if parts[0].startswith("test_"):
juraj.linkes184870a2018-07-16 14:22:01 +0200649 filter_file_name = parts[0]
650 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200651 filter_file_name = "test_%s" % parts[0]
juraj.linkes184870a2018-07-16 14:22:01 +0200652 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200653 if f.startswith("test_"):
juraj.linkes184870a2018-07-16 14:22:01 +0200654 filter_file_name = f
655 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200656 filter_file_name = "test_%s" % f
juraj.linkes184870a2018-07-16 14:22:01 +0200657 if filter_file_name:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200658 filter_file_name = "%s.py" % filter_file_name
juraj.linkes184870a2018-07-16 14:22:01 +0200659 return filter_file_name, filter_class_name, filter_func_name
660
661
662def filter_tests(tests, filter_cb):
Klement Sekera558ceab2021-04-08 19:37:41 +0200663 result = TestSuiteWrapper()
juraj.linkes184870a2018-07-16 14:22:01 +0200664 for t in tests:
665 if isinstance(t, unittest.suite.TestSuite):
666 # this is a bunch of tests, recursively filter...
667 x = filter_tests(t, filter_cb)
668 if x.countTestCases() > 0:
669 result.addTest(x)
670 elif isinstance(t, unittest.TestCase):
671 # this is a single test
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200672 parts = t.id().split(".")
juraj.linkes184870a2018-07-16 14:22:01 +0200673 # t.id() for common cases like this:
674 # test_classifier.TestClassifier.test_acl_ip
675 # apply filtering only if it is so
676 if len(parts) == 3:
677 if not filter_cb(parts[0], parts[1], parts[2]):
678 continue
679 result.addTest(t)
680 else:
681 # unexpected object, don't touch it
682 result.addTest(t)
683 return result
684
685
686class FilterByTestOption:
Klement Sekera08c50e32023-04-14 17:44:04 +0200687 def __init__(self, filters):
688 self.filters = filters
juraj.linkes184870a2018-07-16 14:22:01 +0200689
690 def __call__(self, file_name, class_name, func_name):
Klement Sekera08c50e32023-04-14 17:44:04 +0200691 def test_one(
692 filter_file_name,
693 filter_class_name,
694 filter_func_name,
695 file_name,
696 class_name,
697 func_name,
698 ):
699 if filter_file_name:
700 fn_match = fnmatch.fnmatch(file_name, filter_file_name)
701 if not fn_match:
702 return False
703 if filter_class_name and class_name != filter_class_name:
Andrew Yourtchenkod760f792018-10-03 11:38:31 +0200704 return False
Klement Sekera08c50e32023-04-14 17:44:04 +0200705 if filter_func_name and func_name != filter_func_name:
706 return False
707 return True
708
709 for filter_file_name, filter_class_name, filter_func_name in self.filters:
710 if test_one(
711 filter_file_name,
712 filter_class_name,
713 filter_func_name,
714 file_name,
715 class_name,
716 func_name,
717 ):
718 return True
719
720 return False
juraj.linkes184870a2018-07-16 14:22:01 +0200721
722
723class FilterByClassList:
juraj.linkes721872e2018-09-05 18:13:45 +0200724 def __init__(self, classes_with_filenames):
725 self.classes_with_filenames = classes_with_filenames
Klement Sekeradf2b9802017-10-05 10:26:03 +0200726
727 def __call__(self, file_name, class_name, func_name):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200728 return ".".join([file_name, class_name]) in self.classes_with_filenames
Klement Sekeradf2b9802017-10-05 10:26:03 +0200729
730
731def suite_from_failed(suite, failed):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200732 failed = {x.rsplit(".", 1)[0] for x in failed}
juraj.linkes184870a2018-07-16 14:22:01 +0200733 filter_cb = FilterByClassList(failed)
734 suite = filter_tests(suite, filter_cb)
Klement Sekera4c5422e2018-06-22 13:19:45 +0200735 return suite
Klement Sekeradf2b9802017-10-05 10:26:03 +0200736
737
juraj.linkescae64f82018-09-19 15:01:47 +0200738class AllResults(dict):
juraj.linkes184870a2018-07-16 14:22:01 +0200739 def __init__(self):
juraj.linkescae64f82018-09-19 15:01:47 +0200740 super(AllResults, self).__init__()
juraj.linkes184870a2018-07-16 14:22:01 +0200741 self.all_testcases = 0
juraj.linkescae64f82018-09-19 15:01:47 +0200742 self.results_per_suite = []
Klement Sekera47f35272023-03-29 16:04:58 +0200743 for trc in list(TestResultCode):
744 self[trc] = 0
juraj.linkes184870a2018-07-16 14:22:01 +0200745 self.rerun = []
juraj.linkescae64f82018-09-19 15:01:47 +0200746 self.testsuites_no_tests_run = []
Klement Sekera909a6a12017-08-08 04:33:53 +0200747
juraj.linkescae64f82018-09-19 15:01:47 +0200748 def add_results(self, result):
749 self.results_per_suite.append(result)
Klement Sekera47f35272023-03-29 16:04:58 +0200750 for trc in list(TestResultCode):
751 self[trc] += len(result[trc])
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}",
Klement Sekera47f35272023-03-29 16:04:58 +0200788 f"Executed tests: {self[TestResultCode.TEST_RUN]}",
789 f"Passed tests: {colorize(self[TestResultCode.PASS], GREEN)}",
790 f"Expected failures: {colorize(self[TestResultCode.EXPECTED_FAIL], GREEN)}"
791 if self[TestResultCode.EXPECTED_FAIL]
792 else None,
793 f"Skipped tests: {colorize(self[TestResultCode.SKIP], YELLOW)}"
794 if self[TestResultCode.SKIP]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200795 else None,
796 f"Not Executed tests: {colorize(self.not_executed, RED)}"
797 if self.not_executed
798 else None,
Klement Sekera47f35272023-03-29 16:04:58 +0200799 f"Failures: {colorize(self[TestResultCode.FAIL], RED)}"
800 if self[TestResultCode.FAIL]
801 else None,
802 f"Unexpected passes: {colorize(self[TestResultCode.UNEXPECTED_PASS], RED)}"
803 if self[TestResultCode.UNEXPECTED_PASS]
804 else None,
805 f"Errors: {colorize(self[TestResultCode.ERROR], RED)}"
806 if self[TestResultCode.ERROR]
807 else None,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200808 "Tests skipped due to lack of CPUS: "
Klement Sekera47f35272023-03-29 16:04:58 +0200809 f"{colorize(self[TestResultCode.SKIP_CPU_SHORTAGE], YELLOW)}"
810 if self[TestResultCode.SKIP_CPU_SHORTAGE]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200811 else None,
812 ]
813 )
juraj.linkes184870a2018-07-16 14:22:01 +0200814
815 if self.all_failed > 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200816 print("FAILURES AND ERRORS IN TESTS:")
juraj.linkescae64f82018-09-19 15:01:47 +0200817 for result in self.results_per_suite:
juraj.linkescae64f82018-09-19 15:01:47 +0200818 old_testcase_name = None
Klement Sekera47f35272023-03-29 16:04:58 +0200819 for tr_code, headline in (
820 (TestResultCode.FAIL, "FAILURE"),
821 (TestResultCode.ERROR, "ERROR"),
822 (TestResultCode.UNEXPECTED_PASS, "UNEXPECTED PASS"),
823 ):
824 if not result[tr_code]:
825 continue
826
827 for failed_test_id in result[tr_code]:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200828 new_testcase_name, test_name = result.get_testcase_names(
829 failed_test_id
830 )
juraj.linkescae64f82018-09-19 15:01:47 +0200831 if new_testcase_name != old_testcase_name:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200832 print(
Klement Sekera47f35272023-03-29 16:04:58 +0200833 f" Testcase name: {colorize(new_testcase_name, RED)}"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200834 )
juraj.linkescae64f82018-09-19 15:01:47 +0200835 old_testcase_name = new_testcase_name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200836 print(
Klement Sekera47f35272023-03-29 16:04:58 +0200837 f" {headline}: {colorize(test_name, RED)} [{failed_test_id}]"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200838 )
Klement Sekera47f35272023-03-29 16:04:58 +0200839
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800840 if self.testsuites_no_tests_run:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200841 print("TESTCASES WHERE NO TESTS WERE SUCCESSFULLY EXECUTED:")
juraj.linkes40dd73b2018-09-21 13:55:16 +0200842 tc_classes = set()
juraj.linkescae64f82018-09-19 15:01:47 +0200843 for testsuite in self.testsuites_no_tests_run:
844 for testcase in testsuite:
845 tc_classes.add(get_testcase_doc_name(testcase))
846 for tc_class in tc_classes:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200847 print(" {}".format(colorize(tc_class, RED)))
juraj.linkes184870a2018-07-16 14:22:01 +0200848
Klement Sekera47f35272023-03-29 16:04:58 +0200849 if self[TestResultCode.SKIP_CPU_SHORTAGE]:
Klement Sekera558ceab2021-04-08 19:37:41 +0200850 print()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200851 print(
852 colorize(
853 " SOME TESTS WERE SKIPPED BECAUSE THERE ARE NOT"
854 " ENOUGH CPUS AVAILABLE",
855 YELLOW,
856 )
857 )
juraj.linkes184870a2018-07-16 14:22:01 +0200858 print(double_line_delim)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200859 print("")
juraj.linkes184870a2018-07-16 14:22:01 +0200860
861 @property
juraj.linkescae64f82018-09-19 15:01:47 +0200862 def not_executed(self):
Klement Sekera47f35272023-03-29 16:04:58 +0200863 return self.all_testcases - self[TestResultCode.TEST_RUN]
juraj.linkescae64f82018-09-19 15:01:47 +0200864
865 @property
juraj.linkes184870a2018-07-16 14:22:01 +0200866 def all_failed(self):
Klement Sekera47f35272023-03-29 16:04:58 +0200867 return (
868 self[TestResultCode.FAIL]
869 + self[TestResultCode.ERROR]
870 + self[TestResultCode.UNEXPECTED_PASS]
871 )
juraj.linkes184870a2018-07-16 14:22:01 +0200872
873
874def parse_results(results):
875 """
juraj.linkescae64f82018-09-19 15:01:47 +0200876 Prints the number of scheduled, executed, not executed, passed, failed,
877 errored and skipped tests and details about failed and errored tests.
juraj.linkes184870a2018-07-16 14:22:01 +0200878
juraj.linkescae64f82018-09-19 15:01:47 +0200879 Also returns all suites where any test failed.
juraj.linkes184870a2018-07-16 14:22:01 +0200880
881 :param results:
882 :return:
883 """
884
juraj.linkescae64f82018-09-19 15:01:47 +0200885 results_per_suite = AllResults()
juraj.linkes184870a2018-07-16 14:22:01 +0200886 crashed = False
887 failed = False
juraj.linkescae64f82018-09-19 15:01:47 +0200888 for result in results:
889 result_code = results_per_suite.add_result(result)
juraj.linkes184870a2018-07-16 14:22:01 +0200890 if result_code == 1:
891 failed = True
892 elif result_code == -1:
893 crashed = True
894
895 results_per_suite.print_results()
896
897 if crashed:
898 return_code = -1
899 elif failed:
900 return_code = 1
901 else:
902 return_code = 0
903 return return_code, results_per_suite.rerun
904
905
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200906if __name__ == "__main__":
Klement Sekerab23ffd72021-05-31 16:08:53 +0200907 print(f"Config is: {config}")
Klement Sekera3f6ff192017-08-11 06:56:05 +0200908
Klement Sekerab23ffd72021-05-31 16:08:53 +0200909 if config.sanity:
910 print("Running sanity test case.")
911 try:
912 rc = sanity_run_vpp.main()
913 if rc != 0:
914 sys.exit(rc)
915 except Exception as e:
916 print(traceback.format_exc())
917 print("Couldn't run sanity test case.")
918 sys.exit(-1)
Klement Sekera3f6ff192017-08-11 06:56:05 +0200919
Andrew Yourtchenko42693522019-11-05 01:08:26 +0100920 test_finished_join_timeout = 15
921
Klement Sekerab23ffd72021-05-31 16:08:53 +0200922 debug_gdb = config.debug in ["gdb", "gdbserver", "attach"]
923 debug_core = config.debug == "core"
Klement Sekera3f6ff192017-08-11 06:56:05 +0200924
Klement Sekerab23ffd72021-05-31 16:08:53 +0200925 run_interactive = debug_gdb or config.step or config.force_foreground
juraj.linkes184870a2018-07-16 14:22:01 +0200926
Klement Sekera558ceab2021-04-08 19:37:41 +0200927 max_concurrent_tests = 0
928 print(f"OS reports {num_cpus} available cpu(s).")
Paul Vinciguerra025cd9c2019-07-08 14:14:22 -0400929
Klement Sekerab23ffd72021-05-31 16:08:53 +0200930 test_jobs = config.jobs
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200931 if test_jobs == "auto":
juraj.linkes184870a2018-07-16 14:22:01 +0200932 if run_interactive:
Klement Sekera558ceab2021-04-08 19:37:41 +0200933 max_concurrent_tests = 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200934 print("Interactive mode required, running tests consecutively.")
juraj.linkes184870a2018-07-16 14:22:01 +0200935 else:
Klement Sekera558ceab2021-04-08 19:37:41 +0200936 max_concurrent_tests = num_cpus
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200937 print(
938 f"Running at most {max_concurrent_tests} python test "
939 "processes concurrently."
940 )
juraj.linkes184870a2018-07-16 14:22:01 +0200941 else:
Klement Sekerab23ffd72021-05-31 16:08:53 +0200942 max_concurrent_tests = test_jobs
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200943 print(
944 f"Running at most {max_concurrent_tests} python test processes "
945 "concurrently as set by 'TEST_JOBS'."
946 )
juraj.linkes184870a2018-07-16 14:22:01 +0200947
Klement Sekera558ceab2021-04-08 19:37:41 +0200948 print(f"Using at most {max_vpp_cpus} cpus for VPP threads.")
949
950 if run_interactive and max_concurrent_tests > 1:
juraj.linkes184870a2018-07-16 14:22:01 +0200951 raise NotImplementedError(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200952 "Running tests interactively (DEBUG is gdb[server] or ATTACH or "
953 "STEP is set) in parallel (TEST_JOBS is more than 1) is not "
954 "supported"
955 )
Klement Sekera13a83ef2018-03-21 12:35:51 +0100956
juraj.linkes184870a2018-07-16 14:22:01 +0200957 descriptions = True
Klement Sekera3f6ff192017-08-11 06:56:05 +0200958
Klement Sekera558ceab2021-04-08 19:37:41 +0200959 print("Running tests using custom test runner.")
Klement Sekera08c50e32023-04-14 17:44:04 +0200960 filters = [(parse_test_filter(f)) for f in config.filter.split(",")]
juraj.linkes184870a2018-07-16 14:22:01 +0200961
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200962 print(
Klement Sekera08c50e32023-04-14 17:44:04 +0200963 "Selected filters: ",
964 "|".join(
965 f"file={filter_file}, class={filter_class}, function={filter_func}"
966 for filter_file, filter_class, filter_func in filters
967 ),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200968 )
juraj.linkes184870a2018-07-16 14:22:01 +0200969
Klement Sekera08c50e32023-04-14 17:44:04 +0200970 filter_cb = FilterByTestOption(filters)
juraj.linkes184870a2018-07-16 14:22:01 +0200971
972 cb = SplitToSuitesCallback(filter_cb)
Klement Sekerab23ffd72021-05-31 16:08:53 +0200973 for d in config.test_src_dir:
Klement Sekeradf2b9802017-10-05 10:26:03 +0200974 print("Adding tests from directory tree %s" % d)
Saima Yunusc7f93b32022-08-10 03:25:31 -0400975 discover_tests(d, cb)
Klement Sekera3f6ff192017-08-11 06:56:05 +0200976
juraj.linkes184870a2018-07-16 14:22:01 +0200977 # suites are not hashable, need to use list
978 suites = []
979 tests_amount = 0
980 for testcase_suite in cb.suites.values():
981 tests_amount += testcase_suite.countTestCases()
Klement Sekera558ceab2021-04-08 19:37:41 +0200982 if testcase_suite.cpus_used > max_vpp_cpus:
983 # here we replace test functions with lambdas to just skip them
984 # but we also replace setUp/tearDown functions to do nothing
985 # so that the test can be "started" and "stopped", so that we can
986 # still keep those prints (test description - SKIP), which are done
987 # in stopTest() (for that to trigger, test function must run)
988 for t in testcase_suite:
989 for m in dir(t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200990 if m.startswith("test_"):
Klement Sekera558ceab2021-04-08 19:37:41 +0200991 setattr(t, m, lambda: t.skipTest("not enough cpus"))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200992 setattr(t.__class__, "setUpClass", lambda: None)
993 setattr(t.__class__, "tearDownClass", lambda: None)
994 setattr(t, "setUp", lambda: None)
995 setattr(t, "tearDown", lambda: None)
Klement Sekera558ceab2021-04-08 19:37:41 +0200996 t.__class__.skipped_due_to_cpu_lack = True
juraj.linkes184870a2018-07-16 14:22:01 +0200997 suites.append(testcase_suite)
Klement Sekerabbfa5fd2018-06-27 13:54:32 +0200998
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200999 print(
1000 "%s out of %s tests match specified filters"
1001 % (tests_amount, tests_amount + cb.filtered.countTestCases())
1002 )
juraj.linkes184870a2018-07-16 14:22:01 +02001003
Klement Sekerab23ffd72021-05-31 16:08:53 +02001004 if not config.extended:
juraj.linkes184870a2018-07-16 14:22:01 +02001005 print("Not running extended tests (some tests will be skipped)")
1006
Klement Sekerab23ffd72021-05-31 16:08:53 +02001007 attempts = config.retries + 1
Klement Sekeradf2b9802017-10-05 10:26:03 +02001008 if attempts > 1:
1009 print("Perform %s attempts to pass the suite..." % attempts)
juraj.linkes184870a2018-07-16 14:22:01 +02001010
Naveen Joy2cbf2fb2019-03-06 10:41:06 -08001011 if run_interactive and suites:
juraj.linkes184870a2018-07-16 14:22:01 +02001012 # don't fork if requiring interactive terminal
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001013 print("Running tests in foreground in the current process")
juraj.linkes46e8e912019-01-10 12:13:07 +01001014 full_suite = unittest.TestSuite()
Klement Sekera558ceab2021-04-08 19:37:41 +02001015 free_cpus = list(available_cpus)
1016 cpu_shortage = False
1017 for suite in suites:
1018 if suite.cpus_used <= max_vpp_cpus:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001019 suite.assign_cpus(free_cpus[: suite.cpus_used])
Klement Sekera558ceab2021-04-08 19:37:41 +02001020 else:
1021 suite.assign_cpus([])
1022 cpu_shortage = True
Klement Sekerad743dff2019-10-29 11:03:47 +00001023 full_suite.addTests(suites)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001024 result = VppTestRunner(
1025 verbosity=config.verbose, failfast=config.failfast, print_summary=True
1026 ).run(full_suite)
juraj.linkes40dd73b2018-09-21 13:55:16 +02001027 was_successful = result.wasSuccessful()
1028 if not was_successful:
1029 for test_case_info in result.failed_test_cases_info:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001030 handle_failed_suite(
1031 test_case_info.logger,
1032 test_case_info.tempdir,
1033 test_case_info.vpp_pid,
1034 config.vpp,
1035 )
Klement Sekeraf40ee3a2019-05-06 19:11:25 +02001036 if test_case_info in result.core_crash_test_cases_info:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001037 check_and_handle_core(
1038 test_case_info.vpp_bin_path,
1039 test_case_info.tempdir,
1040 test_case_info.core_crash_test,
1041 )
juraj.linkes40dd73b2018-09-21 13:55:16 +02001042
Klement Sekera558ceab2021-04-08 19:37:41 +02001043 if cpu_shortage:
1044 print()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001045 print(
1046 colorize(
1047 "SOME TESTS WERE SKIPPED BECAUSE THERE ARE NOT"
1048 " ENOUGH CPUS AVAILABLE",
1049 YELLOW,
1050 )
1051 )
Klement Sekera558ceab2021-04-08 19:37:41 +02001052 print()
juraj.linkes40dd73b2018-09-21 13:55:16 +02001053 sys.exit(not was_successful)
Klement Sekera13a83ef2018-03-21 12:35:51 +01001054 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001055 print(
1056 "Running each VPPTestCase in a separate background process"
1057 f" with at most {max_concurrent_tests} parallel python test "
1058 "process(es)"
1059 )
juraj.linkes184870a2018-07-16 14:22:01 +02001060 exit_code = 0
Naveen Joy2cbf2fb2019-03-06 10:41:06 -08001061 while suites and attempts > 0:
Dave Wallace8800f732023-08-31 00:47:44 -04001062 for suite in suites:
1063 failed_link = get_failed_testcase_linkname(
1064 config.failed_dir,
1065 f"{get_testcase_dirname(suite._tests[0].__class__.__name__)}",
1066 )
1067 if os.path.islink(failed_link):
1068 os.unlink(failed_link)
juraj.linkes184870a2018-07-16 14:22:01 +02001069 results = run_forked(suites)
1070 exit_code, suites = parse_results(results)
1071 attempts -= 1
1072 if exit_code == 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001073 print("Test run was successful")
juraj.linkes184870a2018-07-16 14:22:01 +02001074 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001075 print("%s attempt(s) left." % attempts)
juraj.linkes184870a2018-07-16 14:22:01 +02001076 sys.exit(exit_code)