blob: b9c8bb9990dc44deeb49a32594ae7d26b2d25eb8 [file] [log] [blame]
Anusha Dathatri229b76a2019-11-26 03:26:16 -06001#!/usr/bin/python
2
Anusha Dathatri185d5b52020-03-19 04:15:10 -05003# This script generates the unit test coverage report for openbmc project.
Anusha Dathatri229b76a2019-11-26 03:26:16 -06004#
5# Usage:
Anusha Dathatri58cbe5f2020-04-20 08:31:22 -05006# get_unit_test_report.py target_dir [url_file]
Anusha Dathatri229b76a2019-11-26 03:26:16 -06007#
Anusha Dathatri58cbe5f2020-04-20 08:31:22 -05008# Positional arguments:
Anusha Dathatri229b76a2019-11-26 03:26:16 -06009# target_dir Target directory in pwd to place all cloned repos and logs.
Anusha Dathatri58cbe5f2020-04-20 08:31:22 -050010# url_file Text file containing url of repositories. Optional.
11# By using this argument, the user can get a report only for
12# specific repositories given in the file.
13# Refer ./scripts/repositories.txt
Anusha Dathatri229b76a2019-11-26 03:26:16 -060014#
Anusha Dathatri58cbe5f2020-04-20 08:31:22 -050015# Examples:
16# get_unit_test_report.py target_dir
17# get_unit_test_report.py target_dir repositories.txt
Anusha Dathatri229b76a2019-11-26 03:26:16 -060018#
19# Output format:
20#
21# ***********************************OUTPUT***********************************
22# https://github.com/openbmc/phosphor-dbus-monitor.git NO
23# https://github.com/openbmc/phosphor-sel-logger.git;protocol=git NO
24# ***********************************OUTPUT***********************************
25#
26# Other outputs and errors are redirected to output.log and debug.log in target_dir.
27
28import argparse
29import logging
30import os
Anusha Dathatri185d5b52020-03-19 04:15:10 -050031import re
32import requests
Anusha Dathatri229b76a2019-11-26 03:26:16 -060033import shutil
34import sys
35import subprocess
36
Anusha Dathatri58cbe5f2020-04-20 08:31:22 -050037# Repo list not expected to contain UT. Will be moved to a file in future.
38skip_list = ["openbmc-tools", "inarp", "openbmc", "openbmc.github.io",
39 "phosphor-ecc", "phosphor-pcie-presence", "phosphor-u-boot-env-mgr",
40 "rrd-ipmi-blob", "librrdplus", "openpower-inventory-upload",
41 "openpower-logging", "openpower-power-control", "docs",
42 "openbmc-test-automation", "openbmc-build-scripts", "skeleton",
43 "linux",
44 # Not active, expected to be archived soon.
45 "ibm-pldm-oem"]
46
Anusha Dathatri229b76a2019-11-26 03:26:16 -060047
48# Create parser.
Anusha Dathatri58cbe5f2020-04-20 08:31:22 -050049text = '''%(prog)s target_dir [url_file]
50
51Example usages:
52get_unit_test_report.py target_dir
53get_unit_test_report.py target_dir repositories.txt'''
54
55parser = argparse.ArgumentParser(usage=text,
Anusha Dathatri229b76a2019-11-26 03:26:16 -060056 description="Script generates the unit test coverage report")
Anusha Dathatri229b76a2019-11-26 03:26:16 -060057parser.add_argument("target_dir", type=str,
58 help='''Name of a non-existing directory in pwd to store all
59 cloned repos, logs and UT reports''')
Anusha Dathatri58cbe5f2020-04-20 08:31:22 -050060parser.add_argument("url_file", type=str, nargs='?',
61 help='''Text file containing url of repositories.
62 By using this argument, the user can get a report only for
63 specific repositories given in the file.
64 Refer ./scripts/repositories.txt''')
Anusha Dathatri229b76a2019-11-26 03:26:16 -060065args = parser.parse_args()
66
Anusha Dathatri58cbe5f2020-04-20 08:31:22 -050067input_urls = []
68if args.url_file:
69 try:
70 # Get URLs from the file.
71 with open(args.url_file) as reader:
72 file_content = reader.read().splitlines()
73 input_urls = list(filter(lambda x:x, file_content))
74 if not(input_urls):
75 print("Input file {} is empty. Quitting...".format(args.url_file))
76 quit()
77 except IOError as e:
78 print("Issue in reading file '{}'. Reason: {}".format(args.url_file,
79 str(e)))
80 quit()
81
Anusha Dathatri229b76a2019-11-26 03:26:16 -060082
83# Create target working directory.
84pwd = os.getcwd()
85working_dir = os.path.join(pwd, args.target_dir)
86try:
87 os.mkdir(working_dir)
88except OSError as e:
89 answer = raw_input("Target directory " + working_dir + " already exists. "
90 + "Do you want to delete [Y/N]: ")
91 if answer == "Y":
92 try:
93 shutil.rmtree(working_dir)
94 os.mkdir(working_dir)
95 except OSError as e:
96 print(str(e))
97 quit()
98 else:
99 print("Exiting....")
100 quit()
101
102# Create log directory.
103log_dir = os.path.join(working_dir, "logs")
104try:
105 os.mkdir(log_dir)
106except OSError as e:
107 print("Unable to create log directory: " + log_dir)
108 print(str(e))
109 quit()
110
111
112# Log files
113debug_file = os.path.join(log_dir, "debug.log")
114output_file = os.path.join(log_dir, "output.log")
115logging.basicConfig(format='%(levelname)s - %(message)s', level=logging.DEBUG,
116 filename=debug_file)
117logger = logging.getLogger(__name__)
118
119# Create handlers
120console_handler = logging.StreamHandler()
121file_handler = logging.FileHandler(output_file)
122console_handler.setLevel(logging.INFO)
123file_handler.setLevel(logging.INFO)
124
125# Create formatters and add it to handlers
126log_format = logging.Formatter('%(message)s')
127console_handler.setFormatter(log_format)
128file_handler.setFormatter(log_format)
129
130# Add handlers to the logger
131logger.addHandler(console_handler)
132logger.addHandler(file_handler)
133
134
135# Create report directory.
136report_dir = os.path.join(working_dir, "reports")
137try:
138 os.mkdir(report_dir)
139except OSError as e:
140 logger.error("Unable to create report directory: " + report_dir)
141 logger.error(str(e))
142 quit()
143
144# Clone OpenBmc build scripts.
145try:
146 output = subprocess.check_output("git clone https://github.com/openbmc/openbmc-build-scripts.git",
147 shell=True, cwd=working_dir, stderr=subprocess.STDOUT)
148 logger.debug(output)
149except subprocess.CalledProcessError as e:
Anusha Dathatri58cbe5f2020-04-20 08:31:22 -0500150 logger.error(e.output)
151 logger.error(e.cmd)
152 logger.error("Unable to clone openbmc-build-scripts")
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600153 quit()
154
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500155repo_data = []
Anusha Dathatri58cbe5f2020-04-20 08:31:22 -0500156if input_urls:
157 api_url = "https://api.github.com/repos/openbmc/"
158 for url in input_urls:
159 try:
160 repo_name = url.strip().split('/')[-1].split(";")[0].split(".")[0]
161 except IndexError as e:
162 logger.error("ERROR: Unable to get sandbox name for url " + url)
163 logger.error("Reason: " + str(e))
164 continue
165
166 try:
167 resp = requests.get(api_url + repo_name)
168 if resp.status_code != 200:
169 logger.info(api_url + repo_name + " ==> " + resp.reason)
170 continue
171 repo_data.extend([resp.json()])
172 except ValueError as e:
173 logger.error("ERROR: Failed to get response for " + repo_name)
174 logger.error(resp)
175 continue
176
177else:
178 # Get number of pages.
179 resp = requests.head('https://api.github.com/users/openbmc/repos')
180 if resp.status_code != 200:
181 logger.error("Error! Unable to get repositories")
182 logger.error(resp.status_code)
183 logger.error(resp.reason)
184 quit()
185 num_of_pages = int(resp.links['last']['url'].split('page=')[-1])
186 logger.debug("No. of pages: " + str(num_of_pages))
187
188 # Fetch data from all pages.
189 for page in range(1, num_of_pages+1):
190 resp = requests.get('https://api.github.com/users/openbmc/repos?page='
191 + str(page))
192 data = resp.json()
193 repo_data.extend(data)
194
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500195
196# Get URLs and their archive status from response.
197url_info = {}
198for repo in repo_data:
Anusha Dathatri58cbe5f2020-04-20 08:31:22 -0500199 try:
200 url_info[repo["clone_url"]] = repo["archived"]
201 except KeyError as e:
202 logger.error("Failed to get archived status of {}".format(repo))
203 url_info[repo["clone_url"]] = False
204 continue
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500205logger.debug(url_info)
206repo_count = len(url_info)
207logger.info("Number of repositories (Including archived): " + str(repo_count))
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600208
209# Clone repository and run unit test.
210coverage_report = []
211counter = 0
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500212tested_report_count = 0
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600213coverage_count = 0
214unit_test_count = 0
215no_report_count = 0
216error_count = 0
Anusha Dathatria756e8a2020-03-05 06:48:56 -0600217skip_count = 0
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500218archive_count = 0
219url_list = sorted(url_info)
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600220for url in url_list:
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500221 ut_status = "NO"
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600222 skip = False
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500223 if url_info[url]:
224 ut_status = "ARCHIVED"
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600225 skip = True
Anusha Dathatria756e8a2020-03-05 06:48:56 -0600226 else:
Anusha Dathatria756e8a2020-03-05 06:48:56 -0600227 try:
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500228 # Eg: url = "https://github.com/openbmc/u-boot.git"
229 # sandbox_name = "u-boot"
230 sandbox_name = url.strip().split('/')[-1].split(";")[0].split(".")[0]
231 except IndexError as e:
Anusha Dathatri58cbe5f2020-04-20 08:31:22 -0500232 logger.error("ERROR: Unable to get sandbox name for url " + url)
233 logger.error("Reason: " + str(e))
234 continue
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600235
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500236 if (sandbox_name in skip_list or
237 re.match(r'meta-', sandbox_name)):
238 logger.debug("SKIPPING: " + sandbox_name)
239 skip = True
240 ut_status = "SKIPPED"
241 else:
242 checkout_cmd = "rm -rf " + sandbox_name + ";git clone " + url
243 try:
244 subprocess.check_output(checkout_cmd, shell=True, cwd=working_dir,
245 stderr=subprocess.STDOUT)
246 except subprocess.CalledProcessError as e:
247 logger.debug(e.output)
248 logger.debug(e.cmd)
249 logger.debug("Failed to clone " + sandbox_name)
250 ut_status = "ERROR"
251 skip = True
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600252 if not(skip):
253 docker_cmd = "WORKSPACE=$(pwd) UNIT_TEST_PKG=" + sandbox_name + " " + \
254 "./openbmc-build-scripts/run-unit-test-docker.sh"
255 try:
256 result = subprocess.check_output(docker_cmd, cwd=working_dir, shell=True,
257 stderr=subprocess.STDOUT)
258 logger.debug(result)
259 logger.debug("UT BUILD COMPLETED FOR: " + sandbox_name)
260
261 except subprocess.CalledProcessError as e:
262 logger.debug(e.output)
263 logger.debug(e.cmd)
264 logger.debug("UT BUILD EXITED FOR: " + sandbox_name)
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500265 ut_status = "ERROR"
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600266
267 folder_name = os.path.join(working_dir, sandbox_name)
268 repo_report_dir = os.path.join(report_dir, sandbox_name)
269
Anusha Dathatri544d83a2020-03-12 06:07:57 -0500270 report_names = ("coveragereport", "test-suite.log", "LastTest.log")
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600271 find_cmd = "".join("find " + folder_name + " -name " + report + ";"
272 for report in report_names)
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500273 try:
274 result = subprocess.check_output(find_cmd, shell=True)
275 except subprocess.CalledProcessError as e:
276 logger.debug(e.output)
277 logger.debug(e.cmd)
278 logger.debug("CMD TO FIND REPORT FAILED FOR: " + sandbox_name)
279 ut_status = "ERROR"
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600280
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500281 if ut_status != "ERROR":
282 if result:
283 if result.__contains__("coveragereport"):
284 ut_status = "YES, COVERAGE"
285 coverage_count += 1
286 elif "test-suite.log" in result:
287 ut_status = "YES, UNIT TEST"
288 unit_test_count += 1
289 elif "LastTest.log" in result:
290 file_names = result.splitlines()
291 for file in file_names:
292 pattern_count_cmd = "sed -n '/Start testing/,/End testing/p;' " + \
293 file + "|wc -l"
294 try:
295 num_of_lines = subprocess.check_output(pattern_count_cmd,
296 shell=True)
297 except subprocess.CalledProcessError as e:
298 logger.debug(e.output)
299 logger.debug(e.cmd)
300 logger.debug("CONTENT CHECK FAILED FOR: " + sandbox_name)
301 ut_status = "ERROR"
302
303 if int(num_of_lines.strip()) > 5:
304 ut_status = "YES, UNIT TEST"
305 unit_test_count += 1
306
307 if "YES" in ut_status:
308 tested_report_count += 1
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600309 result = result.splitlines()
310 for file_path in result:
311 destination = os.path.dirname(os.path.join(report_dir,
312 os.path.relpath(file_path,
313 working_dir)))
314 copy_cmd = "mkdir -p " + destination + ";cp -rf " + \
315 file_path.strip() + " " + destination
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500316 try:
317 subprocess.check_output(copy_cmd, shell=True)
318 except subprocess.CalledProcessError as e:
319 logger.debug(e.output)
320 logger.debug(e.cmd)
321 logger.info("FAILED TO COPY REPORTS FOR: " + sandbox_name)
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600322
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500323 if ut_status == "ERROR":
324 error_count += 1
325 elif ut_status == "NO":
326 no_report_count += 1
327 elif ut_status == "SKIPPED":
328 skip_count += 1
329 elif ut_status == "ARCHIVED":
330 archive_count += 1
331
332 coverage_report.append("{:<65}{:<10}".format(url.strip(), ut_status))
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600333 counter += 1
334 logger.info(str(counter) + " in " + str(repo_count) + " completed")
335
336logger.info("*" * 30 + "UNIT TEST COVERAGE REPORT" + "*" * 30)
337for res in coverage_report:
338 logger.info(res)
339logger.info("*" * 30 + "UNIT TEST COVERAGE REPORT" + "*" * 30)
340
341logger.info("REPORTS: " + report_dir)
342logger.info("LOGS: " + log_dir)
343logger.info("*" * 85)
344logger.info("SUMMARY: ")
345logger.info("TOTAL REPOSITORIES : " + str(repo_count))
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500346logger.info("TESTED REPOSITORIES : " + str(tested_report_count))
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600347logger.info("ERROR : " + str(error_count))
348logger.info("COVERAGE REPORT : " + str(coverage_count))
349logger.info("UNIT TEST REPORT : " + str(unit_test_count))
350logger.info("NO REPORT : " + str(no_report_count))
Anusha Dathatria756e8a2020-03-05 06:48:56 -0600351logger.info("SKIPPED : " + str(skip_count))
Anusha Dathatri185d5b52020-03-19 04:15:10 -0500352logger.info("ARCHIVED : " + str(archive_count))
Anusha Dathatri229b76a2019-11-26 03:26:16 -0600353logger.info("*" * 85)