blob: c73b46c491b05d76ae95b63d096093136a3290ad [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 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
Paul Vinciguerra496b0de2019-06-20 12:24:12 -04008import signal
Ole Trøan162989e2018-11-26 10:27:50 +00009import unittest
Klement Sekeraf62ae122016-10-11 11:47:09 +020010import tempfile
Klement Sekera277b89c2016-10-28 13:20:27 +020011import time
Paul Vinciguerra72f00042018-11-25 11:05:13 -080012import faulthandler
Ole Trøan162989e2018-11-26 10:27:50 +000013import random
14import copy
Paul Vinciguerra72f00042018-11-25 11:05:13 -080015import psutil
juraj.linkes68ebc832018-11-29 09:37:08 +010016import platform
Ole Trøan162989e2018-11-26 10:27:50 +000017from collections import deque
18from threading import Thread, Event
19from inspect import getdoc, isclass
20from traceback import format_exception
21from logging import FileHandler, DEBUG, Formatter
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -070022
23import scapy.compat
Ole Trøan162989e2018-11-26 10:27:50 +000024from scapy.packet import Raw
Paul Vinciguerra496b0de2019-06-20 12:24:12 -040025import hook as hookmodule
Paul Vinciguerra919efad2018-12-17 21:43:43 -080026from vpp_pg_interface import VppPGInterface
Ole Troana45dc072018-12-21 16:04:22 +010027from vpp_sub_interface import VppSubInterface
Ole Trøan162989e2018-11-26 10:27:50 +000028from vpp_lo_interface import VppLoInterface
Neale Ranns192b13f2019-03-15 02:16:20 -070029from vpp_bvi_interface import VppBviInterface
Ole Trøan162989e2018-11-26 10:27:50 +000030from vpp_papi_provider import VppPapiProvider
Paul Vinciguerra1043fd32019-12-02 21:42:28 -050031import vpp_papi
Ole Trøan162989e2018-11-26 10:27:50 +000032from vpp_papi.vpp_stats import VPPStats
Paul Vinciguerra499ea642019-03-15 09:39:19 -070033from vpp_papi.vpp_transport_shmem import VppTransportShmemIOError
Ole Trøan162989e2018-11-26 10:27:50 +000034from log import RED, GREEN, YELLOW, double_line_delim, single_line_delim, \
35 get_logger, colorize
36from vpp_object import VppObjectRegistry
37from util import ppp, is_core_present
Klement Sekerad81ae412018-05-16 10:52:54 +020038from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror
39from scapy.layers.inet6 import ICMPv6DestUnreach, ICMPv6EchoRequest
40from scapy.layers.inet6 import ICMPv6EchoReply
Paul Vinciguerra6919b0d2018-12-09 15:37:04 -080041
Klement Sekeraacb9b8e2017-02-14 02:55:31 +010042if os.name == 'posix' and sys.version_info[0] < 3:
43 # using subprocess32 is recommended by python official documentation
44 # @ https://docs.python.org/2/library/subprocess.html
45 import subprocess32 as subprocess
46else:
47 import subprocess
Klement Sekeraf62ae122016-10-11 11:47:09 +020048
Paul Vinciguerra852f5ef2018-12-15 10:16:35 -080049# Python2/3 compatible
50try:
51 input = raw_input
52except NameError:
53 pass
54
juraj.linkescae64f82018-09-19 15:01:47 +020055PASS = 0
56FAIL = 1
57ERROR = 2
58SKIP = 3
59TEST_RUN = 4
60
Paul Vinciguerra0cbc71d2019-07-03 08:38:38 -040061
62class BoolEnvironmentVariable(object):
63
64 def __init__(self, env_var_name, default='n', true_values=None):
65 self.name = env_var_name
66 self.default = default
67 self.true_values = true_values if true_values is not None else \
68 ("y", "yes", "1")
69
70 def __bool__(self):
71 return os.getenv(self.name, self.default).lower() in self.true_values
72
73 if sys.version_info[0] == 2:
74 __nonzero__ = __bool__
75
76 def __repr__(self):
77 return 'BoolEnvironmentVariable(%r, default=%r, true_values=%r)' % \
78 (self.name, self.default, self.true_values)
79
80
81debug_framework = BoolEnvironmentVariable('TEST_DEBUG')
82if debug_framework:
Klement Sekeraebbaf552018-02-17 13:41:33 +010083 import debug_internal
84
Klement Sekeraf62ae122016-10-11 11:47:09 +020085"""
86 Test framework module.
87
88 The module provides a set of tools for constructing and running tests and
89 representing the results.
90"""
91
Klement Sekeraf62ae122016-10-11 11:47:09 +020092
Paul Vinciguerra496b0de2019-06-20 12:24:12 -040093class VppDiedError(Exception):
94 """ exception for reporting that the subprocess has died."""
95
96 signals_by_value = {v: k for k, v in signal.__dict__.items() if
97 k.startswith('SIG') and not k.startswith('SIG_')}
98
Paul Vinciguerra5dd6a7b2019-06-19 10:29:24 -040099 def __init__(self, rv=None, testcase=None, method_name=None):
Paul Vinciguerra496b0de2019-06-20 12:24:12 -0400100 self.rv = rv
101 self.signal_name = None
Paul Vinciguerra5dd6a7b2019-06-19 10:29:24 -0400102 self.testcase = testcase
103 self.method_name = method_name
104
Paul Vinciguerra496b0de2019-06-20 12:24:12 -0400105 try:
106 self.signal_name = VppDiedError.signals_by_value[-rv]
Paul Vinciguerrafea82602019-06-26 20:45:08 -0400107 except (KeyError, TypeError):
Paul Vinciguerra496b0de2019-06-20 12:24:12 -0400108 pass
109
Paul Vinciguerra5dd6a7b2019-06-19 10:29:24 -0400110 if testcase is None and method_name is None:
111 in_msg = ''
112 else:
113 in_msg = 'running %s.%s ' % (testcase, method_name)
114
115 msg = "VPP subprocess died %sunexpectedly with return code: %d%s." % (
116 in_msg,
Paul Vinciguerra496b0de2019-06-20 12:24:12 -0400117 self.rv,
Paul Vinciguerraf7457522019-07-13 09:35:38 -0400118 ' [%s]' % (self.signal_name if
119 self.signal_name is not None else ''))
Paul Vinciguerra496b0de2019-06-20 12:24:12 -0400120 super(VppDiedError, self).__init__(msg)
121
122
Damjan Marionf56b77a2016-10-03 19:44:57 +0200123class _PacketInfo(object):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200124 """Private class to create packet info object.
125
126 Help process information about the next packet.
127 Set variables to default values.
Klement Sekeraf62ae122016-10-11 11:47:09 +0200128 """
Matej Klotton86d87c42016-11-11 11:38:55 +0100129 #: Store the index of the packet.
Damjan Marionf56b77a2016-10-03 19:44:57 +0200130 index = -1
Matej Klotton86d87c42016-11-11 11:38:55 +0100131 #: Store the index of the source packet generator interface of the packet.
Damjan Marionf56b77a2016-10-03 19:44:57 +0200132 src = -1
Matej Klotton86d87c42016-11-11 11:38:55 +0100133 #: Store the index of the destination packet generator interface
134 #: of the packet.
Damjan Marionf56b77a2016-10-03 19:44:57 +0200135 dst = -1
Pavel Kotucek59dda062017-03-02 15:22:47 +0100136 #: Store expected ip version
137 ip = -1
138 #: Store expected upper protocol
139 proto = -1
Matej Klotton86d87c42016-11-11 11:38:55 +0100140 #: Store the copy of the former packet.
Damjan Marionf56b77a2016-10-03 19:44:57 +0200141 data = None
Damjan Marionf56b77a2016-10-03 19:44:57 +0200142
Matej Klotton16a14cd2016-12-07 15:09:13 +0100143 def __eq__(self, other):
144 index = self.index == other.index
145 src = self.src == other.src
146 dst = self.dst == other.dst
147 data = self.data == other.data
148 return index and src and dst and data
149
Klement Sekeraf62ae122016-10-11 11:47:09 +0200150
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100151def pump_output(testclass):
152 """ pump output from vpp stdout/stderr to proper queues """
Klement Sekera6a6f4f72017-11-09 09:16:39 +0100153 stdout_fragment = ""
154 stderr_fragment = ""
Neale Ranns16782362018-07-23 05:35:56 -0400155 while not testclass.pump_thread_stop_flag.is_set():
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100156 readable = select.select([testclass.vpp.stdout.fileno(),
157 testclass.vpp.stderr.fileno(),
158 testclass.pump_thread_wakeup_pipe[0]],
159 [], [])[0]
160 if testclass.vpp.stdout.fileno() in readable:
Klement Sekera6a6f4f72017-11-09 09:16:39 +0100161 read = os.read(testclass.vpp.stdout.fileno(), 102400)
162 if len(read) > 0:
Ole Troan45ec5702019-10-17 01:53:47 +0200163 split = read.decode('ascii',
164 errors='backslashreplace').splitlines(True)
Klement Sekera6a6f4f72017-11-09 09:16:39 +0100165 if len(stdout_fragment) > 0:
166 split[0] = "%s%s" % (stdout_fragment, split[0])
167 if len(split) > 0 and split[-1].endswith("\n"):
168 limit = None
169 else:
170 limit = -1
171 stdout_fragment = split[-1]
172 testclass.vpp_stdout_deque.extend(split[:limit])
173 if not testclass.cache_vpp_output:
174 for line in split[:limit]:
Benoît Ganne1a7ed5e2019-11-21 16:50:24 +0100175 testclass.logger.info(
Klement Sekera6a6f4f72017-11-09 09:16:39 +0100176 "VPP STDOUT: %s" % line.rstrip("\n"))
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100177 if testclass.vpp.stderr.fileno() in readable:
Klement Sekera6a6f4f72017-11-09 09:16:39 +0100178 read = os.read(testclass.vpp.stderr.fileno(), 102400)
179 if len(read) > 0:
Ole Troan6ed154f2019-10-15 19:31:55 +0200180 split = read.decode('ascii',
181 errors='backslashreplace').splitlines(True)
Klement Sekera6a6f4f72017-11-09 09:16:39 +0100182 if len(stderr_fragment) > 0:
183 split[0] = "%s%s" % (stderr_fragment, split[0])
Ole Troan6ed154f2019-10-15 19:31:55 +0200184 if len(split) > 0 and split[-1].endswith("\n"):
Klement Sekera6a6f4f72017-11-09 09:16:39 +0100185 limit = None
186 else:
187 limit = -1
188 stderr_fragment = split[-1]
Ole Troan6ed154f2019-10-15 19:31:55 +0200189
Klement Sekera6a6f4f72017-11-09 09:16:39 +0100190 testclass.vpp_stderr_deque.extend(split[:limit])
191 if not testclass.cache_vpp_output:
192 for line in split[:limit]:
Benoît Ganne1a7ed5e2019-11-21 16:50:24 +0100193 testclass.logger.error(
Klement Sekera6a6f4f72017-11-09 09:16:39 +0100194 "VPP STDERR: %s" % line.rstrip("\n"))
Paul Vinciguerra6919b0d2018-12-09 15:37:04 -0800195 # ignoring the dummy pipe here intentionally - the
196 # flag will take care of properly terminating the loop
Klement Sekera277b89c2016-10-28 13:20:27 +0200197
198
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800199def _is_skip_aarch64_set():
Paul Vinciguerra0cbc71d2019-07-03 08:38:38 -0400200 return BoolEnvironmentVariable('SKIP_AARCH64')
juraj.linkes68ebc832018-11-29 09:37:08 +0100201
Klement Sekera6aa58b72019-05-16 14:34:55 +0200202
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800203is_skip_aarch64_set = _is_skip_aarch64_set()
juraj.linkes68ebc832018-11-29 09:37:08 +0100204
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800205
206def _is_platform_aarch64():
juraj.linkes68ebc832018-11-29 09:37:08 +0100207 return platform.machine() == 'aarch64'
208
Klement Sekera6aa58b72019-05-16 14:34:55 +0200209
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800210is_platform_aarch64 = _is_platform_aarch64()
juraj.linkes68ebc832018-11-29 09:37:08 +0100211
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800212
213def _running_extended_tests():
Paul Vinciguerra0cbc71d2019-07-03 08:38:38 -0400214 return BoolEnvironmentVariable("EXTENDED_TESTS")
Klement Sekera87134932017-03-07 11:39:27 +0100215
Klement Sekera6aa58b72019-05-16 14:34:55 +0200216
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800217running_extended_tests = _running_extended_tests()
Klement Sekera87134932017-03-07 11:39:27 +0100218
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800219
Dave Barachd498c9e2020-03-10 16:59:39 -0400220def _running_gcov_tests():
221 return BoolEnvironmentVariable("GCOV_TESTS")
222
223
224running_gcov_tests = _running_gcov_tests()
225
226
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800227def _running_on_centos():
Klement Sekera13a83ef2018-03-21 12:35:51 +0100228 os_id = os.getenv("OS_ID", "")
229 return True if "centos" in os_id.lower() else False
Klement Sekerad3e671e2017-09-29 12:36:37 +0200230
Klement Sekera6aa58b72019-05-16 14:34:55 +0200231
Klement Sekera3a350702019-09-02 14:26:26 +0000232running_on_centos = _running_on_centos()
Paul Vinciguerradefde0f2018-12-06 07:46:13 -0800233
Klement Sekerad3e671e2017-09-29 12:36:37 +0200234
Klement Sekera909a6a12017-08-08 04:33:53 +0200235class KeepAliveReporter(object):
236 """
237 Singleton object which reports test start to parent process
238 """
239 _shared_state = {}
240
241 def __init__(self):
242 self.__dict__ = self._shared_state
Paul Vinciguerrac7b03fe2018-11-18 08:17:34 -0800243 self._pipe = None
Klement Sekera909a6a12017-08-08 04:33:53 +0200244
245 @property
246 def pipe(self):
247 return self._pipe
248
249 @pipe.setter
250 def pipe(self, pipe):
Paul Vinciguerrac7b03fe2018-11-18 08:17:34 -0800251 if self._pipe is not None:
Klement Sekera909a6a12017-08-08 04:33:53 +0200252 raise Exception("Internal error - pipe should only be set once.")
253 self._pipe = pipe
254
juraj.linkes40dd73b2018-09-21 13:55:16 +0200255 def send_keep_alive(self, test, desc=None):
Klement Sekera909a6a12017-08-08 04:33:53 +0200256 """
257 Write current test tmpdir & desc to keep-alive pipe to signal liveness
258 """
Klement Sekera3f6ff192017-08-11 06:56:05 +0200259 if self.pipe is None:
260 # if not running forked..
261 return
262
Klement Sekera909a6a12017-08-08 04:33:53 +0200263 if isclass(test):
juraj.linkes40dd73b2018-09-21 13:55:16 +0200264 desc = '%s (%s)' % (desc, unittest.util.strclass(test))
Klement Sekera909a6a12017-08-08 04:33:53 +0200265 else:
juraj.linkes40dd73b2018-09-21 13:55:16 +0200266 desc = test.id()
Klement Sekera909a6a12017-08-08 04:33:53 +0200267
Dave Wallacee2efd122017-09-30 22:04:21 -0400268 self.pipe.send((desc, test.vpp_bin, test.tempdir, test.vpp.pid))
Klement Sekera909a6a12017-08-08 04:33:53 +0200269
270
Damjan Marionf56b77a2016-10-03 19:44:57 +0200271class VppTestCase(unittest.TestCase):
Matej Klotton86d87c42016-11-11 11:38:55 +0100272 """This subclass is a base class for VPP test cases that are implemented as
273 classes. It provides methods to create and run test case.
Klement Sekeraf62ae122016-10-11 11:47:09 +0200274 """
275
Ole Troana45dc072018-12-21 16:04:22 +0100276 extra_vpp_punt_config = []
277 extra_vpp_plugin_config = []
Paul Vinciguerrabfd7d292019-10-26 22:25:49 -0400278 vapi_response_timeout = 5
Pavel Kotuceke88865d2018-11-28 07:42:11 +0100279
Klement Sekeraf62ae122016-10-11 11:47:09 +0200280 @property
281 def packet_infos(self):
282 """List of packet infos"""
283 return self._packet_infos
284
Klement Sekeradab231a2016-12-21 08:50:14 +0100285 @classmethod
286 def get_packet_count_for_if_idx(cls, dst_if_index):
287 """Get the number of packet info for specified destination if index"""
288 if dst_if_index in cls._packet_count_for_dst_if_idx:
289 return cls._packet_count_for_dst_if_idx[dst_if_index]
290 else:
291 return 0
Klement Sekeraf62ae122016-10-11 11:47:09 +0200292
293 @classmethod
294 def instance(cls):
295 """Return the instance of this testcase"""
296 return cls.test_instance
297
Damjan Marionf56b77a2016-10-03 19:44:57 +0200298 @classmethod
Klement Sekera277b89c2016-10-28 13:20:27 +0200299 def set_debug_flags(cls, d):
Dave Wallace24564332019-10-21 02:53:14 +0000300 cls.gdbserver_port = 7777
Klement Sekera277b89c2016-10-28 13:20:27 +0200301 cls.debug_core = False
302 cls.debug_gdb = False
303 cls.debug_gdbserver = False
Dave Wallace24564332019-10-21 02:53:14 +0000304 cls.debug_all = False
Klement Sekera277b89c2016-10-28 13:20:27 +0200305 if d is None:
306 return
307 dl = d.lower()
308 if dl == "core":
Klement Sekera277b89c2016-10-28 13:20:27 +0200309 cls.debug_core = True
Dave Wallace24564332019-10-21 02:53:14 +0000310 elif dl == "gdb" or dl == "gdb-all":
Klement Sekera277b89c2016-10-28 13:20:27 +0200311 cls.debug_gdb = True
Dave Wallace24564332019-10-21 02:53:14 +0000312 elif dl == "gdbserver" or dl == "gdbserver-all":
Klement Sekera277b89c2016-10-28 13:20:27 +0200313 cls.debug_gdbserver = True
314 else:
315 raise Exception("Unrecognized DEBUG option: '%s'" % d)
Dave Wallace24564332019-10-21 02:53:14 +0000316 if dl == "gdb-all" or dl == "gdbserver-all":
317 cls.debug_all = True
Klement Sekera277b89c2016-10-28 13:20:27 +0200318
Paul Vinciguerra86ebba62018-11-21 09:28:32 -0800319 @staticmethod
320 def get_least_used_cpu():
juraj.linkes184870a2018-07-16 14:22:01 +0200321 cpu_usage_list = [set(range(psutil.cpu_count()))]
322 vpp_processes = [p for p in psutil.process_iter(attrs=['pid', 'name'])
323 if 'vpp_main' == p.info['name']]
324 for vpp_process in vpp_processes:
325 for cpu_usage_set in cpu_usage_list:
326 try:
327 cpu_num = vpp_process.cpu_num()
328 if cpu_num in cpu_usage_set:
329 cpu_usage_set_index = cpu_usage_list.index(
330 cpu_usage_set)
331 if cpu_usage_set_index == len(cpu_usage_list) - 1:
332 cpu_usage_list.append({cpu_num})
333 else:
334 cpu_usage_list[cpu_usage_set_index + 1].add(
335 cpu_num)
336 cpu_usage_set.remove(cpu_num)
337 break
338 except psutil.NoSuchProcess:
339 pass
340
341 for cpu_usage_set in cpu_usage_list:
342 if len(cpu_usage_set) > 0:
343 min_usage_set = cpu_usage_set
344 break
345
346 return random.choice(tuple(min_usage_set))
347
Paul Vinciguerra86ebba62018-11-21 09:28:32 -0800348 @classmethod
Damjan Marionf56b77a2016-10-03 19:44:57 +0200349 def setUpConstants(cls):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200350 """ Set-up the test case class based on environment variables """
Paul Vinciguerra0cbc71d2019-07-03 08:38:38 -0400351 cls.step = BoolEnvironmentVariable('STEP')
Klement Sekera13a83ef2018-03-21 12:35:51 +0100352 d = os.getenv("DEBUG", None)
Paul Vinciguerra0cbc71d2019-07-03 08:38:38 -0400353 # inverted case to handle '' == True
Klement Sekera13a83ef2018-03-21 12:35:51 +0100354 c = os.getenv("CACHE_OUTPUT", "1")
355 cls.cache_vpp_output = False if c.lower() in ("n", "no", "0") else True
Klement Sekera277b89c2016-10-28 13:20:27 +0200356 cls.set_debug_flags(d)
Klement Sekerab8c72a42018-11-08 11:21:39 +0100357 cls.vpp_bin = os.getenv('VPP_BIN', "vpp")
358 cls.plugin_path = os.getenv('VPP_PLUGIN_PATH')
Dave Barach7d31ab22019-05-08 19:18:18 -0400359 cls.test_plugin_path = os.getenv('VPP_TEST_PLUGIN_PATH')
Klement Sekera47e275b2017-03-21 08:21:25 +0100360 cls.extern_plugin_path = os.getenv('EXTERN_PLUGINS')
361 plugin_path = None
362 if cls.plugin_path is not None:
363 if cls.extern_plugin_path is not None:
364 plugin_path = "%s:%s" % (
365 cls.plugin_path, cls.extern_plugin_path)
Klement Sekera6abbc282017-03-24 05:47:15 +0100366 else:
367 plugin_path = cls.plugin_path
Klement Sekera47e275b2017-03-21 08:21:25 +0100368 elif cls.extern_plugin_path is not None:
369 plugin_path = cls.extern_plugin_path
Ole Troana45dc072018-12-21 16:04:22 +0100370 debug_cli = ""
Klement Sekera01bbbe92016-11-02 09:25:05 +0100371 if cls.step or cls.debug_gdb or cls.debug_gdbserver:
Ole Troana45dc072018-12-21 16:04:22 +0100372 debug_cli = "cli-listen localhost:5002"
Klement Sekera80a7f0a2017-03-02 11:27:11 +0100373 coredump_size = None
Klement Sekera13a83ef2018-03-21 12:35:51 +0100374 size = os.getenv("COREDUMP_SIZE")
Ole Troana45dc072018-12-21 16:04:22 +0100375 if size is not None:
376 coredump_size = "coredump-size %s" % size
377 if coredump_size is None:
378 coredump_size = "coredump-size unlimited"
juraj.linkes184870a2018-07-16 14:22:01 +0200379
Ole Troana45dc072018-12-21 16:04:22 +0100380 cpu_core_number = cls.get_least_used_cpu()
Klement Sekera630ab582019-07-19 09:14:19 +0000381 if not hasattr(cls, "worker_config"):
382 cls.worker_config = ""
juraj.linkes184870a2018-07-16 14:22:01 +0200383
Ray Kinsella4830e4f2020-03-10 14:35:32 +0000384 default_variant = os.getenv("VARIANT")
385 if default_variant is not None:
386 default_variant = "defaults { %s 100 }" % default_variant
387 else:
388 default_variant = ""
389
Ole Troana45dc072018-12-21 16:04:22 +0100390 cls.vpp_cmdline = [cls.vpp_bin, "unix",
391 "{", "nodaemon", debug_cli, "full-coredump",
392 coredump_size, "runtime-dir", cls.tempdir, "}",
393 "api-trace", "{", "on", "}", "api-segment", "{",
394 "prefix", cls.shm_prefix, "}", "cpu", "{",
Klement Sekera630ab582019-07-19 09:14:19 +0000395 "main-core", str(cpu_core_number),
396 cls.worker_config, "}",
Dave Barach4ed25982019-12-25 09:24:58 -0500397 "physmem", "{", "max-size", "32m", "}",
Ole Troan4ff09ae2019-04-15 11:27:22 +0200398 "statseg", "{", "socket-name", cls.stats_sock, "}",
399 "socksvr", "{", "socket-name", cls.api_sock, "}",
Ray Kinsella4830e4f2020-03-10 14:35:32 +0000400 "node { ", default_variant, "}",
Ole Troan4ff09ae2019-04-15 11:27:22 +0200401 "plugins",
Ole Troana45dc072018-12-21 16:04:22 +0100402 "{", "plugin", "dpdk_plugin.so", "{", "disable",
Ole Troan2e1c8962019-04-10 09:44:23 +0200403 "}", "plugin", "rdma_plugin.so", "{", "disable",
Ole Troana45dc072018-12-21 16:04:22 +0100404 "}", "plugin", "unittest_plugin.so", "{", "enable",
405 "}"] + cls.extra_vpp_plugin_config + ["}", ]
Ray Kinsella4830e4f2020-03-10 14:35:32 +0000406
Ole Troana45dc072018-12-21 16:04:22 +0100407 if cls.extra_vpp_punt_config is not None:
408 cls.vpp_cmdline.extend(cls.extra_vpp_punt_config)
Klement Sekera47e275b2017-03-21 08:21:25 +0100409 if plugin_path is not None:
Ole Troana45dc072018-12-21 16:04:22 +0100410 cls.vpp_cmdline.extend(["plugin_path", plugin_path])
Dave Barach7d31ab22019-05-08 19:18:18 -0400411 if cls.test_plugin_path is not None:
412 cls.vpp_cmdline.extend(["test_plugin_path", cls.test_plugin_path])
413
Klement Sekeraf37c3ba2018-11-08 11:24:34 +0100414 cls.logger.info("vpp_cmdline args: %s" % cls.vpp_cmdline)
415 cls.logger.info("vpp_cmdline: %s" % " ".join(cls.vpp_cmdline))
Klement Sekera277b89c2016-10-28 13:20:27 +0200416
417 @classmethod
418 def wait_for_enter(cls):
419 if cls.debug_gdbserver:
420 print(double_line_delim)
421 print("Spawned GDB server with PID: %d" % cls.vpp.pid)
422 elif cls.debug_gdb:
423 print(double_line_delim)
424 print("Spawned VPP with PID: %d" % cls.vpp.pid)
425 else:
426 cls.logger.debug("Spawned VPP with PID: %d" % cls.vpp.pid)
427 return
428 print(single_line_delim)
Dave Wallace24564332019-10-21 02:53:14 +0000429 print("You can debug VPP using:")
Klement Sekera277b89c2016-10-28 13:20:27 +0200430 if cls.debug_gdbserver:
Paul Vinciguerra3a9f11e2019-06-18 22:59:55 -0400431 print("sudo gdb " + cls.vpp_bin +
Dave Wallace24564332019-10-21 02:53:14 +0000432 " -ex 'target remote localhost:{port}'"
433 .format(port=cls.gdbserver_port))
434 print("Now is the time to attach gdb by running the above "
435 "command, set up breakpoints etc., then resume VPP from "
Klement Sekera277b89c2016-10-28 13:20:27 +0200436 "within gdb by issuing the 'continue' command")
Dave Wallace24564332019-10-21 02:53:14 +0000437 cls.gdbserver_port += 1
Klement Sekera277b89c2016-10-28 13:20:27 +0200438 elif cls.debug_gdb:
Paul Vinciguerra3a9f11e2019-06-18 22:59:55 -0400439 print("sudo gdb " + cls.vpp_bin + " -ex 'attach %s'" % cls.vpp.pid)
Dave Wallace24564332019-10-21 02:53:14 +0000440 print("Now is the time to attach gdb by running the above "
441 "command and set up breakpoints etc., then resume VPP from"
442 " within gdb by issuing the 'continue' command")
Klement Sekera277b89c2016-10-28 13:20:27 +0200443 print(single_line_delim)
Paul Vinciguerra852f5ef2018-12-15 10:16:35 -0800444 input("Press ENTER to continue running the testcase...")
Klement Sekera277b89c2016-10-28 13:20:27 +0200445
446 @classmethod
447 def run_vpp(cls):
448 cmdline = cls.vpp_cmdline
449
450 if cls.debug_gdbserver:
Klement Sekera931be3a2016-11-03 05:36:01 +0100451 gdbserver = '/usr/bin/gdbserver'
452 if not os.path.isfile(gdbserver) or \
453 not os.access(gdbserver, os.X_OK):
454 raise Exception("gdbserver binary '%s' does not exist or is "
455 "not executable" % gdbserver)
456
Dave Wallace24564332019-10-21 02:53:14 +0000457 cmdline = [gdbserver, 'localhost:{port}'
458 .format(port=cls.gdbserver_port)] + cls.vpp_cmdline
Klement Sekera277b89c2016-10-28 13:20:27 +0200459 cls.logger.info("Gdbserver cmdline is %s", " ".join(cmdline))
460
Klement Sekera931be3a2016-11-03 05:36:01 +0100461 try:
462 cls.vpp = subprocess.Popen(cmdline,
463 stdout=subprocess.PIPE,
Ole Troan6e6ad642020-02-04 13:28:13 +0100464 stderr=subprocess.PIPE)
Paul Vinciguerra61e63bf2018-11-24 21:19:38 -0800465 except subprocess.CalledProcessError as e:
Paul Vinciguerra38a4ec72018-11-28 11:34:21 -0800466 cls.logger.critical("Subprocess returned with non-0 return code: ("
467 "%s)", e.returncode)
468 raise
469 except OSError as e:
470 cls.logger.critical("Subprocess returned with OS error: "
471 "(%s) %s", e.errno, e.strerror)
472 raise
473 except Exception as e:
474 cls.logger.exception("Subprocess returned unexpected from "
475 "%s:", cmdline)
Klement Sekera931be3a2016-11-03 05:36:01 +0100476 raise
477
Klement Sekera277b89c2016-10-28 13:20:27 +0200478 cls.wait_for_enter()
Pierre Pfistercd8e3182016-10-07 16:30:03 +0100479
Damjan Marionf56b77a2016-10-03 19:44:57 +0200480 @classmethod
Andrew Yourtchenkob31d3932019-10-31 08:34:22 +0000481 def wait_for_coredump(cls):
482 corefile = cls.tempdir + "/core"
Dave Wallace3e9b7a22019-04-09 20:19:51 -0400483 if os.path.isfile(corefile):
Andrew Yourtchenkob31d3932019-10-31 08:34:22 +0000484 cls.logger.error("Waiting for coredump to complete: %s", corefile)
Dave Wallace3e9b7a22019-04-09 20:19:51 -0400485 curr_size = os.path.getsize(corefile)
Andrew Yourtchenkob31d3932019-10-31 08:34:22 +0000486 deadline = time.time() + 60
Dave Wallace3e9b7a22019-04-09 20:19:51 -0400487 ok = False
488 while time.time() < deadline:
489 cls.sleep(1)
490 size = curr_size
491 curr_size = os.path.getsize(corefile)
492 if size == curr_size:
493 ok = True
494 break
495 if not ok:
496 cls.logger.error("Timed out waiting for coredump to complete:"
497 " %s", corefile)
498 else:
499 cls.logger.error("Coredump complete: %s, size %d",
500 corefile, curr_size)
501
502 @classmethod
Damjan Marionf56b77a2016-10-03 19:44:57 +0200503 def setUpClass(cls):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200504 """
505 Perform class setup before running the testcase
506 Remove shared memory files, start vpp and connect the vpp-api
507 """
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800508 super(VppTestCase, cls).setUpClass()
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100509 gc.collect() # run garbage collection first
juraj.linkesdfb5f2a2018-11-09 11:58:54 +0100510 cls.logger = get_logger(cls.__name__)
Klement Sekera45a95dd2019-11-05 11:18:25 +0000511 seed = os.environ["RND_SEED"]
512 random.seed(seed)
juraj.linkesdfb5f2a2018-11-09 11:58:54 +0100513 if hasattr(cls, 'parallel_handler'):
514 cls.logger.addHandler(cls.parallel_handler)
juraj.linkes3d9b92a2018-11-21 13:13:39 +0100515 cls.logger.propagate = False
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -0700516
Klement Sekeraf62ae122016-10-11 11:47:09 +0200517 cls.tempdir = tempfile.mkdtemp(
Klement Sekeraf413bef2017-08-15 07:09:02 +0200518 prefix='vpp-unittest-%s-' % cls.__name__)
Klement Sekera611864f2018-09-26 11:19:00 +0200519 cls.stats_sock = "%s/stats.sock" % cls.tempdir
Ole Troan4ff09ae2019-04-15 11:27:22 +0200520 cls.api_sock = "%s/api.sock" % cls.tempdir
Klement Sekera027dbd52017-04-11 06:01:53 +0200521 cls.file_handler = FileHandler("%s/log.txt" % cls.tempdir)
522 cls.file_handler.setFormatter(
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100523 Formatter(fmt='%(asctime)s,%(msecs)03d %(message)s',
524 datefmt="%H:%M:%S"))
Klement Sekera027dbd52017-04-11 06:01:53 +0200525 cls.file_handler.setLevel(DEBUG)
526 cls.logger.addHandler(cls.file_handler)
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -0700527 cls.logger.debug("--- setUpClass() for %s called ---" %
528 cls.__name__)
juraj.linkes184870a2018-07-16 14:22:01 +0200529 cls.shm_prefix = os.path.basename(cls.tempdir)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200530 os.chdir(cls.tempdir)
Klement Sekera277b89c2016-10-28 13:20:27 +0200531 cls.logger.info("Temporary dir is %s, shm prefix is %s",
532 cls.tempdir, cls.shm_prefix)
Klement Sekera45a95dd2019-11-05 11:18:25 +0000533 cls.logger.debug("Random seed is %s" % seed)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200534 cls.setUpConstants()
Klement Sekeradab231a2016-12-21 08:50:14 +0100535 cls.reset_packet_infos()
Klement Sekera9225dee2016-12-12 08:36:58 +0100536 cls._captures = []
Klement Sekeraf62ae122016-10-11 11:47:09 +0200537 cls.verbose = 0
Klement Sekera085f5c02016-11-24 01:59:16 +0100538 cls.vpp_dead = False
Klement Sekera10db26f2017-01-11 08:16:53 +0100539 cls.registry = VppObjectRegistry()
Klement Sekera3747c752017-04-10 06:30:17 +0200540 cls.vpp_startup_failed = False
Klement Sekera909a6a12017-08-08 04:33:53 +0200541 cls.reporter = KeepAliveReporter()
Klement Sekeraf62ae122016-10-11 11:47:09 +0200542 # need to catch exceptions here because if we raise, then the cleanup
543 # doesn't get called and we might end with a zombie vpp
544 try:
Klement Sekera277b89c2016-10-28 13:20:27 +0200545 cls.run_vpp()
juraj.linkes40dd73b2018-09-21 13:55:16 +0200546 cls.reporter.send_keep_alive(cls, 'setUpClass')
547 VppTestResult.current_test_case_info = TestCaseInfo(
548 cls.logger, cls.tempdir, cls.vpp.pid, cls.vpp_bin)
Klement Sekerae4504c62016-12-08 10:16:41 +0100549 cls.vpp_stdout_deque = deque()
Klement Sekerae4504c62016-12-08 10:16:41 +0100550 cls.vpp_stderr_deque = deque()
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100551 cls.pump_thread_stop_flag = Event()
552 cls.pump_thread_wakeup_pipe = os.pipe()
553 cls.pump_thread = Thread(target=pump_output, args=(cls,))
Klement Sekeraaeeac3b2017-02-14 07:11:52 +0100554 cls.pump_thread.daemon = True
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100555 cls.pump_thread.start()
Klement Sekera611864f2018-09-26 11:19:00 +0200556 if cls.debug_gdb or cls.debug_gdbserver:
Paul Vinciguerrabfd7d292019-10-26 22:25:49 -0400557 cls.vapi_response_timeout = 0
Klement Sekera611864f2018-09-26 11:19:00 +0200558 cls.vapi = VppPapiProvider(cls.shm_prefix, cls.shm_prefix, cls,
Paul Vinciguerrabfd7d292019-10-26 22:25:49 -0400559 cls.vapi_response_timeout)
Klement Sekera085f5c02016-11-24 01:59:16 +0100560 if cls.step:
Paul Vinciguerra496b0de2019-06-20 12:24:12 -0400561 hook = hookmodule.StepHook(cls)
Klement Sekera085f5c02016-11-24 01:59:16 +0100562 else:
Paul Vinciguerra496b0de2019-06-20 12:24:12 -0400563 hook = hookmodule.PollHook(cls)
Klement Sekera085f5c02016-11-24 01:59:16 +0100564 cls.vapi.register_hook(hook)
Klement Sekera611864f2018-09-26 11:19:00 +0200565 cls.statistics = VPPStats(socketname=cls.stats_sock)
Klement Sekera3747c752017-04-10 06:30:17 +0200566 try:
567 hook.poll_vpp()
Klement Sekera13a83ef2018-03-21 12:35:51 +0100568 except VppDiedError:
Klement Sekera3747c752017-04-10 06:30:17 +0200569 cls.vpp_startup_failed = True
570 cls.logger.critical(
571 "VPP died shortly after startup, check the"
572 " output to standard error for possible cause")
573 raise
Klement Sekera085f5c02016-11-24 01:59:16 +0100574 try:
575 cls.vapi.connect()
Paul Vinciguerra1043fd32019-12-02 21:42:28 -0500576 except vpp_papi.VPPIOError as e:
577 cls.logger.debug("Exception connecting to vapi: %s" % e)
578 cls.vapi.disconnect()
579
Klement Sekera085f5c02016-11-24 01:59:16 +0100580 if cls.debug_gdbserver:
581 print(colorize("You're running VPP inside gdbserver but "
582 "VPP-API connection failed, did you forget "
583 "to 'continue' VPP from within gdb?", RED))
584 raise
Paul Vinciguerrae64e5ff2020-04-28 00:27:38 -0400585 except vpp_papi.VPPRuntimeError as e:
586 cls.logger.debug("%s" % e)
587 cls.quit()
588 raise
Andrew Yourtchenko4f05a8e2019-10-13 10:06:46 +0000589 except Exception as e:
590 cls.logger.debug("Exception connecting to VPP: %s" % e)
Paul Vinciguerra496b0de2019-06-20 12:24:12 -0400591 cls.quit()
Klement Sekera13a83ef2018-03-21 12:35:51 +0100592 raise
Damjan Marionf56b77a2016-10-03 19:44:57 +0200593
Damjan Marionf56b77a2016-10-03 19:44:57 +0200594 @classmethod
Paul Vinciguerrac701e572019-12-19 16:09:43 -0500595 def _debug_quit(cls):
596 if (cls.debug_gdbserver or cls.debug_gdb):
597 try:
598 cls.vpp.poll()
599
600 if cls.vpp.returncode is None:
601 print()
602 print(double_line_delim)
603 print("VPP or GDB server is still running")
604 print(single_line_delim)
605 input("When done debugging, press ENTER to kill the "
606 "process and finish running the testcase...")
607 except AttributeError:
608 pass
609
610 @classmethod
Damjan Marionf56b77a2016-10-03 19:44:57 +0200611 def quit(cls):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200612 """
613 Disconnect vpp-api, kill vpp and cleanup shared memory files
614 """
Paul Vinciguerrac701e572019-12-19 16:09:43 -0500615 cls._debug_quit()
Klement Sekera277b89c2016-10-28 13:20:27 +0200616
juraj.linkes184870a2018-07-16 14:22:01 +0200617 # first signal that we want to stop the pump thread, then wake it up
618 if hasattr(cls, 'pump_thread_stop_flag'):
619 cls.pump_thread_stop_flag.set()
620 if hasattr(cls, 'pump_thread_wakeup_pipe'):
Ole Troan7f991832018-12-06 17:35:12 +0100621 os.write(cls.pump_thread_wakeup_pipe[1], b'ding dong wake up')
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100622 if hasattr(cls, 'pump_thread'):
623 cls.logger.debug("Waiting for pump thread to stop")
624 cls.pump_thread.join()
625 if hasattr(cls, 'vpp_stderr_reader_thread'):
Paul Vinciguerrac701e572019-12-19 16:09:43 -0500626 cls.logger.debug("Waiting for stderr pump to stop")
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100627 cls.vpp_stderr_reader_thread.join()
628
Klement Sekeraf62ae122016-10-11 11:47:09 +0200629 if hasattr(cls, 'vpp'):
Klement Sekera0529a742016-12-02 07:05:24 +0100630 if hasattr(cls, 'vapi'):
Ole Troanfd574082019-11-27 23:12:48 +0100631 cls.logger.debug(cls.vapi.vpp.get_stats())
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700632 cls.logger.debug("Disconnecting class vapi client on %s",
633 cls.__name__)
Klement Sekera0529a742016-12-02 07:05:24 +0100634 cls.vapi.disconnect()
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700635 cls.logger.debug("Deleting class vapi attribute on %s",
636 cls.__name__)
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100637 del cls.vapi
Klement Sekeraf62ae122016-10-11 11:47:09 +0200638 cls.vpp.poll()
639 if cls.vpp.returncode is None:
Andrew Yourtchenkob31d3932019-10-31 08:34:22 +0000640 cls.wait_for_coredump()
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100641 cls.logger.debug("Sending TERM to vpp")
Dave Barachad646872019-05-06 10:49:41 -0400642 cls.vpp.terminate()
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100643 cls.logger.debug("Waiting for vpp to die")
644 cls.vpp.communicate()
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -0700645 cls.logger.debug("Deleting class vpp attribute on %s",
646 cls.__name__)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200647 del cls.vpp
Damjan Marionf56b77a2016-10-03 19:44:57 +0200648
Klement Sekera3747c752017-04-10 06:30:17 +0200649 if cls.vpp_startup_failed:
650 stdout_log = cls.logger.info
651 stderr_log = cls.logger.critical
652 else:
653 stdout_log = cls.logger.info
654 stderr_log = cls.logger.info
655
Klement Sekerae4504c62016-12-08 10:16:41 +0100656 if hasattr(cls, 'vpp_stdout_deque'):
Klement Sekera3747c752017-04-10 06:30:17 +0200657 stdout_log(single_line_delim)
658 stdout_log('VPP output to stdout while running %s:', cls.__name__)
659 stdout_log(single_line_delim)
Klement Sekerae4504c62016-12-08 10:16:41 +0100660 vpp_output = "".join(cls.vpp_stdout_deque)
Klement Sekera027dbd52017-04-11 06:01:53 +0200661 with open(cls.tempdir + '/vpp_stdout.txt', 'w') as f:
662 f.write(vpp_output)
Klement Sekera3747c752017-04-10 06:30:17 +0200663 stdout_log('\n%s', vpp_output)
664 stdout_log(single_line_delim)
Klement Sekera277b89c2016-10-28 13:20:27 +0200665
Klement Sekerae4504c62016-12-08 10:16:41 +0100666 if hasattr(cls, 'vpp_stderr_deque'):
Klement Sekera3747c752017-04-10 06:30:17 +0200667 stderr_log(single_line_delim)
668 stderr_log('VPP output to stderr while running %s:', cls.__name__)
669 stderr_log(single_line_delim)
Klement Sekera0ede47a2019-01-29 11:49:09 +0100670 vpp_output = "".join(cls.vpp_stderr_deque)
Klement Sekera027dbd52017-04-11 06:01:53 +0200671 with open(cls.tempdir + '/vpp_stderr.txt', 'w') as f:
672 f.write(vpp_output)
Klement Sekera3747c752017-04-10 06:30:17 +0200673 stderr_log('\n%s', vpp_output)
674 stderr_log(single_line_delim)
Klement Sekera277b89c2016-10-28 13:20:27 +0200675
Damjan Marionf56b77a2016-10-03 19:44:57 +0200676 @classmethod
677 def tearDownClass(cls):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200678 """ Perform final cleanup after running all tests in this test-case """
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -0700679 cls.logger.debug("--- tearDownClass() for %s called ---" %
680 cls.__name__)
juraj.linkes40dd73b2018-09-21 13:55:16 +0200681 cls.reporter.send_keep_alive(cls, 'tearDownClass')
Damjan Marionf56b77a2016-10-03 19:44:57 +0200682 cls.quit()
Klement Sekera027dbd52017-04-11 06:01:53 +0200683 cls.file_handler.close()
Klement Sekeraebbaf552018-02-17 13:41:33 +0100684 cls.reset_packet_infos()
685 if debug_framework:
686 debug_internal.on_tear_down_class(cls)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200687
Paul Vinciguerra90cf21b2019-03-13 09:23:05 -0700688 def show_commands_at_teardown(self):
689 """ Allow subclass specific teardown logging additions."""
690 self.logger.info("--- No test specific show commands provided. ---")
691
Damjan Marionf56b77a2016-10-03 19:44:57 +0200692 def tearDown(self):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200693 """ Show various debug prints after each test """
Klement Sekerab91017a2017-02-09 06:04:36 +0100694 self.logger.debug("--- tearDown() for %s.%s(%s) called ---" %
695 (self.__class__.__name__, self._testMethodName,
696 self._testMethodDoc))
Paul Vinciguerra499ea642019-03-15 09:39:19 -0700697
698 try:
699 if not self.vpp_dead:
700 self.logger.debug(self.vapi.cli("show trace max 1000"))
701 self.logger.info(self.vapi.ppcli("show interface"))
702 self.logger.info(self.vapi.ppcli("show hardware"))
703 self.logger.info(self.statistics.set_errors_str())
704 self.logger.info(self.vapi.ppcli("show run"))
705 self.logger.info(self.vapi.ppcli("show log"))
Dave Barach32dcd3b2019-07-08 12:25:38 -0400706 self.logger.info(self.vapi.ppcli("show bihash"))
Paul Vinciguerra499ea642019-03-15 09:39:19 -0700707 self.logger.info("Logging testcase specific show commands.")
708 self.show_commands_at_teardown()
709 self.registry.remove_vpp_config(self.logger)
Dave Wallace90c55722017-02-16 11:25:26 -0500710 # Save/Dump VPP api trace log
Andrew Yourtchenko586d3ed2019-10-21 12:55:48 +0000711 m = self._testMethodName
712 api_trace = "vpp_api_trace.%s.%d.log" % (m, self.vpp.pid)
Dave Wallace90c55722017-02-16 11:25:26 -0500713 tmp_api_trace = "/tmp/%s" % api_trace
714 vpp_api_trace_log = "%s/%s" % (self.tempdir, api_trace)
715 self.logger.info(self.vapi.ppcli("api trace save %s" % api_trace))
716 self.logger.info("Moving %s to %s\n" % (tmp_api_trace,
717 vpp_api_trace_log))
718 os.rename(tmp_api_trace, vpp_api_trace_log)
Dave Wallace5ba58372018-02-13 16:14:06 -0500719 self.logger.info(self.vapi.ppcli("api trace custom-dump %s" %
Dave Wallace90c55722017-02-16 11:25:26 -0500720 vpp_api_trace_log))
Paul Vinciguerra499ea642019-03-15 09:39:19 -0700721 except VppTransportShmemIOError:
722 self.logger.debug("VppTransportShmemIOError: Vpp dead. "
723 "Cannot log show commands.")
724 self.vpp_dead = True
Klement Sekera1b686402017-03-02 11:29:19 +0100725 else:
726 self.registry.unregister_all(self.logger)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200727
Damjan Marionf56b77a2016-10-03 19:44:57 +0200728 def setUp(self):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200729 """ Clear trace before running each test"""
Paul Vinciguerra8d991d92019-01-25 14:05:48 -0800730 super(VppTestCase, self).setUp()
Klement Sekera909a6a12017-08-08 04:33:53 +0200731 self.reporter.send_keep_alive(self)
Klement Sekera0c1519b2016-12-08 05:03:32 +0100732 if self.vpp_dead:
Paul Vinciguerrafea82602019-06-26 20:45:08 -0400733
734 raise VppDiedError(rv=None, testcase=self.__class__.__name__,
735 method_name=self._testMethodName)
Klement Sekeraacb9b8e2017-02-14 02:55:31 +0100736 self.sleep(.1, "during setUp")
Klement Sekerae4504c62016-12-08 10:16:41 +0100737 self.vpp_stdout_deque.append(
738 "--- test setUp() for %s.%s(%s) starts here ---\n" %
739 (self.__class__.__name__, self._testMethodName,
740 self._testMethodDoc))
741 self.vpp_stderr_deque.append(
742 "--- test setUp() for %s.%s(%s) starts here ---\n" %
743 (self.__class__.__name__, self._testMethodName,
744 self._testMethodDoc))
Klement Sekeraf62ae122016-10-11 11:47:09 +0200745 self.vapi.cli("clear trace")
746 # store the test instance inside the test class - so that objects
747 # holding the class can access instance methods (like assertEqual)
748 type(self).test_instance = self
Damjan Marionf56b77a2016-10-03 19:44:57 +0200749
Damjan Marionf56b77a2016-10-03 19:44:57 +0200750 @classmethod
Klement Sekera75e7d132017-09-20 08:26:30 +0200751 def pg_enable_capture(cls, interfaces=None):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200752 """
753 Enable capture on packet-generator interfaces
Damjan Marionf56b77a2016-10-03 19:44:57 +0200754
Klement Sekera75e7d132017-09-20 08:26:30 +0200755 :param interfaces: iterable interface indexes (if None,
756 use self.pg_interfaces)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200757
Klement Sekeraf62ae122016-10-11 11:47:09 +0200758 """
Klement Sekera75e7d132017-09-20 08:26:30 +0200759 if interfaces is None:
760 interfaces = cls.pg_interfaces
Klement Sekeraf62ae122016-10-11 11:47:09 +0200761 for i in interfaces:
762 i.enable_capture()
Damjan Marionf56b77a2016-10-03 19:44:57 +0200763
Damjan Marionf56b77a2016-10-03 19:44:57 +0200764 @classmethod
Klement Sekera9225dee2016-12-12 08:36:58 +0100765 def register_capture(cls, cap_name):
766 """ Register a capture in the testclass """
767 # add to the list of captures with current timestamp
768 cls._captures.append((time.time(), cap_name))
Klement Sekera9225dee2016-12-12 08:36:58 +0100769
770 @classmethod
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +0000771 def get_vpp_time(cls):
Dave Barach19718002020-03-11 10:31:36 -0400772 # processes e.g. "Time now 2.190522, Wed, 11 Mar 2020 17:29:54 GMT"
773 # returns float("2.190522")
774 timestr = cls.vapi.cli('show clock')
775 head, sep, tail = timestr.partition(',')
776 head, sep, tail = head.partition('Time now')
777 return float(tail)
Andrew Yourtchenko63cb8822019-10-13 18:56:03 +0000778
779 @classmethod
780 def sleep_on_vpp_time(cls, sec):
781 """ Sleep according to time in VPP world """
782 # On a busy system with many processes
783 # we might end up with VPP time being slower than real world
784 # So take that into account when waiting for VPP to do something
785 start_time = cls.get_vpp_time()
786 while cls.get_vpp_time() - start_time < sec:
787 cls.sleep(0.1)
788
789 @classmethod
Klement Sekera9225dee2016-12-12 08:36:58 +0100790 def pg_start(cls):
Andrew Yourtchenko8d829f62019-10-13 10:09:50 +0000791 """ Enable the PG, wait till it is done, then clean up """
Klement Sekerad91fa612019-01-15 13:25:09 +0100792 cls.vapi.cli("trace add pg-input 1000")
Klement Sekeraf62ae122016-10-11 11:47:09 +0200793 cls.vapi.cli('packet-generator enable')
Andrew Yourtchenko8d829f62019-10-13 10:09:50 +0000794 # PG, when starts, runs to completion -
795 # so let's avoid a race condition,
796 # and wait a little till it's done.
797 # Then clean it up - and then be gone.
798 deadline = time.time() + 300
799 while cls.vapi.cli('show packet-generator').find("Yes") != -1:
800 cls.sleep(0.01) # yield
801 if time.time() > deadline:
802 cls.logger.error("Timeout waiting for pg to stop")
803 break
804 for stamp, cap_name in cls._captures:
805 cls.vapi.cli('packet-generator delete %s' % cap_name)
Klement Sekera9225dee2016-12-12 08:36:58 +0100806 cls._captures = []
Damjan Marionf56b77a2016-10-03 19:44:57 +0200807
Damjan Marionf56b77a2016-10-03 19:44:57 +0200808 @classmethod
Mohsin Kazmi22e9cfd2019-07-23 11:54:48 +0200809 def create_pg_interfaces(cls, interfaces, gso=0, gso_size=0):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200810 """
Matej Klotton8d8a1da2016-12-22 11:06:56 +0100811 Create packet-generator interfaces.
Damjan Marionf56b77a2016-10-03 19:44:57 +0200812
Matej Klotton8d8a1da2016-12-22 11:06:56 +0100813 :param interfaces: iterable indexes of the interfaces.
814 :returns: List of created interfaces.
Damjan Marionf56b77a2016-10-03 19:44:57 +0200815
Klement Sekeraf62ae122016-10-11 11:47:09 +0200816 """
817 result = []
818 for i in interfaces:
Mohsin Kazmi22e9cfd2019-07-23 11:54:48 +0200819 intf = VppPGInterface(cls, i, gso, gso_size)
Klement Sekeraf62ae122016-10-11 11:47:09 +0200820 setattr(cls, intf.name, intf)
821 result.append(intf)
822 cls.pg_interfaces = result
823 return result
824
Matej Klotton0178d522016-11-04 11:11:44 +0100825 @classmethod
Klement Sekerab9ef2732018-06-24 22:49:33 +0200826 def create_loopback_interfaces(cls, count):
Matej Klotton0178d522016-11-04 11:11:44 +0100827 """
Matej Klotton8d8a1da2016-12-22 11:06:56 +0100828 Create loopback interfaces.
Matej Klotton0178d522016-11-04 11:11:44 +0100829
Klement Sekerab9ef2732018-06-24 22:49:33 +0200830 :param count: number of interfaces created.
Matej Klotton8d8a1da2016-12-22 11:06:56 +0100831 :returns: List of created interfaces.
Matej Klotton0178d522016-11-04 11:11:44 +0100832 """
Klement Sekerab9ef2732018-06-24 22:49:33 +0200833 result = [VppLoInterface(cls) for i in range(count)]
834 for intf in result:
Matej Klotton0178d522016-11-04 11:11:44 +0100835 setattr(cls, intf.name, intf)
Matej Klotton0178d522016-11-04 11:11:44 +0100836 cls.lo_interfaces = result
837 return result
838
Neale Ranns192b13f2019-03-15 02:16:20 -0700839 @classmethod
840 def create_bvi_interfaces(cls, count):
841 """
842 Create BVI interfaces.
843
844 :param count: number of interfaces created.
845 :returns: List of created interfaces.
846 """
847 result = [VppBviInterface(cls) for i in range(count)]
848 for intf in result:
849 setattr(cls, intf.name, intf)
850 cls.bvi_interfaces = result
851 return result
852
Damjan Marionf56b77a2016-10-03 19:44:57 +0200853 @staticmethod
Klement Sekera75e7d132017-09-20 08:26:30 +0200854 def extend_packet(packet, size, padding=' '):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200855 """
Klement Sekera75e7d132017-09-20 08:26:30 +0200856 Extend packet to given size by padding with spaces or custom padding
Klement Sekeraf62ae122016-10-11 11:47:09 +0200857 NOTE: Currently works only when Raw layer is present.
858
859 :param packet: packet
860 :param size: target size
Klement Sekera75e7d132017-09-20 08:26:30 +0200861 :param padding: padding used to extend the payload
Klement Sekeraf62ae122016-10-11 11:47:09 +0200862
863 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200864 packet_len = len(packet) + 4
865 extend = size - packet_len
866 if extend > 0:
Alexandre Poirriercc991492019-05-07 10:39:57 +0200867 num = (extend // len(padding)) + 1
868 packet[Raw].load += (padding * num)[:extend].encode("ascii")
Damjan Marionf56b77a2016-10-03 19:44:57 +0200869
Klement Sekeradab231a2016-12-21 08:50:14 +0100870 @classmethod
871 def reset_packet_infos(cls):
872 """ Reset the list of packet info objects and packet counts to zero """
873 cls._packet_infos = {}
874 cls._packet_count_for_dst_if_idx = {}
Klement Sekeraf62ae122016-10-11 11:47:09 +0200875
Klement Sekeradab231a2016-12-21 08:50:14 +0100876 @classmethod
877 def create_packet_info(cls, src_if, dst_if):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200878 """
879 Create packet info object containing the source and destination indexes
880 and add it to the testcase's packet info list
881
Klement Sekeradab231a2016-12-21 08:50:14 +0100882 :param VppInterface src_if: source interface
883 :param VppInterface dst_if: destination interface
Klement Sekeraf62ae122016-10-11 11:47:09 +0200884
885 :returns: _PacketInfo object
886
887 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200888 info = _PacketInfo()
Klement Sekeradab231a2016-12-21 08:50:14 +0100889 info.index = len(cls._packet_infos)
890 info.src = src_if.sw_if_index
891 info.dst = dst_if.sw_if_index
892 if isinstance(dst_if, VppSubInterface):
893 dst_idx = dst_if.parent.sw_if_index
894 else:
895 dst_idx = dst_if.sw_if_index
896 if dst_idx in cls._packet_count_for_dst_if_idx:
897 cls._packet_count_for_dst_if_idx[dst_idx] += 1
898 else:
899 cls._packet_count_for_dst_if_idx[dst_idx] = 1
900 cls._packet_infos[info.index] = info
Damjan Marionf56b77a2016-10-03 19:44:57 +0200901 return info
Damjan Marionf56b77a2016-10-03 19:44:57 +0200902
Damjan Marionf56b77a2016-10-03 19:44:57 +0200903 @staticmethod
904 def info_to_payload(info):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200905 """
906 Convert _PacketInfo object to packet payload
907
908 :param info: _PacketInfo object
909
910 :returns: string containing serialized data from packet info
911 """
Pavel Kotucek59dda062017-03-02 15:22:47 +0100912 return "%d %d %d %d %d" % (info.index, info.src, info.dst,
913 info.ip, info.proto)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200914
Damjan Marionf56b77a2016-10-03 19:44:57 +0200915 @staticmethod
Paul Vinciguerraeaea4212019-03-06 11:58:06 -0800916 def payload_to_info(payload, payload_field='load'):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200917 """
918 Convert packet payload to _PacketInfo object
919
920 :param payload: packet payload
Paul Vinciguerra22364e42019-03-12 20:04:56 -0700921 :type payload: <class 'scapy.packet.Raw'>
922 :param payload_field: packet fieldname of payload "load" for
Paul Vinciguerraeaea4212019-03-06 11:58:06 -0800923 <class 'scapy.packet.Raw'>
Paul Vinciguerra22364e42019-03-12 20:04:56 -0700924 :type payload_field: str
Klement Sekeraf62ae122016-10-11 11:47:09 +0200925 :returns: _PacketInfo object containing de-serialized data from payload
926
927 """
Paul Vinciguerraeaea4212019-03-06 11:58:06 -0800928 numbers = getattr(payload, payload_field).split()
Damjan Marionf56b77a2016-10-03 19:44:57 +0200929 info = _PacketInfo()
930 info.index = int(numbers[0])
931 info.src = int(numbers[1])
932 info.dst = int(numbers[2])
Pavel Kotucek59dda062017-03-02 15:22:47 +0100933 info.ip = int(numbers[3])
934 info.proto = int(numbers[4])
Damjan Marionf56b77a2016-10-03 19:44:57 +0200935 return info
Damjan Marionf56b77a2016-10-03 19:44:57 +0200936
Damjan Marionf56b77a2016-10-03 19:44:57 +0200937 def get_next_packet_info(self, info):
Klement Sekeraf62ae122016-10-11 11:47:09 +0200938 """
939 Iterate over the packet info list stored in the testcase
940 Start iteration with first element if info is None
941 Continue based on index in info if info is specified
942
943 :param info: info or None
944 :returns: next info in list or None if no more infos
945 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200946 if info is None:
947 next_index = 0
948 else:
949 next_index = info.index + 1
Klement Sekeradab231a2016-12-21 08:50:14 +0100950 if next_index == len(self._packet_infos):
Damjan Marionf56b77a2016-10-03 19:44:57 +0200951 return None
952 else:
Klement Sekeradab231a2016-12-21 08:50:14 +0100953 return self._packet_infos[next_index]
Damjan Marionf56b77a2016-10-03 19:44:57 +0200954
Klement Sekeraf62ae122016-10-11 11:47:09 +0200955 def get_next_packet_info_for_interface(self, src_index, info):
956 """
957 Search the packet info list for the next packet info with same source
958 interface index
959
960 :param src_index: source interface index to search for
961 :param info: packet info - where to start the search
962 :returns: packet info or None
963
964 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200965 while True:
966 info = self.get_next_packet_info(info)
967 if info is None:
968 return None
Klement Sekeraf62ae122016-10-11 11:47:09 +0200969 if info.src == src_index:
Damjan Marionf56b77a2016-10-03 19:44:57 +0200970 return info
Damjan Marionf56b77a2016-10-03 19:44:57 +0200971
Klement Sekeraf62ae122016-10-11 11:47:09 +0200972 def get_next_packet_info_for_interface2(self, src_index, dst_index, info):
973 """
974 Search the packet info list for the next packet info with same source
975 and destination interface indexes
976
977 :param src_index: source interface index to search for
978 :param dst_index: destination interface index to search for
979 :param info: packet info - where to start the search
980 :returns: packet info or None
981
982 """
Damjan Marionf56b77a2016-10-03 19:44:57 +0200983 while True:
Klement Sekeraf62ae122016-10-11 11:47:09 +0200984 info = self.get_next_packet_info_for_interface(src_index, info)
Damjan Marionf56b77a2016-10-03 19:44:57 +0200985 if info is None:
986 return None
Klement Sekeraf62ae122016-10-11 11:47:09 +0200987 if info.dst == dst_index:
Damjan Marionf56b77a2016-10-03 19:44:57 +0200988 return info
Damjan Marionf56b77a2016-10-03 19:44:57 +0200989
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200990 def assert_equal(self, real_value, expected_value, name_or_class=None):
991 if name_or_class is None:
Klement Sekera239790f2017-02-16 10:53:53 +0100992 self.assertEqual(real_value, expected_value)
Klement Sekera0e3c0de2016-09-29 14:43:44 +0200993 return
994 try:
995 msg = "Invalid %s: %d('%s') does not match expected value %d('%s')"
996 msg = msg % (getdoc(name_or_class).strip(),
997 real_value, str(name_or_class(real_value)),
998 expected_value, str(name_or_class(expected_value)))
Klement Sekera13a83ef2018-03-21 12:35:51 +0100999 except Exception:
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001000 msg = "Invalid %s: %s does not match expected value %s" % (
1001 name_or_class, real_value, expected_value)
1002
1003 self.assertEqual(real_value, expected_value, msg)
1004
Klement Sekerab17dd962017-01-09 07:43:48 +01001005 def assert_in_range(self,
1006 real_value,
1007 expected_min,
1008 expected_max,
1009 name=None):
Klement Sekera0e3c0de2016-09-29 14:43:44 +02001010 if name is None:
1011 msg = None
1012 else:
1013 msg = "Invalid %s: %s out of range <%s,%s>" % (
1014 name, real_value, expected_min, expected_max)
1015 self.assertTrue(expected_min <= real_value <= expected_max, msg)
1016
Klement Sekerad81ae412018-05-16 10:52:54 +02001017 def assert_packet_checksums_valid(self, packet,
1018 ignore_zero_udp_checksums=True):
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001019 received = packet.__class__(scapy.compat.raw(packet))
Klement Sekerad81ae412018-05-16 10:52:54 +02001020 udp_layers = ['UDP', 'UDPerror']
1021 checksum_fields = ['cksum', 'chksum']
1022 checksums = []
1023 counter = 0
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001024 temp = received.__class__(scapy.compat.raw(received))
Klement Sekerad81ae412018-05-16 10:52:54 +02001025 while True:
1026 layer = temp.getlayer(counter)
1027 if layer:
Klement Sekera66cea092019-12-05 13:13:21 +00001028 layer = layer.copy()
1029 layer.remove_payload()
Klement Sekerad81ae412018-05-16 10:52:54 +02001030 for cf in checksum_fields:
1031 if hasattr(layer, cf):
1032 if ignore_zero_udp_checksums and \
Klement Sekera6aa58b72019-05-16 14:34:55 +02001033 0 == getattr(layer, cf) and \
1034 layer.name in udp_layers:
Klement Sekerad81ae412018-05-16 10:52:54 +02001035 continue
Klement Sekera66cea092019-12-05 13:13:21 +00001036 delattr(temp.getlayer(counter), cf)
Klement Sekerad81ae412018-05-16 10:52:54 +02001037 checksums.append((counter, cf))
1038 else:
1039 break
1040 counter = counter + 1
Klement Sekera31da2e32018-06-24 22:49:55 +02001041 if 0 == len(checksums):
1042 return
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001043 temp = temp.__class__(scapy.compat.raw(temp))
Klement Sekerad81ae412018-05-16 10:52:54 +02001044 for layer, cf in checksums:
Klement Sekera31da2e32018-06-24 22:49:55 +02001045 calc_sum = getattr(temp[layer], cf)
1046 self.assert_equal(
1047 getattr(received[layer], cf), calc_sum,
1048 "packet checksum on layer #%d: %s" % (layer, temp[layer].name))
1049 self.logger.debug(
1050 "Checksum field `%s` on `%s` layer has correct value `%s`" %
1051 (cf, temp[layer].name, calc_sum))
Klement Sekerad81ae412018-05-16 10:52:54 +02001052
1053 def assert_checksum_valid(self, received_packet, layer,
1054 field_name='chksum',
1055 ignore_zero_checksum=False):
1056 """ Check checksum of received packet on given layer """
1057 received_packet_checksum = getattr(received_packet[layer], field_name)
1058 if ignore_zero_checksum and 0 == received_packet_checksum:
1059 return
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001060 recalculated = received_packet.__class__(
1061 scapy.compat.raw(received_packet))
Klement Sekerad81ae412018-05-16 10:52:54 +02001062 delattr(recalculated[layer], field_name)
Paul Vinciguerraa7427ec2019-03-10 10:04:23 -07001063 recalculated = recalculated.__class__(scapy.compat.raw(recalculated))
Klement Sekerad81ae412018-05-16 10:52:54 +02001064 self.assert_equal(received_packet_checksum,
1065 getattr(recalculated[layer], field_name),
1066 "packet checksum on layer: %s" % layer)
1067
1068 def assert_ip_checksum_valid(self, received_packet,
1069 ignore_zero_checksum=False):
1070 self.assert_checksum_valid(received_packet, 'IP',
1071 ignore_zero_checksum=ignore_zero_checksum)
1072
1073 def assert_tcp_checksum_valid(self, received_packet,
1074 ignore_zero_checksum=False):
1075 self.assert_checksum_valid(received_packet, 'TCP',
1076 ignore_zero_checksum=ignore_zero_checksum)
1077
1078 def assert_udp_checksum_valid(self, received_packet,
1079 ignore_zero_checksum=True):
1080 self.assert_checksum_valid(received_packet, 'UDP',
1081 ignore_zero_checksum=ignore_zero_checksum)
1082
1083 def assert_embedded_icmp_checksum_valid(self, received_packet):
1084 if received_packet.haslayer(IPerror):
1085 self.assert_checksum_valid(received_packet, 'IPerror')
1086 if received_packet.haslayer(TCPerror):
1087 self.assert_checksum_valid(received_packet, 'TCPerror')
1088 if received_packet.haslayer(UDPerror):
1089 self.assert_checksum_valid(received_packet, 'UDPerror',
1090 ignore_zero_checksum=True)
1091 if received_packet.haslayer(ICMPerror):
1092 self.assert_checksum_valid(received_packet, 'ICMPerror')
1093
1094 def assert_icmp_checksum_valid(self, received_packet):
1095 self.assert_checksum_valid(received_packet, 'ICMP')
1096 self.assert_embedded_icmp_checksum_valid(received_packet)
1097
1098 def assert_icmpv6_checksum_valid(self, pkt):
1099 if pkt.haslayer(ICMPv6DestUnreach):
1100 self.assert_checksum_valid(pkt, 'ICMPv6DestUnreach', 'cksum')
1101 self.assert_embedded_icmp_checksum_valid(pkt)
1102 if pkt.haslayer(ICMPv6EchoRequest):
1103 self.assert_checksum_valid(pkt, 'ICMPv6EchoRequest', 'cksum')
1104 if pkt.haslayer(ICMPv6EchoReply):
1105 self.assert_checksum_valid(pkt, 'ICMPv6EchoReply', 'cksum')
1106
Klement Sekera3a343d42019-05-16 14:35:46 +02001107 def get_packet_counter(self, counter):
1108 if counter.startswith("/"):
1109 counter_value = self.statistics.get_counter(counter)
1110 else:
1111 counters = self.vapi.cli("sh errors").split('\n')
Klement Sekera6aa58b72019-05-16 14:34:55 +02001112 counter_value = 0
Klement Sekera3a343d42019-05-16 14:35:46 +02001113 for i in range(1, len(counters) - 1):
1114 results = counters[i].split()
1115 if results[1] == counter:
1116 counter_value = int(results[0])
1117 break
1118 return counter_value
1119
Klement Sekeraf37c3ba2018-11-08 11:24:34 +01001120 def assert_packet_counter_equal(self, counter, expected_value):
Klement Sekera6aa58b72019-05-16 14:34:55 +02001121 counter_value = self.get_packet_counter(counter)
1122 self.assert_equal(counter_value, expected_value,
1123 "packet counter `%s'" % counter)
Klement Sekeraf37c3ba2018-11-08 11:24:34 +01001124
Ole Troan233e4682019-05-16 15:01:34 +02001125 def assert_error_counter_equal(self, counter, expected_value):
1126 counter_value = self.statistics.get_err_counter(counter)
1127 self.assert_equal(counter_value, expected_value,
1128 "error counter `%s'" % counter)
1129
Klement Sekeraacb9b8e2017-02-14 02:55:31 +01001130 @classmethod
1131 def sleep(cls, timeout, remark=None):
Paul Vinciguerra0f6602c2019-03-10 09:10:54 -07001132
1133 # /* Allow sleep(0) to maintain win32 semantics, and as decreed
1134 # * by Guido, only the main thread can be interrupted.
1135 # */
1136 # https://github.com/python/cpython/blob/6673decfa0fb078f60587f5cb5e98460eea137c2/Modules/timemodule.c#L1892 # noqa
1137 if timeout == 0:
1138 # yield quantum
1139 if hasattr(os, 'sched_yield'):
1140 os.sched_yield()
1141 else:
1142 time.sleep(0)
1143 return
1144
Klement Sekeraacb9b8e2017-02-14 02:55:31 +01001145 if hasattr(cls, 'logger'):
Paul Vinciguerra6919b0d2018-12-09 15:37:04 -08001146 cls.logger.debug("Starting sleep for %es (%s)", timeout, remark)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001147 before = time.time()
Klement Sekeraa57a9702017-02-02 06:58:07 +01001148 time.sleep(timeout)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001149 after = time.time()
Paul Vinciguerra6919b0d2018-12-09 15:37:04 -08001150 if hasattr(cls, 'logger') and after - before > 2 * timeout:
Paul Vinciguerra0f6602c2019-03-10 09:10:54 -07001151 cls.logger.error("unexpected self.sleep() result - "
Paul Vinciguerra6919b0d2018-12-09 15:37:04 -08001152 "slept for %es instead of ~%es!",
1153 after - before, timeout)
Klement Sekera3cfa5582017-04-19 07:10:58 +00001154 if hasattr(cls, 'logger'):
1155 cls.logger.debug(
Paul Vinciguerra6919b0d2018-12-09 15:37:04 -08001156 "Finished sleep (%s) - slept %es (wanted %es)",
1157 remark, after - before, timeout)
Klement Sekeraa57a9702017-02-02 06:58:07 +01001158
Neale Ranns4a56f4e2019-12-23 04:10:25 +00001159 def pg_send(self, intf, pkts, worker=None):
Neale Ranns52fae862018-01-08 04:41:42 -08001160 self.vapi.cli("clear trace")
Neale Ranns4a56f4e2019-12-23 04:10:25 +00001161 intf.add_stream(pkts, worker=worker)
Neale Ranns52fae862018-01-08 04:41:42 -08001162 self.pg_enable_capture(self.pg_interfaces)
1163 self.pg_start()
Paul Vinciguerraeb414432019-02-20 09:01:14 -08001164
1165 def send_and_assert_no_replies(self, intf, pkts, remark="", timeout=None):
1166 self.pg_send(intf, pkts)
Neale Ranns947ea622018-06-07 23:48:20 -07001167 if not timeout:
1168 timeout = 1
Neale Ranns52fae862018-01-08 04:41:42 -08001169 for i in self.pg_interfaces:
1170 i.get_capture(0, timeout=timeout)
1171 i.assert_nothing_captured(remark=remark)
1172 timeout = 0.1
1173
Neale Ranns4a56f4e2019-12-23 04:10:25 +00001174 def send_and_expect(self, intf, pkts, output, n_rx=None, worker=None):
Neale Rannsd7603d92019-03-28 08:56:10 +00001175 if not n_rx:
1176 n_rx = len(pkts)
Neale Ranns4a56f4e2019-12-23 04:10:25 +00001177 self.pg_send(intf, pkts, worker=worker)
Neale Rannsd7603d92019-03-28 08:56:10 +00001178 rx = output.get_capture(n_rx)
Neale Ranns93cc3ee2018-10-10 07:22:51 -07001179 return rx
1180
Paul Vinciguerraeb414432019-02-20 09:01:14 -08001181 def send_and_expect_only(self, intf, pkts, output, timeout=None):
1182 self.pg_send(intf, pkts)
Paul Vinciguerra8aeb2202019-01-07 16:29:26 -08001183 rx = output.get_capture(len(pkts))
1184 outputs = [output]
Neale Ranns93cc3ee2018-10-10 07:22:51 -07001185 if not timeout:
1186 timeout = 1
1187 for i in self.pg_interfaces:
1188 if i not in outputs:
1189 i.get_capture(0, timeout=timeout)
1190 i.assert_nothing_captured()
1191 timeout = 0.1
1192
Neale Ranns52fae862018-01-08 04:41:42 -08001193 return rx
1194
Damjan Marionf56b77a2016-10-03 19:44:57 +02001195
juraj.linkes184870a2018-07-16 14:22:01 +02001196def get_testcase_doc_name(test):
1197 return getdoc(test.__class__).splitlines()[0]
1198
1199
Ole Trøan5ba91592018-11-22 10:01:09 +00001200def get_test_description(descriptions, test):
1201 short_description = test.shortDescription()
1202 if descriptions and short_description:
1203 return short_description
1204 else:
1205 return str(test)
1206
1207
juraj.linkes40dd73b2018-09-21 13:55:16 +02001208class TestCaseInfo(object):
1209 def __init__(self, logger, tempdir, vpp_pid, vpp_bin_path):
1210 self.logger = logger
1211 self.tempdir = tempdir
1212 self.vpp_pid = vpp_pid
1213 self.vpp_bin_path = vpp_bin_path
1214 self.core_crash_test = None
Klement Sekera87134932017-03-07 11:39:27 +01001215
1216
Damjan Marionf56b77a2016-10-03 19:44:57 +02001217class VppTestResult(unittest.TestResult):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001218 """
1219 @property result_string
1220 String variable to store the test case result string.
1221 @property errors
1222 List variable containing 2-tuples of TestCase instances and strings
1223 holding formatted tracebacks. Each tuple represents a test which
1224 raised an unexpected exception.
1225 @property failures
1226 List variable containing 2-tuples of TestCase instances and strings
1227 holding formatted tracebacks. Each tuple represents a test where
1228 a failure was explicitly signalled using the TestCase.assert*()
1229 methods.
1230 """
1231
juraj.linkes40dd73b2018-09-21 13:55:16 +02001232 failed_test_cases_info = set()
1233 core_crash_test_cases_info = set()
1234 current_test_case_info = None
1235
Paul Vinciguerra1ec06ff2019-01-16 11:12:50 -08001236 def __init__(self, stream=None, descriptions=None, verbosity=None,
1237 runner=None):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001238 """
Klement Sekerada505f62017-01-04 12:58:53 +01001239 :param stream File descriptor to store where to report test results.
1240 Set to the standard error stream by default.
1241 :param descriptions Boolean variable to store information if to use
1242 test case descriptions.
Klement Sekeraf62ae122016-10-11 11:47:09 +02001243 :param verbosity Integer variable to store required verbosity level.
1244 """
Paul Vinciguerradd3c5d22019-01-13 16:09:10 -08001245 super(VppTestResult, self).__init__(stream, descriptions, verbosity)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001246 self.stream = stream
1247 self.descriptions = descriptions
1248 self.verbosity = verbosity
1249 self.result_string = None
juraj.linkesabec0122018-11-16 17:28:56 +01001250 self.runner = runner
Damjan Marionf56b77a2016-10-03 19:44:57 +02001251
Damjan Marionf56b77a2016-10-03 19:44:57 +02001252 def addSuccess(self, test):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001253 """
1254 Record a test succeeded result
1255
1256 :param test:
1257
1258 """
juraj.linkes40dd73b2018-09-21 13:55:16 +02001259 if self.current_test_case_info:
1260 self.current_test_case_info.logger.debug(
1261 "--- addSuccess() %s.%s(%s) called" % (test.__class__.__name__,
1262 test._testMethodName,
1263 test._testMethodDoc))
Damjan Marionf56b77a2016-10-03 19:44:57 +02001264 unittest.TestResult.addSuccess(self, test)
Klement Sekera277b89c2016-10-28 13:20:27 +02001265 self.result_string = colorize("OK", GREEN)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001266
juraj.linkescae64f82018-09-19 15:01:47 +02001267 self.send_result_through_pipe(test, PASS)
1268
Klement Sekeraf62ae122016-10-11 11:47:09 +02001269 def addSkip(self, test, reason):
1270 """
1271 Record a test skipped.
1272
1273 :param test:
1274 :param reason:
1275
1276 """
juraj.linkes40dd73b2018-09-21 13:55:16 +02001277 if self.current_test_case_info:
1278 self.current_test_case_info.logger.debug(
1279 "--- addSkip() %s.%s(%s) called, reason is %s" %
1280 (test.__class__.__name__, test._testMethodName,
1281 test._testMethodDoc, reason))
Klement Sekeraf62ae122016-10-11 11:47:09 +02001282 unittest.TestResult.addSkip(self, test, reason)
Klement Sekera277b89c2016-10-28 13:20:27 +02001283 self.result_string = colorize("SKIP", YELLOW)
Klement Sekeraf62ae122016-10-11 11:47:09 +02001284
juraj.linkescae64f82018-09-19 15:01:47 +02001285 self.send_result_through_pipe(test, SKIP)
1286
juraj.linkes40dd73b2018-09-21 13:55:16 +02001287 def symlink_failed(self):
1288 if self.current_test_case_info:
Klement Sekeraf413bef2017-08-15 07:09:02 +02001289 try:
Klement Sekerab8c72a42018-11-08 11:21:39 +01001290 failed_dir = os.getenv('FAILED_DIR')
juraj.linkes40dd73b2018-09-21 13:55:16 +02001291 link_path = os.path.join(
1292 failed_dir,
1293 '%s-FAILED' %
1294 os.path.basename(self.current_test_case_info.tempdir))
1295 if self.current_test_case_info.logger:
1296 self.current_test_case_info.logger.debug(
1297 "creating a link to the failed test")
1298 self.current_test_case_info.logger.debug(
1299 "os.symlink(%s, %s)" %
1300 (self.current_test_case_info.tempdir, link_path))
juraj.linkes184870a2018-07-16 14:22:01 +02001301 if os.path.exists(link_path):
juraj.linkes40dd73b2018-09-21 13:55:16 +02001302 if self.current_test_case_info.logger:
1303 self.current_test_case_info.logger.debug(
1304 'symlink already exists')
juraj.linkes184870a2018-07-16 14:22:01 +02001305 else:
juraj.linkes40dd73b2018-09-21 13:55:16 +02001306 os.symlink(self.current_test_case_info.tempdir, link_path)
juraj.linkes184870a2018-07-16 14:22:01 +02001307
Klement Sekeraf413bef2017-08-15 07:09:02 +02001308 except Exception as e:
juraj.linkes40dd73b2018-09-21 13:55:16 +02001309 if self.current_test_case_info.logger:
1310 self.current_test_case_info.logger.error(e)
Klement Sekeraf413bef2017-08-15 07:09:02 +02001311
juraj.linkescae64f82018-09-19 15:01:47 +02001312 def send_result_through_pipe(self, test, result):
1313 if hasattr(self, 'test_framework_result_pipe'):
1314 pipe = self.test_framework_result_pipe
juraj.linkes5e2c54d2018-08-30 10:51:45 +02001315 if pipe:
juraj.linkescae64f82018-09-19 15:01:47 +02001316 pipe.send((test.id(), result))
juraj.linkes5e2c54d2018-08-30 10:51:45 +02001317
juraj.linkes40dd73b2018-09-21 13:55:16 +02001318 def log_error(self, test, err, fn_name):
1319 if self.current_test_case_info:
1320 if isinstance(test, unittest.suite._ErrorHolder):
1321 test_name = test.description
1322 else:
1323 test_name = '%s.%s(%s)' % (test.__class__.__name__,
1324 test._testMethodName,
1325 test._testMethodDoc)
1326 self.current_test_case_info.logger.debug(
1327 "--- %s() %s called, err is %s" %
1328 (fn_name, test_name, err))
1329 self.current_test_case_info.logger.debug(
1330 "formatted exception is:\n%s" %
1331 "".join(format_exception(*err)))
1332
1333 def add_error(self, test, err, unittest_fn, error_type):
1334 if error_type == FAIL:
1335 self.log_error(test, err, 'addFailure')
1336 error_type_str = colorize("FAIL", RED)
1337 elif error_type == ERROR:
1338 self.log_error(test, err, 'addError')
1339 error_type_str = colorize("ERROR", RED)
1340 else:
1341 raise Exception('Error type %s cannot be used to record an '
1342 'error or a failure' % error_type)
1343
1344 unittest_fn(self, test, err)
1345 if self.current_test_case_info:
1346 self.result_string = "%s [ temp dir used by test case: %s ]" % \
1347 (error_type_str,
1348 self.current_test_case_info.tempdir)
1349 self.symlink_failed()
1350 self.failed_test_cases_info.add(self.current_test_case_info)
1351 if is_core_present(self.current_test_case_info.tempdir):
1352 if not self.current_test_case_info.core_crash_test:
1353 if isinstance(test, unittest.suite._ErrorHolder):
1354 test_name = str(test)
1355 else:
Paul Vinciguerraea2450f2019-03-06 08:23:58 -08001356 test_name = "'{!s}' ({!s})".format(
juraj.linkes40dd73b2018-09-21 13:55:16 +02001357 get_testcase_doc_name(test), test.id())
1358 self.current_test_case_info.core_crash_test = test_name
1359 self.core_crash_test_cases_info.add(
1360 self.current_test_case_info)
1361 else:
1362 self.result_string = '%s [no temp dir]' % error_type_str
1363
1364 self.send_result_through_pipe(test, error_type)
1365
Damjan Marionf56b77a2016-10-03 19:44:57 +02001366 def addFailure(self, test, err):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001367 """
1368 Record a test failed result
1369
1370 :param test:
1371 :param err: error message
1372
1373 """
juraj.linkes40dd73b2018-09-21 13:55:16 +02001374 self.add_error(test, err, unittest.TestResult.addFailure, FAIL)
juraj.linkescae64f82018-09-19 15:01:47 +02001375
Damjan Marionf56b77a2016-10-03 19:44:57 +02001376 def addError(self, test, err):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001377 """
1378 Record a test error result
Damjan Marionf56b77a2016-10-03 19:44:57 +02001379
Klement Sekeraf62ae122016-10-11 11:47:09 +02001380 :param test:
1381 :param err: error message
1382
1383 """
juraj.linkes40dd73b2018-09-21 13:55:16 +02001384 self.add_error(test, err, unittest.TestResult.addError, ERROR)
juraj.linkescae64f82018-09-19 15:01:47 +02001385
Damjan Marionf56b77a2016-10-03 19:44:57 +02001386 def getDescription(self, test):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001387 """
1388 Get test description
1389
1390 :param test:
1391 :returns: test description
1392
1393 """
Ole Trøan5ba91592018-11-22 10:01:09 +00001394 return get_test_description(self.descriptions, test)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001395
Damjan Marionf56b77a2016-10-03 19:44:57 +02001396 def startTest(self, test):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001397 """
1398 Start a test
1399
1400 :param test:
1401
1402 """
Paul Vinciguerradd3c5d22019-01-13 16:09:10 -08001403
1404 def print_header(test):
1405 if not hasattr(test.__class__, '_header_printed'):
1406 print(double_line_delim)
1407 print(colorize(getdoc(test).splitlines()[0], GREEN))
1408 print(double_line_delim)
1409 test.__class__._header_printed = True
1410
1411 print_header(test)
Ole Troan0c629322019-11-28 14:48:44 +01001412 self.start_test = time.time()
Damjan Marionf56b77a2016-10-03 19:44:57 +02001413 unittest.TestResult.startTest(self, test)
1414 if self.verbosity > 0:
Klement Sekeraf62ae122016-10-11 11:47:09 +02001415 self.stream.writeln(
1416 "Starting " + self.getDescription(test) + " ...")
1417 self.stream.writeln(single_line_delim)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001418
Damjan Marionf56b77a2016-10-03 19:44:57 +02001419 def stopTest(self, test):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001420 """
juraj.linkes5e2c54d2018-08-30 10:51:45 +02001421 Called when the given test has been run
Klement Sekeraf62ae122016-10-11 11:47:09 +02001422
1423 :param test:
1424
1425 """
Damjan Marionf56b77a2016-10-03 19:44:57 +02001426 unittest.TestResult.stopTest(self, test)
Ole Troan0c629322019-11-28 14:48:44 +01001427
Damjan Marionf56b77a2016-10-03 19:44:57 +02001428 if self.verbosity > 0:
Klement Sekeraf62ae122016-10-11 11:47:09 +02001429 self.stream.writeln(single_line_delim)
Klement Sekera52e84f32017-01-13 07:25:25 +01001430 self.stream.writeln("%-73s%s" % (self.getDescription(test),
Klement Sekerada505f62017-01-04 12:58:53 +01001431 self.result_string))
Klement Sekeraf62ae122016-10-11 11:47:09 +02001432 self.stream.writeln(single_line_delim)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001433 else:
Ole Troan0c629322019-11-28 14:48:44 +01001434 self.stream.writeln("%-68s %4.2f %s" %
1435 (self.getDescription(test),
1436 time.time() - self.start_test,
1437 self.result_string))
juraj.linkescae64f82018-09-19 15:01:47 +02001438
1439 self.send_result_through_pipe(test, TEST_RUN)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001440
Damjan Marionf56b77a2016-10-03 19:44:57 +02001441 def printErrors(self):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001442 """
1443 Print errors from running the test case
1444 """
juraj.linkesabec0122018-11-16 17:28:56 +01001445 if len(self.errors) > 0 or len(self.failures) > 0:
1446 self.stream.writeln()
1447 self.printErrorList('ERROR', self.errors)
1448 self.printErrorList('FAIL', self.failures)
1449
1450 # ^^ that is the last output from unittest before summary
1451 if not self.runner.print_summary:
1452 devnull = unittest.runner._WritelnDecorator(open(os.devnull, 'w'))
1453 self.stream = devnull
1454 self.runner.stream = devnull
Damjan Marionf56b77a2016-10-03 19:44:57 +02001455
Damjan Marionf56b77a2016-10-03 19:44:57 +02001456 def printErrorList(self, flavour, errors):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001457 """
1458 Print error list to the output stream together with error type
1459 and test case description.
1460
1461 :param flavour: error type
1462 :param errors: iterable errors
1463
1464 """
Damjan Marionf56b77a2016-10-03 19:44:57 +02001465 for test, err in errors:
Klement Sekeraf62ae122016-10-11 11:47:09 +02001466 self.stream.writeln(double_line_delim)
1467 self.stream.writeln("%s: %s" %
1468 (flavour, self.getDescription(test)))
1469 self.stream.writeln(single_line_delim)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001470 self.stream.writeln("%s" % err)
Damjan Marionf56b77a2016-10-03 19:44:57 +02001471
1472
Damjan Marionf56b77a2016-10-03 19:44:57 +02001473class VppTestRunner(unittest.TextTestRunner):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001474 """
Klement Sekera104543f2017-02-03 07:29:43 +01001475 A basic test runner implementation which prints results to standard error.
Klement Sekeraf62ae122016-10-11 11:47:09 +02001476 """
Paul Vinciguerra6919b0d2018-12-09 15:37:04 -08001477
Klement Sekeraf62ae122016-10-11 11:47:09 +02001478 @property
1479 def resultclass(self):
1480 """Class maintaining the results of the tests"""
1481 return VppTestResult
Damjan Marionf56b77a2016-10-03 19:44:57 +02001482
juraj.linkes184870a2018-07-16 14:22:01 +02001483 def __init__(self, keep_alive_pipe=None, descriptions=True, verbosity=1,
juraj.linkescae64f82018-09-19 15:01:47 +02001484 result_pipe=None, failfast=False, buffer=False,
Paul Vinciguerra98894022019-01-13 21:32:37 -08001485 resultclass=None, print_summary=True, **kwargs):
Klement Sekera7a161da2017-01-17 13:42:48 +01001486 # ignore stream setting here, use hard-coded stdout to be in sync
1487 # with prints from VppTestCase methods ...
1488 super(VppTestRunner, self).__init__(sys.stdout, descriptions,
1489 verbosity, failfast, buffer,
Paul Vinciguerra98894022019-01-13 21:32:37 -08001490 resultclass, **kwargs)
juraj.linkesccfead62018-11-21 13:20:43 +01001491 KeepAliveReporter.pipe = keep_alive_pipe
Klement Sekera104543f2017-02-03 07:29:43 +01001492
juraj.linkesabec0122018-11-16 17:28:56 +01001493 self.orig_stream = self.stream
1494 self.resultclass.test_framework_result_pipe = result_pipe
1495
1496 self.print_summary = print_summary
1497
1498 def _makeResult(self):
1499 return self.resultclass(self.stream,
1500 self.descriptions,
1501 self.verbosity,
1502 self)
juraj.linkes5e2c54d2018-08-30 10:51:45 +02001503
Damjan Marionf56b77a2016-10-03 19:44:57 +02001504 def run(self, test):
Klement Sekeraf62ae122016-10-11 11:47:09 +02001505 """
1506 Run the tests
1507
1508 :param test:
1509
1510 """
Klement Sekera3658adc2017-06-07 08:19:47 +02001511 faulthandler.enable() # emit stack trace to stderr if killed by signal
juraj.linkes184870a2018-07-16 14:22:01 +02001512
1513 result = super(VppTestRunner, self).run(test)
juraj.linkesabec0122018-11-16 17:28:56 +01001514 if not self.print_summary:
1515 self.stream = self.orig_stream
1516 result.stream = self.orig_stream
juraj.linkes184870a2018-07-16 14:22:01 +02001517 return result
Neale Ranns812ed392017-10-16 04:20:13 -07001518
1519
1520class Worker(Thread):
Paul Vinciguerra48bdbcd2019-12-04 19:43:53 -05001521 def __init__(self, executable_args, logger, env=None, *args, **kwargs):
1522 super(Worker, self).__init__(*args, **kwargs)
Neale Ranns812ed392017-10-16 04:20:13 -07001523 self.logger = logger
Paul Vinciguerra48bdbcd2019-12-04 19:43:53 -05001524 self.args = executable_args
Dave Wallace24564332019-10-21 02:53:14 +00001525 if hasattr(self, 'testcase') and self.testcase.debug_all:
1526 if self.testcase.debug_gdbserver:
1527 self.args = ['/usr/bin/gdbserver', 'localhost:{port}'
1528 .format(port=self.testcase.gdbserver_port)] + args
1529 elif self.testcase.debug_gdb and hasattr(self, 'wait_for_gdb'):
1530 self.args.append(self.wait_for_gdb)
Paul Vinciguerra48bdbcd2019-12-04 19:43:53 -05001531 self.app_bin = executable_args[0]
Dave Wallace24564332019-10-21 02:53:14 +00001532 self.app_name = os.path.basename(self.app_bin)
1533 if hasattr(self, 'role'):
1534 self.app_name += ' {role}'.format(role=self.role)
Paul Vinciguerra063366e2019-06-30 15:38:55 -04001535 self.process = None
Neale Ranns812ed392017-10-16 04:20:13 -07001536 self.result = None
Paul Vinciguerra063366e2019-06-30 15:38:55 -04001537 env = {} if env is None else env
Dave Wallace42996c02018-02-26 14:40:13 -05001538 self.env = copy.deepcopy(env)
Neale Ranns812ed392017-10-16 04:20:13 -07001539
Dave Wallace24564332019-10-21 02:53:14 +00001540 def wait_for_enter(self):
1541 if not hasattr(self, 'testcase'):
1542 return
1543 if self.testcase.debug_all and self.testcase.debug_gdbserver:
1544 print()
1545 print(double_line_delim)
1546 print("Spawned GDB Server for '{app}' with PID: {pid}"
1547 .format(app=self.app_name, pid=self.process.pid))
1548 elif self.testcase.debug_all and self.testcase.debug_gdb:
1549 print()
1550 print(double_line_delim)
1551 print("Spawned '{app}' with PID: {pid}"
1552 .format(app=self.app_name, pid=self.process.pid))
1553 else:
1554 return
1555 print(single_line_delim)
1556 print("You can debug '{app}' using:".format(app=self.app_name))
1557 if self.testcase.debug_gdbserver:
1558 print("sudo gdb " + self.app_bin +
1559 " -ex 'target remote localhost:{port}'"
1560 .format(port=self.testcase.gdbserver_port))
1561 print("Now is the time to attach gdb by running the above "
1562 "command, set up breakpoints etc., then resume from "
1563 "within gdb by issuing the 'continue' command")
1564 self.testcase.gdbserver_port += 1
1565 elif self.testcase.debug_gdb:
1566 print("sudo gdb " + self.app_bin +
1567 " -ex 'attach {pid}'".format(pid=self.process.pid))
1568 print("Now is the time to attach gdb by running the above "
1569 "command and set up breakpoints etc., then resume from"
1570 " within gdb by issuing the 'continue' command")
1571 print(single_line_delim)
1572 input("Press ENTER to continue running the testcase...")
1573
Neale Ranns812ed392017-10-16 04:20:13 -07001574 def run(self):
1575 executable = self.args[0]
Paul Vinciguerra063366e2019-06-30 15:38:55 -04001576 if not os.path.exists(executable) or not os.access(
1577 executable, os.F_OK | os.X_OK):
1578 # Exit code that means some system file did not exist,
1579 # could not be opened, or had some other kind of error.
1580 self.result = os.EX_OSFILE
1581 raise EnvironmentError(
1582 "executable '%s' is not found or executable." % executable)
Dave Wallace24564332019-10-21 02:53:14 +00001583 self.logger.debug("Running executable: '{app}'"
1584 .format(app=' '.join(self.args)))
Neale Ranns812ed392017-10-16 04:20:13 -07001585 env = os.environ.copy()
Dave Wallacecfcf2f42018-02-16 18:31:56 -05001586 env.update(self.env)
Neale Ranns812ed392017-10-16 04:20:13 -07001587 env["CK_LOG_FILE_NAME"] = "-"
1588 self.process = subprocess.Popen(
1589 self.args, shell=False, env=env, preexec_fn=os.setpgrp,
1590 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
Dave Wallace24564332019-10-21 02:53:14 +00001591 self.wait_for_enter()
Neale Ranns812ed392017-10-16 04:20:13 -07001592 out, err = self.process.communicate()
Dave Wallace24564332019-10-21 02:53:14 +00001593 self.logger.debug("Finished running `{app}'".format(app=self.app_name))
Neale Ranns812ed392017-10-16 04:20:13 -07001594 self.logger.info("Return code is `%s'" % self.process.returncode)
1595 self.logger.info(single_line_delim)
Dave Wallace24564332019-10-21 02:53:14 +00001596 self.logger.info("Executable `{app}' wrote to stdout:"
1597 .format(app=self.app_name))
Neale Ranns812ed392017-10-16 04:20:13 -07001598 self.logger.info(single_line_delim)
Dave Wallace97ea2f42019-10-29 19:12:03 -04001599 self.logger.info(out.decode('utf-8'))
Neale Ranns812ed392017-10-16 04:20:13 -07001600 self.logger.info(single_line_delim)
Dave Wallace24564332019-10-21 02:53:14 +00001601 self.logger.info("Executable `{app}' wrote to stderr:"
1602 .format(app=self.app_name))
Neale Ranns812ed392017-10-16 04:20:13 -07001603 self.logger.info(single_line_delim)
Dave Wallace97ea2f42019-10-29 19:12:03 -04001604 self.logger.info(err.decode('utf-8'))
Neale Ranns812ed392017-10-16 04:20:13 -07001605 self.logger.info(single_line_delim)
1606 self.result = self.process.returncode
Paul Vinciguerradd3c5d22019-01-13 16:09:10 -08001607
Klement Sekera6aa58b72019-05-16 14:34:55 +02001608
Paul Vinciguerradd3c5d22019-01-13 16:09:10 -08001609if __name__ == '__main__':
1610 pass