From 26cd0242c95025e0d644db3a80dfe8dee83b6d7a Mon Sep 17 00:00:00 2001 From: Klement Sekera Date: Fri, 18 Feb 2022 10:35:08 +0000 Subject: [PATCH] tests: better reporting for unexpected packets Raise a new UnexpectedPacketErrror, when a packet is captured unexpectedly. This pretty-prints a terse description of said packet. Type: improvement Signed-off-by: Klement Sekera Change-Id: Ibac19fc5bbd82a150fec3c90940a37af6344fd4f --- test/framework.py | 6 ++---- test/util.py | 30 ++++++++++++++++++++---------- test/vpp_pg_interface.py | 23 +++++++++++++++-------- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/test/framework.py b/test/framework.py index 1c81e8afabc..9266227f18e 100644 --- a/test/framework.py +++ b/test/framework.py @@ -1310,8 +1310,7 @@ class VppTestCase(CPUInterface, unittest.TestCase): if not timeout: timeout = 1 for i in self.pg_interfaces: - i.get_capture(0, timeout=timeout) - i.assert_nothing_captured(remark=remark) + i.assert_nothing_captured(timeout=timeout, remark=remark) timeout = 0.1 finally: if trace: @@ -1365,8 +1364,7 @@ class VppTestCase(CPUInterface, unittest.TestCase): timeout = 1 for i in self.pg_interfaces: if i not in outputs: - i.get_capture(0, timeout=timeout) - i.assert_nothing_captured() + i.assert_nothing_captured(timeout=timeout) timeout = 0.1 if stats_diff: diff --git a/test/util.py b/test/util.py index 653b667eb6c..2c24571c350 100644 --- a/test/util.py +++ b/test/util.py @@ -6,6 +6,7 @@ import socket from socket import AF_INET6 import os.path from copy import deepcopy +from collections import UserDict import scapy.compat from scapy.layers.l2 import Ether @@ -24,8 +25,12 @@ null_logger = logging.getLogger('VppTestCase.util') null_logger.addHandler(logging.NullHandler()) +def pr(packet): + return packet.__repr__() + + def ppp(headline, packet): - """ Return string containing the output of scapy packet.show() call. """ + """ Return string containing headline and output of scapy packet.show() """ return '%s\n%s\n\n%s\n' % (headline, hexdump(packet, dump=True), packet.show(dump=True)) @@ -453,6 +458,15 @@ def reassemble4(listoffragments): return reassemble4_core(listoffragments, True) +class UnexpectedPacketError(Exception): + def __init__(self, packet, msg=""): + self.packet = packet + self.msg = msg + + def __str__(self): + return f"\nUnexpected packet:\n{pr(self.packet)}{self.msg}" + + def recursive_dict_merge(dict_base, dict_update): """Recursively merge base dict with update dict, return merged dict""" for key in dict_update: @@ -467,7 +481,7 @@ def recursive_dict_merge(dict_base, dict_update): return dict_base -class StatsDiff: +class StatsDiff(UserDict): """ Diff dictionary is a dictionary of dictionaries of interesting stats: @@ -487,14 +501,10 @@ class StatsDiff: sw-if-index. """ - def __init__(self, stats_diff={}): - self.stats_diff = stats_diff + __slots__ = () # prevent setting properties to act like a dictionary - def update(self, sw_if_index, key, value): - if sw_if_index in self.stats_diff: - self.stats_diff[sw_if_index][key] = value - else: - self.stats_diff[sw_if_index] = {key: value} + def __init__(self, data): + super().__init__(data) def __or__(self, other): - return recursive_dict_merge(deepcopy(self.stats_diff), other) + return recursive_dict_merge(deepcopy(self.data), other) diff --git a/test/vpp_pg_interface.py b/test/vpp_pg_interface.py index 01f10fccfc9..434a3005bd7 100644 --- a/test/vpp_pg_interface.py +++ b/test/vpp_pg_interface.py @@ -16,7 +16,7 @@ from scapy.layers.l2 import Ether, ARP from scapy.layers.inet6 import IPv6, ICMPv6ND_NS, ICMPv6ND_NA,\ ICMPv6NDOptSrcLLAddr, ICMPv6NDOptDstLLAddr, ICMPv6ND_RA, RouterAlert, \ IPv6ExtHdrHopByHop -from util import ppp, ppc +from util import ppp, ppc, UnexpectedPacketError from scapy.utils6 import in6_getnsma, in6_getnsmac, in6_ismaddr @@ -287,13 +287,19 @@ class VppPGInterface(VppInterface): remaining_time -= elapsed_time if capture: self.generate_debug_aid("count-mismatch") + if len(capture) > 0 and 0 == expected_count: + rem = f"\n{remark}" if remark else "" + raise UnexpectedPacketError( + capture[0], + f"\n({len(capture)} packets captured in total){rem}") raise Exception("Captured packets mismatch, captured %s packets, " "expected %s packets on %s" % (len(capture.res), expected_count, name)) else: raise Exception("No packets captured on %s" % name) - def assert_nothing_captured(self, remark=None, filter_out_fn=is_ipv6_misc): + def assert_nothing_captured(self, timeout=1, remark=None, + filter_out_fn=is_ipv6_misc): """ Assert that nothing unfiltered was captured on interface :param remark: remark printed into debug logs @@ -303,7 +309,8 @@ class VppPGInterface(VppInterface): if os.path.isfile(self.out_path): try: capture = self.get_capture( - 0, remark=remark, filter_out_fn=filter_out_fn) + 0, timeout=timeout, remark=remark, + filter_out_fn=filter_out_fn) if not capture or len(capture.res) == 0: # junk filtered out, we're good return @@ -311,12 +318,12 @@ class VppPGInterface(VppInterface): pass self.generate_debug_aid("empty-assert") if remark: - raise AssertionError( - "Non-empty capture file present for interface %s (%s)" % - (self.name, remark)) + raise UnexpectedPacketError( + capture[0], + f" ({len(capture)} packets captured in total) ({remark})") else: - raise AssertionError("Capture file present for interface %s" % - self.name) + raise UnexpectedPacketError( + capture[0], f" ({len(capture)} packets captured in total)") def wait_for_pg_stop(self): # wait till packet-generator is stopped -- 2.16.6