blob: 2bbb4ce44f7029a537cc0e1202406589e04da1d5 [file] [log] [blame]
Damjan Marionf56b77a2016-10-03 19:44:57 +02001#!/usr/bin/env python
Damjan Marionf56b77a2016-10-03 19:44:57 +02002
Klement Sekeraacb9b8e2017-02-14 02:55:31 +01003from __future__ import print_function
4import gc
Paul Vinciguerra72f00042018-11-25 11:05:13 -08005import sys
Ole Trøan162989e2018-11-26 10:27:50 +00006import os
7import select
8import unittest
Klement Sekeraf62ae122016-10-11 11:47:09 +02009import tempfile
Klement Sekera277b89c2016-10-28 13:20:27 +020010import time
Paul Vinciguerra72f00042018-11-25 11:05:13 -080011import faulthandler
Ole Trøan162989e2018-11-26 10:27:50 +000012import random
13import copy
Paul Vinciguerra72f00042018-11-25 11:05:13 -080014import psutil
Ole Trøan162989e2018-11-26 10:27:50 +000015from collections import deque
16from threading import Thread, Event
17from inspect import getdoc, isclass
18from traceback import format_exception
19from logging import FileHandler, DEBUG, Formatter
20from scapy.packet import Raw
21from hook import StepHook, PollHook, VppDiedError
22from vpp_pg_interface import VppPGInterface
23from vpp_sub_interface import VppSubInterface
24from vpp_lo_interface import VppLoInterface
25from vpp_papi_provider import VppPapiProvider
26from vpp_papi.vpp_stats import VPPStats
27from log import RED, GREEN, YELLOW, double_line_delim, single_line_delim, \
28 get_logger, colorize
29from vpp_object import VppObjectRegistry
30from util import ppp, is_core_present
Klement Sekerad81ae412018-05-16 10:52:54 +020031from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror
32from scapy.layers.inet6 import ICMPv6DestUnreach, ICMPv6EchoRequest
33from scapy.layers.inet6 import ICMPv6EchoReply
Klement Sekeraacb9b8e2017-02-14 02:55:31 +010034if os.name == 'posix' and sys.version_info[0] < 3:
35 # using subprocess32 is recommended by python official documentation
36 # @ https://docs.python.org/2/library/subprocess.html
37 import subprocess32 as subprocess
38else:
39 import subprocess
Klement Sekeraf62ae122016-10-11 11:47:09 +020040
Klement Sekerad81ae412018-05-16 10:52:54 +020041
juraj.linkescae64f82018-09-19 15:01:47 +020042PASS = 0
43FAIL = 1
44ERROR = 2
45SKIP = 3
46TEST_RUN = 4
47
48
Klement Sekeraebbaf552018-02-17 13:41:33 +010049debug_framework = False
50if os.getenv('TEST_DEBUG', "0") == "1":
51 debug_framework = True
52 import debug_internal
53
54
Klement Sekeraf62ae122016-10-11 11:47:09 +020055"""
56 Test framework module.
57
58 The module provides a set of tools for constructing and running tests and
59 representing the results.
60"""
61
Klement Sekeraf62ae122016-10-11 11:47:09 +020062
Damjan Marionf56b77a2016-10-03 19:44:57 +020063class _PacketInfo(object):
Klement Sekeraf62ae122016-10-11 11:47:09 +020064 """Private class to create packet info object.
65
66 Help process information about the next packet.
67 Set variables to default values.
Klement Sekeraf62ae122016-10-11 11:47:09 +020068 """
Matej Klotton86d87c42016-11-11 11:38:55 +010069 #: Store the index of the packet.
Damjan Marionf56b77a2016-10-03 19:44:57 +020070 index = -1
Matej Klotton86d87c42016-11-11 11:38:55 +010071 #: Store the index of the source packet generator interface of the packet.
Damjan Marionf56b77a2016-10-03 19:44:57 +020072 src = -1
Matej Klotton86d87c42016-11-11 11:38:55 +010073 #: Store the index of the destination packet generator interface
74 #: of the packet.
Damjan Marionf56b77a2016-10-03 19:44:57 +020075 dst = -1
Pavel Kotucek59dda062017-03-02 15:22:47 +010076 #: Store expected ip version
77 ip = -1
78 #: Store expected upper protocol
79 proto = -1
Matej Klotton86d87c42016-11-11 11:38:55 +010080 #: Store the copy of the former packet.
Damjan Marionf56b77a2016-10-03 19:44:57 +020081 data = None
Damjan Marionf56b77a2016-10-03 19:44:57 +020082
Matej Klotton16a14cd2016-12-07 15:09:13 +010083 def __eq__(self, other):
84 index = self.index == other.index
85 src = self.src == other.src
86 dst = self.dst == other.dst
87 data = self.data == other.data
88 return index and src and dst and data
89
Klement Sekeraf62ae122016-10-11 11:47:09 +020090
Klement Sekeraacb9b8e2017-02-14 02:55:31 +010091def pump_output(testclass):
92 """ pump output from vpp stdout/stderr to proper queues """
Klement Sekera6a6f4f72017-11-09 09:16:39 +010093 stdout_fragment = ""
94 stderr_fragment = ""
Neale Ranns16782362018-07-23 05:35:56 -040095 while not testclass.pump_thread_stop_flag.is_set():
Klement Sekeraacb9b8e2017-02-14 02:55:31 +010096 readable = select.select([testclass.vpp.stdout.fileno(),
97 testclass.vpp.stderr.fileno(),
98 testclass.pump_thread_wakeup_pipe[0]],
99 [], [])[0]
100 if testclass.vpp.stdout.fileno() in readable:
Klement Sekera6a6f4f72017-11-09 09:16:39 +0100101 read = os.read(testclass.vpp.stdout.fileno(), 102400)
102 if len(read) > 0:
103 split = read.splitlines(True)
104 if len(stdout_fragment) > 0:
105 split[0] = "%s%s" % (stdout_fragment, split[0])
106 if len(split) > 0 and split[-1].endswith("\n"):
107 limit = None
108 else:
109 limit = -1
110 stdout_fragment = split[-1]
111 testclass.vpp_stdout_deque.extend(split[:limit])
112 if not testclass.cache_vpp_output:
113 for line in split[:limit]:
114 testclass.logger.debug(
115 "VPP STDOUT: %s" % line.rstrip("\n"))
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100116 if testclass.vpp.stderr.fileno() in readable:
Klement Sekera6a6f4f72017-11-09 09:16:39 +0100117 read = os.read(testclass.vpp.stderr.fileno(), 102400)
118 if len(read) > 0:
119 split = read.splitlines(True)
120 if len(stderr_fragment) > 0:
121 split[0] = "%s%s" % (stderr_fragment, split[0])
122 if len(split) > 0 and split[-1].endswith("\n"):
123 limit = None
124 else:
125 limit = -1
126 stderr_fragment = split[-1]
127 testclass.vpp_stderr_deque.extend(split[:limit])
128 if not testclass.cache_vpp_output:
129 for line in split[:limit]:
130 testclass.logger.debug(
131 "VPP STDERR: %s" % line.rstrip("\n"))
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100132 # ignoring the dummy pipe here intentionally - the flag will take care
133 # of properly terminating the loop
Klement Sekera277b89c2016-10-28 13:20:27 +0200134
135
Klement Sekera87134932017-03-07 11:39:27 +0100136def running_extended_tests():
Klement Sekera13a83ef2018-03-21 12:35:51 +0100137 s = os.getenv("EXTENDED_TESTS", "n")
138 return True if s.lower() in ("y", "yes", "1") else False
Klement Sekera87134932017-03-07 11:39:27 +0100139
140
Klement Sekerad3e671e2017-09-29 12:36:37 +0200141def running_on_centos():
Klement Sekera13a83ef2018-03-21 12:35:51 +0100142 os_id = os.getenv("OS_ID", "")
143 return True if "centos" in os_id.lower() else False
Klement Sekerad3e671e2017-09-29 12:36:37 +0200144
145
Klement Sekera909a6a12017-08-08 04:33:53 +0200146class KeepAliveReporter(object):
147 """
148 Singleton object which reports test start to parent process
149 """
150 _shared_state = {}
151
152 def __init__(self):
153 self.__dict__ = self._shared_state
Paul Vinciguerrac7b03fe2018-11-18 08:17:34 -0800154 self._pipe = None
Klement Sekera909a6a12017-08-08 04:33:53 +0200155
156 @property
157 def pipe(self):
158 return self._pipe
159
160 @pipe.setter
161 def pipe(self, pipe):
Paul Vinciguerrac7b03fe2018-11-18 08:17:34 -0800162 if self._pipe is not None:
Klement Sekera909a6a12017-08-08 04:33:53 +0200163 raise Exception("Internal error - pipe should only be set once.")
164 self._pipe = pipe
165
juraj.linkes40dd73b2018-09-21 13:55:16 +0200166 def send_keep_alive(self, test, desc=None):
Klement Sekera909a6a12017-08-08 04:33:53 +0200167 """
168 Write current test tmpdir & desc to keep-alive pipe to signal liveness
169 """
Klement Sekera3f6ff192017-08-11 06:56:05 +0200170 if self.pipe is None:
171 # if not running forked..
172 return
173
Klement Sekera909a6a12017-08-08 04:33:53 +0200174 if isclass(test):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200175 desc = '%s (%s)' % (desc, unittest.util.strclass(test))
Klement Sekera909a6a12017-08-08 04:33:53 +0200176 else:
juraj.linkes40dd73b2018-09-21 13:55:16 +0200177 desc = test.id()
Klement Sekera909a6a12017-08-08 04:33:53 +0200178
Dave Wallacee2efd122017-09-30 22:04:21 -0400179 self.pipe.send((desc, test.vpp_bin, test.tempdir, test.vpp.pid))
Klement Sekera909a6a12017-08-08 04:33:53 +0200180
181
Damjan Marionf56b77a2016-10-03 19:44:57 +0200182class VppTestCase(unittest.TestCase):
Matej Klotton86d87c42016-11-11 11:38:55 +0100183 """This subclass is a base class for VPP test cases that are implemented as
184 classes. It provides methods to create and run test case.
Klement Sekeraf62ae122016-10-11 11:47:09 +0200185 """
186
187 @property
188 def packet_infos(self):
189 """List of packet infos"""
190 return self._packet_infos
191
Klement Sekeradab231a2016-12-21 08:50:14 +0100192 @classmethod
193 def get_packet_count_for_if_idx(cls, dst_if_index):
194 """Get the number of packet info for specified destination if index"""
195 if dst_if_index in cls._packet_count_for_dst_if_idx:
196 return cls._packet_count_for_dst_if_idx[dst_if_index]
197 else:
198 return 0
Klement Sekeraf62ae122016-10-11 11:47:09 +0200199
200 @classmethod
201 def instance(cls):
202 """Return the instance of this testcase"""
203 return cls.test_instance
204
Damjan Marionf56b77a2016-10-03 19:44:57 +0200205 @classmethod
Klement Sekera277b89c2016-10-28 13:20:27 +0200206 def set_debug_flags(cls, d):
207 cls.debug_core = False
208 cls.debug_gdb = False
209 cls.debug_gdbserver = False
210 if d is None:
211 return
212 dl = d.lower()
213 if dl == "core":
Klement Sekera277b89c2016-10-28 13:20:27 +0200214 cls.debug_core = True
215 elif dl == "gdb":
216 cls.debug_gdb = True
217 elif dl == "gdbserver":
218 cls.debug_gdbserver = True
219 else:
220 raise Exception("Unrecognized DEBUG option: '%s'" % d)
221
Paul Vinciguerra86ebba62018-11-21 09:28:32 -0800222 @staticmethod
223 def get_least_used_cpu():
juraj.linkes184870a2018-07-16 14:22:01 +0200224 cpu_usage_list = [set(range(psutil.cpu_count()))]
225 vpp_processes = [p for p in psutil.process_iter(attrs=['pid', 'name'])
226 if 'vpp_main' == p.info['name']]
227 for vpp_process in vpp_processes:
228 for cpu_usage_set in cpu_usage_list:
229 try:
230 cpu_num = vpp_process.cpu_num()
231 if cpu_num in cpu_usage_set:
232 cpu_usage_set_index = cpu_usage_list.index(
233 cpu_usage_set)
234 if cpu_usage_set_index == len(cpu_usage_list) - 1:
235 cpu_usage_list.append({cpu_num})
236 else:
237 cpu_usage_list[cpu_usage_set_index + 1].add(
238 cpu_num)
239 cpu_usage_set.remove(cpu_num)
240 break
241 except psutil.NoSuchProcess:
242 pass
243
244 for cpu_usage_set in cpu_usage_list:
245 if len(cpu_usage_set) > 0:
246 min_usage_set = cpu_usage_set
247 break
248
249 return random.choice(tuple(min_usage_set))
250
Paul Vinciguerra86ebba62018-11-21 09:28:32 -0800251 @classmethod
juraj.linkes40dd73b2018-09-21 13:55:16 +0200252 def print_header(cls):
253 if not hasattr(cls, '_header_printed'):
254 print(double_line_delim)
255 print(colorize(getdoc(cls).splitlines()[0], GREEN))
256 print(double_line_delim)
257 cls._header_printed = True
258
juraj.linkes184870a2018-07-16 14:22:01 +0200259 @classmethod
Damjan Marionf56b77a2016-10-03 19:44:57 +0200260 def setUpConstants(cls):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200261 """ Set-up the test case class based on environment variables """
Klement Sekera13a83ef2018-03-21 12:35:51 +0100262 s = os.getenv("STEP", "n")
263 cls.step = True if s.lower() in ("y", "yes", "1") else False
264 d = os.getenv("DEBUG", None)
265 c = os.getenv("CACHE_OUTPUT", "1")
266 cls.cache_vpp_output = False if c.lower() in ("n", "no", "0") else True
Klement Sekera277b89c2016-10-28 13:20:27 +0200267 cls.set_debug_flags(d)
Klement Sekerab8c72a42018-11-08 11:21:39 +0100268 cls.vpp_bin = os.getenv('VPP_BIN', "vpp")
269 cls.plugin_path = os.getenv('VPP_PLUGIN_PATH')
Klement Sekera47e275b2017-03-21 08:21:25 +0100270 cls.extern_plugin_path = os.getenv('EXTERN_PLUGINS')
271 plugin_path = None
272 if cls.plugin_path is not None:
273 if cls.extern_plugin_path is not None:
274 plugin_path = "%s:%s" % (
275 cls.plugin_path, cls.extern_plugin_path)
Klement Sekera6abbc282017-03-24 05:47:15 +0100276 else:
277 plugin_path = cls.plugin_path
Klement Sekera47e275b2017-03-21 08:21:25 +0100278 elif cls.extern_plugin_path is not None:
279 plugin_path = cls.extern_plugin_path
Klement Sekera01bbbe92016-11-02 09:25:05 +0100280 debug_cli = ""
281 if cls.step or cls.debug_gdb or cls.debug_gdbserver:
282 debug_cli = "cli-listen localhost:5002"
Klement Sekera80a7f0a2017-03-02 11:27:11 +0100283 coredump_size = None
Klement Sekera13a83ef2018-03-21 12:35:51 +0100284 size = os.getenv("COREDUMP_SIZE")
285 if size is not None:
286 coredump_size = "coredump-size %s" % size
Klement Sekera80a7f0a2017-03-02 11:27:11 +0100287 if coredump_size is None:
Dave Wallacee2efd122017-09-30 22:04:21 -0400288 coredump_size = "coredump-size unlimited"
juraj.linkes184870a2018-07-16 14:22:01 +0200289
290 cpu_core_number = cls.get_least_used_cpu()
291
Klement Sekera80a7f0a2017-03-02 11:27:11 +0100292 cls.vpp_cmdline = [cls.vpp_bin, "unix",
Dave Wallacee2efd122017-09-30 22:04:21 -0400293 "{", "nodaemon", debug_cli, "full-coredump",
Jakub Grajciar99743912018-10-09 12:28:21 +0200294 coredump_size, "runtime-dir", cls.tempdir, "}",
295 "api-trace", "{", "on", "}", "api-segment", "{",
296 "prefix", cls.shm_prefix, "}", "cpu", "{",
297 "main-core", str(cpu_core_number), "}", "statseg",
298 "{", "socket-name", cls.stats_sock, "}", "plugins",
299 "{", "plugin", "dpdk_plugin.so", "{", "disable",
300 "}", "plugin", "unittest_plugin.so", "{", "enable",
301 "}", "}", ]
Klement Sekera47e275b2017-03-21 08:21:25 +0100302 if plugin_path is not None:
303 cls.vpp_cmdline.extend(["plugin_path", plugin_path])
Klement Sekeraf37c3ba2018-11-08 11:24:34 +0100304 cls.logger.info("vpp_cmdline args: %s" % cls.vpp_cmdline)
305 cls.logger.info("vpp_cmdline: %s" % " ".join(cls.vpp_cmdline))
Klement Sekera277b89c2016-10-28 13:20:27 +0200306
307 @classmethod
308 def wait_for_enter(cls):
309 if cls.debug_gdbserver:
310 print(double_line_delim)
311 print("Spawned GDB server with PID: %d" % cls.vpp.pid)
312 elif cls.debug_gdb:
313 print(double_line_delim)
314 print("Spawned VPP with PID: %d" % cls.vpp.pid)
315 else:
316 cls.logger.debug("Spawned VPP with PID: %d" % cls.vpp.pid)
317 return
318 print(single_line_delim)
319 print("You can debug the VPP using e.g.:")
320 if cls.debug_gdbserver:
321 print("gdb " + cls.vpp_bin + " -ex 'target remote localhost:7777'")
322 print("Now is the time to attach a gdb by running the above "
323 "command, set up breakpoints etc. and then resume VPP from "
324 "within gdb by issuing the 'continue' command")
325 elif cls.debug_gdb:
326 print("gdb " + cls.vpp_bin + " -ex 'attach %s'" % cls.vpp.pid)
327 print("Now is the time to attach a gdb by running the above "
328 "command and set up breakpoints etc.")
329 print(single_line_delim)
Ole Trøan162989e2018-11-26 10:27:50 +0000330 raw_input("Press ENTER to continue running the testcase...")
Klement Sekera277b89c2016-10-28 13:20:27 +0200331
332 @classmethod
333 def run_vpp(cls):
334 cmdline = cls.vpp_cmdline
335
336 if cls.debug_gdbserver:
Klement Sekera931be3a2016-11-03 05:36:01 +0100337 gdbserver = '/usr/bin/gdbserver'
338 if not os.path.isfile(gdbserver) or \
339 not os.access(gdbserver, os.X_OK):
340 raise Exception("gdbserver binary '%s' does not exist or is "
341 "not executable" % gdbserver)
342
343 cmdline = [gdbserver, 'localhost:7777'] + cls.vpp_cmdline
Klement Sekera277b89c2016-10-28 13:20:27 +0200344 cls.logger.info("Gdbserver cmdline is %s", " ".join(cmdline))
345
Klement Sekera931be3a2016-11-03 05:36:01 +0100346 try:
347 cls.vpp = subprocess.Popen(cmdline,
348 stdout=subprocess.PIPE,
349 stderr=subprocess.PIPE,
350 bufsize=1)
Paul Vinciguerra61e63bf2018-11-24 21:19:38 -0800351 except subprocess.CalledProcessError as e:
Klement Sekera931be3a2016-11-03 05:36:01 +0100352 cls.logger.critical("Couldn't start vpp: %s" % e)
353 raise
354
Klement Sekera277b89c2016-10-28 13:20:27 +0200355 cls.wait_for_enter()
Pierre Pfistercd8e3182016-10-07 16:30:03 +0100356
Damjan Marionf56b77a2016-10-03 19:44:57 +0200357 @classmethod
Klement Sekera611864f2018-09-26 11:19:00 +0200358 def wait_for_stats_socket(cls):
359 deadline = time.time() + 3
Paul Vinciguerradd4b2bb2018-11-15 08:13:03 -0800360 ok = False
361 while time.time() < deadline or \
362 cls.debug_gdb or cls.debug_gdbserver:
Klement Sekera611864f2018-09-26 11:19:00 +0200363 if os.path.exists(cls.stats_sock):
Paul Vinciguerradd4b2bb2018-11-15 08:13:03 -0800364 ok = True
Klement Sekera611864f2018-09-26 11:19:00 +0200365 break
Paul Vinciguerradd4b2bb2018-11-15 08:13:03 -0800366 time.sleep(0.8)
367 if not ok:
368 cls.logger.critical("Couldn't stat : {}".format(cls.stats_sock))
Klement Sekera611864f2018-09-26 11:19:00 +0200369
370 @classmethod
Damjan Marionf56b77a2016-10-03 19:44:57 +0200371 def setUpClass(cls):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200372 """
373 Perform class setup before running the testcase
374 Remove shared memory files, start vpp and connect the vpp-api
375 """
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100376 gc.collect() # run garbage collection first
Klement Sekera96867ba2018-02-02 11:27:53 +0100377 random.seed()
Paul Vinciguerra86ebba62018-11-21 09:28:32 -0800378 cls.print_header()
juraj.linkesdfb5f2a2018-11-09 11:58:54 +0100379 cls.logger = get_logger(cls.__name__)
380 if hasattr(cls, 'parallel_handler'):
381 cls.logger.addHandler(cls.parallel_handler)
juraj.linkes3d9b92a2018-11-21 13:13:39 +0100382 cls.logger.propagate = False
Klement Sekeraf62ae122016-10-11 11:47:09 +0200383 cls.tempdir = tempfile.mkdtemp(
Klement Sekeraf413bef2017-08-15 07:09:02 +0200384 prefix='vpp-unittest-%s-' % cls.__name__)
Klement Sekera611864f2018-09-26 11:19:00 +0200385 cls.stats_sock = "%s/stats.sock" % cls.tempdir
Klement Sekera027dbd52017-04-11 06:01:53 +0200386 cls.file_handler = FileHandler("%s/log.txt" % cls.tempdir)
387 cls.file_handler.setFormatter(
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100388 Formatter(fmt='%(asctime)s,%(msecs)03d %(message)s',
389 datefmt="%H:%M:%S"))
Klement Sekera027dbd52017-04-11 06:01:53 +0200390 cls.file_handler.setLevel(DEBUG)
391 cls.logger.addHandler(cls.file_handler)
juraj.linkes184870a2018-07-16 14:22:01 +0200392 cls.shm_prefix = os.path.basename(cls.tempdir)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200393 os.chdir(cls.tempdir)
Klement Sekera277b89c2016-10-28 13:20:27 +0200394 cls.logger.info("Temporary dir is %s, shm prefix is %s",
395 cls.tempdir, cls.shm_prefix)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200396 cls.setUpConstants()
Klement Sekeradab231a2016-12-21 08:50:14 +0100397 cls.reset_packet_infos()
Klement Sekera9225dee2016-12-12 08:36:58 +0100398 cls._captures = []
399 cls._zombie_captures = []
Klement Sekeraf62ae122016-10-11 11:47:09 +0200400 cls.verbose = 0
Klement Sekera085f5c02016-11-24 01:59:16 +0100401 cls.vpp_dead = False
Klement Sekera10db26f2017-01-11 08:16:53 +0100402 cls.registry = VppObjectRegistry()
Klement Sekera3747c752017-04-10 06:30:17 +0200403 cls.vpp_startup_failed = False
Klement Sekera909a6a12017-08-08 04:33:53 +0200404 cls.reporter = KeepAliveReporter()
Klement Sekeraf62ae122016-10-11 11:47:09 +0200405 # need to catch exceptions here because if we raise, then the cleanup
406 # doesn't get called and we might end with a zombie vpp
407 try:
Klement Sekera277b89c2016-10-28 13:20:27 +0200408 cls.run_vpp()
juraj.linkes40dd73b2018-09-21 13:55:16 +0200409 cls.reporter.send_keep_alive(cls, 'setUpClass')
410 VppTestResult.current_test_case_info = TestCaseInfo(
411 cls.logger, cls.tempdir, cls.vpp.pid, cls.vpp_bin)
Klement Sekerae4504c62016-12-08 10:16:41 +0100412 cls.vpp_stdout_deque = deque()
Klement Sekerae4504c62016-12-08 10:16:41 +0100413 cls.vpp_stderr_deque = deque()
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100414 cls.pump_thread_stop_flag = Event()
415 cls.pump_thread_wakeup_pipe = os.pipe()
416 cls.pump_thread = Thread(target=pump_output, args=(cls,))
Klement Sekeraaeeac3b2017-02-14 07:11:52 +0100417 cls.pump_thread.daemon = True
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100418 cls.pump_thread.start()
Klement Sekera611864f2018-09-26 11:19:00 +0200419 if cls.debug_gdb or cls.debug_gdbserver:
420 read_timeout = 0
421 else:
422 read_timeout = 5
423 cls.vapi = VppPapiProvider(cls.shm_prefix, cls.shm_prefix, cls,
424 read_timeout)
Klement Sekera085f5c02016-11-24 01:59:16 +0100425 if cls.step:
426 hook = StepHook(cls)
427 else:
428 hook = PollHook(cls)
429 cls.vapi.register_hook(hook)
Klement Sekera611864f2018-09-26 11:19:00 +0200430 cls.wait_for_stats_socket()
431 cls.statistics = VPPStats(socketname=cls.stats_sock)
Klement Sekera3747c752017-04-10 06:30:17 +0200432 try:
433 hook.poll_vpp()
Klement Sekera13a83ef2018-03-21 12:35:51 +0100434 except VppDiedError:
Klement Sekera3747c752017-04-10 06:30:17 +0200435 cls.vpp_startup_failed = True
436 cls.logger.critical(
437 "VPP died shortly after startup, check the"
438 " output to standard error for possible cause")
439 raise
Klement Sekera085f5c02016-11-24 01:59:16 +0100440 try:
441 cls.vapi.connect()
Klement Sekera13a83ef2018-03-21 12:35:51 +0100442 except Exception:
Klement Sekera4c533132018-02-22 11:41:12 +0100443 try:
444 cls.vapi.disconnect()
Klement Sekera13a83ef2018-03-21 12:35:51 +0100445 except Exception:
Klement Sekera4c533132018-02-22 11:41:12 +0100446 pass
Klement Sekera085f5c02016-11-24 01:59:16 +0100447 if cls.debug_gdbserver:
448 print(colorize("You're running VPP inside gdbserver but "
449 "VPP-API connection failed, did you forget "
450 "to 'continue' VPP from within gdb?", RED))
451 raise
Klement Sekera13a83ef2018-03-21 12:35:51 +0100452 except Exception:
Klement Sekera085f5c02016-11-24 01:59:16 +0100453 try:
454 cls.quit()
Klement Sekera13a83ef2018-03-21 12:35:51 +0100455 except Exception:
Klement Sekera085f5c02016-11-24 01:59:16 +0100456 pass
Klement Sekera13a83ef2018-03-21 12:35:51 +0100457 raise
Damjan Marionf56b77a2016-10-03 19:44:57 +0200458
Damjan Marionf56b77a2016-10-03 19:44:57 +0200459 @classmethod
460 def quit(cls):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200461 """
462 Disconnect vpp-api, kill vpp and cleanup shared memory files
463 """
Klement Sekera277b89c2016-10-28 13:20:27 +0200464 if (cls.debug_gdbserver or cls.debug_gdb) and hasattr(cls, 'vpp'):
465 cls.vpp.poll()
466 if cls.vpp.returncode is None:
467 print(double_line_delim)
468 print("VPP or GDB server is still running")
469 print(single_line_delim)
Ole Trøan162989e2018-11-26 10:27:50 +0000470 raw_input("When done debugging, press ENTER to kill the "
Klement Sekerae1ace192018-03-23 21:54:12 +0100471 "process and finish running the testcase...")
Klement Sekera277b89c2016-10-28 13:20:27 +0200472
juraj.linkes184870a2018-07-16 14:22:01 +0200473 # first signal that we want to stop the pump thread, then wake it up
474 if hasattr(cls, 'pump_thread_stop_flag'):
475 cls.pump_thread_stop_flag.set()
476 if hasattr(cls, 'pump_thread_wakeup_pipe'):
477 os.write(cls.pump_thread_wakeup_pipe[1], 'ding dong wake up')
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100478 if hasattr(cls, 'pump_thread'):
479 cls.logger.debug("Waiting for pump thread to stop")
480 cls.pump_thread.join()
481 if hasattr(cls, 'vpp_stderr_reader_thread'):
482 cls.logger.debug("Waiting for stdderr pump to stop")
483 cls.vpp_stderr_reader_thread.join()
484
Klement Sekeraf62ae122016-10-11 11:47:09 +0200485 if hasattr(cls, 'vpp'):
Klement Sekera0529a742016-12-02 07:05:24 +0100486 if hasattr(cls, 'vapi'):
487 cls.vapi.disconnect()
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100488 del cls.vapi
Klement Sekeraf62ae122016-10-11 11:47:09 +0200489 cls.vpp.poll()
490 if cls.vpp.returncode is None:
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100491 cls.logger.debug("Sending TERM to vpp")
Klement Sekera611864f2018-09-26 11:19:00 +0200492 cls.vpp.kill()
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100493 cls.logger.debug("Waiting for vpp to die")
494 cls.vpp.communicate()
Klement Sekeraf62ae122016-10-11 11:47:09 +0200495 del cls.vpp
Damjan Marionf56b77a2016-10-03 19:44:57 +0200496
Klement Sekera3747c752017-04-10 06:30:17 +0200497 if cls.vpp_startup_failed:
498 stdout_log = cls.logger.info
499 stderr_log = cls.logger.critical
500 else:
501 stdout_log = cls.logger.info
502 stderr_log = cls.logger.info
503
Klement Sekerae4504c62016-12-08 10:16:41 +0100504 if hasattr(cls, 'vpp_stdout_deque'):
Klement Sekera3747c752017-04-10 06:30:17 +0200505 stdout_log(single_line_delim)
506 stdout_log('VPP output to stdout while running %s:', cls.__name__)
507 stdout_log(single_line_delim)
Klement Sekerae4504c62016-12-08 10:16:41 +0100508 vpp_output = "".join(cls.vpp_stdout_deque)
Klement Sekera027dbd52017-04-11 06:01:53 +0200509 with open(cls.tempdir + '/vpp_stdout.txt', 'w') as f:
510 f.write(vpp_output)
Klement Sekera3747c752017-04-10 06:30:17 +0200511 stdout_log('\n%s', vpp_output)
512 stdout_log(single_line_delim)
Klement Sekera277b89c2016-10-28 13:20:27 +0200513
Klement Sekerae4504c62016-12-08 10:16:41 +0100514 if hasattr(cls, 'vpp_stderr_deque'):
Klement Sekera3747c752017-04-10 06:30:17 +0200515 stderr_log(single_line_delim)
516 stderr_log('VPP output to stderr while running %s:', cls.__name__)
517 stderr_log(single_line_delim)
Klement Sekerae4504c62016-12-08 10:16:41 +0100518 vpp_output = "".join(cls.vpp_stderr_deque)
Klement Sekera027dbd52017-04-11 06:01:53 +0200519 with open(cls.tempdir + '/vpp_stderr.txt', 'w') as f:
520 f.write(vpp_output)
Klement Sekera3747c752017-04-10 06:30:17 +0200521 stderr_log('\n%s', vpp_output)
522 stderr_log(single_line_delim)
Klement Sekera277b89c2016-10-28 13:20:27 +0200523
Damjan Marionf56b77a2016-10-03 19:44:57 +0200524 @classmethod
525 def tearDownClass(cls):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200526 """ Perform final cleanup after running all tests in this test-case """
juraj.linkes40dd73b2018-09-21 13:55:16 +0200527 cls.reporter.send_keep_alive(cls, 'tearDownClass')
Damjan Marionf56b77a2016-10-03 19:44:57 +0200528 cls.quit()
Klement Sekera027dbd52017-04-11 06:01:53 +0200529 cls.file_handler.close()
Klement Sekeraebbaf552018-02-17 13:41:33 +0100530 cls.reset_packet_infos()
531 if debug_framework:
532 debug_internal.on_tear_down_class(cls)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200533
Damjan Marionf56b77a2016-10-03 19:44:57 +0200534 def tearDown(self):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200535 """ Show various debug prints after each test """
Klement Sekerab91017a2017-02-09 06:04:36 +0100536 self.logger.debug("--- tearDown() for %s.%s(%s) called ---" %
537 (self.__class__.__name__, self._testMethodName,
538 self._testMethodDoc))
Klement Sekeraf62ae122016-10-11 11:47:09 +0200539 if not self.vpp_dead:
Jan49c0fca2016-10-26 15:44:27 +0200540 self.logger.debug(self.vapi.cli("show trace"))
Neale Ranns88fc83e2017-04-05 08:11:14 -0700541 self.logger.info(self.vapi.ppcli("show interface"))
Jan49c0fca2016-10-26 15:44:27 +0200542 self.logger.info(self.vapi.ppcli("show hardware"))
Ole Troan73202102018-08-31 00:29:48 +0200543 self.logger.info(self.statistics.set_errors_str())
Jan49c0fca2016-10-26 15:44:27 +0200544 self.logger.info(self.vapi.ppcli("show run"))
Damjan Marion07a38572018-01-21 06:44:18 -0800545 self.logger.info(self.vapi.ppcli("show log"))
Klement Sekera10db26f2017-01-11 08:16:53 +0100546 self.registry.remove_vpp_config(self.logger)
Dave Wallace90c55722017-02-16 11:25:26 -0500547 # Save/Dump VPP api trace log
548 api_trace = "vpp_api_trace.%s.log" % self._testMethodName
549 tmp_api_trace = "/tmp/%s" % api_trace
550 vpp_api_trace_log = "%s/%s" % (self.tempdir, api_trace)
551 self.logger.info(self.vapi.ppcli("api trace save %s" % api_trace))
552 self.logger.info("Moving %s to %s\n" % (tmp_api_trace,
553 vpp_api_trace_log))
554 os.rename(tmp_api_trace, vpp_api_trace_log)
Dave Wallace5ba58372018-02-13 16:14:06 -0500555 self.logger.info(self.vapi.ppcli("api trace custom-dump %s" %
Dave Wallace90c55722017-02-16 11:25:26 -0500556 vpp_api_trace_log))
Klement Sekera1b686402017-03-02 11:29:19 +0100557 else:
558 self.registry.unregister_all(self.logger)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200559
Damjan Marionf56b77a2016-10-03 19:44:57 +0200560 def setUp(self):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200561 """ Clear trace before running each test"""
Klement Sekera909a6a12017-08-08 04:33:53 +0200562 self.reporter.send_keep_alive(self)
Klement Sekerab91017a2017-02-09 06:04:36 +0100563 self.logger.debug("--- setUp() for %s.%s(%s) called ---" %
564 (self.__class__.__name__, self._testMethodName,
565 self._testMethodDoc))
Klement Sekera0c1519b2016-12-08 05:03:32 +0100566 if self.vpp_dead:
567 raise Exception("VPP is dead when setting up the test")
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100568 self.sleep(.1, "during setUp")
Klement Sekerae4504c62016-12-08 10:16:41 +0100569 self.vpp_stdout_deque.append(
570 "--- test setUp() for %s.%s(%s) starts here ---\n" %
571 (self.__class__.__name__, self._testMethodName,
572 self._testMethodDoc))
573 self.vpp_stderr_deque.append(
574 "--- test setUp() for %s.%s(%s) starts here ---\n" %
575 (self.__class__.__name__, self._testMethodName,
576 self._testMethodDoc))
Klement Sekeraf62ae122016-10-11 11:47:09 +0200577 self.vapi.cli("clear trace")
578 # store the test instance inside the test class - so that objects
579 # holding the class can access instance methods (like assertEqual)
580 type(self).test_instance = self
Damjan Marionf56b77a2016-10-03 19:44:57 +0200581
Damjan Marionf56b77a2016-10-03 19:44:57 +0200582 @classmethod
Klement Sekera75e7d132017-09-20 08:26:30 +0200583 def pg_enable_capture(cls, interfaces=None):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200584 """
585 Enable capture on packet-generator interfaces
Damjan Marionf56b77a2016-10-03 19:44:57 +0200586
Klement Sekera75e7d132017-09-20 08:26:30 +0200587 :param interfaces: iterable interface indexes (if None,
588 use self.pg_interfaces)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200589
Klement Sekeraf62ae122016-10-11 11:47:09 +0200590 """
Klement Sekera75e7d132017-09-20 08:26:30 +0200591 if interfaces is None:
592 interfaces = cls.pg_interfaces
Klement Sekeraf62ae122016-10-11 11:47:09 +0200593 for i in interfaces:
594 i.enable_capture()
Damjan Marionf56b77a2016-10-03 19:44:57 +0200595
Damjan Marionf56b77a2016-10-03 19:44:57 +0200596 @classmethod
Klement Sekera9225dee2016-12-12 08:36:58 +0100597 def register_capture(cls, cap_name):
598 """ Register a capture in the testclass """
599 # add to the list of captures with current timestamp
600 cls._captures.append((time.time(), cap_name))
601 # filter out from zombies
602 cls._zombie_captures = [(stamp, name)
603 for (stamp, name) in cls._zombie_captures
604 if name != cap_name]
605
606 @classmethod
607 def pg_start(cls):
608 """ Remove any zombie captures and enable the packet generator """
609 # how long before capture is allowed to be deleted - otherwise vpp
610 # crashes - 100ms seems enough (this shouldn't be needed at all)
611 capture_ttl = 0.1
612 now = time.time()
613 for stamp, cap_name in cls._zombie_captures:
614 wait = stamp + capture_ttl - now
615 if wait > 0:
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100616 cls.sleep(wait, "before deleting capture %s" % cap_name)
Klement Sekera9225dee2016-12-12 08:36:58 +0100617 now = time.time()
618 cls.logger.debug("Removing zombie capture %s" % cap_name)
619 cls.vapi.cli('packet-generator delete %s' % cap_name)
620
Klement Sekeraf62ae122016-10-11 11:47:09 +0200621 cls.vapi.cli("trace add pg-input 50") # 50 is maximum
622 cls.vapi.cli('packet-generator enable')
Klement Sekera9225dee2016-12-12 08:36:58 +0100623 cls._zombie_captures = cls._captures
624 cls._captures = []
Damjan Marionf56b77a2016-10-03 19:44:57 +0200625
Damjan Marionf56b77a2016-10-03 19:44:57 +0200626 @classmethod
Klement Sekeraf62ae122016-10-11 11:47:09 +0200627 def create_pg_interfaces(cls, interfaces):
628 """
Matej Klotton8d8a1da2016-12-22 11:06:56 +0100629 Create packet-generator interfaces.
Damjan Marionf56b77a2016-10-03 19:44:57 +0200630
Matej Klotton8d8a1da2016-12-22 11:06:56 +0100631 :param interfaces: iterable indexes of the interfaces.
632 :returns: List of created interfaces.
Damjan Marionf56b77a2016-10-03 19:44:57 +0200633
Klement Sekeraf62ae122016-10-11 11:47:09 +0200634 """
635 result = []
636 for i in interfaces:
637 intf = VppPGInterface(cls, i)
638 setattr(cls, intf.name, intf)
639 result.append(intf)
640 cls.pg_interfaces = result
641 return result
642
Matej Klotton0178d522016-11-04 11:11:44 +0100643 @classmethod
Klement Sekerab9ef2732018-06-24 22:49:33 +0200644 def create_loopback_interfaces(cls, count):
Matej Klotton0178d522016-11-04 11:11:44 +0100645 """
Matej Klotton8d8a1da2016-12-22 11:06:56 +0100646 Create loopback interfaces.
Matej Klotton0178d522016-11-04 11:11:44 +0100647
Klement Sekerab9ef2732018-06-24 22:49:33 +0200648 :param count: number of interfaces created.
Matej Klotton8d8a1da2016-12-22 11:06:56 +0100649 :returns: List of created interfaces.
Matej Klotton0178d522016-11-04 11:11:44 +0100650 """
Klement Sekerab9ef2732018-06-24 22:49:33 +0200651 result = [VppLoInterface(cls) for i in range(count)]
652 for intf in result:
Matej Klotton0178d522016-11-04 11:11:44 +0100653 setattr(cls, intf.name, intf)
Matej Klotton0178d522016-11-04 11:11:44 +0100654 cls.lo_interfaces = result
655 return result
656
Damjan Marionf56b77a2016-10-03 19:44:57 +0200657 @staticmethod
Klement Sekera75e7d132017-09-20 08:26:30 +0200658 def extend_packet(packet, size, padding=' '):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200659 """
Klement Sekera75e7d132017-09-20 08:26:30 +0200660 Extend packet to given size by padding with spaces or custom padding
Klement Sekeraf62ae122016-10-11 11:47:09 +0200661 NOTE: Currently works only when Raw layer is present.
662
663 :param packet: packet
664 :param size: target size
Klement Sekera75e7d132017-09-20 08:26:30 +0200665 :param padding: padding used to extend the payload
Klement Sekeraf62ae122016-10-11 11:47:09 +0200666
667 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200668 packet_len = len(packet) + 4
669 extend = size - packet_len
670 if extend > 0:
Klement Sekera75e7d132017-09-20 08:26:30 +0200671 num = (extend / len(padding)) + 1
672 packet[Raw].load += (padding * num)[:extend]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200673
Klement Sekeradab231a2016-12-21 08:50:14 +0100674 @classmethod
675 def reset_packet_infos(cls):
676 """ Reset the list of packet info objects and packet counts to zero """
677 cls._packet_infos = {}
678 cls._packet_count_for_dst_if_idx = {}
Klement Sekeraf62ae122016-10-11 11:47:09 +0200679
Klement Sekeradab231a2016-12-21 08:50:14 +0100680 @classmethod
681 def create_packet_info(cls, src_if, dst_if):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200682 """
683 Create packet info object containing the source and destination indexes
684 and add it to the testcase's packet info list
685
Klement Sekeradab231a2016-12-21 08:50:14 +0100686 :param VppInterface src_if: source interface
687 :param VppInterface dst_if: destination interface
Klement Sekeraf62ae122016-10-11 11:47:09 +0200688
689 :returns: _PacketInfo object
690
691 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200692 info = _PacketInfo()
Klement Sekeradab231a2016-12-21 08:50:14 +0100693 info.index = len(cls._packet_infos)
694 info.src = src_if.sw_if_index
695 info.dst = dst_if.sw_if_index
696 if isinstance(dst_if, VppSubInterface):
697 dst_idx = dst_if.parent.sw_if_index
698 else:
699 dst_idx = dst_if.sw_if_index
700 if dst_idx in cls._packet_count_for_dst_if_idx:
701 cls._packet_count_for_dst_if_idx[dst_idx] += 1
702 else:
703 cls._packet_count_for_dst_if_idx[dst_idx] = 1
704 cls._packet_infos[info.index] = info
Damjan Marionf56b77a2016-10-03 19:44:57 +0200705 return info
Damjan Marionf56b77a2016-10-03 19:44:57 +0200706
Damjan Marionf56b77a2016-10-03 19:44:57 +0200707 @staticmethod
708 def info_to_payload(info):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200709 """
710 Convert _PacketInfo object to packet payload
711
712 :param info: _PacketInfo object
713
714 :returns: string containing serialized data from packet info
715 """
Pavel Kotucek59dda062017-03-02 15:22:47 +0100716 return "%d %d %d %d %d" % (info.index, info.src, info.dst,
717 info.ip, info.proto)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200718
Damjan Marionf56b77a2016-10-03 19:44:57 +0200719 @staticmethod
720 def payload_to_info(payload):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200721 """
722 Convert packet payload to _PacketInfo object
723
724 :param payload: packet payload
725
726 :returns: _PacketInfo object containing de-serialized data from payload
727
728 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200729 numbers = payload.split()
730 info = _PacketInfo()
731 info.index = int(numbers[0])
732 info.src = int(numbers[1])
733 info.dst = int(numbers[2])
Pavel Kotucek59dda062017-03-02 15:22:47 +0100734 info.ip = int(numbers[3])
735 info.proto = int(numbers[4])
Damjan Marionf56b77a2016-10-03 19:44:57 +0200736 return info
Damjan Marionf56b77a2016-10-03 19:44:57 +0200737
Damjan Marionf56b77a2016-10-03 19:44:57 +0200738 def get_next_packet_info(self, info):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200739 """
740 Iterate over the packet info list stored in the testcase
741 Start iteration with first element if info is None
742 Continue based on index in info if info is specified
743
744 :param info: info or None
745 :returns: next info in list or None if no more infos
746 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200747 if info is None:
748 next_index = 0
749 else:
750 next_index = info.index + 1
Klement Sekeradab231a2016-12-21 08:50:14 +0100751 if next_index == len(self._packet_infos):
Damjan Marionf56b77a2016-10-03 19:44:57 +0200752 return None
753 else:
Klement Sekeradab231a2016-12-21 08:50:14 +0100754 return self._packet_infos[next_index]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200755
Klement Sekeraf62ae122016-10-11 11:47:09 +0200756 def get_next_packet_info_for_interface(self, src_index, info):
757 """
758 Search the packet info list for the next packet info with same source
759 interface index
760
761 :param src_index: source interface index to search for
762 :param info: packet info - where to start the search
763 :returns: packet info or None
764
765 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200766 while True:
767 info = self.get_next_packet_info(info)
768 if info is None:
769 return None
Klement Sekeraf62ae122016-10-11 11:47:09 +0200770 if info.src == src_index:
Damjan Marionf56b77a2016-10-03 19:44:57 +0200771 return info
Damjan Marionf56b77a2016-10-03 19:44:57 +0200772
Klement Sekeraf62ae122016-10-11 11:47:09 +0200773 def get_next_packet_info_for_interface2(self, src_index, dst_index, info):
774 """
775 Search the packet info list for the next packet info with same source
776 and destination interface indexes
777
778 :param src_index: source interface index to search for
779 :param dst_index: destination interface index to search for
780 :param info: packet info - where to start the search
781 :returns: packet info or None
782
783 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200784 while True:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200785 info = self.get_next_packet_info_for_interface(src_index, info)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200786 if info is None:
787 return None
Klement Sekeraf62ae122016-10-11 11:47:09 +0200788 if info.dst == dst_index:
Damjan Marionf56b77a2016-10-03 19:44:57 +0200789 return info
Damjan Marionf56b77a2016-10-03 19:44:57 +0200790
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200791 def assert_equal(self, real_value, expected_value, name_or_class=None):
792 if name_or_class is None:
Klement Sekera239790f2017-02-16 10:53:53 +0100793 self.assertEqual(real_value, expected_value)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200794 return
795 try:
796 msg = "Invalid %s: %d('%s') does not match expected value %d('%s')"
797 msg = msg % (getdoc(name_or_class).strip(),
798 real_value, str(name_or_class(real_value)),
799 expected_value, str(name_or_class(expected_value)))
Klement Sekera13a83ef2018-03-21 12:35:51 +0100800 except Exception:
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200801 msg = "Invalid %s: %s does not match expected value %s" % (
802 name_or_class, real_value, expected_value)
803
804 self.assertEqual(real_value, expected_value, msg)
805
Klement Sekerab17dd962017-01-09 07:43:48 +0100806 def assert_in_range(self,
807 real_value,
808 expected_min,
809 expected_max,
810 name=None):
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200811 if name is None:
812 msg = None
813 else:
814 msg = "Invalid %s: %s out of range <%s,%s>" % (
815 name, real_value, expected_min, expected_max)
816 self.assertTrue(expected_min <= real_value <= expected_max, msg)
817
Klement Sekerad81ae412018-05-16 10:52:54 +0200818 def assert_packet_checksums_valid(self, packet,
819 ignore_zero_udp_checksums=True):
Klement Sekera31da2e32018-06-24 22:49:55 +0200820 received = packet.__class__(str(packet))
821 self.logger.debug(
822 ppp("Verifying packet checksums for packet:", received))
Klement Sekerad81ae412018-05-16 10:52:54 +0200823 udp_layers = ['UDP', 'UDPerror']
824 checksum_fields = ['cksum', 'chksum']
825 checksums = []
826 counter = 0
Klement Sekera31da2e32018-06-24 22:49:55 +0200827 temp = received.__class__(str(received))
Klement Sekerad81ae412018-05-16 10:52:54 +0200828 while True:
829 layer = temp.getlayer(counter)
830 if layer:
831 for cf in checksum_fields:
832 if hasattr(layer, cf):
833 if ignore_zero_udp_checksums and \
834 0 == getattr(layer, cf) and \
835 layer.name in udp_layers:
836 continue
837 delattr(layer, cf)
838 checksums.append((counter, cf))
839 else:
840 break
841 counter = counter + 1
Klement Sekera31da2e32018-06-24 22:49:55 +0200842 if 0 == len(checksums):
843 return
Klement Sekerad81ae412018-05-16 10:52:54 +0200844 temp = temp.__class__(str(temp))
845 for layer, cf in checksums:
Klement Sekera31da2e32018-06-24 22:49:55 +0200846 calc_sum = getattr(temp[layer], cf)
847 self.assert_equal(
848 getattr(received[layer], cf), calc_sum,
849 "packet checksum on layer #%d: %s" % (layer, temp[layer].name))
850 self.logger.debug(
851 "Checksum field `%s` on `%s` layer has correct value `%s`" %
852 (cf, temp[layer].name, calc_sum))
Klement Sekerad81ae412018-05-16 10:52:54 +0200853
854 def assert_checksum_valid(self, received_packet, layer,
855 field_name='chksum',
856 ignore_zero_checksum=False):
857 """ Check checksum of received packet on given layer """
858 received_packet_checksum = getattr(received_packet[layer], field_name)
859 if ignore_zero_checksum and 0 == received_packet_checksum:
860 return
861 recalculated = received_packet.__class__(str(received_packet))
862 delattr(recalculated[layer], field_name)
863 recalculated = recalculated.__class__(str(recalculated))
864 self.assert_equal(received_packet_checksum,
865 getattr(recalculated[layer], field_name),
866 "packet checksum on layer: %s" % layer)
867
868 def assert_ip_checksum_valid(self, received_packet,
869 ignore_zero_checksum=False):
870 self.assert_checksum_valid(received_packet, 'IP',
871 ignore_zero_checksum=ignore_zero_checksum)
872
873 def assert_tcp_checksum_valid(self, received_packet,
874 ignore_zero_checksum=False):
875 self.assert_checksum_valid(received_packet, 'TCP',
876 ignore_zero_checksum=ignore_zero_checksum)
877
878 def assert_udp_checksum_valid(self, received_packet,
879 ignore_zero_checksum=True):
880 self.assert_checksum_valid(received_packet, 'UDP',
881 ignore_zero_checksum=ignore_zero_checksum)
882
883 def assert_embedded_icmp_checksum_valid(self, received_packet):
884 if received_packet.haslayer(IPerror):
885 self.assert_checksum_valid(received_packet, 'IPerror')
886 if received_packet.haslayer(TCPerror):
887 self.assert_checksum_valid(received_packet, 'TCPerror')
888 if received_packet.haslayer(UDPerror):
889 self.assert_checksum_valid(received_packet, 'UDPerror',
890 ignore_zero_checksum=True)
891 if received_packet.haslayer(ICMPerror):
892 self.assert_checksum_valid(received_packet, 'ICMPerror')
893
894 def assert_icmp_checksum_valid(self, received_packet):
895 self.assert_checksum_valid(received_packet, 'ICMP')
896 self.assert_embedded_icmp_checksum_valid(received_packet)
897
898 def assert_icmpv6_checksum_valid(self, pkt):
899 if pkt.haslayer(ICMPv6DestUnreach):
900 self.assert_checksum_valid(pkt, 'ICMPv6DestUnreach', 'cksum')
901 self.assert_embedded_icmp_checksum_valid(pkt)
902 if pkt.haslayer(ICMPv6EchoRequest):
903 self.assert_checksum_valid(pkt, 'ICMPv6EchoRequest', 'cksum')
904 if pkt.haslayer(ICMPv6EchoReply):
905 self.assert_checksum_valid(pkt, 'ICMPv6EchoReply', 'cksum')
906
Klement Sekeraf37c3ba2018-11-08 11:24:34 +0100907 def assert_packet_counter_equal(self, counter, expected_value):
908 counters = self.vapi.cli("sh errors").split('\n')
909 counter_value = -1
910 for i in range(1, len(counters)-1):
911 results = counters[i].split()
912 if results[1] == counter:
913 counter_value = int(results[0])
914 break
915 self.assert_equal(counter_value, expected_value,
916 "packet counter `%s'" % counter)
917
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100918 @classmethod
919 def sleep(cls, timeout, remark=None):
920 if hasattr(cls, 'logger'):
Klement Sekera3cfa5582017-04-19 07:10:58 +0000921 cls.logger.debug("Starting sleep for %ss (%s)" % (timeout, remark))
922 before = time.time()
Klement Sekeraa57a9702017-02-02 06:58:07 +0100923 time.sleep(timeout)
Klement Sekera3cfa5582017-04-19 07:10:58 +0000924 after = time.time()
925 if after - before > 2 * timeout:
Klement Sekera60c12232017-07-18 10:33:06 +0200926 cls.logger.error("unexpected time.sleep() result - "
927 "slept for %ss instead of ~%ss!" % (
928 after - before, timeout))
Klement Sekera3cfa5582017-04-19 07:10:58 +0000929 if hasattr(cls, 'logger'):
930 cls.logger.debug(
931 "Finished sleep (%s) - slept %ss (wanted %ss)" % (
932 remark, after - before, timeout))
Klement Sekeraa57a9702017-02-02 06:58:07 +0100933
Neale Ranns947ea622018-06-07 23:48:20 -0700934 def send_and_assert_no_replies(self, intf, pkts, remark="", timeout=None):
Neale Ranns52fae862018-01-08 04:41:42 -0800935 self.vapi.cli("clear trace")
936 intf.add_stream(pkts)
937 self.pg_enable_capture(self.pg_interfaces)
938 self.pg_start()
Neale Ranns947ea622018-06-07 23:48:20 -0700939 if not timeout:
940 timeout = 1
Neale Ranns52fae862018-01-08 04:41:42 -0800941 for i in self.pg_interfaces:
942 i.get_capture(0, timeout=timeout)
943 i.assert_nothing_captured(remark=remark)
944 timeout = 0.1
945
946 def send_and_expect(self, input, pkts, output):
947 self.vapi.cli("clear trace")
948 input.add_stream(pkts)
949 self.pg_enable_capture(self.pg_interfaces)
950 self.pg_start()
Neale Ranns93cc3ee2018-10-10 07:22:51 -0700951 if isinstance(object, (list,)):
952 rx = []
953 for o in output:
954 rx.append(output.get_capture(len(pkts)))
955 else:
956 rx = output.get_capture(len(pkts))
957 return rx
958
959 def send_and_expect_only(self, input, pkts, output, timeout=None):
960 self.vapi.cli("clear trace")
961 input.add_stream(pkts)
962 self.pg_enable_capture(self.pg_interfaces)
963 self.pg_start()
964 if isinstance(object, (list,)):
965 outputs = output
966 rx = []
967 for o in outputs:
968 rx.append(output.get_capture(len(pkts)))
969 else:
970 rx = output.get_capture(len(pkts))
971 outputs = [output]
972 if not timeout:
973 timeout = 1
974 for i in self.pg_interfaces:
975 if i not in outputs:
976 i.get_capture(0, timeout=timeout)
977 i.assert_nothing_captured()
978 timeout = 0.1
979
Neale Ranns52fae862018-01-08 04:41:42 -0800980 return rx
981
Damjan Marionf56b77a2016-10-03 19:44:57 +0200982
juraj.linkes184870a2018-07-16 14:22:01 +0200983def get_testcase_doc_name(test):
984 return getdoc(test.__class__).splitlines()[0]
985
986
Ole Trøan5ba91592018-11-22 10:01:09 +0000987def get_test_description(descriptions, test):
988 short_description = test.shortDescription()
989 if descriptions and short_description:
990 return short_description
991 else:
992 return str(test)
993
994
juraj.linkes40dd73b2018-09-21 13:55:16 +0200995class TestCaseInfo(object):
996 def __init__(self, logger, tempdir, vpp_pid, vpp_bin_path):
997 self.logger = logger
998 self.tempdir = tempdir
999 self.vpp_pid = vpp_pid
1000 self.vpp_bin_path = vpp_bin_path
1001 self.core_crash_test = None
Klement Sekera87134932017-03-07 11:39:27 +01001002
1003
Damjan Marionf56b77a2016-10-03 19:44:57 +02001004class VppTestResult(unittest.TestResult):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001005 """
1006 @property result_string
1007 String variable to store the test case result string.
1008 @property errors
1009 List variable containing 2-tuples of TestCase instances and strings
1010 holding formatted tracebacks. Each tuple represents a test which
1011 raised an unexpected exception.
1012 @property failures
1013 List variable containing 2-tuples of TestCase instances and strings
1014 holding formatted tracebacks. Each tuple represents a test where
1015 a failure was explicitly signalled using the TestCase.assert*()
1016 methods.
1017 """
1018
juraj.linkes40dd73b2018-09-21 13:55:16 +02001019 failed_test_cases_info = set()
1020 core_crash_test_cases_info = set()
1021 current_test_case_info = None
1022
juraj.linkesabec0122018-11-16 17:28:56 +01001023 def __init__(self, stream, descriptions, verbosity, runner):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001024 """
Klement Sekerada505f62017-01-04 12:58:53 +01001025 :param stream File descriptor to store where to report test results.
1026 Set to the standard error stream by default.
1027 :param descriptions Boolean variable to store information if to use
1028 test case descriptions.
Klement Sekeraf62ae122016-10-11 11:47:09 +02001029 :param verbosity Integer variable to store required verbosity level.
1030 """
Damjan Marionf56b77a2016-10-03 19:44:57 +02001031 unittest.TestResult.__init__(self, stream, descriptions, verbosity)
1032 self.stream = stream
1033 self.descriptions = descriptions
1034 self.verbosity = verbosity
1035 self.result_string = None
juraj.linkesabec0122018-11-16 17:28:56 +01001036 self.runner = runner
Damjan Marionf56b77a2016-10-03 19:44:57 +02001037
Damjan Marionf56b77a2016-10-03 19:44:57 +02001038 def addSuccess(self, test):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001039 """
1040 Record a test succeeded result
1041
1042 :param test:
1043
1044 """
juraj.linkes40dd73b2018-09-21 13:55:16 +02001045 if self.current_test_case_info:
1046 self.current_test_case_info.logger.debug(
1047 "--- addSuccess() %s.%s(%s) called" % (test.__class__.__name__,
1048 test._testMethodName,
1049 test._testMethodDoc))
Damjan Marionf56b77a2016-10-03 19:44:57 +02001050 unittest.TestResult.addSuccess(self, test)
Klement Sekera277b89c2016-10-28 13:20:27 +02001051 self.result_string = colorize("OK", GREEN)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001052
juraj.linkescae64f82018-09-19 15:01:47 +02001053 self.send_result_through_pipe(test, PASS)
1054
Klement Sekeraf62ae122016-10-11 11:47:09 +02001055 def addSkip(self, test, reason):
1056 """
1057 Record a test skipped.
1058
1059 :param test:
1060 :param reason:
1061
1062 """
juraj.linkes40dd73b2018-09-21 13:55:16 +02001063 if self.current_test_case_info:
1064 self.current_test_case_info.logger.debug(
1065 "--- addSkip() %s.%s(%s) called, reason is %s" %
1066 (test.__class__.__name__, test._testMethodName,
1067 test._testMethodDoc, reason))
Klement Sekeraf62ae122016-10-11 11:47:09 +02001068 unittest.TestResult.addSkip(self, test, reason)
Klement Sekera277b89c2016-10-28 13:20:27 +02001069 self.result_string = colorize("SKIP", YELLOW)
Klement Sekeraf62ae122016-10-11 11:47:09 +02001070
juraj.linkescae64f82018-09-19 15:01:47 +02001071 self.send_result_through_pipe(test, SKIP)
1072
juraj.linkes40dd73b2018-09-21 13:55:16 +02001073 def symlink_failed(self):
1074 if self.current_test_case_info:
Klement Sekeraf413bef2017-08-15 07:09:02 +02001075 try:
Klement Sekerab8c72a42018-11-08 11:21:39 +01001076 failed_dir = os.getenv('FAILED_DIR')
juraj.linkes40dd73b2018-09-21 13:55:16 +02001077 link_path = os.path.join(
1078 failed_dir,
1079 '%s-FAILED' %
1080 os.path.basename(self.current_test_case_info.tempdir))
1081 if self.current_test_case_info.logger:
1082 self.current_test_case_info.logger.debug(
1083 "creating a link to the failed test")
1084 self.current_test_case_info.logger.debug(
1085 "os.symlink(%s, %s)" %
1086 (self.current_test_case_info.tempdir, link_path))
juraj.linkes184870a2018-07-16 14:22:01 +02001087 if os.path.exists(link_path):
juraj.linkes40dd73b2018-09-21 13:55:16 +02001088 if self.current_test_case_info.logger:
1089 self.current_test_case_info.logger.debug(
1090 'symlink already exists')
juraj.linkes184870a2018-07-16 14:22:01 +02001091 else:
juraj.linkes40dd73b2018-09-21 13:55:16 +02001092 os.symlink(self.current_test_case_info.tempdir, link_path)
juraj.linkes184870a2018-07-16 14:22:01 +02001093
Klement Sekeraf413bef2017-08-15 07:09:02 +02001094 except Exception as e:
juraj.linkes40dd73b2018-09-21 13:55:16 +02001095 if self.current_test_case_info.logger:
1096 self.current_test_case_info.logger.error(e)
Klement Sekeraf413bef2017-08-15 07:09:02 +02001097
juraj.linkescae64f82018-09-19 15:01:47 +02001098 def send_result_through_pipe(self, test, result):
1099 if hasattr(self, 'test_framework_result_pipe'):
1100 pipe = self.test_framework_result_pipe
juraj.linkes5e2c54d2018-08-30 10:51:45 +02001101 if pipe:
juraj.linkescae64f82018-09-19 15:01:47 +02001102 pipe.send((test.id(), result))
juraj.linkes5e2c54d2018-08-30 10:51:45 +02001103
juraj.linkes40dd73b2018-09-21 13:55:16 +02001104 def log_error(self, test, err, fn_name):
1105 if self.current_test_case_info:
1106 if isinstance(test, unittest.suite._ErrorHolder):
1107 test_name = test.description
1108 else:
1109 test_name = '%s.%s(%s)' % (test.__class__.__name__,
1110 test._testMethodName,
1111 test._testMethodDoc)
1112 self.current_test_case_info.logger.debug(
1113 "--- %s() %s called, err is %s" %
1114 (fn_name, test_name, err))
1115 self.current_test_case_info.logger.debug(
1116 "formatted exception is:\n%s" %
1117 "".join(format_exception(*err)))
1118
1119 def add_error(self, test, err, unittest_fn, error_type):
1120 if error_type == FAIL:
1121 self.log_error(test, err, 'addFailure')
1122 error_type_str = colorize("FAIL", RED)
1123 elif error_type == ERROR:
1124 self.log_error(test, err, 'addError')
1125 error_type_str = colorize("ERROR", RED)
1126 else:
1127 raise Exception('Error type %s cannot be used to record an '
1128 'error or a failure' % error_type)
1129
1130 unittest_fn(self, test, err)
1131 if self.current_test_case_info:
1132 self.result_string = "%s [ temp dir used by test case: %s ]" % \
1133 (error_type_str,
1134 self.current_test_case_info.tempdir)
1135 self.symlink_failed()
1136 self.failed_test_cases_info.add(self.current_test_case_info)
1137 if is_core_present(self.current_test_case_info.tempdir):
1138 if not self.current_test_case_info.core_crash_test:
1139 if isinstance(test, unittest.suite._ErrorHolder):
1140 test_name = str(test)
1141 else:
1142 test_name = "'{}' ({})".format(
1143 get_testcase_doc_name(test), test.id())
1144 self.current_test_case_info.core_crash_test = test_name
1145 self.core_crash_test_cases_info.add(
1146 self.current_test_case_info)
1147 else:
1148 self.result_string = '%s [no temp dir]' % error_type_str
1149
1150 self.send_result_through_pipe(test, error_type)
1151
Damjan Marionf56b77a2016-10-03 19:44:57 +02001152 def addFailure(self, test, err):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001153 """
1154 Record a test failed result
1155
1156 :param test:
1157 :param err: error message
1158
1159 """
juraj.linkes40dd73b2018-09-21 13:55:16 +02001160 self.add_error(test, err, unittest.TestResult.addFailure, FAIL)
juraj.linkescae64f82018-09-19 15:01:47 +02001161
Damjan Marionf56b77a2016-10-03 19:44:57 +02001162 def addError(self, test, err):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001163 """
1164 Record a test error result
Damjan Marionf56b77a2016-10-03 19:44:57 +02001165
Klement Sekeraf62ae122016-10-11 11:47:09 +02001166 :param test:
1167 :param err: error message
1168
1169 """
juraj.linkes40dd73b2018-09-21 13:55:16 +02001170 self.add_error(test, err, unittest.TestResult.addError, ERROR)
juraj.linkescae64f82018-09-19 15:01:47 +02001171
Damjan Marionf56b77a2016-10-03 19:44:57 +02001172 def getDescription(self, test):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001173 """
1174 Get test description
1175
1176 :param test:
1177 :returns: test description
1178
1179 """
Ole Trøan5ba91592018-11-22 10:01:09 +00001180 return get_test_description(self.descriptions, test)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001181
Damjan Marionf56b77a2016-10-03 19:44:57 +02001182 def startTest(self, test):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001183 """
1184 Start a test
1185
1186 :param test:
1187
1188 """
Paul Vinciguerra86ebba62018-11-21 09:28:32 -08001189 test.print_header()
juraj.linkes40dd73b2018-09-21 13:55:16 +02001190
Damjan Marionf56b77a2016-10-03 19:44:57 +02001191 unittest.TestResult.startTest(self, test)
1192 if self.verbosity > 0:
Klement Sekeraf62ae122016-10-11 11:47:09 +02001193 self.stream.writeln(
1194 "Starting " + self.getDescription(test) + " ...")
1195 self.stream.writeln(single_line_delim)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001196
Damjan Marionf56b77a2016-10-03 19:44:57 +02001197 def stopTest(self, test):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001198 """
juraj.linkes5e2c54d2018-08-30 10:51:45 +02001199 Called when the given test has been run
Klement Sekeraf62ae122016-10-11 11:47:09 +02001200
1201 :param test:
1202
1203 """
Damjan Marionf56b77a2016-10-03 19:44:57 +02001204 unittest.TestResult.stopTest(self, test)
1205 if self.verbosity > 0:
Klement Sekeraf62ae122016-10-11 11:47:09 +02001206 self.stream.writeln(single_line_delim)
Klement Sekera52e84f32017-01-13 07:25:25 +01001207 self.stream.writeln("%-73s%s" % (self.getDescription(test),
Klement Sekerada505f62017-01-04 12:58:53 +01001208 self.result_string))
Klement Sekeraf62ae122016-10-11 11:47:09 +02001209 self.stream.writeln(single_line_delim)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001210 else:
Klement Sekera52e84f32017-01-13 07:25:25 +01001211 self.stream.writeln("%-73s%s" % (self.getDescription(test),
Klement Sekerada505f62017-01-04 12:58:53 +01001212 self.result_string))
juraj.linkescae64f82018-09-19 15:01:47 +02001213
1214 self.send_result_through_pipe(test, TEST_RUN)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001215
Damjan Marionf56b77a2016-10-03 19:44:57 +02001216 def printErrors(self):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001217 """
1218 Print errors from running the test case
1219 """
juraj.linkesabec0122018-11-16 17:28:56 +01001220 if len(self.errors) > 0 or len(self.failures) > 0:
1221 self.stream.writeln()
1222 self.printErrorList('ERROR', self.errors)
1223 self.printErrorList('FAIL', self.failures)
1224
1225 # ^^ that is the last output from unittest before summary
1226 if not self.runner.print_summary:
1227 devnull = unittest.runner._WritelnDecorator(open(os.devnull, 'w'))
1228 self.stream = devnull
1229 self.runner.stream = devnull
Damjan Marionf56b77a2016-10-03 19:44:57 +02001230
Damjan Marionf56b77a2016-10-03 19:44:57 +02001231 def printErrorList(self, flavour, errors):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001232 """
1233 Print error list to the output stream together with error type
1234 and test case description.
1235
1236 :param flavour: error type
1237 :param errors: iterable errors
1238
1239 """
Damjan Marionf56b77a2016-10-03 19:44:57 +02001240 for test, err in errors:
Klement Sekeraf62ae122016-10-11 11:47:09 +02001241 self.stream.writeln(double_line_delim)
1242 self.stream.writeln("%s: %s" %
1243 (flavour, self.getDescription(test)))
1244 self.stream.writeln(single_line_delim)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001245 self.stream.writeln("%s" % err)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001246
1247
Damjan Marionf56b77a2016-10-03 19:44:57 +02001248class VppTestRunner(unittest.TextTestRunner):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001249 """
Klement Sekera104543f2017-02-03 07:29:43 +01001250 A basic test runner implementation which prints results to standard error.
Klement Sekeraf62ae122016-10-11 11:47:09 +02001251 """
1252 @property
1253 def resultclass(self):
1254 """Class maintaining the results of the tests"""
1255 return VppTestResult
Damjan Marionf56b77a2016-10-03 19:44:57 +02001256
juraj.linkes184870a2018-07-16 14:22:01 +02001257 def __init__(self, keep_alive_pipe=None, descriptions=True, verbosity=1,
juraj.linkescae64f82018-09-19 15:01:47 +02001258 result_pipe=None, failfast=False, buffer=False,
juraj.linkesabec0122018-11-16 17:28:56 +01001259 resultclass=None, print_summary=True):
juraj.linkes40dd73b2018-09-21 13:55:16 +02001260
Klement Sekera7a161da2017-01-17 13:42:48 +01001261 # ignore stream setting here, use hard-coded stdout to be in sync
1262 # with prints from VppTestCase methods ...
1263 super(VppTestRunner, self).__init__(sys.stdout, descriptions,
1264 verbosity, failfast, buffer,
1265 resultclass)
juraj.linkesccfead62018-11-21 13:20:43 +01001266 KeepAliveReporter.pipe = keep_alive_pipe
Klement Sekera104543f2017-02-03 07:29:43 +01001267
juraj.linkesabec0122018-11-16 17:28:56 +01001268 self.orig_stream = self.stream
1269 self.resultclass.test_framework_result_pipe = result_pipe
1270
1271 self.print_summary = print_summary
1272
1273 def _makeResult(self):
1274 return self.resultclass(self.stream,
1275 self.descriptions,
1276 self.verbosity,
1277 self)
juraj.linkes5e2c54d2018-08-30 10:51:45 +02001278
Damjan Marionf56b77a2016-10-03 19:44:57 +02001279 def run(self, test):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001280 """
1281 Run the tests
1282
1283 :param test:
1284
1285 """
Klement Sekera3658adc2017-06-07 08:19:47 +02001286 faulthandler.enable() # emit stack trace to stderr if killed by signal
juraj.linkes184870a2018-07-16 14:22:01 +02001287
1288 result = super(VppTestRunner, self).run(test)
juraj.linkesabec0122018-11-16 17:28:56 +01001289 if not self.print_summary:
1290 self.stream = self.orig_stream
1291 result.stream = self.orig_stream
juraj.linkes184870a2018-07-16 14:22:01 +02001292 return result
Neale Ranns812ed392017-10-16 04:20:13 -07001293
1294
1295class Worker(Thread):
Dave Wallace42996c02018-02-26 14:40:13 -05001296 def __init__(self, args, logger, env={}):
Neale Ranns812ed392017-10-16 04:20:13 -07001297 self.logger = logger
1298 self.args = args
1299 self.result = None
Dave Wallace42996c02018-02-26 14:40:13 -05001300 self.env = copy.deepcopy(env)
Neale Ranns812ed392017-10-16 04:20:13 -07001301 super(Worker, self).__init__()
1302
1303 def run(self):
1304 executable = self.args[0]
1305 self.logger.debug("Running executable w/args `%s'" % self.args)
1306 env = os.environ.copy()
Dave Wallacecfcf2f42018-02-16 18:31:56 -05001307 env.update(self.env)
Neale Ranns812ed392017-10-16 04:20:13 -07001308 env["CK_LOG_FILE_NAME"] = "-"
1309 self.process = subprocess.Popen(
1310 self.args, shell=False, env=env, preexec_fn=os.setpgrp,
1311 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
1312 out, err = self.process.communicate()
1313 self.logger.debug("Finished running `%s'" % executable)
1314 self.logger.info("Return code is `%s'" % self.process.returncode)
1315 self.logger.info(single_line_delim)
1316 self.logger.info("Executable `%s' wrote to stdout:" % executable)
1317 self.logger.info(single_line_delim)
1318 self.logger.info(out)
1319 self.logger.info(single_line_delim)
1320 self.logger.info("Executable `%s' wrote to stderr:" % executable)
1321 self.logger.info(single_line_delim)
Klement Sekerade0203e2018-02-22 19:21:27 +01001322 self.logger.info(err)
Neale Ranns812ed392017-10-16 04:20:13 -07001323 self.logger.info(single_line_delim)
1324 self.result = self.process.returncode