From ad3187fe23bb139b44c1bac7cd13dd86523fb90a Mon Sep 17 00:00:00 2001 From: Klement Sekera Date: Fri, 18 Feb 2022 10:34:35 +0000 Subject: tests: add enhanced packet counter verification Add support for inline packet counter verification to send_and_* functions. Diff dictionary is a dictionary of dictionaries of interesting stats: diff_dictionary = { "err" : { '/error/counter1' : 4, }, sw_if_index1 : { '/stat/segment/counter1' : 5, '/stat/segment/counter2' : 6, }, sw_if_index2 : { '/stat/segment/counter1' : 7, }, } It describes a per sw-if-index diffset, where each key is stat segment path and value is the expected change for that counter for sw-if-index. Special case string "err" is used for error counters. This then allows more precise packet counter verification by first defining a "zero" dictionary, e.g. for ED NAT: cls.no_diff = StatsDiff({ pg.sw_if_index: { '/nat44-ed/in2out/fastpath/tcp': 0, '/nat44-ed/in2out/fastpath/udp': 0, '/nat44-ed/in2out/fastpath/icmp': 0, '/nat44-ed/in2out/fastpath/drops': 0, '/nat44-ed/in2out/slowpath/tcp': 0, '/nat44-ed/in2out/slowpath/udp': 0, '/nat44-ed/in2out/slowpath/icmp': 0, '/nat44-ed/in2out/slowpath/drops': 0, '/nat44-ed/in2out/fastpath/tcp': 0, '/nat44-ed/in2out/fastpath/udp': 0, '/nat44-ed/in2out/fastpath/icmp': 0, '/nat44-ed/in2out/fastpath/drops': 0, '/nat44-ed/in2out/slowpath/tcp': 0, '/nat44-ed/in2out/slowpath/udp': 0, '/nat44-ed/in2out/slowpath/icmp': 0, '/nat44-ed/in2out/slowpath/drops': 0, } for pg in cls.pg_interfaces }) and then to specify only changed counters directly when calling one of send_and_* functions: self.send_and_assert_no_replies( self.pg0, pkts, msg="i2o pkts", stats_diff=self.no_diff | { "err": { '/err/nat44-ed-in2out-slowpath/out of ports': len(pkts), }, self.pg0.sw_if_index: { '/nat44-ed/in2out/slowpath/drops': len(pkts), }, } ) operator | is overloaded by StatsDiff class to perform a deep merge operation, so in above case, dictionaries for "err" and self.pg0.sw_if_index do not overwrite whole sub-dictionaries, rather the contents are merged, assuring that all the remaining counters are verified to be zero. Type: improvement Signed-off-by: Klement Sekera Change-Id: I2b87f7bd58a7d4b34ee72344e2f871b2f372e2d9 --- test/util.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) (limited to 'test/util.py') diff --git a/test/util.py b/test/util.py index e21fdb81026..653b667eb6c 100644 --- a/test/util.py +++ b/test/util.py @@ -1,12 +1,11 @@ """ test framework utilities """ -import abc import ipaddress import logging import socket from socket import AF_INET6 -import sys import os.path +from copy import deepcopy import scapy.compat from scapy.layers.l2 import Ether @@ -452,3 +451,50 @@ def reassemble4_ether(listoffragments): def reassemble4(listoffragments): return reassemble4_core(listoffragments, True) + + +def recursive_dict_merge(dict_base, dict_update): + """Recursively merge base dict with update dict, return merged dict""" + for key in dict_update: + if key in dict_base: + if type(dict_update[key]) is dict: + dict_base[key] = recursive_dict_merge(dict_base[key], + dict_update[key]) + else: + dict_base[key] = dict_update[key] + else: + dict_base[key] = dict_update[key] + return dict_base + + +class StatsDiff: + """ + Diff dictionary is a dictionary of dictionaries of interesting stats: + + diff_dictionary = + { + "err" : { '/error/counter1' : 4, }, + sw_if_index1 : { '/stat/segment/counter1' : 5, + '/stat/segment/counter2' : 6, + }, + sw_if_index2 : { '/stat/segment/counter1' : 7, + }, + } + + It describes a per sw-if-index diffset, where each key is stat segment + path and value is the expected change for that counter for sw-if-index. + Special case string "err" is used for error counters, which are not per + sw-if-index. + """ + + def __init__(self, stats_diff={}): + self.stats_diff = stats_diff + + 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 __or__(self, other): + return recursive_dict_merge(deepcopy(self.stats_diff), other) -- cgit 1.2.3-korg