From 489ce2f42514b4324e5c63e93ae7570cab995254 Mon Sep 17 00:00:00 2001 From: Lucas Bates Date: Mon, 24 Jun 2019 21:00:27 -0400 Subject: tc-testing: Restore original behaviour for namespaces in tdc This patch restores the original behaviour for tdc prior to the introduction of the plugin system, where the network namespace functionality was split from the main script. It introduces the concept of required plugins for testcases, and will automatically load any plugin that isn't already enabled when said plugin is required by even one testcase. Additionally, the -n option for the nsPlugin is deprecated so the default action is to make use of the namespaces. Instead, we introduce -N to not use them, but still create the veth pair. buildebpfPlugin's -B option is also deprecated. If a test cases requires the features of a specific plugin in order to pass, it should instead include a new key/value pair describing plugin interactions: "plugins": { "requires": "buildebpfPlugin" }, A test case can have more than one required plugin: a list can be inserted as the value for 'requires'. Signed-off-by: Lucas Bates Acked-by: Davide Caratti Tested-by: Nicolas Dichtel Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 78 +++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 3 deletions(-) (limited to 'tools/testing/selftests/tc-testing/tdc.py') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index 5cee15659e5f..678182a2676d 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -25,6 +25,9 @@ from tdc_helper import * import TdcPlugin from TdcResults import * +class PluginDependencyException(Exception): + def __init__(self, missing_pg): + self.missing_pg = missing_pg class PluginMgrTestFail(Exception): def __init__(self, stage, output, message): @@ -37,7 +40,7 @@ class PluginMgr: super().__init__() self.plugins = {} self.plugin_instances = [] - self.args = [] + self.failed_plugins = {} self.argparser = argparser # TODO, put plugins in order @@ -53,6 +56,64 @@ class PluginMgr: self.plugins[mn] = foo self.plugin_instances.append(foo.SubPlugin()) + def load_plugin(self, pgdir, pgname): + pgname = pgname[0:-3] + foo = importlib.import_module('{}.{}'.format(pgdir, pgname)) + self.plugins[pgname] = foo + self.plugin_instances.append(foo.SubPlugin()) + self.plugin_instances[-1].check_args(self.args, None) + + def get_required_plugins(self, testlist): + ''' + Get all required plugins from the list of test cases and return + all unique items. + ''' + reqs = [] + for t in testlist: + try: + if 'requires' in t['plugins']: + if isinstance(t['plugins']['requires'], list): + reqs.extend(t['plugins']['requires']) + else: + reqs.append(t['plugins']['requires']) + except KeyError: + continue + reqs = get_unique_item(reqs) + return reqs + + def load_required_plugins(self, reqs, parser, args, remaining): + ''' + Get all required plugins from the list of test cases and load any plugin + that is not already enabled. + ''' + pgd = ['plugin-lib', 'plugin-lib-custom'] + pnf = [] + + for r in reqs: + if r not in self.plugins: + fname = '{}.py'.format(r) + source_path = [] + for d in pgd: + pgpath = '{}/{}'.format(d, fname) + if os.path.isfile(pgpath): + source_path.append(pgpath) + if len(source_path) == 0: + print('ERROR: unable to find required plugin {}'.format(r)) + pnf.append(fname) + continue + elif len(source_path) > 1: + print('WARNING: multiple copies of plugin {} found, using version found') + print('at {}'.format(source_path[0])) + pgdir = source_path[0] + pgdir = pgdir.split('/')[0] + self.load_plugin(pgdir, fname) + if len(pnf) > 0: + raise PluginDependencyException(pnf) + + parser = self.call_add_args(parser) + (args, remaining) = parser.parse_known_args(args=remaining, namespace=args) + return args + def call_pre_suite(self, testcount, testidlist): for pgn_inst in self.plugin_instances: pgn_inst.pre_suite(testcount, testidlist) @@ -98,6 +159,9 @@ class PluginMgr: command = pgn_inst.adjust_command(stage, command) return command + def set_args(self, args): + self.args = args + @staticmethod def _make_argparser(args): self.argparser = argparse.ArgumentParser( @@ -550,6 +614,7 @@ def filter_tests_by_category(args, testlist): return answer + def get_test_cases(args): """ If a test case file is specified, retrieve tests from that file. @@ -611,7 +676,7 @@ def get_test_cases(args): return allcatlist, allidlist, testcases_by_cats, alltestcases -def set_operation_mode(pm, args): +def set_operation_mode(pm, parser, args, remaining): """ Load the test case data and process remaining arguments to determine what the script should do for this run, and call the appropriate @@ -649,6 +714,12 @@ def set_operation_mode(pm, args): exit(0) if len(alltests): + req_plugins = pm.get_required_plugins(alltests) + try: + args = pm.load_required_plugins(req_plugins, parser, args, remaining) + except PluginDependencyException as pde: + print('The following plugins were not found:') + print('{}'.format(pde.missing_pg)) catresults = test_runner(pm, args, alltests) if args.format == 'none': print('Test results output suppression requested\n') @@ -686,11 +757,12 @@ def main(): parser = pm.call_add_args(parser) (args, remaining) = parser.parse_known_args() args.NAMES = NAMES + pm.set_args(args) check_default_settings(args, remaining, pm) if args.verbose > 2: print('args is {}'.format(args)) - set_operation_mode(pm, args) + set_operation_mode(pm, parser, args, remaining) exit(0) -- cgit v1.2.3 From a7d50a0dd81b09dc13fa9e4b55765e8684bc8226 Mon Sep 17 00:00:00 2001 From: Lucas Bates Date: Mon, 8 Jul 2019 21:34:26 -0400 Subject: tc-testing: Allow tdc plugins to see test case data Instead of only passing the test case name and ID, pass the entire current test case down to the plugins. This change allows plugins to start accepting commands and directives from the test cases themselves, for greater flexibility in testing. Signed-off-by: Lucas Bates Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/TdcPlugin.py | 5 ++--- tools/testing/selftests/tc-testing/tdc.py | 10 +++++----- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'tools/testing/selftests/tc-testing/tdc.py') diff --git a/tools/testing/selftests/tc-testing/TdcPlugin.py b/tools/testing/selftests/tc-testing/TdcPlugin.py index b980a565fa89..79f3ca8617c9 100644 --- a/tools/testing/selftests/tc-testing/TdcPlugin.py +++ b/tools/testing/selftests/tc-testing/TdcPlugin.py @@ -18,12 +18,11 @@ class TdcPlugin: if self.args.verbose > 1: print(' -- {}.post_suite'.format(self.sub_class)) - def pre_case(self, testid, test_name, test_skip): + def pre_case(self, caseinfo, test_skip): '''run commands before test_runner does one test''' if self.args.verbose > 1: print(' -- {}.pre_case'.format(self.sub_class)) - self.args.testid = testid - self.args.test_name = test_name + self.args.caseinfo = caseinfo self.args.test_skip = test_skip def post_case(self): diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index 678182a2676d..f04321ace9fb 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -122,15 +122,15 @@ class PluginMgr: for pgn_inst in reversed(self.plugin_instances): pgn_inst.post_suite(index) - def call_pre_case(self, testid, test_name, *, test_skip=False): + def call_pre_case(self, caseinfo, *, test_skip=False): for pgn_inst in self.plugin_instances: try: - pgn_inst.pre_case(testid, test_name, test_skip) + pgn_inst.pre_case(caseinfo, test_skip) except Exception as ee: print('exception {} in call to pre_case for {} plugin'. format(ee, pgn_inst.__class__)) print('test_ordinal is {}'.format(test_ordinal)) - print('testid is {}'.format(testid)) + print('testid is {}'.format(caseinfo['id'])) raise def call_post_case(self): @@ -261,14 +261,14 @@ def run_one_test(pm, args, index, tidx): res = TestResult(tidx['id'], tidx['name']) res.set_result(ResultState.skip) res.set_errormsg('Test case designated as skipped.') - pm.call_pre_case(tidx['id'], tidx['name'], test_skip=True) + pm.call_pre_case(tidx, test_skip=True) pm.call_post_execute() return res # populate NAMES with TESTID for this test NAMES['TESTID'] = tidx['id'] - pm.call_pre_case(tidx['id'], tidx['name']) + pm.call_pre_case(tidx) prepare_env(args, pm, 'setup', "-----> prepare stage", tidx["setup"]) if (args.verbose > 0): -- cgit v1.2.3