Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 3 | # This script generates the unit test coverage report for openbmc project. |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 4 | # |
| 5 | # Usage: |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 6 | # get_unit_test_report.py target_dir |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 7 | # |
| 8 | # Description of arguments: |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 9 | # target_dir Target directory in pwd to place all cloned repos and logs. |
| 10 | # |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 11 | # Eg: get_unit_test_report.py target_dir |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 12 | # |
| 13 | # Output format: |
| 14 | # |
| 15 | # ***********************************OUTPUT*********************************** |
| 16 | # https://github.com/openbmc/phosphor-dbus-monitor.git NO |
| 17 | # https://github.com/openbmc/phosphor-sel-logger.git;protocol=git NO |
| 18 | # ***********************************OUTPUT*********************************** |
| 19 | # |
| 20 | # Other outputs and errors are redirected to output.log and debug.log in target_dir. |
| 21 | |
| 22 | import argparse |
| 23 | import logging |
| 24 | import os |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 25 | import re |
| 26 | import requests |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 27 | import shutil |
| 28 | import sys |
| 29 | import subprocess |
| 30 | |
| 31 | |
| 32 | # Create parser. |
| 33 | parser = argparse.ArgumentParser(usage='%(prog)s file target_dir', |
| 34 | description="Script generates the unit test coverage report") |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 35 | parser.add_argument("target_dir", type=str, |
| 36 | help='''Name of a non-existing directory in pwd to store all |
| 37 | cloned repos, logs and UT reports''') |
| 38 | args = parser.parse_args() |
| 39 | |
| 40 | |
| 41 | # Create target working directory. |
| 42 | pwd = os.getcwd() |
| 43 | working_dir = os.path.join(pwd, args.target_dir) |
| 44 | try: |
| 45 | os.mkdir(working_dir) |
| 46 | except OSError as e: |
| 47 | answer = raw_input("Target directory " + working_dir + " already exists. " |
| 48 | + "Do you want to delete [Y/N]: ") |
| 49 | if answer == "Y": |
| 50 | try: |
| 51 | shutil.rmtree(working_dir) |
| 52 | os.mkdir(working_dir) |
| 53 | except OSError as e: |
| 54 | print(str(e)) |
| 55 | quit() |
| 56 | else: |
| 57 | print("Exiting....") |
| 58 | quit() |
| 59 | |
| 60 | # Create log directory. |
| 61 | log_dir = os.path.join(working_dir, "logs") |
| 62 | try: |
| 63 | os.mkdir(log_dir) |
| 64 | except OSError as e: |
| 65 | print("Unable to create log directory: " + log_dir) |
| 66 | print(str(e)) |
| 67 | quit() |
| 68 | |
| 69 | |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 70 | # Repo list not expected to contain UT. Will be moved to a file in future. |
| 71 | skip_list = ["openbmc-tools", "inarp", "openbmc", "openbmc.github.io", |
| 72 | "phosphor-ecc", "phosphor-pcie-presence", "phosphor-u-boot-env-mgr", |
| 73 | "rrd-ipmi-blob", "librrdplus", "openpower-inventory-upload", |
| 74 | "openpower-logging", "openpower-power-control", "docs", |
| 75 | "openbmc-test-automation", "openbmc-build-scripts", "skeleton", |
| 76 | "linux", |
| 77 | # Not active, expected to be archived soon. |
| 78 | "ibm-pldm-oem"] |
Anusha Dathatri | a756e8a | 2020-03-05 06:48:56 -0600 | [diff] [blame] | 79 | |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 80 | # Log files |
| 81 | debug_file = os.path.join(log_dir, "debug.log") |
| 82 | output_file = os.path.join(log_dir, "output.log") |
| 83 | logging.basicConfig(format='%(levelname)s - %(message)s', level=logging.DEBUG, |
| 84 | filename=debug_file) |
| 85 | logger = logging.getLogger(__name__) |
| 86 | |
| 87 | # Create handlers |
| 88 | console_handler = logging.StreamHandler() |
| 89 | file_handler = logging.FileHandler(output_file) |
| 90 | console_handler.setLevel(logging.INFO) |
| 91 | file_handler.setLevel(logging.INFO) |
| 92 | |
| 93 | # Create formatters and add it to handlers |
| 94 | log_format = logging.Formatter('%(message)s') |
| 95 | console_handler.setFormatter(log_format) |
| 96 | file_handler.setFormatter(log_format) |
| 97 | |
| 98 | # Add handlers to the logger |
| 99 | logger.addHandler(console_handler) |
| 100 | logger.addHandler(file_handler) |
| 101 | |
| 102 | |
| 103 | # Create report directory. |
| 104 | report_dir = os.path.join(working_dir, "reports") |
| 105 | try: |
| 106 | os.mkdir(report_dir) |
| 107 | except OSError as e: |
| 108 | logger.error("Unable to create report directory: " + report_dir) |
| 109 | logger.error(str(e)) |
| 110 | quit() |
| 111 | |
| 112 | # Clone OpenBmc build scripts. |
| 113 | try: |
| 114 | output = subprocess.check_output("git clone https://github.com/openbmc/openbmc-build-scripts.git", |
| 115 | shell=True, cwd=working_dir, stderr=subprocess.STDOUT) |
| 116 | logger.debug(output) |
| 117 | except subprocess.CalledProcessError as e: |
| 118 | logger.debug(e.output) |
| 119 | logger.debug(e.cmd) |
| 120 | logger.debug("Unable to clone openbmc-build-scripts") |
| 121 | quit() |
| 122 | |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 123 | # Get number of pages. |
| 124 | resp = requests.head('https://api.github.com/users/openbmc/repos') |
| 125 | if resp.status_code != 200: |
| 126 | logger.error("Error! Unable to get repositories") |
| 127 | logger.debug(resp.status_code) |
| 128 | logger.debug(resp.text) |
| 129 | quit() |
| 130 | num_of_pages = int(resp.links['last']['url'].split('page=')[-1]) |
| 131 | logger.debug("No. of pages: " + str(num_of_pages)) |
| 132 | |
| 133 | # Fetch data from all pages. |
| 134 | repo_data = [] |
| 135 | for page in range(1, num_of_pages+1): |
| 136 | resp = requests.get('https://api.github.com/users/openbmc/repos?page=' + str(page)) |
| 137 | data = resp.json() |
| 138 | repo_data.extend(data) |
| 139 | |
| 140 | # Get URLs and their archive status from response. |
| 141 | url_info = {} |
| 142 | for repo in repo_data: |
| 143 | url_info[repo["clone_url"]] = repo["archived"] |
| 144 | logger.debug(url_info) |
| 145 | repo_count = len(url_info) |
| 146 | logger.info("Number of repositories (Including archived): " + str(repo_count)) |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 147 | |
| 148 | # Clone repository and run unit test. |
| 149 | coverage_report = [] |
| 150 | counter = 0 |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 151 | tested_report_count = 0 |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 152 | coverage_count = 0 |
| 153 | unit_test_count = 0 |
| 154 | no_report_count = 0 |
| 155 | error_count = 0 |
Anusha Dathatri | a756e8a | 2020-03-05 06:48:56 -0600 | [diff] [blame] | 156 | skip_count = 0 |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 157 | archive_count = 0 |
| 158 | url_list = sorted(url_info) |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 159 | for url in url_list: |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 160 | ut_status = "NO" |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 161 | skip = False |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 162 | if url_info[url]: |
| 163 | ut_status = "ARCHIVED" |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 164 | skip = True |
Anusha Dathatri | a756e8a | 2020-03-05 06:48:56 -0600 | [diff] [blame] | 165 | else: |
Anusha Dathatri | a756e8a | 2020-03-05 06:48:56 -0600 | [diff] [blame] | 166 | try: |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 167 | # Eg: url = "https://github.com/openbmc/u-boot.git" |
| 168 | # sandbox_name = "u-boot" |
| 169 | sandbox_name = url.strip().split('/')[-1].split(";")[0].split(".")[0] |
| 170 | except IndexError as e: |
| 171 | logger.debug("ERROR: Unable to get sandbox name for url " + url) |
| 172 | logger.debug("Reason: " + str(e)) |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 173 | |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 174 | if (sandbox_name in skip_list or |
| 175 | re.match(r'meta-', sandbox_name)): |
| 176 | logger.debug("SKIPPING: " + sandbox_name) |
| 177 | skip = True |
| 178 | ut_status = "SKIPPED" |
| 179 | else: |
| 180 | checkout_cmd = "rm -rf " + sandbox_name + ";git clone " + url |
| 181 | try: |
| 182 | subprocess.check_output(checkout_cmd, shell=True, cwd=working_dir, |
| 183 | stderr=subprocess.STDOUT) |
| 184 | except subprocess.CalledProcessError as e: |
| 185 | logger.debug(e.output) |
| 186 | logger.debug(e.cmd) |
| 187 | logger.debug("Failed to clone " + sandbox_name) |
| 188 | ut_status = "ERROR" |
| 189 | skip = True |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 190 | if not(skip): |
| 191 | docker_cmd = "WORKSPACE=$(pwd) UNIT_TEST_PKG=" + sandbox_name + " " + \ |
| 192 | "./openbmc-build-scripts/run-unit-test-docker.sh" |
| 193 | try: |
| 194 | result = subprocess.check_output(docker_cmd, cwd=working_dir, shell=True, |
| 195 | stderr=subprocess.STDOUT) |
| 196 | logger.debug(result) |
| 197 | logger.debug("UT BUILD COMPLETED FOR: " + sandbox_name) |
| 198 | |
| 199 | except subprocess.CalledProcessError as e: |
| 200 | logger.debug(e.output) |
| 201 | logger.debug(e.cmd) |
| 202 | logger.debug("UT BUILD EXITED FOR: " + sandbox_name) |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 203 | ut_status = "ERROR" |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 204 | |
| 205 | folder_name = os.path.join(working_dir, sandbox_name) |
| 206 | repo_report_dir = os.path.join(report_dir, sandbox_name) |
| 207 | |
Anusha Dathatri | 544d83a | 2020-03-12 06:07:57 -0500 | [diff] [blame] | 208 | report_names = ("coveragereport", "test-suite.log", "LastTest.log") |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 209 | find_cmd = "".join("find " + folder_name + " -name " + report + ";" |
| 210 | for report in report_names) |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 211 | try: |
| 212 | result = subprocess.check_output(find_cmd, shell=True) |
| 213 | except subprocess.CalledProcessError as e: |
| 214 | logger.debug(e.output) |
| 215 | logger.debug(e.cmd) |
| 216 | logger.debug("CMD TO FIND REPORT FAILED FOR: " + sandbox_name) |
| 217 | ut_status = "ERROR" |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 218 | |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 219 | if ut_status != "ERROR": |
| 220 | if result: |
| 221 | if result.__contains__("coveragereport"): |
| 222 | ut_status = "YES, COVERAGE" |
| 223 | coverage_count += 1 |
| 224 | elif "test-suite.log" in result: |
| 225 | ut_status = "YES, UNIT TEST" |
| 226 | unit_test_count += 1 |
| 227 | elif "LastTest.log" in result: |
| 228 | file_names = result.splitlines() |
| 229 | for file in file_names: |
| 230 | pattern_count_cmd = "sed -n '/Start testing/,/End testing/p;' " + \ |
| 231 | file + "|wc -l" |
| 232 | try: |
| 233 | num_of_lines = subprocess.check_output(pattern_count_cmd, |
| 234 | shell=True) |
| 235 | except subprocess.CalledProcessError as e: |
| 236 | logger.debug(e.output) |
| 237 | logger.debug(e.cmd) |
| 238 | logger.debug("CONTENT CHECK FAILED FOR: " + sandbox_name) |
| 239 | ut_status = "ERROR" |
| 240 | |
| 241 | if int(num_of_lines.strip()) > 5: |
| 242 | ut_status = "YES, UNIT TEST" |
| 243 | unit_test_count += 1 |
| 244 | |
| 245 | if "YES" in ut_status: |
| 246 | tested_report_count += 1 |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 247 | result = result.splitlines() |
| 248 | for file_path in result: |
| 249 | destination = os.path.dirname(os.path.join(report_dir, |
| 250 | os.path.relpath(file_path, |
| 251 | working_dir))) |
| 252 | copy_cmd = "mkdir -p " + destination + ";cp -rf " + \ |
| 253 | file_path.strip() + " " + destination |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 254 | try: |
| 255 | subprocess.check_output(copy_cmd, shell=True) |
| 256 | except subprocess.CalledProcessError as e: |
| 257 | logger.debug(e.output) |
| 258 | logger.debug(e.cmd) |
| 259 | logger.info("FAILED TO COPY REPORTS FOR: " + sandbox_name) |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 260 | |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 261 | if ut_status == "ERROR": |
| 262 | error_count += 1 |
| 263 | elif ut_status == "NO": |
| 264 | no_report_count += 1 |
| 265 | elif ut_status == "SKIPPED": |
| 266 | skip_count += 1 |
| 267 | elif ut_status == "ARCHIVED": |
| 268 | archive_count += 1 |
| 269 | |
| 270 | coverage_report.append("{:<65}{:<10}".format(url.strip(), ut_status)) |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 271 | counter += 1 |
| 272 | logger.info(str(counter) + " in " + str(repo_count) + " completed") |
| 273 | |
| 274 | logger.info("*" * 30 + "UNIT TEST COVERAGE REPORT" + "*" * 30) |
| 275 | for res in coverage_report: |
| 276 | logger.info(res) |
| 277 | logger.info("*" * 30 + "UNIT TEST COVERAGE REPORT" + "*" * 30) |
| 278 | |
| 279 | logger.info("REPORTS: " + report_dir) |
| 280 | logger.info("LOGS: " + log_dir) |
| 281 | logger.info("*" * 85) |
| 282 | logger.info("SUMMARY: ") |
| 283 | logger.info("TOTAL REPOSITORIES : " + str(repo_count)) |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 284 | logger.info("TESTED REPOSITORIES : " + str(tested_report_count)) |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 285 | logger.info("ERROR : " + str(error_count)) |
| 286 | logger.info("COVERAGE REPORT : " + str(coverage_count)) |
| 287 | logger.info("UNIT TEST REPORT : " + str(unit_test_count)) |
| 288 | logger.info("NO REPORT : " + str(no_report_count)) |
Anusha Dathatri | a756e8a | 2020-03-05 06:48:56 -0600 | [diff] [blame] | 289 | logger.info("SKIPPED : " + str(skip_count)) |
Anusha Dathatri | 185d5b5 | 2020-03-19 04:15:10 -0500 | [diff] [blame^] | 290 | logger.info("ARCHIVED : " + str(archive_count)) |
Anusha Dathatri | 229b76a | 2019-11-26 03:26:16 -0600 | [diff] [blame] | 291 | logger.info("*" * 85) |