diff --git a/avocado-setup.py b/avocado-setup.py index 87e3165..f130430 100644 --- a/avocado-setup.py +++ b/avocado-setup.py @@ -379,17 +379,20 @@ def bootstrap(enable_kvm=False, guest_os=None): helper.copy_dir_file(postscript, postscript_dir) -def run_test(testsuite, avocado_bin, nrunner): +def run_test(testsuite, avocado_bin, runner, linux_src_path): """ To run given testsuite :param testsuite: Testsuite object which has details about the tests :param avocado_bin: Executable path of avocado + :param runner: Whether to use --test-runner runner (True) or --max-parallel-tasks=1 (False) + :param linux_src_path: Path to kernel source for gcov coverage (or None) """ - - if not nrunner: - nrunner = '--test-runner runner' + nrun = True + if runner: + runner = '--test-runner runner' + nrun = False else: - nrunner = '' + runner = '--max-parallel-tasks=1' logger.info('') if 'guest' in testsuite.type: @@ -405,7 +408,10 @@ def run_test(testsuite, avocado_bin, nrunner): testsuite.resultdir, guest_args) if 'host' in testsuite.type: logger.info("Running Host Tests Suite %s", testsuite.shortname) - cmd = "%s run %s %s" % (avocado_bin, nrunner, testsuite.test) + if nrun: + cmd = "%s run %s %s" % (avocado_bin, runner, os.path.join(TEST_DIR, testsuite.test)) + else: + cmd = "%s run %s %s" % (avocado_bin, runner, testsuite.test) if testsuite.mux: cmd += " -m %s" % os.path.join(TEST_DIR, testsuite.mux) cmd += " --force-job-id %s \ @@ -415,10 +421,33 @@ def run_test(testsuite, avocado_bin, nrunner): if testsuite.args: cmd += testsuite.args + input_file = args.inputfile try: + # Resetting the gcov flag to zero if code coverage is needed + if linux_src_path: + logger.info("kernel_src path=%s" % linux_src_path) + if not os.path.exists(linux_src_path): + exit("kernel-src path is not available, please check") + helper.gcov_reset() logger.info("Running: %s", cmd) status = os.system(cmd) status = int(bin(int(status))[2:].zfill(16)[:-8], 2) + # Capturing the test and yaml names for gcov here + if linux_src_path: + test_name = testsuite.test + " " + testsuite.tempmux + out = (testsuite.name).split("_") + test_bucket = "_".join([out[1], out[2]]) + logger.info("Capturing the Gcov data.....") + if test_bucket.startswith("io_"): + with open(input_file, 'r') as file: + for line in file: + if line.startswith("module"): + driver_name = (line.split("=")[-1]).strip() + helper.gcov_code_coverage(linux_src_path, test_name, driver_name) + else: + helper.gcov_code_coverage(linux_src_path, test_name) + helper.runcmd("cp %s/final_files.txt %s/" % (linux_src_path, outputdir), + ignore_status=True) if status >= 2: testsuite.runstatus(Testsuite_status.Not_Run.value, "Command execution failed") count_testsuites_status[Testsuite_status.Not_Run.value] += 1 @@ -507,7 +536,7 @@ def edit_mux_file(test_config_name, mux_file_path, tmp_mux_path): mux_fp.write(str("\n".join(mux_str_edited))) -def parse_test_config(test_config_file, avocado_bin, enable_kvm): +def parse_test_config(test_config_file, avocado_bin, enable_kvm, runner): """ Parses Test Config file and returns list of indivual tests dictionaries, with test path and yaml file path. @@ -572,6 +601,7 @@ def parse_test_config(test_config_file, avocado_bin, enable_kvm): # Handling yaml file from second param if '.yaml' in line[1]: test_dic['mux'] = line[1] + test_dic['tempmux'] = line[1] mux_flag = 1 test_dic['name'] = "%s_%s" % (test_dic['name'], test_dic['mux'].split("/")[-1].split(".")[0]) @@ -588,6 +618,7 @@ def parse_test_config(test_config_file, avocado_bin, enable_kvm): else: arg_flag = 1 test_dic['args'] = " %s" % line[1] + test_dic['tempmux'] = None count = 0 for list_dic in test_list: if test_dic['name'] == list_dic['name'].split('.')[0]: @@ -599,13 +630,14 @@ def parse_test_config(test_config_file, avocado_bin, enable_kvm): arg_flag = 1 test_dic['args'] = " %s" % line[2] test_list.append(test_dic) - if mux_flag == 0 and arg_flag == 0: - single_test_dic = {} - single_test_dic['name'] = test_config_name - single_test_dic['test'] = '' - for test in test_list: - single_test_dic['test'] += " %s" % test['test'] - return [single_test_dic] + if runner: + if mux_flag == 0 and arg_flag == 0: + single_test_dic = {} + single_test_dic['name'] = test_config_name + single_test_dic['test'] = '' + for test in test_list: + single_test_dic['test'] += " %s" % test['test'] + return [single_test_dic] return test_list logger.error("Test Config %s not present", test_config_file) return [] @@ -670,8 +702,11 @@ def parse_test_config(test_config_file, avocado_bin, enable_kvm): help='To remove/uninstall autotest, avocado from system') parser.add_argument('--enable-kvm', dest="enable_kvm", action='store_true', default=False, help='enable bootstrap kvm tests') - parser.add_argument('--nrunner', dest="nrunner", action='store_true', - default=False, help='enable Parallel run') + parser.add_argument('--runner', dest="runner", action='store_true', + default=False, help='To use legacy runner with --test-runner runner flag') + parser.add_argument('--code-cov', dest='linux_src_path', action='store', + default=None, + help='To enable code coverage. Pass the linux source path') parser.add_argument('--run-tests', dest="run_tests", action='store', default=None, @@ -808,7 +843,7 @@ def parse_test_config(test_config_file, avocado_bin, enable_kvm): for test_suite in test_suites: if 'host' in test_suite: test_list = parse_test_config( - test_suite, avocado_bin, args.enable_kvm) + test_suite, avocado_bin, args.enable_kvm, args.runner) if not test_list: Testsuites[test_suite] = TestSuite(test_suite, outputdir, args.vt_type, @@ -845,7 +880,7 @@ def parse_test_config(test_config_file, avocado_bin, enable_kvm): count_testsuites_status[Testsuite_status.Total.value] = len(Testsuites_list) for test_suite in Testsuites_list: if not Testsuites[test_suite].run == Testsuite_status.Cant_Run.value: - run_test(Testsuites[test_suite], avocado_bin, args.nrunner) + run_test(Testsuites[test_suite], avocado_bin, args.runner, args.linux_src_path) if args.interval: time.sleep(int(args.interval)) diff --git a/lib/helper.py b/lib/helper.py index bcd87f6..132786d 100644 --- a/lib/helper.py +++ b/lib/helper.py @@ -14,6 +14,7 @@ # Helper methods # Author: Satheesh Rajendran +import itertools import subprocess import os import re @@ -21,6 +22,7 @@ import shlex import shutil import stat +import time import platform import importlib.metadata @@ -379,3 +381,64 @@ def __enter__(self): def __exit__(self, exc_type, exc_val, exc_tb): self.close() return False + + +def gcov_reset(): + """ + Resets the gcov to zero + """ + gcov_cmd = "echo 1 > /sys/kernel/debug/gcov/reset" + if runcmd(gcov_cmd, ignore_status=False): + logger.info("Gcov reset successful") + else: + logger.info("Gcov reset fails") + + +def gcov_code_coverage(basedir_name, test_name, driver_name=None): + """ + Capture the gcov code coverage + """ + if not basedir_name.endswith("/"): + basedir_name = basedir_name + "/" + linux_src_gcov = f"/sys/kernel/debug/gcov{basedir_name}" + + # copying all the c files into c_files.txt + os.chdir(basedir_name) + if os.path.exists("c_files.txt"): + os.remove("c_files.txt") + cmd = f"find {linux_src_gcov} -maxdepth 6 -name '*.gcno' > c_files.txt" + runcmd(cmd, ignore_status=False) + cmd = "sed -i 's/gcno/c/g' c_files.txt" + runcmd(cmd, ignore_status=False) + if os.path.exists("object_directory"): + shutil.rmtree("object_directory") + time.sleep(3) + os.mkdir("object_directory") + os.chdir(linux_src_gcov) + gcno_cmd = "find -maxdepth 15 -name '*.gcno' -exec cp {} %sobject_directory \\;" % basedir_name + gcda_cmd = "find -maxdepth 15 -name '*.gcda' -exec cp {} %sobject_directory \\;" % basedir_name + runcmd(gcno_cmd, ignore_status=False) + runcmd(gcda_cmd, ignore_status=False) + os.chdir(basedir_name) + with open('c_files.txt', 'r+') as f: + for line in f.readlines(): + line = line.strip() + cmd = f"gcov -n -f {line} -o {basedir_name}object_directory > coverage.txt" + runcmd(cmd, ignore_status=False) + runcmd("sed -n -i '/Function/{N;p}' coverage.txt", ignore_status=True) + covrg_percentage = 0 + with open('coverage.txt', 'r+') as fs1: + for line1, line2 in itertools.zip_longest(*[fs1]*2): + if not line2.startswith("Line"): + continue + out = line2.split(":")[-1] + covrg_percentage = float(out.split("%")[0]) + if covrg_percentage > 0: + line1 = line1.split(" ")[-1] + line1 = line1.replace("'", "") + line = line.split("gcov")[-1] + if driver_name: + final_line = line + ":" + line1.strip() + "::" + test_name + "::" + str(covrg_percentage) + "::" + driver_name + else: + final_line = line + ":" + line1.strip() + "::" + test_name + "::" + str(covrg_percentage) + runcmd(f"echo '{final_line}' >> final_files.txt", ignore_status=False)