blob: 66e0ee4db398ac2cbedecb5767239d9f40a6962f [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
Maxime Peim77caeb12023-11-14 15:26:41 +010017from vpp_papi import VPPApiJSONFiles
Dave Wallace8800f732023-08-31 00:47:44 -040018from asfframework import (
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020019 VppTestRunner,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020020 get_testcase_doc_name,
21 get_test_description,
Dave Wallace8800f732023-08-31 00:47:44 -040022 get_failed_testcase_linkname,
23 get_testcase_dirname,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020024)
Dave Wallace8800f732023-08-31 00:47:44 -040025from framework import VppTestCase
Klement Sekera47f35272023-03-29 16:04:58 +020026from test_result_code import TestResultCode
Klement Sekera152a9b62022-05-13 18:01:36 +020027from debug import spawn_gdb
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020028from log import (
29 get_parallel_logger,
30 double_line_delim,
31 RED,
32 YELLOW,
33 GREEN,
34 colorize,
35 single_line_delim,
36)
Klement Sekerafcbf4442017-08-17 07:38:42 +020037from discover_tests import discover_tests
Klement Sekerab23ffd72021-05-31 16:08:53 +020038import sanity_run_vpp
Klement Sekera9b6ece72018-03-23 10:50:11 +010039from subprocess import check_output, CalledProcessError
juraj.linkes40dd73b2018-09-21 13:55:16 +020040from util import check_core_path, get_core_path, is_core_present
Klement Sekera993e0ed2017-03-16 09:14:59 +010041
Klement Sekera05742262018-03-14 18:14:49 +010042# timeout which controls how long the child has to finish after seeing
43# a core dump in test temporary directory. If this is exceeded, parent assumes
Klement Sekeraeb506be2021-03-16 12:52:29 +010044# that child process is stuck (e.g. waiting for event from vpp) and kill
45# the child
Klement Sekera05742262018-03-14 18:14:49 +010046core_timeout = 3
47
Klement Sekera909a6a12017-08-08 04:33:53 +020048
juraj.linkes184870a2018-07-16 14:22:01 +020049class StreamQueue(Queue):
50 def write(self, msg):
51 self.put(msg)
52
53 def flush(self):
54 sys.__stdout__.flush()
55 sys.__stderr__.flush()
56
57 def fileno(self):
58 return self._writer.fileno()
59
60
61class StreamQueueManager(BaseManager):
62 pass
63
64
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020065StreamQueueManager.register("StreamQueue", StreamQueue)
juraj.linkes184870a2018-07-16 14:22:01 +020066
67
juraj.linkescae64f82018-09-19 15:01:47 +020068class TestResult(dict):
juraj.linkes40dd73b2018-09-21 13:55:16 +020069 def __init__(self, testcase_suite, testcases_by_id=None):
juraj.linkescae64f82018-09-19 15:01:47 +020070 super(TestResult, self).__init__()
Klement Sekera47f35272023-03-29 16:04:58 +020071 for trc in list(TestResultCode):
72 self[trc] = []
juraj.linkes40dd73b2018-09-21 13:55:16 +020073 self.crashed = False
juraj.linkescae64f82018-09-19 15:01:47 +020074 self.testcase_suite = testcase_suite
75 self.testcases = [testcase for testcase in testcase_suite]
juraj.linkes40dd73b2018-09-21 13:55:16 +020076 self.testcases_by_id = testcases_by_id
juraj.linkescae64f82018-09-19 15:01:47 +020077
78 def was_successful(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020079 return (
Klement Sekera47f35272023-03-29 16:04:58 +020080 0
81 == len(self[TestResultCode.FAIL])
82 == len(self[TestResultCode.ERROR])
83 == len(self[TestResultCode.UNEXPECTED_PASS])
84 and len(self[TestResultCode.PASS])
85 + len(self[TestResultCode.SKIP])
86 + len(self[TestResultCode.SKIP_CPU_SHORTAGE])
87 + len(self[TestResultCode.EXPECTED_FAIL])
Klement Sekera558ceab2021-04-08 19:37:41 +020088 == self.testcase_suite.countTestCases()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +020089 )
juraj.linkescae64f82018-09-19 15:01:47 +020090
91 def no_tests_run(self):
Klement Sekera47f35272023-03-29 16:04:58 +020092 return 0 == len(self[TestResultCode.TEST_RUN])
juraj.linkescae64f82018-09-19 15:01:47 +020093
94 def process_result(self, test_id, result):
95 self[result].append(test_id)
juraj.linkescae64f82018-09-19 15:01:47 +020096
97 def suite_from_failed(self):
98 rerun_ids = set([])
99 for testcase in self.testcase_suite:
100 tc_id = testcase.id()
Klement Sekera47f35272023-03-29 16:04:58 +0200101 if (
102 tc_id
103 not in self[TestResultCode.PASS]
104 + self[TestResultCode.SKIP]
105 + self[TestResultCode.SKIP_CPU_SHORTAGE]
106 + self[TestResultCode.EXPECTED_FAIL]
107 ):
juraj.linkescae64f82018-09-19 15:01:47 +0200108 rerun_ids.add(tc_id)
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800109 if rerun_ids:
juraj.linkescae64f82018-09-19 15:01:47 +0200110 return suite_from_failed(self.testcase_suite, rerun_ids)
111
112 def get_testcase_names(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +0100113 # could be tearDownClass (test_ipsec_esp.TestIpsecEsp1)
114 setup_teardown_match = re.match(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200115 r"((tearDownClass)|(setUpClass)) \((.+\..+)\)", test_id
116 )
juraj.linkes2eca70d2018-12-13 11:10:47 +0100117 if setup_teardown_match:
118 test_name, _, _, testcase_name = setup_teardown_match.groups()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200119 if len(testcase_name.split(".")) == 2:
juraj.linkes2eca70d2018-12-13 11:10:47 +0100120 for key in self.testcases_by_id.keys():
121 if key.startswith(testcase_name):
122 testcase_name = key
123 break
124 testcase_name = self._get_testcase_doc_name(testcase_name)
125 else:
Ole Trøan5ba91592018-11-22 10:01:09 +0000126 test_name = self._get_test_description(test_id)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200127 testcase_name = self._get_testcase_doc_name(test_id)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200128
129 return testcase_name, test_name
juraj.linkescae64f82018-09-19 15:01:47 +0200130
Ole Trøan5ba91592018-11-22 10:01:09 +0000131 def _get_test_description(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +0100132 if test_id in self.testcases_by_id:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200133 desc = get_test_description(descriptions, self.testcases_by_id[test_id])
juraj.linkes2eca70d2018-12-13 11:10:47 +0100134 else:
135 desc = test_id
136 return desc
Ole Trøan5ba91592018-11-22 10:01:09 +0000137
juraj.linkes40dd73b2018-09-21 13:55:16 +0200138 def _get_testcase_doc_name(self, test_id):
juraj.linkes2eca70d2018-12-13 11:10:47 +0100139 if test_id in self.testcases_by_id:
140 doc_name = get_testcase_doc_name(self.testcases_by_id[test_id])
141 else:
142 doc_name = test_id
143 return doc_name
juraj.linkescae64f82018-09-19 15:01:47 +0200144
145
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200146def test_runner_wrapper(
147 suite, keep_alive_pipe, stdouterr_queue, finished_pipe, result_pipe, logger
148):
juraj.linkes184870a2018-07-16 14:22:01 +0200149 sys.stdout = stdouterr_queue
150 sys.stderr = stdouterr_queue
juraj.linkesdfb5f2a2018-11-09 11:58:54 +0100151 VppTestCase.parallel_handler = logger.handlers[0]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200152 result = VppTestRunner(
153 keep_alive_pipe=keep_alive_pipe,
154 descriptions=descriptions,
155 verbosity=config.verbose,
156 result_pipe=result_pipe,
157 failfast=config.failfast,
158 print_summary=False,
159 ).run(suite)
juraj.linkescae64f82018-09-19 15:01:47 +0200160 finished_pipe.send(result.wasSuccessful())
161 finished_pipe.close()
Klement Sekera909a6a12017-08-08 04:33:53 +0200162 keep_alive_pipe.close()
163
164
juraj.linkes184870a2018-07-16 14:22:01 +0200165class TestCaseWrapper(object):
166 def __init__(self, testcase_suite, manager):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200167 self.keep_alive_parent_end, self.keep_alive_child_end = Pipe(duplex=False)
juraj.linkescae64f82018-09-19 15:01:47 +0200168 self.finished_parent_end, self.finished_child_end = Pipe(duplex=False)
juraj.linkes184870a2018-07-16 14:22:01 +0200169 self.result_parent_end, self.result_child_end = Pipe(duplex=False)
170 self.testcase_suite = testcase_suite
Klement Sekera558ceab2021-04-08 19:37:41 +0200171 self.stdouterr_queue = manager.StreamQueue(ctx=get_context())
juraj.linkes184870a2018-07-16 14:22:01 +0200172 self.logger = get_parallel_logger(self.stdouterr_queue)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200173 self.child = Process(
174 target=test_runner_wrapper,
175 args=(
176 testcase_suite,
177 self.keep_alive_child_end,
178 self.stdouterr_queue,
179 self.finished_child_end,
180 self.result_child_end,
181 self.logger,
182 ),
183 )
juraj.linkes184870a2018-07-16 14:22:01 +0200184 self.child.start()
juraj.linkes184870a2018-07-16 14:22:01 +0200185 self.last_test_temp_dir = None
186 self.last_test_vpp_binary = None
juraj.linkes40dd73b2018-09-21 13:55:16 +0200187 self._last_test = None
188 self.last_test_id = None
juraj.linkes721872e2018-09-05 18:13:45 +0200189 self.vpp_pid = None
juraj.linkes184870a2018-07-16 14:22:01 +0200190 self.last_heard = time.time()
191 self.core_detected_at = None
juraj.linkes40dd73b2018-09-21 13:55:16 +0200192 self.testcases_by_id = {}
193 self.testclasess_with_core = {}
194 for testcase in self.testcase_suite:
195 self.testcases_by_id[testcase.id()] = testcase
196 self.result = TestResult(testcase_suite, self.testcases_by_id)
197
198 @property
199 def last_test(self):
200 return self._last_test
201
202 @last_test.setter
203 def last_test(self, test_id):
204 self.last_test_id = test_id
205 if test_id in self.testcases_by_id:
206 testcase = self.testcases_by_id[test_id]
207 self._last_test = testcase.shortDescription()
208 if not self._last_test:
209 self._last_test = str(testcase)
210 else:
211 self._last_test = test_id
212
213 def add_testclass_with_core(self):
214 if self.last_test_id in self.testcases_by_id:
215 test = self.testcases_by_id[self.last_test_id]
216 class_name = unittest.util.strclass(test.__class__)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200217 test_name = "'{}' ({})".format(
218 get_test_description(descriptions, test), self.last_test_id
219 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200220 else:
221 test_name = self.last_test_id
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200222 class_name = re.match(
223 r"((tearDownClass)|(setUpClass)) " r"\((.+\..+)\)", test_name
224 ).groups()[3]
juraj.linkes40dd73b2018-09-21 13:55:16 +0200225 if class_name not in self.testclasess_with_core:
226 self.testclasess_with_core[class_name] = (
227 test_name,
228 self.last_test_vpp_binary,
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200229 self.last_test_temp_dir,
230 )
juraj.linkes184870a2018-07-16 14:22:01 +0200231
232 def close_pipes(self):
233 self.keep_alive_child_end.close()
juraj.linkescae64f82018-09-19 15:01:47 +0200234 self.finished_child_end.close()
juraj.linkes184870a2018-07-16 14:22:01 +0200235 self.result_child_end.close()
236 self.keep_alive_parent_end.close()
juraj.linkescae64f82018-09-19 15:01:47 +0200237 self.finished_parent_end.close()
juraj.linkes184870a2018-07-16 14:22:01 +0200238 self.result_parent_end.close()
239
juraj.linkes40dd73b2018-09-21 13:55:16 +0200240 def was_successful(self):
241 return self.result.was_successful()
242
Klement Sekera558ceab2021-04-08 19:37:41 +0200243 @property
244 def cpus_used(self):
245 return self.testcase_suite.cpus_used
246
247 def get_assigned_cpus(self):
248 return self.testcase_suite.get_assigned_cpus()
249
juraj.linkes184870a2018-07-16 14:22:01 +0200250
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200251def stdouterr_reader_wrapper(
252 unread_testcases, finished_unread_testcases, read_testcases
253):
juraj.linkes184870a2018-07-16 14:22:01 +0200254 read_testcase = None
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800255 while read_testcases.is_set() or unread_testcases:
256 if finished_unread_testcases:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100257 read_testcase = finished_unread_testcases.pop()
258 unread_testcases.remove(read_testcase)
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800259 elif unread_testcases:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100260 read_testcase = unread_testcases.pop()
juraj.linkes184870a2018-07-16 14:22:01 +0200261 if read_testcase:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200262 data = ""
juraj.linkes184870a2018-07-16 14:22:01 +0200263 while data is not None:
264 sys.stdout.write(data)
265 data = read_testcase.stdouterr_queue.get()
266
267 read_testcase.stdouterr_queue.close()
268 finished_unread_testcases.discard(read_testcase)
269 read_testcase = None
270
271
Dmitry Valter3ace4d62022-03-26 15:43:14 +0000272def handle_failed_suite(logger, last_test_temp_dir, vpp_pid, vpp_binary):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200273 if last_test_temp_dir:
274 # Need to create link in case of a timeout or core dump without failure
275 lttd = os.path.basename(last_test_temp_dir)
Klement Sekera152a9b62022-05-13 18:01:36 +0200276 link_path = os.path.join(config.failed_dir, f"{lttd}-FAILED")
juraj.linkes40dd73b2018-09-21 13:55:16 +0200277 if not os.path.exists(link_path):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200278 os.symlink(last_test_temp_dir, link_path)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200279 logger.error(
280 "Symlink to failed testcase directory: %s -> %s" % (link_path, lttd)
281 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200282
283 # Report core existence
284 core_path = get_core_path(last_test_temp_dir)
285 if os.path.exists(core_path):
286 logger.error(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200287 "Core-file exists in test temporary directory: %s!" % core_path
288 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200289 check_core_path(logger, core_path)
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800290 logger.debug("Running 'file %s':" % core_path)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200291 try:
292 info = check_output(["file", core_path])
293 logger.debug(info)
294 except CalledProcessError as e:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200295 logger.error(
296 "Subprocess returned with return code "
297 "while running `file' utility on core-file "
298 "returned: "
299 "rc=%s",
300 e.returncode,
301 )
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800302 except OSError as e:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200303 logger.error(
304 "Subprocess returned with OS error while "
305 "running 'file' utility "
306 "on core-file: "
307 "(%s) %s",
308 e.errno,
309 e.strerror,
310 )
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800311 except Exception as e:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200312 logger.exception("Unexpected error running `file' utility on core-file")
Dmitry Valter3ace4d62022-03-26 15:43:14 +0000313 logger.error(f"gdb {vpp_binary} {core_path}")
juraj.linkes40dd73b2018-09-21 13:55:16 +0200314
315 if vpp_pid:
316 # Copy api post mortem
317 api_post_mortem_path = "/tmp/api_post_mortem.%d" % vpp_pid
318 if os.path.isfile(api_post_mortem_path):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200319 logger.error(
320 "Copying api_post_mortem.%d to %s" % (vpp_pid, last_test_temp_dir)
321 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200322 shutil.copy2(api_post_mortem_path, last_test_temp_dir)
323
324
325def check_and_handle_core(vpp_binary, tempdir, core_crash_test):
326 if is_core_present(tempdir):
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200327 if debug_core:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200328 print(
329 "VPP core detected in %s. Last test running was %s"
330 % (tempdir, core_crash_test)
331 )
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200332 print(single_line_delim)
333 spawn_gdb(vpp_binary, get_core_path(tempdir))
334 print(single_line_delim)
Klement Sekerab23ffd72021-05-31 16:08:53 +0200335 elif config.compress_core:
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200336 print("Compressing core-file in test directory `%s'" % tempdir)
337 os.system("gzip %s" % get_core_path(tempdir))
juraj.linkes40dd73b2018-09-21 13:55:16 +0200338
339
340def handle_cores(failed_testcases):
Klement Sekeraf40ee3a2019-05-06 19:11:25 +0200341 for failed_testcase in failed_testcases:
342 tcs_with_core = failed_testcase.testclasess_with_core
343 if tcs_with_core:
344 for test, vpp_binary, tempdir in tcs_with_core.values():
345 check_and_handle_core(vpp_binary, tempdir, test)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200346
347
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200348def process_finished_testsuite(
349 wrapped_testcase_suite, finished_testcase_suites, failed_wrapped_testcases, results
350):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200351 results.append(wrapped_testcase_suite.result)
352 finished_testcase_suites.add(wrapped_testcase_suite)
353 stop_run = False
Klement Sekerab23ffd72021-05-31 16:08:53 +0200354 if config.failfast and not wrapped_testcase_suite.was_successful():
juraj.linkes40dd73b2018-09-21 13:55:16 +0200355 stop_run = True
356
357 if not wrapped_testcase_suite.was_successful():
358 failed_wrapped_testcases.add(wrapped_testcase_suite)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200359 handle_failed_suite(
360 wrapped_testcase_suite.logger,
361 wrapped_testcase_suite.last_test_temp_dir,
362 wrapped_testcase_suite.vpp_pid,
363 wrapped_testcase_suite.last_test_vpp_binary,
364 )
juraj.linkes40dd73b2018-09-21 13:55:16 +0200365
366 return stop_run
367
368
juraj.linkes721872e2018-09-05 18:13:45 +0200369def run_forked(testcase_suites):
juraj.linkes184870a2018-07-16 14:22:01 +0200370 wrapped_testcase_suites = set()
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000371 solo_testcase_suites = []
juraj.linkes184870a2018-07-16 14:22:01 +0200372
373 # suites are unhashable, need to use list
374 results = []
juraj.linkes184870a2018-07-16 14:22:01 +0200375 unread_testcases = set()
376 finished_unread_testcases = set()
377 manager = StreamQueueManager()
378 manager.start()
Klement Sekera558ceab2021-04-08 19:37:41 +0200379 tests_running = 0
380 free_cpus = list(available_cpus)
381
382 def on_suite_start(tc):
383 nonlocal tests_running
384 nonlocal free_cpus
385 tests_running = tests_running + 1
386
387 def on_suite_finish(tc):
388 nonlocal tests_running
389 nonlocal free_cpus
390 tests_running = tests_running - 1
391 assert tests_running >= 0
392 free_cpus.extend(tc.get_assigned_cpus())
393
394 def run_suite(suite):
395 nonlocal manager
396 nonlocal wrapped_testcase_suites
397 nonlocal unread_testcases
398 nonlocal free_cpus
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200399 suite.assign_cpus(free_cpus[: suite.cpus_used])
400 free_cpus = free_cpus[suite.cpus_used :]
Klement Sekera558ceab2021-04-08 19:37:41 +0200401 wrapper = TestCaseWrapper(suite, manager)
402 wrapped_testcase_suites.add(wrapper)
403 unread_testcases.add(wrapper)
404 on_suite_start(suite)
405
406 def can_run_suite(suite):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200407 return tests_running < max_concurrent_tests and (
408 suite.cpus_used <= len(free_cpus) or suite.cpus_used > max_vpp_cpus
409 )
Klement Sekera558ceab2021-04-08 19:37:41 +0200410
411 while free_cpus and testcase_suites:
412 a_suite = testcase_suites[0]
413 if a_suite.is_tagged_run_solo:
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000414 a_suite = testcase_suites.pop(0)
Klement Sekera558ceab2021-04-08 19:37:41 +0200415 solo_testcase_suites.append(a_suite)
416 continue
417 if can_run_suite(a_suite):
418 a_suite = testcase_suites.pop(0)
419 run_suite(a_suite)
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000420 else:
421 break
422
Klement Sekera558ceab2021-04-08 19:37:41 +0200423 if tests_running == 0 and solo_testcase_suites:
424 a_suite = solo_testcase_suites.pop(0)
425 run_suite(a_suite)
juraj.linkes184870a2018-07-16 14:22:01 +0200426
427 read_from_testcases = threading.Event()
428 read_from_testcases.set()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200429 stdouterr_thread = threading.Thread(
430 target=stdouterr_reader_wrapper,
431 args=(unread_testcases, finished_unread_testcases, read_from_testcases),
432 )
juraj.linkes184870a2018-07-16 14:22:01 +0200433 stdouterr_thread.start()
434
juraj.linkes40dd73b2018-09-21 13:55:16 +0200435 failed_wrapped_testcases = set()
436 stop_run = False
juraj.linkese6b58cf2018-11-29 09:56:35 +0100437
438 try:
Klement Sekerac7d50472023-04-14 17:43:35 +0200439 while wrapped_testcase_suites or testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100440 finished_testcase_suites = set()
441 for wrapped_testcase_suite in wrapped_testcase_suites:
442 while wrapped_testcase_suite.result_parent_end.poll():
443 wrapped_testcase_suite.result.process_result(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200444 *wrapped_testcase_suite.result_parent_end.recv()
445 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100446 wrapped_testcase_suite.last_heard = time.time()
447
448 while wrapped_testcase_suite.keep_alive_parent_end.poll():
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200449 (
450 wrapped_testcase_suite.last_test,
451 wrapped_testcase_suite.last_test_vpp_binary,
452 wrapped_testcase_suite.last_test_temp_dir,
453 wrapped_testcase_suite.vpp_pid,
454 ) = wrapped_testcase_suite.keep_alive_parent_end.recv()
juraj.linkese6b58cf2018-11-29 09:56:35 +0100455 wrapped_testcase_suite.last_heard = time.time()
456
457 if wrapped_testcase_suite.finished_parent_end.poll():
458 wrapped_testcase_suite.finished_parent_end.recv()
459 wrapped_testcase_suite.last_heard = time.time()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200460 stop_run = (
461 process_finished_testsuite(
462 wrapped_testcase_suite,
463 finished_testcase_suites,
464 failed_wrapped_testcases,
465 results,
466 )
467 or stop_run
468 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100469 continue
470
471 fail = False
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200472 if wrapped_testcase_suite.last_heard + config.timeout < time.time():
juraj.linkese6b58cf2018-11-29 09:56:35 +0100473 fail = True
474 wrapped_testcase_suite.logger.critical(
475 "Child test runner process timed out "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200476 "(last test running was `%s' in `%s')!"
477 % (
478 wrapped_testcase_suite.last_test,
479 wrapped_testcase_suite.last_test_temp_dir,
480 )
481 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100482 elif not wrapped_testcase_suite.child.is_alive():
483 fail = True
484 wrapped_testcase_suite.logger.critical(
485 "Child test runner process unexpectedly died "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200486 "(last test running was `%s' in `%s')!"
487 % (
488 wrapped_testcase_suite.last_test,
489 wrapped_testcase_suite.last_test_temp_dir,
490 )
491 )
492 elif (
493 wrapped_testcase_suite.last_test_temp_dir
494 and wrapped_testcase_suite.last_test_vpp_binary
495 ):
496 if is_core_present(wrapped_testcase_suite.last_test_temp_dir):
juraj.linkese6b58cf2018-11-29 09:56:35 +0100497 wrapped_testcase_suite.add_testclass_with_core()
498 if wrapped_testcase_suite.core_detected_at is None:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200499 wrapped_testcase_suite.core_detected_at = time.time()
500 elif (
501 wrapped_testcase_suite.core_detected_at + core_timeout
502 < time.time()
503 ):
juraj.linkese6b58cf2018-11-29 09:56:35 +0100504 wrapped_testcase_suite.logger.critical(
505 "Child test runner process unresponsive and "
506 "core-file exists in test temporary directory "
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200507 "(last test running was `%s' in `%s')!"
508 % (
509 wrapped_testcase_suite.last_test,
510 wrapped_testcase_suite.last_test_temp_dir,
511 )
512 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100513 fail = True
514
515 if fail:
516 wrapped_testcase_suite.child.terminate()
517 try:
518 # terminating the child process tends to leave orphan
519 # VPP process around
520 if wrapped_testcase_suite.vpp_pid:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200521 os.kill(wrapped_testcase_suite.vpp_pid, signal.SIGTERM)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100522 except OSError:
523 # already dead
524 pass
525 wrapped_testcase_suite.result.crashed = True
526 wrapped_testcase_suite.result.process_result(
Klement Sekera47f35272023-03-29 16:04:58 +0200527 wrapped_testcase_suite.last_test_id, TestResultCode.ERROR
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200528 )
529 stop_run = (
530 process_finished_testsuite(
531 wrapped_testcase_suite,
532 finished_testcase_suites,
533 failed_wrapped_testcases,
534 results,
535 )
536 or stop_run
537 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100538
539 for finished_testcase in finished_testcase_suites:
Andrew Yourtchenko42693522019-11-05 01:08:26 +0100540 # Somewhat surprisingly, the join below may
541 # timeout, even if client signaled that
542 # it finished - so we note it just in case.
543 join_start = time.time()
544 finished_testcase.child.join(test_finished_join_timeout)
545 join_end = time.time()
546 if join_end - join_start >= test_finished_join_timeout:
547 finished_testcase.logger.error(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200548 "Timeout joining finished test: %s (pid %d)"
549 % (finished_testcase.last_test, finished_testcase.child.pid)
550 )
juraj.linkese6b58cf2018-11-29 09:56:35 +0100551 finished_testcase.close_pipes()
552 wrapped_testcase_suites.remove(finished_testcase)
553 finished_unread_testcases.add(finished_testcase)
554 finished_testcase.stdouterr_queue.put(None)
Klement Sekera558ceab2021-04-08 19:37:41 +0200555 on_suite_finish(finished_testcase)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100556 if stop_run:
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800557 while testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100558 results.append(TestResult(testcase_suites.pop(0)))
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800559 elif testcase_suites:
Klement Sekerac7d50472023-04-14 17:43:35 +0200560 a_suite = testcase_suites[0]
Klement Sekera558ceab2021-04-08 19:37:41 +0200561 while a_suite and a_suite.is_tagged_run_solo:
Klement Sekerac7d50472023-04-14 17:43:35 +0200562 testcase_suites.pop(0)
Klement Sekera558ceab2021-04-08 19:37:41 +0200563 solo_testcase_suites.append(a_suite)
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000564 if testcase_suites:
Klement Sekerac7d50472023-04-14 17:43:35 +0200565 a_suite = testcase_suites[0]
Andrew Yourtchenkoa3b7c552020-08-26 14:33:54 +0000566 else:
Klement Sekera558ceab2021-04-08 19:37:41 +0200567 a_suite = None
568 if a_suite and can_run_suite(a_suite):
Klement Sekerac7d50472023-04-14 17:43:35 +0200569 testcase_suites.pop(0)
Klement Sekera558ceab2021-04-08 19:37:41 +0200570 run_suite(a_suite)
571 if solo_testcase_suites and tests_running == 0:
572 a_suite = solo_testcase_suites.pop(0)
573 run_suite(a_suite)
Paul Vinciguerrac0692a42019-03-15 19:16:50 -0700574 time.sleep(0.1)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100575 except Exception:
juraj.linkes184870a2018-07-16 14:22:01 +0200576 for wrapped_testcase_suite in wrapped_testcase_suites:
juraj.linkese6b58cf2018-11-29 09:56:35 +0100577 wrapped_testcase_suite.child.terminate()
578 wrapped_testcase_suite.stdouterr_queue.put(None)
579 raise
580 finally:
581 read_from_testcases.clear()
Klement Sekerab23ffd72021-05-31 16:08:53 +0200582 stdouterr_thread.join(config.timeout)
juraj.linkese6b58cf2018-11-29 09:56:35 +0100583 manager.shutdown()
juraj.linkescae64f82018-09-19 15:01:47 +0200584
juraj.linkes40dd73b2018-09-21 13:55:16 +0200585 handle_cores(failed_wrapped_testcases)
juraj.linkes184870a2018-07-16 14:22:01 +0200586 return results
587
588
Klement Sekera558ceab2021-04-08 19:37:41 +0200589class TestSuiteWrapper(unittest.TestSuite):
590 cpus_used = 0
591
592 def __init__(self):
593 return super().__init__()
594
595 def addTest(self, test):
596 self.cpus_used = max(self.cpus_used, test.get_cpus_required())
597 super().addTest(test)
598
599 def assign_cpus(self, cpus):
600 self.cpus = cpus
601
602 def _handleClassSetUp(self, test, result):
603 if not test.__class__.skipped_due_to_cpu_lack:
604 test.assign_cpus(self.cpus)
605 super()._handleClassSetUp(test, result)
606
607 def get_assigned_cpus(self):
608 return self.cpus
609
610
juraj.linkes184870a2018-07-16 14:22:01 +0200611class SplitToSuitesCallback:
612 def __init__(self, filter_callback):
613 self.suites = {}
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200614 self.suite_name = "default"
juraj.linkes184870a2018-07-16 14:22:01 +0200615 self.filter_callback = filter_callback
Klement Sekera558ceab2021-04-08 19:37:41 +0200616 self.filtered = TestSuiteWrapper()
Klement Sekerafcbf4442017-08-17 07:38:42 +0200617
618 def __call__(self, file_name, cls, method):
juraj.linkes184870a2018-07-16 14:22:01 +0200619 test_method = cls(method)
620 if self.filter_callback(file_name, cls.__name__, method):
621 self.suite_name = file_name + cls.__name__
622 if self.suite_name not in self.suites:
Klement Sekera558ceab2021-04-08 19:37:41 +0200623 self.suites[self.suite_name] = TestSuiteWrapper()
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000624 self.suites[self.suite_name].is_tagged_run_solo = False
juraj.linkes184870a2018-07-16 14:22:01 +0200625 self.suites[self.suite_name].addTest(test_method)
Andrew Yourtchenko06f32812021-01-14 10:19:08 +0000626 if test_method.is_tagged_run_solo():
627 self.suites[self.suite_name].is_tagged_run_solo = True
juraj.linkes184870a2018-07-16 14:22:01 +0200628
629 else:
630 self.filtered.addTest(test_method)
Klement Sekerafcbf4442017-08-17 07:38:42 +0200631
632
Klement Sekerab23ffd72021-05-31 16:08:53 +0200633def parse_test_filter(test_filter):
634 f = test_filter
juraj.linkes184870a2018-07-16 14:22:01 +0200635 filter_file_name = None
636 filter_class_name = None
637 filter_func_name = None
638 if f:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200639 if "." in f:
640 parts = f.split(".")
juraj.linkes184870a2018-07-16 14:22:01 +0200641 if len(parts) > 3:
Klement Sekera08c50e32023-04-14 17:44:04 +0200642 raise Exception(f"Invalid test filter: {test_filter}")
juraj.linkes184870a2018-07-16 14:22:01 +0200643 if len(parts) > 2:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200644 if parts[2] not in ("*", ""):
juraj.linkes184870a2018-07-16 14:22:01 +0200645 filter_func_name = parts[2]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200646 if parts[1] not in ("*", ""):
juraj.linkes184870a2018-07-16 14:22:01 +0200647 filter_class_name = parts[1]
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200648 if parts[0] not in ("*", ""):
649 if parts[0].startswith("test_"):
juraj.linkes184870a2018-07-16 14:22:01 +0200650 filter_file_name = parts[0]
651 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200652 filter_file_name = "test_%s" % parts[0]
juraj.linkes184870a2018-07-16 14:22:01 +0200653 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200654 if f.startswith("test_"):
juraj.linkes184870a2018-07-16 14:22:01 +0200655 filter_file_name = f
656 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200657 filter_file_name = "test_%s" % f
juraj.linkes184870a2018-07-16 14:22:01 +0200658 if filter_file_name:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200659 filter_file_name = "%s.py" % filter_file_name
juraj.linkes184870a2018-07-16 14:22:01 +0200660 return filter_file_name, filter_class_name, filter_func_name
661
662
663def filter_tests(tests, filter_cb):
Klement Sekera558ceab2021-04-08 19:37:41 +0200664 result = TestSuiteWrapper()
juraj.linkes184870a2018-07-16 14:22:01 +0200665 for t in tests:
666 if isinstance(t, unittest.suite.TestSuite):
667 # this is a bunch of tests, recursively filter...
668 x = filter_tests(t, filter_cb)
669 if x.countTestCases() > 0:
670 result.addTest(x)
671 elif isinstance(t, unittest.TestCase):
672 # this is a single test
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200673 parts = t.id().split(".")
juraj.linkes184870a2018-07-16 14:22:01 +0200674 # t.id() for common cases like this:
675 # test_classifier.TestClassifier.test_acl_ip
676 # apply filtering only if it is so
677 if len(parts) == 3:
678 if not filter_cb(parts[0], parts[1], parts[2]):
679 continue
680 result.addTest(t)
681 else:
682 # unexpected object, don't touch it
683 result.addTest(t)
684 return result
685
686
687class FilterByTestOption:
Klement Sekera08c50e32023-04-14 17:44:04 +0200688 def __init__(self, filters):
689 self.filters = filters
juraj.linkes184870a2018-07-16 14:22:01 +0200690
691 def __call__(self, file_name, class_name, func_name):
Klement Sekera08c50e32023-04-14 17:44:04 +0200692 def test_one(
693 filter_file_name,
694 filter_class_name,
695 filter_func_name,
696 file_name,
697 class_name,
698 func_name,
699 ):
700 if filter_file_name:
701 fn_match = fnmatch.fnmatch(file_name, filter_file_name)
702 if not fn_match:
703 return False
704 if filter_class_name and class_name != filter_class_name:
Andrew Yourtchenkod760f792018-10-03 11:38:31 +0200705 return False
Klement Sekera08c50e32023-04-14 17:44:04 +0200706 if filter_func_name and func_name != filter_func_name:
707 return False
708 return True
709
710 for filter_file_name, filter_class_name, filter_func_name in self.filters:
711 if test_one(
712 filter_file_name,
713 filter_class_name,
714 filter_func_name,
715 file_name,
716 class_name,
717 func_name,
718 ):
719 return True
720
721 return False
juraj.linkes184870a2018-07-16 14:22:01 +0200722
723
724class FilterByClassList:
juraj.linkes721872e2018-09-05 18:13:45 +0200725 def __init__(self, classes_with_filenames):
726 self.classes_with_filenames = classes_with_filenames
Klement Sekeradf2b9802017-10-05 10:26:03 +0200727
728 def __call__(self, file_name, class_name, func_name):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200729 return ".".join([file_name, class_name]) in self.classes_with_filenames
Klement Sekeradf2b9802017-10-05 10:26:03 +0200730
731
732def suite_from_failed(suite, failed):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200733 failed = {x.rsplit(".", 1)[0] for x in failed}
juraj.linkes184870a2018-07-16 14:22:01 +0200734 filter_cb = FilterByClassList(failed)
735 suite = filter_tests(suite, filter_cb)
Klement Sekera4c5422e2018-06-22 13:19:45 +0200736 return suite
Klement Sekeradf2b9802017-10-05 10:26:03 +0200737
738
juraj.linkescae64f82018-09-19 15:01:47 +0200739class AllResults(dict):
juraj.linkes184870a2018-07-16 14:22:01 +0200740 def __init__(self):
juraj.linkescae64f82018-09-19 15:01:47 +0200741 super(AllResults, self).__init__()
juraj.linkes184870a2018-07-16 14:22:01 +0200742 self.all_testcases = 0
juraj.linkescae64f82018-09-19 15:01:47 +0200743 self.results_per_suite = []
Klement Sekera47f35272023-03-29 16:04:58 +0200744 for trc in list(TestResultCode):
745 self[trc] = 0
juraj.linkes184870a2018-07-16 14:22:01 +0200746 self.rerun = []
juraj.linkescae64f82018-09-19 15:01:47 +0200747 self.testsuites_no_tests_run = []
Klement Sekera909a6a12017-08-08 04:33:53 +0200748
juraj.linkescae64f82018-09-19 15:01:47 +0200749 def add_results(self, result):
750 self.results_per_suite.append(result)
Klement Sekera47f35272023-03-29 16:04:58 +0200751 for trc in list(TestResultCode):
752 self[trc] += len(result[trc])
Klement Sekera05742262018-03-14 18:14:49 +0100753
juraj.linkescae64f82018-09-19 15:01:47 +0200754 def add_result(self, result):
juraj.linkes184870a2018-07-16 14:22:01 +0200755 retval = 0
juraj.linkescae64f82018-09-19 15:01:47 +0200756 self.all_testcases += result.testcase_suite.countTestCases()
juraj.linkes40dd73b2018-09-21 13:55:16 +0200757 self.add_results(result)
juraj.linkes184870a2018-07-16 14:22:01 +0200758
juraj.linkes40dd73b2018-09-21 13:55:16 +0200759 if result.no_tests_run():
juraj.linkescae64f82018-09-19 15:01:47 +0200760 self.testsuites_no_tests_run.append(result.testcase_suite)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200761 if result.crashed:
762 retval = -1
763 else:
764 retval = 1
765 elif not result.was_successful():
766 retval = 1
juraj.linkes184870a2018-07-16 14:22:01 +0200767
juraj.linkes184870a2018-07-16 14:22:01 +0200768 if retval != 0:
juraj.linkesabec0122018-11-16 17:28:56 +0100769 self.rerun.append(result.testcase_suite)
juraj.linkes184870a2018-07-16 14:22:01 +0200770
771 return retval
772
773 def print_results(self):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200774 print("")
juraj.linkes184870a2018-07-16 14:22:01 +0200775 print(double_line_delim)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200776 print("TEST RESULTS:")
Klement Sekera558ceab2021-04-08 19:37:41 +0200777
778 def indent_results(lines):
779 lines = list(filter(None, lines))
780 maximum = max(lines, key=lambda x: x.index(":"))
781 maximum = 4 + maximum.index(":")
782 for l in lines:
783 padding = " " * (maximum - l.index(":"))
784 print(f"{padding}{l}")
785
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200786 indent_results(
787 [
788 f"Scheduled tests: {self.all_testcases}",
Klement Sekera47f35272023-03-29 16:04:58 +0200789 f"Executed tests: {self[TestResultCode.TEST_RUN]}",
790 f"Passed tests: {colorize(self[TestResultCode.PASS], GREEN)}",
Dave Wallace940a70f2024-04-03 12:31:42 -0400791 (
792 f"Expected failures: {colorize(self[TestResultCode.EXPECTED_FAIL], GREEN)}"
793 if self[TestResultCode.EXPECTED_FAIL]
794 else None
795 ),
796 (
797 f"Skipped tests: {colorize(self[TestResultCode.SKIP], YELLOW)}"
798 if self[TestResultCode.SKIP]
799 else None
800 ),
801 (
802 f"Not Executed tests: {colorize(self.not_executed, RED)}"
803 if self.not_executed
804 else None
805 ),
806 (
807 f"Failures: {colorize(self[TestResultCode.FAIL], RED)}"
808 if self[TestResultCode.FAIL]
809 else None
810 ),
811 (
812 f"Unexpected passes: {colorize(self[TestResultCode.UNEXPECTED_PASS], RED)}"
813 if self[TestResultCode.UNEXPECTED_PASS]
814 else None
815 ),
816 (
817 f"Errors: {colorize(self[TestResultCode.ERROR], RED)}"
818 if self[TestResultCode.ERROR]
819 else None
820 ),
821 (
822 "Tests skipped due to lack of CPUS: "
823 f"{colorize(self[TestResultCode.SKIP_CPU_SHORTAGE], YELLOW)}"
824 if self[TestResultCode.SKIP_CPU_SHORTAGE]
825 else None
826 ),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200827 ]
828 )
juraj.linkes184870a2018-07-16 14:22:01 +0200829
830 if self.all_failed > 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200831 print("FAILURES AND ERRORS IN TESTS:")
juraj.linkescae64f82018-09-19 15:01:47 +0200832 for result in self.results_per_suite:
juraj.linkescae64f82018-09-19 15:01:47 +0200833 old_testcase_name = None
Klement Sekera47f35272023-03-29 16:04:58 +0200834 for tr_code, headline in (
835 (TestResultCode.FAIL, "FAILURE"),
836 (TestResultCode.ERROR, "ERROR"),
837 (TestResultCode.UNEXPECTED_PASS, "UNEXPECTED PASS"),
838 ):
839 if not result[tr_code]:
840 continue
841
842 for failed_test_id in result[tr_code]:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200843 new_testcase_name, test_name = result.get_testcase_names(
844 failed_test_id
845 )
juraj.linkescae64f82018-09-19 15:01:47 +0200846 if new_testcase_name != old_testcase_name:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200847 print(
Klement Sekera47f35272023-03-29 16:04:58 +0200848 f" Testcase name: {colorize(new_testcase_name, RED)}"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200849 )
juraj.linkescae64f82018-09-19 15:01:47 +0200850 old_testcase_name = new_testcase_name
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200851 print(
Klement Sekera47f35272023-03-29 16:04:58 +0200852 f" {headline}: {colorize(test_name, RED)} [{failed_test_id}]"
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200853 )
Klement Sekera47f35272023-03-29 16:04:58 +0200854
Naveen Joy2cbf2fb2019-03-06 10:41:06 -0800855 if self.testsuites_no_tests_run:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200856 print("TESTCASES WHERE NO TESTS WERE SUCCESSFULLY EXECUTED:")
juraj.linkes40dd73b2018-09-21 13:55:16 +0200857 tc_classes = set()
juraj.linkescae64f82018-09-19 15:01:47 +0200858 for testsuite in self.testsuites_no_tests_run:
859 for testcase in testsuite:
860 tc_classes.add(get_testcase_doc_name(testcase))
861 for tc_class in tc_classes:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200862 print(" {}".format(colorize(tc_class, RED)))
juraj.linkes184870a2018-07-16 14:22:01 +0200863
Klement Sekera47f35272023-03-29 16:04:58 +0200864 if self[TestResultCode.SKIP_CPU_SHORTAGE]:
Klement Sekera558ceab2021-04-08 19:37:41 +0200865 print()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200866 print(
867 colorize(
868 " SOME TESTS WERE SKIPPED BECAUSE THERE ARE NOT"
869 " ENOUGH CPUS AVAILABLE",
870 YELLOW,
871 )
872 )
juraj.linkes184870a2018-07-16 14:22:01 +0200873 print(double_line_delim)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200874 print("")
juraj.linkes184870a2018-07-16 14:22:01 +0200875
876 @property
juraj.linkescae64f82018-09-19 15:01:47 +0200877 def not_executed(self):
Klement Sekera47f35272023-03-29 16:04:58 +0200878 return self.all_testcases - self[TestResultCode.TEST_RUN]
juraj.linkescae64f82018-09-19 15:01:47 +0200879
880 @property
juraj.linkes184870a2018-07-16 14:22:01 +0200881 def all_failed(self):
Klement Sekera47f35272023-03-29 16:04:58 +0200882 return (
883 self[TestResultCode.FAIL]
884 + self[TestResultCode.ERROR]
885 + self[TestResultCode.UNEXPECTED_PASS]
886 )
juraj.linkes184870a2018-07-16 14:22:01 +0200887
888
889def parse_results(results):
890 """
juraj.linkescae64f82018-09-19 15:01:47 +0200891 Prints the number of scheduled, executed, not executed, passed, failed,
892 errored and skipped tests and details about failed and errored tests.
juraj.linkes184870a2018-07-16 14:22:01 +0200893
juraj.linkescae64f82018-09-19 15:01:47 +0200894 Also returns all suites where any test failed.
juraj.linkes184870a2018-07-16 14:22:01 +0200895
896 :param results:
897 :return:
898 """
899
juraj.linkescae64f82018-09-19 15:01:47 +0200900 results_per_suite = AllResults()
juraj.linkes184870a2018-07-16 14:22:01 +0200901 crashed = False
902 failed = False
juraj.linkescae64f82018-09-19 15:01:47 +0200903 for result in results:
904 result_code = results_per_suite.add_result(result)
juraj.linkes184870a2018-07-16 14:22:01 +0200905 if result_code == 1:
906 failed = True
907 elif result_code == -1:
908 crashed = True
909
910 results_per_suite.print_results()
911
912 if crashed:
913 return_code = -1
914 elif failed:
915 return_code = 1
916 else:
917 return_code = 0
918 return return_code, results_per_suite.rerun
919
920
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200921if __name__ == "__main__":
Klement Sekerab23ffd72021-05-31 16:08:53 +0200922 print(f"Config is: {config}")
Klement Sekera3f6ff192017-08-11 06:56:05 +0200923
Maxime Peim77caeb12023-11-14 15:26:41 +0100924 if config.api_preload:
925 VPPApiJSONFiles.load_api(apidir=config.extern_apidir + [config.vpp_install_dir])
926
Klement Sekerab23ffd72021-05-31 16:08:53 +0200927 if config.sanity:
928 print("Running sanity test case.")
929 try:
930 rc = sanity_run_vpp.main()
931 if rc != 0:
932 sys.exit(rc)
933 except Exception as e:
934 print(traceback.format_exc())
935 print("Couldn't run sanity test case.")
936 sys.exit(-1)
Klement Sekera3f6ff192017-08-11 06:56:05 +0200937
Andrew Yourtchenko42693522019-11-05 01:08:26 +0100938 test_finished_join_timeout = 15
939
Klement Sekerab23ffd72021-05-31 16:08:53 +0200940 debug_gdb = config.debug in ["gdb", "gdbserver", "attach"]
941 debug_core = config.debug == "core"
Klement Sekera3f6ff192017-08-11 06:56:05 +0200942
Klement Sekerab23ffd72021-05-31 16:08:53 +0200943 run_interactive = debug_gdb or config.step or config.force_foreground
juraj.linkes184870a2018-07-16 14:22:01 +0200944
Klement Sekera558ceab2021-04-08 19:37:41 +0200945 max_concurrent_tests = 0
946 print(f"OS reports {num_cpus} available cpu(s).")
Paul Vinciguerra025cd9c2019-07-08 14:14:22 -0400947
Klement Sekerab23ffd72021-05-31 16:08:53 +0200948 test_jobs = config.jobs
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200949 if test_jobs == "auto":
juraj.linkes184870a2018-07-16 14:22:01 +0200950 if run_interactive:
Klement Sekera558ceab2021-04-08 19:37:41 +0200951 max_concurrent_tests = 1
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200952 print("Interactive mode required, running tests consecutively.")
juraj.linkes184870a2018-07-16 14:22:01 +0200953 else:
Klement Sekera558ceab2021-04-08 19:37:41 +0200954 max_concurrent_tests = num_cpus
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200955 print(
956 f"Running at most {max_concurrent_tests} python test "
957 "processes concurrently."
958 )
juraj.linkes184870a2018-07-16 14:22:01 +0200959 else:
Klement Sekerab23ffd72021-05-31 16:08:53 +0200960 max_concurrent_tests = test_jobs
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200961 print(
962 f"Running at most {max_concurrent_tests} python test processes "
963 "concurrently as set by 'TEST_JOBS'."
964 )
juraj.linkes184870a2018-07-16 14:22:01 +0200965
Klement Sekera558ceab2021-04-08 19:37:41 +0200966 print(f"Using at most {max_vpp_cpus} cpus for VPP threads.")
967
968 if run_interactive and max_concurrent_tests > 1:
juraj.linkes184870a2018-07-16 14:22:01 +0200969 raise NotImplementedError(
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200970 "Running tests interactively (DEBUG is gdb[server] or ATTACH or "
971 "STEP is set) in parallel (TEST_JOBS is more than 1) is not "
972 "supported"
973 )
Klement Sekera13a83ef2018-03-21 12:35:51 +0100974
juraj.linkes184870a2018-07-16 14:22:01 +0200975 descriptions = True
Klement Sekera3f6ff192017-08-11 06:56:05 +0200976
Klement Sekera558ceab2021-04-08 19:37:41 +0200977 print("Running tests using custom test runner.")
Klement Sekera08c50e32023-04-14 17:44:04 +0200978 filters = [(parse_test_filter(f)) for f in config.filter.split(",")]
juraj.linkes184870a2018-07-16 14:22:01 +0200979
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200980 print(
Klement Sekera08c50e32023-04-14 17:44:04 +0200981 "Selected filters: ",
982 "|".join(
983 f"file={filter_file}, class={filter_class}, function={filter_func}"
984 for filter_file, filter_class, filter_func in filters
985 ),
Klement Sekerad9b0c6f2022-04-26 19:02:15 +0200986 )
juraj.linkes184870a2018-07-16 14:22:01 +0200987
Klement Sekera08c50e32023-04-14 17:44:04 +0200988 filter_cb = FilterByTestOption(filters)
juraj.linkes184870a2018-07-16 14:22:01 +0200989
990 cb = SplitToSuitesCallback(filter_cb)
Klement Sekerab23ffd72021-05-31 16:08:53 +0200991 for d in config.test_src_dir:
Klement Sekeradf2b9802017-10-05 10:26:03 +0200992 print("Adding tests from directory tree %s" % d)
Saima Yunusc7f93b32022-08-10 03:25:31 -0400993 discover_tests(d, cb)
Klement Sekera3f6ff192017-08-11 06:56:05 +0200994
juraj.linkes184870a2018-07-16 14:22:01 +0200995 # suites are not hashable, need to use list
996 suites = []
997 tests_amount = 0
998 for testcase_suite in cb.suites.values():
999 tests_amount += testcase_suite.countTestCases()
Klement Sekera558ceab2021-04-08 19:37:41 +02001000 if testcase_suite.cpus_used > max_vpp_cpus:
1001 # here we replace test functions with lambdas to just skip them
1002 # but we also replace setUp/tearDown functions to do nothing
1003 # so that the test can be "started" and "stopped", so that we can
1004 # still keep those prints (test description - SKIP), which are done
1005 # in stopTest() (for that to trigger, test function must run)
1006 for t in testcase_suite:
1007 for m in dir(t):
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001008 if m.startswith("test_"):
Klement Sekera558ceab2021-04-08 19:37:41 +02001009 setattr(t, m, lambda: t.skipTest("not enough cpus"))
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001010 setattr(t.__class__, "setUpClass", lambda: None)
1011 setattr(t.__class__, "tearDownClass", lambda: None)
1012 setattr(t, "setUp", lambda: None)
1013 setattr(t, "tearDown", lambda: None)
Klement Sekera558ceab2021-04-08 19:37:41 +02001014 t.__class__.skipped_due_to_cpu_lack = True
juraj.linkes184870a2018-07-16 14:22:01 +02001015 suites.append(testcase_suite)
Klement Sekerabbfa5fd2018-06-27 13:54:32 +02001016
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001017 print(
1018 "%s out of %s tests match specified filters"
1019 % (tests_amount, tests_amount + cb.filtered.countTestCases())
1020 )
juraj.linkes184870a2018-07-16 14:22:01 +02001021
Klement Sekerab23ffd72021-05-31 16:08:53 +02001022 if not config.extended:
juraj.linkes184870a2018-07-16 14:22:01 +02001023 print("Not running extended tests (some tests will be skipped)")
1024
Klement Sekerab23ffd72021-05-31 16:08:53 +02001025 attempts = config.retries + 1
Klement Sekeradf2b9802017-10-05 10:26:03 +02001026 if attempts > 1:
1027 print("Perform %s attempts to pass the suite..." % attempts)
juraj.linkes184870a2018-07-16 14:22:01 +02001028
Naveen Joy2cbf2fb2019-03-06 10:41:06 -08001029 if run_interactive and suites:
juraj.linkes184870a2018-07-16 14:22:01 +02001030 # don't fork if requiring interactive terminal
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001031 print("Running tests in foreground in the current process")
juraj.linkes46e8e912019-01-10 12:13:07 +01001032 full_suite = unittest.TestSuite()
Klement Sekera558ceab2021-04-08 19:37:41 +02001033 free_cpus = list(available_cpus)
1034 cpu_shortage = False
1035 for suite in suites:
1036 if suite.cpus_used <= max_vpp_cpus:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001037 suite.assign_cpus(free_cpus[: suite.cpus_used])
Klement Sekera558ceab2021-04-08 19:37:41 +02001038 else:
1039 suite.assign_cpus([])
1040 cpu_shortage = True
Klement Sekerad743dff2019-10-29 11:03:47 +00001041 full_suite.addTests(suites)
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001042 result = VppTestRunner(
1043 verbosity=config.verbose, failfast=config.failfast, print_summary=True
1044 ).run(full_suite)
juraj.linkes40dd73b2018-09-21 13:55:16 +02001045 was_successful = result.wasSuccessful()
1046 if not was_successful:
1047 for test_case_info in result.failed_test_cases_info:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001048 handle_failed_suite(
1049 test_case_info.logger,
1050 test_case_info.tempdir,
1051 test_case_info.vpp_pid,
1052 config.vpp,
1053 )
Klement Sekeraf40ee3a2019-05-06 19:11:25 +02001054 if test_case_info in result.core_crash_test_cases_info:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001055 check_and_handle_core(
1056 test_case_info.vpp_bin_path,
1057 test_case_info.tempdir,
1058 test_case_info.core_crash_test,
1059 )
juraj.linkes40dd73b2018-09-21 13:55:16 +02001060
Klement Sekera558ceab2021-04-08 19:37:41 +02001061 if cpu_shortage:
1062 print()
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001063 print(
1064 colorize(
1065 "SOME TESTS WERE SKIPPED BECAUSE THERE ARE NOT"
1066 " ENOUGH CPUS AVAILABLE",
1067 YELLOW,
1068 )
1069 )
Klement Sekera558ceab2021-04-08 19:37:41 +02001070 print()
juraj.linkes40dd73b2018-09-21 13:55:16 +02001071 sys.exit(not was_successful)
Klement Sekera13a83ef2018-03-21 12:35:51 +01001072 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001073 print(
1074 "Running each VPPTestCase in a separate background process"
1075 f" with at most {max_concurrent_tests} parallel python test "
1076 "process(es)"
1077 )
juraj.linkes184870a2018-07-16 14:22:01 +02001078 exit_code = 0
Naveen Joy2cbf2fb2019-03-06 10:41:06 -08001079 while suites and attempts > 0:
Dave Wallace8800f732023-08-31 00:47:44 -04001080 for suite in suites:
1081 failed_link = get_failed_testcase_linkname(
1082 config.failed_dir,
1083 f"{get_testcase_dirname(suite._tests[0].__class__.__name__)}",
1084 )
1085 if os.path.islink(failed_link):
1086 os.unlink(failed_link)
juraj.linkes184870a2018-07-16 14:22:01 +02001087 results = run_forked(suites)
1088 exit_code, suites = parse_results(results)
1089 attempts -= 1
1090 if exit_code == 0:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001091 print("Test run was successful")
juraj.linkes184870a2018-07-16 14:22:01 +02001092 else:
Klement Sekerad9b0c6f2022-04-26 19:02:15 +02001093 print("%s attempt(s) left." % attempts)
juraj.linkes184870a2018-07-16 14:22:01 +02001094 sys.exit(exit_code)