From 7d31ab2a5cc2124ddd973ac5dfac2219619f345a Mon Sep 17 00:00:00 2001 From: Dave Barach Date: Wed, 8 May 2019 19:18:18 -0400 Subject: add mactime plugin unit / code coverage tests The unit and code coverage tests are boring. The rest of the patch involves test and packet-generator infra cleanups. Teach the "make test-xxx" family of targets to set the api test plugin path correctly, to make "binary-api " debug CLI commands work correctly in the "make test" environment. Unfortunately involves both the top-level and test Makefiles. Add a minor pg cli feature, a CLI to manually set s->sw_if_index[VLIB_TX]. Consider the case where one configures an interface with both a device-input and an output feature. To test the output feature using the pg, it's necessary to inject packets into the interface output node with both b->sw_if_index[VLIB_TX] and b->sw_if_index[VLIB_RX] set correctly. For example: packet-generator new { name tx limit 15 size 128-128 interface local0 # rx: device input feature not configured on local0 tx-interface loop0 # tx: output node requires b->sw_if_index[VLIB_TX] node loop0-output data { hex 0x01005e7ffffa000dead0000008000102030405060708090a0b0c0d0e0f0102030405 } } Fix a longstanding bug in the packet generator stream setup. Remove kludges which set b->sw_if_index[VLIB_TX] to ~0 [in multiple places] instead of using the stream value s->sw_if_index[VLIB_TX], and setting THAT datum correctly. Change-Id: I1097a18e8db73661ded6b822c1d718f7e5cf36ed Signed-off-by: Dave Barach --- Makefile | 4 + src/plugins/mactime/mactime.c | 7 +- src/plugins/unittest/CMakeLists.txt | 1 + src/plugins/unittest/mactime_test.c | 181 ++++++++++++++++++++++++++++++++++++ src/vnet/pg/cli.c | 27 ++++-- src/vnet/pg/input.c | 7 +- src/vnet/pg/stream.c | 16 ++-- src/vpp/api/plugin.c | 5 +- src/vpp/vnet/main.c | 22 ++++- test/Makefile | 1 + test/framework.py | 4 + test/test_mactime.py | 155 ++++++++++++++++++++++++++++++ 12 files changed, 400 insertions(+), 30 deletions(-) create mode 100644 src/plugins/unittest/mactime_test.c create mode 100644 test/test_mactime.py diff --git a/Makefile b/Makefile index f5f7ee6d2ca..8a1eaa277d5 100644 --- a/Makefile +++ b/Makefile @@ -388,6 +388,7 @@ define test VPP_BUILD_DIR=$(BR)/build-$(2)-native \ VPP_BIN=$(BR)/install-$(2)-native/vpp/bin/vpp \ VPP_PLUGIN_PATH=$(call libexpand,$(libs),$(2),vpp_plugins) \ + VPP_TEST_PLUGIN_PATH=$(call libexpand,$(libs),$(2),vpp_api_test_plugins) \ VPP_INSTALL_PATH=$(BR)/install-$(2)-native/ \ LD_LIBRARY_PATH=$(call libexpand,$(libs),$(2),) \ EXTENDED_TESTS=$(EXTENDED_TESTS) \ @@ -428,6 +429,9 @@ test-shell: test-shell-debug: $(call test,vpp,vpp_debug,shell) +test-shell-gcov: + $(call test,vpp,vpp_gcov,shell) + test-dep: @make -C test test-dep diff --git a/src/plugins/mactime/mactime.c b/src/plugins/mactime/mactime.c index 6cbddbc7a44..1b053faa2e8 100644 --- a/src/plugins/mactime/mactime.c +++ b/src/plugins/mactime/mactime.c @@ -126,6 +126,8 @@ mactime_enable_disable_command_fn (vlib_main_t * vm, else if (unformat (input, "%U", unformat_vnet_sw_interface, mm->vnet_main, &sw_if_index)) ; + else if (unformat (input, "sw_if_index %d", &sw_if_index)) + ; else break; } @@ -145,11 +147,6 @@ mactime_enable_disable_command_fn (vlib_main_t * vm, (0, "Invalid interface, only works on physical ports"); break; - case VNET_API_ERROR_UNIMPLEMENTED: - return clib_error_return (0, - "Device driver doesn't support redirection"); - break; - default: return clib_error_return (0, "mactime_enable_disable returned %d", rv); } diff --git a/src/plugins/unittest/CMakeLists.txt b/src/plugins/unittest/CMakeLists.txt index 8e8142dee38..5b7e1f7655e 100644 --- a/src/plugins/unittest/CMakeLists.txt +++ b/src/plugins/unittest/CMakeLists.txt @@ -25,6 +25,7 @@ add_vpp_plugin(unittest fib_test.c ipsec_test.c interface_test.c + mactime_test.c mfib_test.c punt_test.c rbtree_test.c diff --git a/src/plugins/unittest/mactime_test.c b/src/plugins/unittest/mactime_test.c new file mode 100644 index 00000000000..907022f4d88 --- /dev/null +++ b/src/plugins/unittest/mactime_test.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2015 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +static int +test_time_range_main (unformat_input_t * input) +{ + clib_timebase_t _tb, *tb = &_tb; + clib_timebase_component_t _c, *cp = &_c; + clib_timebase_range_t *rp = 0; + clib_timebase_range_t *this_rp; + unformat_input_t _input2, *input2 = &_input2; + char *test_range_string; + f64 sunday_midnight; + f64 now, then; + f64 start_time, end_time; + f64 timezone_offset; + + /* Init time base */ + clib_timebase_init (tb, -5 /* EST */ , CLIB_TIMEBASE_DAYLIGHT_USA); + + /* Set up summer time cache */ + now = clib_timebase_now (tb); + + /* Test it */ + now = clib_timebase_now (tb); + + /* show current time */ + fformat (stdout, "Current time in UTC%f, US daylight time rules:\n", + tb->timezone_offset / 3600.0); + fformat (stdout, "%U", format_clib_timebase_time, now); + + /* Test conversion to component structure */ + clib_timebase_time_to_components (now, cp); + now = clib_timebase_components_to_time (cp); + fformat (stdout, " -> %U\n", format_clib_timebase_time, now); + + /* + * test a few other dates, to verify summer time operation + * 2011: started sunday 3/13, ended sunday 11/6 + */ + + fformat (stdout, "Test daylight time rules:\n"); + + clib_memset (cp, 0, sizeof (*cp)); + + /* Just before DST starts */ + cp->year = 2011; + cp->month = 2; + cp->day = 13; + cp->hour = 1; + cp->minute = 59; + cp->second = 59; + then = clib_timebase_components_to_time (cp); + + timezone_offset = clib_timebase_summer_offset_fastpath (tb, then); + + fformat (stdout, "%U should not be in DST, and it %s\n", + format_clib_timebase_time, then, + (timezone_offset != 0.0) ? "is" : "is not"); + + /* add two seconds */ + + then += 2.0; + + timezone_offset = clib_timebase_summer_offset_fastpath (tb, then); + + fformat (stdout, "%U should be in DST, and it %s\n", + format_clib_timebase_time, then, + (timezone_offset != 0.0) ? "is" : "is not"); + + /* Just before DST ends */ + cp->year = 2011; + cp->month = 10; + cp->day = 6; + cp->hour = 1; + cp->minute = 59; + cp->second = 59; + then = clib_timebase_components_to_time (cp); + + timezone_offset = clib_timebase_summer_offset_fastpath (tb, then); + + fformat (stdout, "%U should be in DST, and it %s\n", + format_clib_timebase_time, then, + (timezone_offset != 0.0) ? "is" : "is not"); + + /* add two seconds. */ + + then += 2.0; + + timezone_offset = clib_timebase_summer_offset_fastpath (tb, then); + + fformat (stdout, "%U should not be in DST, and it %s\n", + format_clib_timebase_time, then, + (timezone_offset != 0.0) ? "is" : "is not"); + + /* Back to the future... */ + clib_timebase_time_to_components (now, cp); + + fformat (stdout, "Test time range calculations:\n"); + + /* Find previous Sunday midnight */ + sunday_midnight = now = clib_timebase_find_sunday_midnight (now); + + clib_timebase_time_to_components (now, cp); + + fformat (stdout, "Sunday midnight: %U\n", format_clib_timebase_time, now); + + test_range_string = "Mon 11 - 17 Tue 7 - 11 Wed - Fri 8 - 18"; + + unformat_init_string (input2, test_range_string, + strlen (test_range_string)); + + if (unformat (input2, "%U", unformat_clib_timebase_range_vector, &rp)) + { + vec_foreach (this_rp, rp) + { + start_time = sunday_midnight + this_rp->start; + end_time = sunday_midnight + this_rp->end; + fformat (stdout, "range: %U - %U\n", + format_clib_timebase_time, start_time, + format_clib_timebase_time, end_time); + } + vec_free (rp); + } + else + { + fformat (stdout, "Time convert fail!\n"); + return -1; + } + + unformat_free (input2); + + return 0; +} + + +static clib_error_t * +test_time_range_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + int rv; + + rv = test_time_range_main (input); + + if (rv) + return clib_error_return (0, "test time range FAILED, error %d", rv); + + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (test_time_range_command, static) = +{ + .path = "test time-range", + .short_help = "test time-range", + .function = test_time_range_command_fn, +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/src/vnet/pg/cli.c b/src/vnet/pg/cli.c index 4526986d1ff..9c42d70a383 100644 --- a/src/vnet/pg/cli.c +++ b/src/vnet/pg/cli.c @@ -109,19 +109,26 @@ static clib_error_t * enable_disable_stream (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { + unformat_input_t _line_input, *line_input = &_line_input; pg_main_t *pg = &pg_main; int is_enable = cmd->function_arg != 0; u32 stream_index = ~0; - if (unformat (input, "%U", unformat_eof)) - ; - else if (unformat (input, "%U", unformat_hash_vec_string, - pg->stream_index_by_name, &stream_index)) - ; - else - return clib_error_create ("unknown input `%U'", - format_unformat_error, input); + if (!unformat_user (input, unformat_line_input, line_input)) + goto doit; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "%U", unformat_hash_vec_string, + pg->stream_index_by_name, &stream_index)) + ; + else + return clib_error_create ("unknown input `%U'", + format_unformat_error, line_input); + } + unformat_free (line_input); +doit: pg_enable_disable (stream_index, is_enable); return 0; @@ -374,6 +381,10 @@ new_stream (vlib_main_t * vm, unformat_vnet_sw_interface, vnm, &s.sw_if_index[VLIB_RX])) ; + else if (unformat (input, "tx-interface %U", + unformat_vnet_sw_interface, vnm, + &s.sw_if_index[VLIB_TX])) + ; else if (unformat (input, "pcap %s", &pcap_file_name)) ; diff --git a/src/vnet/pg/input.c b/src/vnet/pg/input.c index 39f06923072..7171bbdda65 100644 --- a/src/vnet/pg/input.c +++ b/src/vnet/pg/input.c @@ -1108,7 +1108,7 @@ init_buffers_inline (vlib_main_t * vm, vnet_buffer (b1)->sw_if_index[VLIB_RX] = s->sw_if_index[VLIB_RX]; vnet_buffer (b0)->sw_if_index[VLIB_TX] = - vnet_buffer (b1)->sw_if_index[VLIB_TX] = (u32) ~ 0; + vnet_buffer (b1)->sw_if_index[VLIB_TX] = s->sw_if_index[VLIB_TX]; if (set_data) { @@ -1133,8 +1133,7 @@ init_buffers_inline (vlib_main_t * vm, b0 = vlib_get_buffer (vm, bi0); vnet_buffer (b0)->sw_if_index[VLIB_RX] = s->sw_if_index[VLIB_RX]; - /* s->sw_if_index[VLIB_TX]; */ - vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = s->sw_if_index[VLIB_TX]; if (set_data) clib_memcpy_fast (b0->data, data, n_data); @@ -1266,7 +1265,7 @@ pg_stream_fill_replay (pg_main_t * pg, pg_stream_t * s, u32 n_alloc) b = vlib_get_buffer (vm, buffers[current_buffer_index]); clib_memcpy_fast (b->data, d0 + data_offset, bytes_this_chunk); vnet_buffer (b)->sw_if_index[VLIB_RX] = s->sw_if_index[VLIB_RX]; - vnet_buffer (b)->sw_if_index[VLIB_TX] = (u32) ~ 0; + vnet_buffer (b)->sw_if_index[VLIB_TX] = s->sw_if_index[VLIB_TX]; b->flags = 0; b->next_buffer = 0; b->current_data = 0; diff --git a/src/vnet/pg/stream.c b/src/vnet/pg/stream.c index c60c5845af6..64fe7c859ae 100644 --- a/src/vnet/pg/stream.c +++ b/src/vnet/pg/stream.c @@ -447,16 +447,16 @@ pg_stream_add (pg_main_t * pg, pg_stream_t * s_init) /* Find an interface to use. */ s->pg_if_index = pg_interface_add_or_get (pg, s->if_id); - { - pg_interface_t *pi = pool_elt_at_index (pg->interfaces, s->pg_if_index); - vlib_rx_or_tx_t rx_or_tx; - - vlib_foreach_rx_tx (rx_or_tx) + if (s->sw_if_index[VLIB_RX] == ~0) { - if (s->sw_if_index[rx_or_tx] == ~0) - s->sw_if_index[rx_or_tx] = pi->sw_if_index; + pg_interface_t *pi = pool_elt_at_index (pg->interfaces, s->pg_if_index); + /* + * Default the RX interface if unset. It's a bad mistake to + * set [VLIB_TX] prior to ip lookup, since the ip lookup code + * interprets [VLIB_TX] as a fib index... + */ + s->sw_if_index[VLIB_RX] = pi->sw_if_index; } - } /* Connect the graph. */ s->next_index = vlib_node_add_next (vm, device_input_node.index, diff --git a/src/vpp/api/plugin.c b/src/vpp/api/plugin.c index 51f3461f1ec..73a20d42dc1 100644 --- a/src/vpp/api/plugin.c +++ b/src/vpp/api/plugin.c @@ -177,10 +177,7 @@ vat_load_new_plugins (plugin_main_t * pm) #define QUOTE_(x) #x #define QUOTE(x) QUOTE_(x) -/* - * Load plugins from /usr/lib/vpp_api_test_plugins by default - */ -char *vat_plugin_path = "/usr/lib/vpp_api_test_plugins"; +extern char *vat_plugin_path; char *vat_plugin_name_filter = 0; diff --git a/src/vpp/vnet/main.c b/src/vpp/vnet/main.c index 6819ae6a3a4..5100d5c79b8 100644 --- a/src/vpp/vnet/main.c +++ b/src/vpp/vnet/main.c @@ -31,6 +31,7 @@ */ char *vlib_plugin_path = NULL; char *vlib_plugin_app_version = VPP_BUILD_VER; +char *vat_plugin_path = NULL; static void vpp_find_plugin_path () @@ -219,6 +220,11 @@ main (int argc, char *argv[]) if (i < (argc - 1)) vlib_plugin_path = argv[++i]; } + if (!strncmp (argv[i], "test_plugin_path", 16)) + { + if (i < (argc - 1)) + vat_plugin_path = argv[++i]; + } else if (!strncmp (argv[i], "heapsize", 8)) { sizep = (u8 *) argv[i + 1]; @@ -304,7 +310,7 @@ heapsize_config (vlib_main_t * vm, unformat_input_t * input) VLIB_CONFIG_FUNCTION (heapsize_config, "heapsize"); static clib_error_t * -plugin_path_config (vlib_main_t * vm, unformat_input_t * input) +dummy_path_config (vlib_main_t * vm, unformat_input_t * input) { u8 *junk; @@ -322,8 +328,22 @@ plugin_path_config (vlib_main_t * vm, unformat_input_t * input) return 0; } +static clib_error_t * +plugin_path_config (vlib_main_t * vm, unformat_input_t * input) +{ + return dummy_path_config (vm, input); +} + VLIB_CONFIG_FUNCTION (plugin_path_config, "plugin_path"); +static clib_error_t * +test_plugin_path_config (vlib_main_t * vm, unformat_input_t * input) +{ + return dummy_path_config (vm, input); +} + +VLIB_CONFIG_FUNCTION (test_plugin_path_config, "test_plugin_path"); + void vl_msg_api_post_mortem_dump (void); void elog_post_mortem_dump (void); diff --git a/test/Makefile b/test/Makefile index a5788223623..8c06516f991 100644 --- a/test/Makefile +++ b/test/Makefile @@ -177,6 +177,7 @@ shell: verify-test-dir $(PAPI_INSTALL_DONE) echo VPP_BUILD_DIR=$(VPP_BUILD_DIR);\ echo VPP_BIN=$(VPP_BIN);\ echo VPP_PLUGIN_PATH=$(VPP_PLUGIN_PATH);\ + echo VPP_TEST_PLUGIN_PATH=$(VPP_TEST_PLUGIN_PATH);\ echo VPP_INSTALL_PATH=$(VPP_INSTALL_PATH);\ echo EXTERN_TESTS=$(EXTERN_TESTS);\ echo EXTERN_PLUGINS=$(EXTERN_PLUGINS);\ diff --git a/test/framework.py b/test/framework.py index 1a22acd0115..47de2c4d967 100644 --- a/test/framework.py +++ b/test/framework.py @@ -286,6 +286,7 @@ class VppTestCase(unittest.TestCase): cls.set_debug_flags(d) cls.vpp_bin = os.getenv('VPP_BIN', "vpp") cls.plugin_path = os.getenv('VPP_PLUGIN_PATH') + cls.test_plugin_path = os.getenv('VPP_TEST_PLUGIN_PATH') cls.extern_plugin_path = os.getenv('EXTERN_PLUGINS') plugin_path = None if cls.plugin_path is not None: @@ -325,6 +326,9 @@ class VppTestCase(unittest.TestCase): cls.vpp_cmdline.extend(cls.extra_vpp_punt_config) if plugin_path is not None: cls.vpp_cmdline.extend(["plugin_path", plugin_path]) + if cls.test_plugin_path is not None: + cls.vpp_cmdline.extend(["test_plugin_path", cls.test_plugin_path]) + cls.logger.info("vpp_cmdline args: %s" % cls.vpp_cmdline) cls.logger.info("vpp_cmdline: %s" % " ".join(cls.vpp_cmdline)) diff --git a/test/test_mactime.py b/test/test_mactime.py new file mode 100644 index 00000000000..ab3d5371815 --- /dev/null +++ b/test/test_mactime.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python + +import unittest + +from framework import VppTestCase, VppTestRunner, running_extended_tests +from vpp_ip_route import VppIpTable, VppIpRoute, VppRoutePath + + +class TestMactime(VppTestCase): + """ Mactime Unit Test Cases """ + + @classmethod + def setUpClass(cls): + super(TestMactime, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestMactime, cls).tearDownClass() + + def setUp(self): + super(TestMactime, self).setUp() + + def tearDown(self): + super(TestMactime, self).tearDown() + + def test_mactime_range_unittest(self): + """ Time Range Test """ + error = self.vapi.cli("test time-range") + + if error: + self.logger.critical(error) + self.assertNotIn('FAILED', error) + + @unittest.skipUnless(running_extended_tests, "part of extended tests") + def test_mactime_unittest(self): + """ Mactime Plugin Code Coverage Test """ + cmds = ["loopback create", + "mactime enable-disable disable", + "mactime enable-disable loop0", + "mactime enable-disable loop0 disable", + "mactime enable-disable sw_if_index 9999", + "bin mactime_enable_disable loop0", + "bin mactime_enable_disable loop0 disable", + "bin mactime_enable_disable sw_if_index 1", + "set interface state loop0 up", + "clear mactime", + "set ip arp loop0 192.168.1.1 00:d0:2d:5e:86:85", + "bin mactime_add_del_range name sallow " + "mac 00:d0:2d:5e:86:85 allow-static del", + "bin mactime_add_del_range name sallow " + "mac 00:d0:2d:5e:86:85 allow-static", + "bin mactime_add_del_range name sallow " + "mac 00:d0:2d:5e:86:85 allow-static del", + "bin mactime_add_del_range name sallow " + "mac 00:d0:2d:5e:86:85 allow-static", + "bin mactime_add_del_range name sblock " + "mac 01:00:5e:7f:ff:fa drop-static", + "bin mactime_add_del_range name ddrop " + "mac c8:bc:c8:5a:ba:f3 drop-range Sun - Sat " + "00:00 - 23:59", + "bin mactime_add_del_range name dallow " + "mac c8:bc:c8:5a:ba:f4 allow-range Sun - Sat " + "00:00 - 23:59", + "bin mactime_add_del_range name multi " + "mac c8:bc:c8:f0:f0:f0 allow-range Sun - Mon " + "00:00 - 23:59 Tue - Sat 00:00 - 23:59", + "bin mactime_add_del_range bogus", + "bin mactime_add_del_range mac 01:00:5e:7f:f0:f0 allow-static", + "bin mactime_add_del_range " + "name tooloooooooooooooooooooooooooooooooooooooooooooooooo" + "nnnnnnnnnnnnnnnnnnnnnnnnnnnng mac 00:00:de:ad:be:ef " + "allow-static", + "packet-generator new {\n" + " name allow\n" + " limit 15\n" + " size 128-128\n" + " interface loop0\n" + " node ethernet-input\n" + " data {\n" + " IP6: 00:d0:2d:5e:86:85 -> 00:0d:ea:d0:00:00\n" + " ICMP: db00::1 -> db00::2\n" + " incrementing 30\n" + " }\n", + "}\n", + "packet-generator new {\n" + " name deny\n" + " limit 15\n" + " size 128-128\n" + " interface loop0\n" + " node ethernet-input\n" + " data {\n" + " IP6: 01:00:5e:7f:ff:fa -> 00:0d:ea:d0:00:00\n" + " ICMP: db00::1 -> db00::2\n" + " incrementing 30\n" + " }\n", + "}\n", + "packet-generator new {\n" + " name ddrop\n" + " limit 15\n" + " size 128-128\n" + " interface loop0\n" + " node ethernet-input\n" + " data {\n" + " IP6: c8:bc:c8:5a:ba:f3 -> 00:0d:ea:d0:00:00\n" + " ICMP: db00::1 -> db00::2\n" + " incrementing 30\n" + " }\n", + "}\n", + "packet-generator new {\n" + " name dallow\n" + " limit 15\n" + " size 128-128\n" + " interface loop0\n" + " node ethernet-input\n" + " data {\n" + " IP6: c8:bc:c8:5a:ba:f4 -> 00:0d:ea:d0:00:00\n" + " ICMP: db00::1 -> db00::2\n" + " incrementing 30\n" + " }\n" + "}\n" + "packet-generator new {\n" + " name makeentry\n" + " limit 15\n" + " size 128-128\n" + " interface loop0\n" + " node ethernet-input\n" + " data {\n" + " IP6: c8:bc:c8:5a:b0:0b -> 00:0d:ea:d0:00:00\n" + " ICMP: db00::1 -> db00::2\n" + " incrementing 30\n" + " }\n" + "}\n" + "packet-generator new {\n" + " name tx\n" + " limit 15\n" + " size 128-128\n" + " interface local0\n" + " tx-interface loop0\n" + " node loop0-output\n" + " data {\n" + " hex 0x01005e7ffffa000dead000000800" + "0102030405060708090a0b0c0d0e0f0102030405\n" + " }\n" + "}\n" + "trace add pg-input 2", + "pa en", + "show mactime verbose 2", + "show trace", + "show error"] + + for cmd in cmds: + self.logger.info(self.vapi.cli(cmd)) + +if __name__ == '__main__': + unittest.main(testRunner=VppTestRunner) -- cgit 1.2.3-korg