-#!/usr/bin/env python
+#!/usr/bin/env python3
from __future__ import print_function
import gc
from vpp_lo_interface import VppLoInterface
from vpp_bvi_interface import VppBviInterface
from vpp_papi_provider import VppPapiProvider
+import vpp_papi
from vpp_papi.vpp_stats import VPPStats
from vpp_papi.vpp_transport_shmem import VppTransportShmemIOError
from log import RED, GREEN, YELLOW, double_line_delim, single_line_delim, \
testclass.vpp_stdout_deque.extend(split[:limit])
if not testclass.cache_vpp_output:
for line in split[:limit]:
- testclass.logger.debug(
+ testclass.logger.info(
"VPP STDOUT: %s" % line.rstrip("\n"))
if testclass.vpp.stderr.fileno() in readable:
read = os.read(testclass.vpp.stderr.fileno(), 102400)
testclass.vpp_stderr_deque.extend(split[:limit])
if not testclass.cache_vpp_output:
for line in split[:limit]:
- testclass.logger.debug(
+ testclass.logger.error(
"VPP STDERR: %s" % line.rstrip("\n"))
# ignoring the dummy pipe here intentionally - the
# flag will take care of properly terminating the loop
extra_vpp_punt_config = []
extra_vpp_plugin_config = []
+ vapi_response_timeout = 5
@property
def packet_infos(self):
@classmethod
def set_debug_flags(cls, d):
+ cls.gdbserver_port = 7777
cls.debug_core = False
cls.debug_gdb = False
cls.debug_gdbserver = False
+ cls.debug_all = False
if d is None:
return
dl = d.lower()
if dl == "core":
cls.debug_core = True
- elif dl == "gdb":
+ elif dl == "gdb" or dl == "gdb-all":
cls.debug_gdb = True
- elif dl == "gdbserver":
+ elif dl == "gdbserver" or dl == "gdbserver-all":
cls.debug_gdbserver = True
else:
raise Exception("Unrecognized DEBUG option: '%s'" % d)
+ if dl == "gdb-all" or dl == "gdbserver-all":
+ cls.debug_all = True
@staticmethod
def get_least_used_cpu():
cls.logger.debug("Spawned VPP with PID: %d" % cls.vpp.pid)
return
print(single_line_delim)
- print("You can debug the VPP using e.g.:")
+ print("You can debug VPP using:")
if cls.debug_gdbserver:
print("sudo gdb " + cls.vpp_bin +
- " -ex 'target remote localhost:7777'")
- print("Now is the time to attach a gdb by running the above "
- "command, set up breakpoints etc. and then resume VPP from "
+ " -ex 'target remote localhost:{port}'"
+ .format(port=cls.gdbserver_port))
+ print("Now is the time to attach gdb by running the above "
+ "command, set up breakpoints etc., then resume VPP from "
"within gdb by issuing the 'continue' command")
+ cls.gdbserver_port += 1
elif cls.debug_gdb:
print("sudo gdb " + cls.vpp_bin + " -ex 'attach %s'" % cls.vpp.pid)
- print("Now is the time to attach a gdb by running the above "
- "command and set up breakpoints etc.")
+ print("Now is the time to attach gdb by running the above "
+ "command and set up breakpoints etc., then resume VPP from"
+ " within gdb by issuing the 'continue' command")
print(single_line_delim)
input("Press ENTER to continue running the testcase...")
raise Exception("gdbserver binary '%s' does not exist or is "
"not executable" % gdbserver)
- cmdline = [gdbserver, 'localhost:7777'] + cls.vpp_cmdline
+ cmdline = [gdbserver, 'localhost:{port}'
+ .format(port=cls.gdbserver_port)] + cls.vpp_cmdline
cls.logger.info("Gdbserver cmdline is %s", " ".join(cmdline))
try:
"""
super(VppTestCase, cls).setUpClass()
gc.collect() # run garbage collection first
- random.seed()
cls.logger = get_logger(cls.__name__)
+ seed = os.environ["RND_SEED"]
+ random.seed(seed)
if hasattr(cls, 'parallel_handler'):
cls.logger.addHandler(cls.parallel_handler)
cls.logger.propagate = False
os.chdir(cls.tempdir)
cls.logger.info("Temporary dir is %s, shm prefix is %s",
cls.tempdir, cls.shm_prefix)
+ cls.logger.debug("Random seed is %s" % seed)
cls.setUpConstants()
cls.reset_packet_infos()
cls._captures = []
cls.pump_thread.daemon = True
cls.pump_thread.start()
if cls.debug_gdb or cls.debug_gdbserver:
- read_timeout = 0
- else:
- read_timeout = 5
+ cls.vapi_response_timeout = 0
cls.vapi = VppPapiProvider(cls.shm_prefix, cls.shm_prefix, cls,
- read_timeout)
+ cls.vapi_response_timeout)
if cls.step:
hook = hookmodule.StepHook(cls)
else:
raise
try:
cls.vapi.connect()
- except Exception:
- try:
- cls.vapi.disconnect()
- except Exception:
- pass
+ except vpp_papi.VPPIOError as e:
+ cls.logger.debug("Exception connecting to vapi: %s" % e)
+ cls.vapi.disconnect()
+
if cls.debug_gdbserver:
print(colorize("You're running VPP inside gdbserver but "
"VPP-API connection failed, did you forget "
if (cls.debug_gdbserver or cls.debug_gdb) and hasattr(cls, 'vpp'):
cls.vpp.poll()
if cls.vpp.returncode is None:
+ print()
print(double_line_delim)
print("VPP or GDB server is still running")
print(single_line_delim)
if hasattr(cls, 'vpp'):
if hasattr(cls, 'vapi'):
+ cls.logger.debug(cls.vapi.vpp.get_stats())
cls.logger.debug("Disconnecting class vapi client on %s",
cls.__name__)
cls.vapi.disconnect()
self.show_commands_at_teardown()
self.registry.remove_vpp_config(self.logger)
# Save/Dump VPP api trace log
- api_trace = "vpp_api_trace.%s.log" % self._testMethodName
+ m = self._testMethodName
+ api_trace = "vpp_api_trace.%s.%d.log" % (m, self.vpp.pid)
tmp_api_trace = "/tmp/%s" % api_trace
vpp_api_trace_log = "%s/%s" % (self.tempdir, api_trace)
self.logger.info(self.vapi.ppcli("api trace save %s" % api_trace))
# add to the list of captures with current timestamp
cls._captures.append((time.time(), cap_name))
+ @classmethod
+ def get_vpp_time(cls):
+ return float(cls.vapi.cli('show clock').replace("Time now ", ""))
+
+ @classmethod
+ def sleep_on_vpp_time(cls, sec):
+ """ Sleep according to time in VPP world """
+ # On a busy system with many processes
+ # we might end up with VPP time being slower than real world
+ # So take that into account when waiting for VPP to do something
+ start_time = cls.get_vpp_time()
+ while cls.get_vpp_time() - start_time < sec:
+ cls.sleep(0.1)
+
@classmethod
def pg_start(cls):
""" Enable the PG, wait till it is done, then clean up """
while True:
layer = temp.getlayer(counter)
if layer:
+ layer = layer.copy()
+ layer.remove_payload()
for cf in checksum_fields:
if hasattr(layer, cf):
if ignore_zero_udp_checksums and \
0 == getattr(layer, cf) and \
layer.name in udp_layers:
continue
- delattr(layer, cf)
+ delattr(temp.getlayer(counter), cf)
checksums.append((counter, cf))
else:
break
return rx
- def runTest(self):
- """ unittest calls runTest when TestCase is instantiated without a
- test case. Use case: Writing unittests against VppTestCase"""
- pass
-
def get_testcase_doc_name(test):
return getdoc(test.__class__).splitlines()[0]
test.__class__._header_printed = True
print_header(test)
-
+ self.start_test = time.time()
unittest.TestResult.startTest(self, test)
if self.verbosity > 0:
self.stream.writeln(
"""
unittest.TestResult.stopTest(self, test)
+
if self.verbosity > 0:
self.stream.writeln(single_line_delim)
self.stream.writeln("%-73s%s" % (self.getDescription(test),
self.result_string))
self.stream.writeln(single_line_delim)
else:
- self.stream.writeln("%-73s%s" % (self.getDescription(test),
- self.result_string))
+ self.stream.writeln("%-68s %4.2f %s" %
+ (self.getDescription(test),
+ time.time() - self.start_test,
+ self.result_string))
self.send_result_through_pipe(test, TEST_RUN)
def __init__(self, args, logger, env=None):
self.logger = logger
self.args = args
+ if hasattr(self, 'testcase') and self.testcase.debug_all:
+ if self.testcase.debug_gdbserver:
+ self.args = ['/usr/bin/gdbserver', 'localhost:{port}'
+ .format(port=self.testcase.gdbserver_port)] + args
+ elif self.testcase.debug_gdb and hasattr(self, 'wait_for_gdb'):
+ self.args.append(self.wait_for_gdb)
+ self.app_bin = args[0]
+ self.app_name = os.path.basename(self.app_bin)
+ if hasattr(self, 'role'):
+ self.app_name += ' {role}'.format(role=self.role)
self.process = None
self.result = None
env = {} if env is None else env
self.env = copy.deepcopy(env)
super(Worker, self).__init__()
+ def wait_for_enter(self):
+ if not hasattr(self, 'testcase'):
+ return
+ if self.testcase.debug_all and self.testcase.debug_gdbserver:
+ print()
+ print(double_line_delim)
+ print("Spawned GDB Server for '{app}' with PID: {pid}"
+ .format(app=self.app_name, pid=self.process.pid))
+ elif self.testcase.debug_all and self.testcase.debug_gdb:
+ print()
+ print(double_line_delim)
+ print("Spawned '{app}' with PID: {pid}"
+ .format(app=self.app_name, pid=self.process.pid))
+ else:
+ return
+ print(single_line_delim)
+ print("You can debug '{app}' using:".format(app=self.app_name))
+ if self.testcase.debug_gdbserver:
+ print("sudo gdb " + self.app_bin +
+ " -ex 'target remote localhost:{port}'"
+ .format(port=self.testcase.gdbserver_port))
+ print("Now is the time to attach gdb by running the above "
+ "command, set up breakpoints etc., then resume from "
+ "within gdb by issuing the 'continue' command")
+ self.testcase.gdbserver_port += 1
+ elif self.testcase.debug_gdb:
+ print("sudo gdb " + self.app_bin +
+ " -ex 'attach {pid}'".format(pid=self.process.pid))
+ print("Now is the time to attach gdb by running the above "
+ "command and set up breakpoints etc., then resume from"
+ " within gdb by issuing the 'continue' command")
+ print(single_line_delim)
+ input("Press ENTER to continue running the testcase...")
+
def run(self):
executable = self.args[0]
if not os.path.exists(executable) or not os.access(
self.result = os.EX_OSFILE
raise EnvironmentError(
"executable '%s' is not found or executable." % executable)
- self.logger.debug("Running executable w/args `%s'" % self.args)
+ self.logger.debug("Running executable: '{app}'"
+ .format(app=' '.join(self.args)))
env = os.environ.copy()
env.update(self.env)
env["CK_LOG_FILE_NAME"] = "-"
self.process = subprocess.Popen(
self.args, shell=False, env=env, preexec_fn=os.setpgrp,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ self.wait_for_enter()
out, err = self.process.communicate()
- self.logger.debug("Finished running `%s'" % executable)
+ self.logger.debug("Finished running `{app}'".format(app=self.app_name))
self.logger.info("Return code is `%s'" % self.process.returncode)
self.logger.info(single_line_delim)
- self.logger.info("Executable `%s' wrote to stdout:" % executable)
+ self.logger.info("Executable `{app}' wrote to stdout:"
+ .format(app=self.app_name))
self.logger.info(single_line_delim)
- self.logger.info(out)
+ self.logger.info(out.decode('utf-8'))
self.logger.info(single_line_delim)
- self.logger.info("Executable `%s' wrote to stderr:" % executable)
+ self.logger.info("Executable `{app}' wrote to stderr:"
+ .format(app=self.app_name))
self.logger.info(single_line_delim)
- self.logger.info(err)
+ self.logger.info(err.decode('utf-8'))
self.logger.info(single_line_delim)
self.result = self.process.returncode