1#!/usr/bin/python 2 3# This script generates the unit test coverage report. 4# 5# Usage: 6# get_unit_test_report.py file target_dir 7# 8# Description of arguments: 9# file File with repository URLs, one on each line without quotes. 10# Eg: git://github.com/openbmc/ibm-dbus-interfaces 11# target_dir Target directory in pwd to place all cloned repos and logs. 12# 13# Eg: get_unit_test_report.py repo_names target_dir 14# 15# Output format: 16# 17# ***********************************OUTPUT*********************************** 18# https://github.com/openbmc/phosphor-dbus-monitor.git NO 19# https://github.com/openbmc/phosphor-sel-logger.git;protocol=git NO 20# ***********************************OUTPUT*********************************** 21# 22# Other outputs and errors are redirected to output.log and debug.log in target_dir. 23 24import argparse 25import logging 26import os 27import shutil 28import sys 29import subprocess 30 31 32# Create parser. 33parser = argparse.ArgumentParser(usage='%(prog)s file target_dir', 34 description="Script generates the unit test coverage report") 35 36parser.add_argument("file", type=str, 37 help='''Text file containing repository links separated by 38 new line 39 Eg: git://github.com/openbmc/ibm-dbus-interfaces''') 40 41parser.add_argument("target_dir", type=str, 42 help='''Name of a non-existing directory in pwd to store all 43 cloned repos, logs and UT reports''') 44args = parser.parse_args() 45 46 47# Create target working directory. 48pwd = os.getcwd() 49working_dir = os.path.join(pwd, args.target_dir) 50try: 51 os.mkdir(working_dir) 52except OSError as e: 53 answer = raw_input("Target directory " + working_dir + " already exists. " 54 + "Do you want to delete [Y/N]: ") 55 if answer == "Y": 56 try: 57 shutil.rmtree(working_dir) 58 os.mkdir(working_dir) 59 except OSError as e: 60 print(str(e)) 61 quit() 62 else: 63 print("Exiting....") 64 quit() 65 66# Create log directory. 67log_dir = os.path.join(working_dir, "logs") 68try: 69 os.mkdir(log_dir) 70except OSError as e: 71 print("Unable to create log directory: " + log_dir) 72 print(str(e)) 73 quit() 74 75 76# List contains archived repos and those repos which are not expected to contain 77# a UT. Will be moved to a file in future. 78skip_list = ["openbmc-tools", "phosphor-mboxd", "boost-dbus", "inarp"] 79 80 81# Log files 82debug_file = os.path.join(log_dir, "debug.log") 83output_file = os.path.join(log_dir, "output.log") 84logging.basicConfig(format='%(levelname)s - %(message)s', level=logging.DEBUG, 85 filename=debug_file) 86logger = logging.getLogger(__name__) 87 88# Create handlers 89console_handler = logging.StreamHandler() 90file_handler = logging.FileHandler(output_file) 91console_handler.setLevel(logging.INFO) 92file_handler.setLevel(logging.INFO) 93 94# Create formatters and add it to handlers 95log_format = logging.Formatter('%(message)s') 96console_handler.setFormatter(log_format) 97file_handler.setFormatter(log_format) 98 99# Add handlers to the logger 100logger.addHandler(console_handler) 101logger.addHandler(file_handler) 102 103 104# Create report directory. 105report_dir = os.path.join(working_dir, "reports") 106try: 107 os.mkdir(report_dir) 108except OSError as e: 109 logger.error("Unable to create report directory: " + report_dir) 110 logger.error(str(e)) 111 quit() 112 113# Clone OpenBmc build scripts. 114try: 115 output = subprocess.check_output("git clone https://github.com/openbmc/openbmc-build-scripts.git", 116 shell=True, cwd=working_dir, stderr=subprocess.STDOUT) 117 logger.debug(output) 118except subprocess.CalledProcessError as e: 119 logger.debug(e.output) 120 logger.debug(e.cmd) 121 logger.debug("Unable to clone openbmc-build-scripts") 122 quit() 123 124# Read URLs from input file. 125handle = open(args.file) 126url_list = handle.readlines() 127repo_count = len(url_list) 128logger.info("Number of repositories: " + str(repo_count)) 129 130# Clone repository and run unit test. 131coverage_report = [] 132counter = 0 133total_report_count = 0 134coverage_count = 0 135unit_test_count = 0 136no_report_count = 0 137error_count = 0 138skip_count = 0 139for url in url_list: 140 ci_exists = "NO" 141 skip = False 142 sandbox_name = url.strip().split('/')[-1].split(";")[0].split(".")[0] 143 if sandbox_name in skip_list: 144 skip = True 145 ci_exists = "SKIPPED" 146 else: 147 checkout_cmd = "git clone " + url 148 149 try: 150 result = subprocess.check_output(checkout_cmd, shell=True, cwd=working_dir, 151 stderr=subprocess.STDOUT) 152 except subprocess.CalledProcessError as e: 153 logger.debug(e.output) 154 logger.debug(e.cmd) 155 logger.debug("Failed to clone " + sandbox_name) 156 ci_exists = "ERROR" 157 skip = True 158 159 if not(skip): 160 docker_cmd = "WORKSPACE=$(pwd) UNIT_TEST_PKG=" + sandbox_name + " " + \ 161 "./openbmc-build-scripts/run-unit-test-docker.sh" 162 try: 163 result = subprocess.check_output(docker_cmd, cwd=working_dir, shell=True, 164 stderr=subprocess.STDOUT) 165 logger.debug(result) 166 logger.debug("UT BUILD COMPLETED FOR: " + sandbox_name) 167 168 except subprocess.CalledProcessError as e: 169 logger.debug(e.output) 170 logger.debug(e.cmd) 171 logger.debug("UT BUILD EXITED FOR: " + sandbox_name) 172 ci_exists = "ERROR" 173 174 folder_name = os.path.join(working_dir, sandbox_name) 175 repo_report_dir = os.path.join(report_dir, sandbox_name) 176 177 report_names = ("coveragereport", "test-suite.log") 178 find_cmd = "".join("find " + folder_name + " -name " + report + ";" 179 for report in report_names) 180 result = subprocess.check_output(find_cmd, shell=True) 181 if result: 182 total_report_count += 1 183 ci_exists = "YES" 184 if result.__contains__("coveragereport"): 185 ci_exists += ", COVERAGE" 186 coverage_count += 1 187 if result.__contains__("test-suite.log"): 188 ci_exists += ", UNIT TEST" 189 unit_test_count += 1 190 191 result = result.splitlines() 192 for file_path in result: 193 destination = os.path.dirname(os.path.join(report_dir, 194 os.path.relpath(file_path, 195 working_dir))) 196 copy_cmd = "mkdir -p " + destination + ";cp -rf " + \ 197 file_path.strip() + " " + destination 198 subprocess.check_output(copy_cmd, shell=True) 199 if ci_exists == "ERROR": 200 error_count += 1 201 elif ci_exists == "NO": 202 no_report_count += 1 203 elif ci_exists == "SKIPPED": 204 skip_count += 1 205 206 coverage_report.append("{:<65}{:<10}".format(url.strip(), ci_exists)) 207 counter += 1 208 logger.info(str(counter) + " in " + str(repo_count) + " completed") 209 210logger.info("*" * 30 + "UNIT TEST COVERAGE REPORT" + "*" * 30) 211for res in coverage_report: 212 logger.info(res) 213logger.info("*" * 30 + "UNIT TEST COVERAGE REPORT" + "*" * 30) 214 215logger.info("REPORTS: " + report_dir) 216logger.info("LOGS: " + log_dir) 217logger.info("*" * 85) 218logger.info("SUMMARY: ") 219logger.info("TOTAL REPOSITORIES : " + str(repo_count)) 220logger.info("TESTED REPOSITORIES : " + str(total_report_count)) 221logger.info("ERROR : " + str(error_count)) 222logger.info("COVERAGE REPORT : " + str(coverage_count)) 223logger.info("UNIT TEST REPORT : " + str(unit_test_count)) 224logger.info("NO REPORT : " + str(no_report_count)) 225logger.info("SKIPPED : " + str(skip_count)) 226logger.info("*" * 85) 227