From mboxrd@z Thu Jan 1 00:00:00 1970 From: Amos Kong Subject: Re: [AUTOTEST][PATCH] Add ability to call autotest client tests from kvm tests like a subtest. Date: Wed, 11 May 2011 11:13:49 +0800 Message-ID: <20110511031349.GA2632@t400> References: <1304520159-9267-1-git-send-email-jzupka@redhat.com> Reply-To: Amos Kong Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: kvm-autotest@redhat.com, kvm@vger.kernel.org, autotest@test.kernel.org, lmr@redhat.com, ldoktor@redhat.com To: =?utf-8?B?SmnFmcOtIMW9dXBrYQ==?= Return-path: Received: from mx1.redhat.com ([209.132.183.28]:39312 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753960Ab1EKDNx (ORCPT ); Tue, 10 May 2011 23:13:53 -0400 Content-Disposition: inline In-Reply-To: <1304520159-9267-1-git-send-email-jzupka@redhat.com> Sender: kvm-owner@vger.kernel.org List-ID: On Wed, May 04, 2011 at 04:42:39PM +0200, Ji=C5=99=C3=AD =C5=BDupka wro= te: > Example run client/tests/sleeptest. >=20 > test.runsubtest("sleeptest", **args) >=20 > args is dictionary with parameters for subtest. > For sleeptest looks like { "seconds":5 }. > This args says sleeptest sleep 5 seconds. >=20 > This patch are necessary to avoid of creation double version of test. > netperf, multicast, etc.. >=20 > Make patch of tests_base.cfs.sample in correct way. >=20 > Signed-off-by: Ji=C5=99=C3=AD =C5=BDupka Patch works for me, it would be better if you can split different=20 kind of fixes(adding new feature, adding helper function, fixing bug, fixing coding style, ..) to single patches > --- > client/bin/client_logging_config.py | 5 +- > client/bin/net/net_utils.py | 16 ++++- > client/common_lib/base_job.py | 2 + > client/common_lib/logging_config.py | 3 +- > client/common_lib/test.py | 21 ++++++- > client/tests/kvm/tests/subtest.py | 19 +++++ > client/tests/kvm/tests_base.cfg.sample | 6 ++ > client/tests/netperf2/netperf2.py | 3 +- > client/tools/html_report.py | 115 ++++++++++++++++++----= ---------- > client/virt/virt_test_utils.py | 19 ++++-- > 10 files changed, 148 insertions(+), 61 deletions(-) > create mode 100644 client/tests/kvm/tests/subtest.py >=20 > diff --git a/client/bin/client_logging_config.py b/client/bin/client_= logging_config.py > index a59b078..28c007d 100644 > --- a/client/bin/client_logging_config.py > +++ b/client/bin/client_logging_config.py > @@ -12,8 +12,9 @@ class ClientLoggingConfig(logging_config.LoggingCon= fig): > =20 > =20 > def configure_logging(self, results_dir=3DNone, verbose=3DFalse)= : > - super(ClientLoggingConfig, self).configure_logging(use_conso= le=3DTrue, > - verbose=3D= verbose) > + super(ClientLoggingConfig, self).configure_logging( > + use_console=3Dself= =2Euse_console, > + verbose=3Dverbose) > =20 > if results_dir: > log_dir =3D os.path.join(results_dir, 'debug') > diff --git a/client/bin/net/net_utils.py b/client/bin/net/net_utils.p= y > index 868958c..ac9b494 100644 > --- a/client/bin/net/net_utils.py > +++ b/client/bin/net/net_utils.py > @@ -5,7 +5,7 @@ This library is to release in the public repository. > =20 > import commands, os, re, socket, sys, time, struct > from autotest_lib.client.common_lib import error > -import utils > +from autotest_lib.client.common_lib import utils > =20 > TIMEOUT =3D 10 # Used for socket timeout and barrier timeout > =20 > @@ -27,6 +27,20 @@ class network_utils(object): > utils.system('/sbin/ifconfig -a') > =20 > =20 > + def get_corespond_local_ip(self, query_ip, netmask=3D"24"): This function is not used in your patch, you can split it to a single p= atch. > + """ > + Get ip address in local system which can communicate with qu= ert_ip. > + > + @param query_ip: IP of client which want communicate with au= totest machine. > + @return: IP address which can communicate with query_ip > + """ > + ip =3D utils.system_output("ip addr show to %s/%s" % (query_= ip, netmask)) > + ip =3D re.search(r"inet ([0-9.]*)/",ip) > + if ip is None: > + return ip > + return ip.group(1) > + > + > def disable_ip_local_loopback(self, ignore_status=3DFalse): > utils.system("echo '1' > /proc/sys/net/ipv4/route/no_local_l= oopback", > ignore_status=3Dignore_status) > diff --git a/client/common_lib/base_job.py b/client/common_lib/base_j= ob.py > index 843c0e8..eef9efc 100644 > --- a/client/common_lib/base_job.py > +++ b/client/common_lib/base_job.py > @@ -1117,6 +1117,7 @@ class base_job(object): > tag_parts =3D [] > =20 > # build up the parts of the tag used for the test name > + master_testpath =3D dargs.get('master_testpath', "") > base_tag =3D dargs.pop('tag', None) > if base_tag: > tag_parts.append(str(base_tag)) > @@ -1132,6 +1133,7 @@ class base_job(object): > if subdir_tag: > tag_parts.append(subdir_tag) > subdir =3D '.'.join([testname] + tag_parts) > + subdir =3D os.path.join(master_testpath, subdir) > tag =3D '.'.join(tag_parts) > =20 > return full_testname, subdir, tag > diff --git a/client/common_lib/logging_config.py b/client/common_lib/= logging_config.py > index afe754a..9114d7a 100644 > --- a/client/common_lib/logging_config.py > +++ b/client/common_lib/logging_config.py > @@ -32,9 +32,10 @@ class LoggingConfig(object): > fmt=3D'%(asctime)s %(levelname)-5.5s| %(message)s', > datefmt=3D'%H:%M:%S') > =20 > - def __init__(self): > + def __init__(self, use_console=3DTrue): > self.logger =3D logging.getLogger() > self.global_level =3D logging.DEBUG > + self.use_console =3D use_console > =20 > =20 > @classmethod > diff --git a/client/common_lib/test.py b/client/common_lib/test.py > index c55d23b..b1a0904 100644 > --- a/client/common_lib/test.py > +++ b/client/common_lib/test.py > @@ -465,6 +465,24 @@ class base_test(object): > self.job.enable_warnings("NETWORK") > =20 > =20 > + def runsubtest(self, url, *args, **dargs): > + """ > + This call subtest in running test. > + > + @param test: Parent test. > + @param url: Url of new test. > + @param tag: Tag added to test name. > + @param args: Args for subtest. > + @param dargs: Distionary args for subtest. > + @iterations: Number of iteration of subtest. > + @profile_inly: If true not profile. > + """ > + dargs["profile_only"] =3D dargs.get("profile_only", True) > + test_basepath =3D self.outputdir[len(self.job.resultdir + "/= "):] > + self.job.run_test(url, master_testpath=3Dtest_basepath, > + *args, **dargs) > + > + > def _get_nonstar_args(func): > """Extract all the (normal) function parameter names. > =20 > @@ -658,7 +676,8 @@ def runtest(job, url, tag, args, dargs, > if not bindir: > raise error.TestError(testname + ': test does not exist'= ) > =20 > - outputdir =3D os.path.join(job.resultdir, testname) > + subdir =3D os.path.join(dargs.pop('master_testpath', ""), testna= me) > + outputdir =3D os.path.join(job.resultdir, subdir) > if tag: > outputdir +=3D '.' + tag > =20 > diff --git a/client/tests/kvm/tests/subtest.py b/client/tests/kvm/tes= ts/subtest.py > new file mode 100644 > index 0000000..c2baadc > --- /dev/null > +++ b/client/tests/kvm/tests/subtest.py > @@ -0,0 +1,19 @@ > +import os, logging > + > + > +def run_subtest(test, params, env): > + """ > + Run an autotest test inside a guest and subtest on host side. > + This test should be substitution netperf test in kvm. > + > + @param test: kvm test object. > + @param params: Dictionary with test parameters. > + @param env: Dictionary with the test environment. > + """ > + > + # Collect test parameters > + test_control_file =3D params.get("test_control_file") > + args =3D eval(params.get("test_control_args")) > + > + # Run subtest with args. > + test.runsubtest(test_control_file, **args) > diff --git a/client/tests/kvm/tests_base.cfg.sample b/client/tests/kv= m/tests_base.cfg.sample > index 810a4bd..c7c05a5 100644 > --- a/client/tests/kvm/tests_base.cfg.sample > +++ b/client/tests/kvm/tests_base.cfg.sample > @@ -261,6 +261,12 @@ variants: > - systemtap: > test_control_file =3D systemtap.control > =20 > + - subtest: install setup unattended_install.cdrom > + type =3D subtest > + test_timeout =3D 1800 > + test_control_file =3D sleeptest > + test_control_args =3D {"seconds": 5} > + > - linux_s3: install setup unattended_install.cdrom > only Linux > type =3D linux_s3 > diff --git a/client/tests/netperf2/netperf2.py b/client/tests/netperf= 2/netperf2.py > index 1b659dd..23d25c5 100644 > --- a/client/tests/netperf2/netperf2.py > +++ b/client/tests/netperf2/netperf2.py > @@ -2,6 +2,7 @@ import os, time, re, logging > from autotest_lib.client.bin import test, utils > from autotest_lib.client.bin.net import net_utils > from autotest_lib.client.common_lib import error > +from autotest_lib.client.common_lib import barrier > =20 > MPSTAT_IX =3D 0 > NETPERF_IX =3D 1 > @@ -36,7 +37,7 @@ class netperf2(test.test): > =20 > def run_once(self, server_ip, client_ip, role, test =3D 'TCP_STR= EAM', > test_time =3D 15, stream_list =3D [1], test_specifi= c_args =3D '', > - cpu_affinity =3D '', dev =3D '', bidi =3D False, wa= it_time =3D 5): > + cpu_affinity =3D '', dev =3D '', bidi =3D False, wa= it_time =3D 2): why reduce the wait time ? > """ > server_ip: IP address of host running netserver > client_ip: IP address of host running netperf client(s) > diff --git a/client/tools/html_report.py b/client/tools/html_report.p= y > index 7b17a75..563a7a9 100755 > --- a/client/tools/html_report.py > +++ b/client/tools/html_report.py need split fix of html_report to a single patch. > @@ -1372,7 +1372,7 @@ function processList(ul) { > } > """ > =20 > -stimelist =3D [] > + > =20 > =20 > def make_html_file(metadata, results, tag, host, output_file_name, d= irname): > @@ -1430,11 +1430,12 @@ return true; > total_failed =3D 0 > total_passed =3D 0 > for res in results: > - total_executed +=3D 1 > - if res['status'] =3D=3D 'GOOD': > - total_passed +=3D 1 > - else: > - total_failed +=3D 1 > + if results[res][2] !=3D None: > + total_executed +=3D 1 > + if results[res][2]['status'] =3D=3D 'GOOD': > + total_passed +=3D 1 > + else: > + total_failed +=3D 1 > stat_str =3D 'No test cases executed' > if total_executed > 0: > failed_perct =3D int(float(total_failed)/float(total_execute= d)*100) > @@ -1471,39 +1472,46 @@ id=3D"t1" class=3D"stats table-autosort:4 tab= le-autofilter table-stripeclass:alterna > > """ > print >> output, result_table_prefix > - for res in results: > - print >> output, '' > - print >> output, '%s' % res['time'] > - print >> output, '%s' % res['testcas= e'] > - if res['status'] =3D=3D 'GOOD': > - print >> output, 'PASS' > - elif res['status'] =3D=3D 'FAIL': > - print >> output, 'FAIL' > - elif res['status'] =3D=3D 'ERROR': > - print >> output, 'ERROR!' > - else: > - print >> output, '%s' % res['s= tatus'] > - # print exec time (seconds) > - print >> output, '%s' % res['exec_ti= me_sec'] > - # print log only if test failed.. > - if res['log']: > - #chop all '\n' from log text (to prevent html errors) > - rx1 =3D re.compile('(\s+)') > - log_text =3D rx1.sub(' ', res['log']) > - > - # allow only a-zA-Z0-9_ in html title name > - # (due to bug in MS-explorer) > - rx2 =3D re.compile('([^a-zA-Z_0-9])') > - updated_tag =3D rx2.sub('_', res['title']) > - > - html_body_text =3D '%s= %s' % (str(updated_tag), log_text) > - print >> output, 'Info' % (str(updated_tag), s= tr(html_body_text)) > - else: > - print >> output, '' > - # print execution time > - print >> output, 'Debug<= /A>' % os.path.join(dirname, res['title'], "debug") > + def print_result(result, indent): > + while result !=3D []: > + r =3D result.pop(0) > + print r > + res =3D results[r][2] > + print >> output, '' > + print >> output, '%s' % res['tim= e'] > + print >> output, '%s' % (indent * 20, res['title']) > + if res['status'] =3D=3D 'GOOD': > + print >> output, 'PASS' > + elif res['status'] =3D=3D 'FAIL': > + print >> output, 'FAIL' > + elif res['status'] =3D=3D 'ERROR': > + print >> output, 'ERROR!' > + else: > + print >> output, '%s' % re= s['status'] > + # print exec time (seconds) > + print >> output, '%s' % res['exe= c_time_sec'] > + # print log only if test failed.. > + if res['log']: > + #chop all '\n' from log text (to prevent html errors= ) > + rx1 =3D re.compile('(\s+)') > + log_text =3D rx1.sub(' ', res['log']) > + > + # allow only a-zA-Z0-9_ in html title name > + # (due to bug in MS-explorer) > + rx2 =3D re.compile('([^a-zA-Z_0-9])') > + updated_tag =3D rx2.sub('_', res['title']) > + > + html_body_text =3D '%s%s' % (str(updated_tag), log_text) > + print >> output, 'Info' % (str(updated_tag= ), str(html_body_text)) > + else: > + print >> output, '' > + # print execution time > + print >> output, 'De= bug' % os.path.join(dirname, res['subdir'], "debug") > =20 > - print >> output, '' > + print >> output, '' > + print_result(results[r][1], indent + 1) > + > + print_result(results[""][1], 0) > print >> output, "" > =20 > =20 > @@ -1531,21 +1539,27 @@ id=3D"t1" class=3D"stats table-autosort:4 tab= le-autofilter table-stripeclass:alterna > output.close() > =20 > =20 > -def parse_result(dirname, line): > +def parse_result(dirname, line, results_data): > """ > Parse job status log line. > =20 > @param dirname: Job results dir > @param line: Status log line. > + @param results_data: Dictionary with for results. > """ > parts =3D line.split() > if len(parts) < 4: > return None > - global stimelist > + global tests > if parts[0] =3D=3D 'START': > pair =3D parts[3].split('=3D') > stime =3D int(pair[1]) > - stimelist.append(stime) > + results_data[parts[1]] =3D [stime, [], None] > + try: > + parent_test =3D re.findall(r".*/", parts[1])[0][:-1] > + results_data[parent_test][1].append(parts[1]) > + except IndexError: > + results_data[""][1].append(parts[1]) > =20 > elif (parts[0] =3D=3D 'END'): > result =3D {} > @@ -1562,21 +1576,25 @@ def parse_result(dirname, line): > result['exec_time_sec'] =3D 'na' > tag =3D parts[3] > =20 > + result['subdir'] =3D parts[2] > # assign actual values > rx =3D re.compile('^(\w+)\.(.*)$') > m1 =3D rx.findall(parts[3]) > - result['testcase'] =3D str(tag) > + if len(m1): > + result['testcase'] =3D m1[0][1] > + else: > + result['testcase'] =3D parts[3] > result['title'] =3D str(tag) > result['status'] =3D parts[1] > if result['status'] !=3D 'GOOD': > result['log'] =3D get_exec_log(dirname, tag) > - if len(stimelist)>0: > + if len(results_data)>0: > pair =3D parts[4].split('=3D') > etime =3D int(pair[1]) > - stime =3D stimelist.pop() > + stime =3D results_data[parts[2]][0] > total_exec_time_sec =3D etime - stime > result['exec_time_sec'] =3D total_exec_time_sec > - return result > + results_data[parts[2]][2] =3D result > return None > =20 > =20 > @@ -1699,16 +1717,15 @@ def create_report(dirname, html_path=3D'', ou= tput_file_name=3DNone): > host =3D get_info_file(os.path.join(sysinfo_dir, 'hostname')) > rx =3D re.compile('^\s+[END|START].*$') > # create the results set dict > - results_data =3D [] > + results_data =3D {} > + results_data[""] =3D [0, [], None] > if os.path.exists(status_file_name): > f =3D open(status_file_name, "r") > lines =3D f.readlines() > f.close() > for line in lines: > if rx.match(line): > - result_dict =3D parse_result(dirname, line) > - if result_dict: > - results_data.append(result_dict) > + parse_result(dirname, line, results_data) > # create the meta info dict > metalist =3D { > 'uname': get_info_file(os.path.join(sysinfo_dir, 'un= ame')), > diff --git a/client/virt/virt_test_utils.py b/client/virt/virt_test_u= tils.py > index e3a18d2..556d3e5 100644 > --- a/client/virt/virt_test_utils.py > +++ b/client/virt/virt_test_utils.py > @@ -430,13 +430,15 @@ def get_memory_info(lvms): > return meminfo > =20 > =20 > -def run_autotest(vm, session, control_path, timeout, outputdir, para= ms): > +def run_autotest(vm, session, control_path, control_args, timeout, o= utputdir, > + params): > """ > Run an autotest control file inside a guest (linux only utility)= =2E > =20 > @param vm: VM object. > @param session: A shell session on the VM provided. > @param control_path: A path to an autotest control file. > + @param control_args: An argumets for control file. > @param timeout: Timeout under which the autotest control file mu= st complete. > @param outputdir: Path on host where we should copy the guest au= totest > results to. > @@ -561,6 +563,10 @@ def run_autotest(vm, session, control_path, time= out, outputdir, params): > pass > try: > bg =3D None > + if control_args !=3D None: > + control_args =3D ' -a "' + control_args + '"' > + else: > + control_args =3D "" > try: > logging.info("---------------- Test output -------------= ---") > if migrate_background: > @@ -568,7 +574,8 @@ def run_autotest(vm, session, control_path, timeo= ut, outputdir, params): > mig_protocol =3D params.get("migration_protocol", "t= cp") > =20 > bg =3D virt_utils.Thread(session.cmd_output, > - kwargs=3D{'cmd': "bin/autotest= control", > + kwargs=3D{'cmd': "bin/autotest= control" + > + control_args, > 'timeout': timeout, > 'print_func': logging.= info}) > =20 > @@ -579,8 +586,8 @@ def run_autotest(vm, session, control_path, timeo= ut, outputdir, params): > "migration ...") > vm.migrate(timeout=3Dmig_timeout, protocol=3Dmig= _protocol) > else: > - session.cmd_output("bin/autotest control", timeout=3D= timeout, > - print_func=3Dlogging.info) > + session.cmd_output("bin/autotest control" + control_= args, > + timeout=3Dtimeout, print_func=3Dl= ogging.info) > finally: > logging.info("------------- End of test output ---------= ---") > if migrate_background and bg: > @@ -624,8 +631,8 @@ def run_autotest(vm, session, control_path, timeo= ut, outputdir, params): > =20 > def get_loss_ratio(output): > """ > - Get the packet loss ratio from the output of ping > -. > + Get the packet loss ratio from the output of ping. > + > @param output: Ping output. > """ > try: > --=20 > 1.7.4.4 >=20