blob: 80bd3fd67125a0d0e2fb7c10e898d8472cf903d1 [file] [log] [blame]
Matthew Hartfb6fd362020-03-04 21:03:59 +00001#!/usr/bin/env python3
2
3from __future__ import print_function
4
5__copyright__ = """
6/*
Xinyu Zhang78c146a2022-09-05 19:06:40 +08007 * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
Matthew Hartfb6fd362020-03-04 21:03:59 +00008 *
9 * SPDX-License-Identifier: BSD-3-Clause
10 *
11 */
12 """
13
14"""
15Script for waiting for LAVA jobs and parsing the results
16"""
17
18import os
19import sys
Matthew Hartfb6fd362020-03-04 21:03:59 +000020import time
21import yaml
22import argparse
Xinyu Zhang1b8f5152020-11-13 16:10:58 +080023import csv
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080024import shutil
Matthew Hartfb6fd362020-03-04 21:03:59 +000025from jinja2 import Environment, FileSystemLoader
26from lava_helper_configs import *
27from lava_helper import test_lava_dispatch_credentials
Xinyu Zhangc918b6e2022-10-08 17:13:17 +080028from lava_submit_jobs import submit_lava_jobs
Paul Sokolovsky2512ec52022-03-04 00:15:39 +030029import codecov_helper
30
Matthew Hartfb6fd362020-03-04 21:03:59 +000031
Xinyu Zhang1b8f5152020-11-13 16:10:58 +080032cfgs = ["Default", "CoreIPC", "CoreIPCTfmLevel2", "CoreIPCTfmLevel3",
33 "Regression", "RegressionIPC",
34 "RegressionIPCTfmLevel2", "RegressionIPCTfmLevel3",
35 "DefaultProfileS", "RegressionProfileS",
36 "DefaultProfileM", "RegressionProfileM", "RegressionProfileM PSOFF",
Xinyu Zhang9b1aef92021-03-12 15:36:44 +080037 "DefaultProfileL", "RegressionProfileL",
Xinyu Zhang1b8f5152020-11-13 16:10:58 +080038 "PsaApiTest (Attest)", "PsaApiTestIPC (Attest)",
39 "PsaApiTestIPCTfmLevel2 (Attest)",
40 "PsaApiTest (Crypto)", "PsaApiTestIPC (Crypto)",
41 "PsaApiTestIPCTfmLevel2 (Crypto)",
42 "PsaApiTest (PS)", "PsaApiTestIPC (PS)",
43 "PsaApiTestIPCTfmLevel2 (PS)",
44 "PsaApiTest (ITS)", "PsaApiTestIPC (ITS)",
45 "PsaApiTestIPCTfmLevel2 (ITS)",
46 "PsaApiTestIPC (FF)",
47 "PsaApiTestIPCTfmLevel2 (FF)",
Paul Sokolovskyb6003112022-02-04 00:36:14 +030048 "PsaApiTest (STORAGE)",
49 "PsaApiTestIPC (STORAGE)",
50 "PsaApiTestIPCTfmLevel2 (STORAGE)",
51 "PsaApiTestIPCTfmLevel3 (STORAGE)",
Xinyu Zhang1b8f5152020-11-13 16:10:58 +080052 "PsaApiTestIPCTfmLevel3 (ITS)", "PsaApiTestIPCTfmLevel3 (PS)",
53 "PsaApiTestIPCTfmLevel3 (Crypto)", "PsaApiTestIPCTfmLevel3 (Attest)",
54 "PsaApiTestIPCTfmLevel3 (FF)"]
55
Paul Sokolovskyf1ff6c12022-02-02 21:42:41 +030056# Convert test config identifiers to LAVA naming convention.
57cfgs = [x.replace(" (", "_").replace(")", "") for x in cfgs]
58
Matthew Hartfb6fd362020-03-04 21:03:59 +000059def wait_for_jobs(user_args):
60 job_list = user_args.job_ids.split(",")
61 job_list = [int(x) for x in job_list if x != '']
62 lava = test_lava_dispatch_credentials(user_args)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080063 finished_jobs = get_finished_jobs(job_list, user_args, lava)
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080064 resubmit_jobs = resubmit_failed_jobs(finished_jobs, user_args)
Paul Sokolovskyc87beee2022-04-30 08:50:47 +030065 if resubmit_jobs:
66 info_print("Waiting for resubmitted jobs: {}".format(resubmit_jobs))
67 finished_resubmit_jobs = get_finished_jobs(resubmit_jobs, user_args, lava)
68 finished_jobs.update(finished_resubmit_jobs)
Paul Sokolovsky451f67b2022-03-08 19:44:41 +030069 return finished_jobs
70
71
72def process_finished_jobs(finished_jobs, user_args):
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080073 print_lava_urls(finished_jobs, user_args)
Paul Sokolovsky451f67b2022-03-08 19:44:41 +030074 test_report(finished_jobs, user_args)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080075 failure_report(finished_jobs, user_args)
Xinyu Zhang82dab282022-10-09 16:33:19 +080076 job_links(finished_jobs, user_args)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080077 csv_report(finished_jobs)
Paul Sokolovsky2512ec52022-03-04 00:15:39 +030078 codecov_helper.coverage_reports(finished_jobs, user_args)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080079
Paul Sokolovsky451f67b2022-03-08 19:44:41 +030080
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080081def get_finished_jobs(job_list, user_args, lava):
Paul Sokolovsky697f9552022-05-05 10:44:27 +030082 finished_jobs = lava.block_wait_for_jobs(job_list, user_args.dispatch_timeout, 5)
Matthew Hartfb6fd362020-03-04 21:03:59 +000083 unfinished_jobs = [item for item in job_list if item not in finished_jobs]
84 for job in unfinished_jobs:
85 info_print("Cancelling unfinished job: {}".format(job))
86 lava.cancel_job(job)
87 if user_args.artifacts_path:
88 for job, info in finished_jobs.items():
89 info['job_dir'] = os.path.join(user_args.artifacts_path, "{}_{}".format(str(job), info['description']))
90 finished_jobs[job] = info
91 finished_jobs = fetch_artifacts(finished_jobs, user_args, lava)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080092 return finished_jobs
Matthew Hartfb6fd362020-03-04 21:03:59 +000093
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080094def resubmit_failed_jobs(jobs, user_args):
95 if not jobs:
96 return []
Xinyu Zhang4aca6d02021-05-31 11:43:32 +080097 time.sleep(2) # be friendly to LAVA
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080098 failed_job = []
99 os.makedirs('failed_jobs', exist_ok=True)
100 for job_id, info in jobs.items():
101 if not (info['health'] == "Complete" and info['state'] == "Finished"):
102 job_dir = info['job_dir']
103 def_path = os.path.join(job_dir, 'definition.yaml')
104 os.rename(def_path, 'failed_jobs/{}_definition.yaml'.format(job_id))
105 shutil.rmtree(job_dir)
106 failed_job.append(job_id)
107 for failed_job_id in failed_job:
108 jobs.pop(failed_job_id)
Xinyu Zhangc918b6e2022-10-08 17:13:17 +0800109 resubmitted_jobs = submit_lava_jobs(user_args, job_dir='failed_jobs')
Xinyu Zhangc8a670c2021-05-18 20:20:53 +0800110 resubmitted_jobs = [int(x) for x in resubmitted_jobs if x != '']
111 return resubmitted_jobs
112
Paul Sokolovskyc2d6d882022-02-25 19:11:18 +0300113
Matthew Hartfb6fd362020-03-04 21:03:59 +0000114def fetch_artifacts(jobs, user_args, lava):
115 if not user_args.artifacts_path:
116 return
117 for job_id, info in jobs.items():
118 job_dir = info['job_dir']
119 info_print("Fetching artifacts for JOB: {} to {}".format(job_id, job_dir))
120 os.makedirs(job_dir, exist_ok=True)
121 def_path = os.path.join(job_dir, 'definition.yaml')
122 target_log = os.path.join(job_dir, 'target_log.txt')
Matthew Hart4a4f1202020-06-12 15:52:46 +0100123 config = os.path.join(job_dir, 'config.tar.bz2')
124 results_file = os.path.join(job_dir, 'results.yaml')
Xinyu Zhang82dab282022-10-09 16:33:19 +0800125 definition = lava.get_job_definition(job_id, def_path)
126 jobs[job_id]['metadata'] = definition.get('metadata', [])
Matthew Hartfb6fd362020-03-04 21:03:59 +0000127 time.sleep(0.2) # be friendly to LAVA
Matthew Hart4a4f1202020-06-12 15:52:46 +0100128 lava.get_job_log(job_id, target_log)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000129 time.sleep(0.2)
130 lava.get_job_config(job_id, config)
131 time.sleep(0.2)
Matthew Hart4a4f1202020-06-12 15:52:46 +0100132 lava.get_job_results(job_id, results_file)
Paul Sokolovskyc2d6d882022-02-25 19:11:18 +0300133 codecov_helper.extract_trace_data(target_log, job_dir)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000134 return(jobs)
135
136
137def lava_id_to_url(id, user_args):
138 return "{}/scheduler/job/{}".format(user_args.lava_url, id)
139
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800140def generateTestResult(info):
141 if info['health'] == "Complete" and info['state'] == "Finished":
142 return "PASS"
143 else:
144 return "FAIL"
145
Xinyu Zhang97ee3fd2020-12-14 14:45:06 +0800146def job_links(jobs, user_args):
147 job_links = ""
148 for job, info in jobs.items():
Xinyu Zhang82dab282022-10-09 16:33:19 +0800149 job_links += "\nLAVA Test Config:\n"
150 job_links += "Config Name: {}\n".format(info['metadata']['build_name'])
151 job_links += "Test Result: {}\n".format(info['result'])
152 job_links += "Device Type: {}\n".format(info['metadata']['device_type'])
Xinyu Zhang97ee3fd2020-12-14 14:45:06 +0800153 job_links += "Build link: {}\n".format(info['metadata']['build_job_url'])
Xinyu Zhang78c146a2022-09-05 19:06:40 +0800154 job_links += "LAVA link: {}\n".format(lava_id_to_url(job, user_args))
Xinyu Zhang82dab282022-10-09 16:33:19 +0800155 job_links += "TFM LOG: {}artifact/{}/target_log.txt\n".format(os.getenv("BUILD_URL"), info['job_dir'])
Xinyu Zhang97ee3fd2020-12-14 14:45:06 +0800156 print(job_links)
157
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800158def csv_report(jobs):
159 lava_jobs = []
160 for job, info in jobs.items():
161 exist = False
162 for record in lava_jobs:
163 if info['metadata']['platform'] == record["Platform"] and \
164 info['metadata']['compiler'] == record["Compiler"] and \
165 info['metadata']['build_type'] == record["Build Type"]:
166 if record[info['metadata']['name']] != "FAIL":
167 record[info['metadata']['name']] = generateTestResult(info)
168 exist = True
169 break
170 if not exist:
171 record = {}
172 record["Platform"] = info['metadata']['platform']
173 record["Compiler"] = info['metadata']['compiler']
174 record["Build Type"] = info['metadata']['build_type']
175 record["Config Name"] = info['metadata']['name']
176 for cfg in cfgs:
177 record[cfg] = "N.A."
178 record[info['metadata']['name']] = generateTestResult(info)
179 lava_jobs.append(record)
180 lava_jobs.sort(key=lambda x: x["Platform"] + x["Compiler"] + x["Build Type"])
181 with open("test_results.csv", "w", newline="") as csvfile:
182 fieldnames = ["Platform", "Compiler", "Build Type"] + cfgs
183 writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore')
184
185 writer.writeheader()
186 writer.writerows(lava_jobs)
187
Matthew Hartfb6fd362020-03-04 21:03:59 +0000188
Xinyu Zhang38a18872020-11-23 16:45:28 +0800189def failure_report(jobs, user_args):
190 failed_report = "FAILURE_TESTS:"
191 for job, info in jobs.items():
192 if info['health'] != "Complete" or info['state'] != "Finished":
Xinyu Zhange9033f62022-10-08 11:15:27 +0800193 failed_report += " {}:{}artifact/{}/target_log.txt\n".format(info['metadata']['build_name'],
194 os.getenv("BUILD_URL"),
195 info['job_dir'])
Xinyu Zhang82dab282022-10-09 16:33:19 +0800196 info['result'] = 'FAILURE'
197 else:
198 info['result'] = 'SUCCESS'
Xinyu Zhang38a18872020-11-23 16:45:28 +0800199 print(failed_report)
200
Matthew Hartfb6fd362020-03-04 21:03:59 +0000201def remove_lava_dupes(results):
202 for result in results:
203 if result['result'] != 'pass':
204 if result['suite'] == "lava":
205 for other in [x for x in results if x != result]:
206 if other['name'] == result['name']:
207 if other['result'] == 'pass':
208 results.remove(result)
209 return(results)
210
Paul Sokolovsky451f67b2022-03-08 19:44:41 +0300211def test_report(jobs, user_args):
Matthew Hartfb6fd362020-03-04 21:03:59 +0000212 # parsing of test results is WIP
213 fail_j = []
214 jinja_data = []
215 for job, info in jobs.items():
Xinyu Zhang82dab282022-10-09 16:33:19 +0800216 if info['health'] != 'Complete':
217 fail_j.append(job)
218 continue
Matthew Hart4a4f1202020-06-12 15:52:46 +0100219 results_file = os.path.join(info['job_dir'], 'results.yaml')
220 if not os.path.exists(results_file) or (os.path.getsize(results_file) == 0):
221 fail_j.append(job)
222 continue
223 with open(results_file, "r") as F:
224 res_data = F.read()
Paul Sokolovskyf2f385d2022-01-11 00:36:31 +0300225 results = yaml.safe_load(res_data)
Paul Sokolovsky07f6dfb2022-07-15 12:26:24 +0300226 non_lava_results = [x for x in results if x['suite'] != 'lava' or x['name'] == 'lava-test-monitor']
Matthew Hartfb6fd362020-03-04 21:03:59 +0000227 info['lava_url'] = lava_id_to_url(job, user_args)
Arthur She38d5f5a2022-09-02 17:32:14 -0700228 info['artifacts_dir'] = info['job_dir']
Matthew Hartfb6fd362020-03-04 21:03:59 +0000229 jinja_data.append({job: [info, non_lava_results]})
230 for result in non_lava_results:
Paul Sokolovsky58f00de2022-02-01 00:26:32 +0300231 if result['result'] == 'fail':
Matthew Hartfb6fd362020-03-04 21:03:59 +0000232 fail_j.append(job) if job not in fail_j else fail_j
233 time.sleep(0.5) # be friendly to LAVA
Matthew Hartfb6fd362020-03-04 21:03:59 +0000234 data = {}
235 data['jobs'] = jinja_data
236 render_jinja(data)
237
238def render_jinja(data):
239 work_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "jinja2_templates")
240 template_loader = FileSystemLoader(searchpath=work_dir)
241 template_env = Environment(loader=template_loader)
242 html = template_env.get_template("test_summary.jinja2").render(data)
243 csv = template_env.get_template("test_summary_csv.jinja2").render(data)
244 with open('test_summary.html', "w") as F:
245 F.write(html)
246 with open('test_summary.csv', "w") as F:
247 F.write(csv)
248
249def print_lava_urls(jobs, user_args):
250 output = [lava_id_to_url(x, user_args) for x in jobs]
Xinyu Zhang78c146a2022-09-05 19:06:40 +0800251 info_print("LAVA jobs triggered for this build: {}".format(output))
Matthew Hartfb6fd362020-03-04 21:03:59 +0000252
253
Xinyu Zhang78c146a2022-09-05 19:06:40 +0800254def info_print(line, silent=True):
255 if not silent:
256 print("INFO: {}".format(line))
Matthew Hartfb6fd362020-03-04 21:03:59 +0000257
258def main(user_args):
259 """ Main logic """
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800260 for try_time in range(3):
261 try:
Paul Sokolovsky451f67b2022-03-08 19:44:41 +0300262 finished_jobs = wait_for_jobs(user_args)
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800263 break
264 except Exception as e:
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800265 if try_time < 2:
Paul Sokolovskycc51ea92022-02-02 19:34:02 +0300266 print("Exception in wait_for_jobs: {!r}".format(e))
267 print("Trying to get LAVA jobs again...")
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800268 else:
269 raise e
Paul Sokolovsky451f67b2022-03-08 19:44:41 +0300270 process_finished_jobs(finished_jobs, user_args)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000271
272def get_cmd_args():
273 """ Parse command line arguments """
274
275 # Parse command line arguments to override config
276 parser = argparse.ArgumentParser(description="Lava Wait Jobs")
277 cmdargs = parser.add_argument_group("Lava Wait Jobs")
278
279 # Configuration control
280 cmdargs.add_argument(
281 "--lava-url", dest="lava_url", action="store", help="LAVA lab URL (without RPC2)"
282 )
283 cmdargs.add_argument(
284 "--job-ids", dest="job_ids", action="store", required=True, help="Comma separated list of job IDS"
285 )
286 cmdargs.add_argument(
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +0800287 "--lava-token", dest="lava_token", action="store", help="LAVA auth token"
Matthew Hartfb6fd362020-03-04 21:03:59 +0000288 )
289 cmdargs.add_argument(
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +0800290 "--lava-user", dest="lava_user", action="store", help="LAVA username"
Matthew Hartfb6fd362020-03-04 21:03:59 +0000291 )
292 cmdargs.add_argument(
293 "--use-env", dest="token_from_env", action="store_true", default=False, help="Use LAVA auth info from environment"
294 )
295 cmdargs.add_argument(
296 "--lava-timeout", dest="dispatch_timeout", action="store", type=int, default=3600, help="Time in seconds to wait for all jobs"
297 )
298 cmdargs.add_argument(
299 "--artifacts-path", dest="artifacts_path", action="store", help="Download LAVA artifacts to this directory"
300 )
301 return parser.parse_args()
302
303
304if __name__ == "__main__":
305 main(get_cmd_args())