blob: 789fae25dedb2577be0d432136766ca389e9716b [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)
74 job_links(finished_jobs, user_args)
75 boot_report(finished_jobs, user_args)
Paul Sokolovsky451f67b2022-03-08 19:44:41 +030076 test_report(finished_jobs, user_args)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080077 failure_report(finished_jobs, user_args)
78 csv_report(finished_jobs)
Paul Sokolovsky2512ec52022-03-04 00:15:39 +030079 codecov_helper.coverage_reports(finished_jobs, user_args)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080080
Paul Sokolovsky451f67b2022-03-08 19:44:41 +030081
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080082def get_finished_jobs(job_list, user_args, lava):
Paul Sokolovsky697f9552022-05-05 10:44:27 +030083 finished_jobs = lava.block_wait_for_jobs(job_list, user_args.dispatch_timeout, 5)
Matthew Hartfb6fd362020-03-04 21:03:59 +000084 unfinished_jobs = [item for item in job_list if item not in finished_jobs]
85 for job in unfinished_jobs:
86 info_print("Cancelling unfinished job: {}".format(job))
87 lava.cancel_job(job)
88 if user_args.artifacts_path:
89 for job, info in finished_jobs.items():
90 info['job_dir'] = os.path.join(user_args.artifacts_path, "{}_{}".format(str(job), info['description']))
91 finished_jobs[job] = info
92 finished_jobs = fetch_artifacts(finished_jobs, user_args, lava)
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +080093 return finished_jobs
Matthew Hartfb6fd362020-03-04 21:03:59 +000094
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080095def resubmit_failed_jobs(jobs, user_args):
96 if not jobs:
97 return []
Xinyu Zhang4aca6d02021-05-31 11:43:32 +080098 time.sleep(2) # be friendly to LAVA
Xinyu Zhangc8a670c2021-05-18 20:20:53 +080099 failed_job = []
100 os.makedirs('failed_jobs', exist_ok=True)
101 for job_id, info in jobs.items():
102 if not (info['health'] == "Complete" and info['state'] == "Finished"):
103 job_dir = info['job_dir']
104 def_path = os.path.join(job_dir, 'definition.yaml')
105 os.rename(def_path, 'failed_jobs/{}_definition.yaml'.format(job_id))
106 shutil.rmtree(job_dir)
107 failed_job.append(job_id)
108 for failed_job_id in failed_job:
109 jobs.pop(failed_job_id)
Xinyu Zhangc918b6e2022-10-08 17:13:17 +0800110 resubmitted_jobs = submit_lava_jobs(user_args, job_dir='failed_jobs')
Xinyu Zhangc8a670c2021-05-18 20:20:53 +0800111 resubmitted_jobs = [int(x) for x in resubmitted_jobs if x != '']
112 return resubmitted_jobs
113
Paul Sokolovskyc2d6d882022-02-25 19:11:18 +0300114
Matthew Hartfb6fd362020-03-04 21:03:59 +0000115def fetch_artifacts(jobs, user_args, lava):
116 if not user_args.artifacts_path:
117 return
118 for job_id, info in jobs.items():
119 job_dir = info['job_dir']
120 info_print("Fetching artifacts for JOB: {} to {}".format(job_id, job_dir))
121 os.makedirs(job_dir, exist_ok=True)
122 def_path = os.path.join(job_dir, 'definition.yaml')
123 target_log = os.path.join(job_dir, 'target_log.txt')
Matthew Hart4a4f1202020-06-12 15:52:46 +0100124 config = os.path.join(job_dir, 'config.tar.bz2')
125 results_file = os.path.join(job_dir, 'results.yaml')
Matthew Hartfb6fd362020-03-04 21:03:59 +0000126 definition, metadata = lava.get_job_definition(job_id, def_path)
127 jobs[job_id]['metadata'] = metadata
128 time.sleep(0.2) # be friendly to LAVA
Matthew Hart4a4f1202020-06-12 15:52:46 +0100129 lava.get_job_log(job_id, target_log)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000130 time.sleep(0.2)
131 lava.get_job_config(job_id, config)
132 time.sleep(0.2)
Matthew Hart4a4f1202020-06-12 15:52:46 +0100133 lava.get_job_results(job_id, results_file)
Paul Sokolovskyc2d6d882022-02-25 19:11:18 +0300134 codecov_helper.extract_trace_data(target_log, job_dir)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000135 return(jobs)
136
137
138def lava_id_to_url(id, user_args):
139 return "{}/scheduler/job/{}".format(user_args.lava_url, id)
140
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800141def generateTestResult(info):
142 if info['health'] == "Complete" and info['state'] == "Finished":
143 return "PASS"
144 else:
145 return "FAIL"
146
Xinyu Zhang97ee3fd2020-12-14 14:45:06 +0800147def job_links(jobs, user_args):
148 job_links = ""
149 for job, info in jobs.items():
Xinyu Zhang78c146a2022-09-05 19:06:40 +0800150 job_links += "Build Config: {}\n".format(info['metadata']['build_name'])
Xinyu Zhang97ee3fd2020-12-14 14:45:06 +0800151 job_links += "Build link: {}\n".format(info['metadata']['build_job_url'])
Xinyu Zhang78c146a2022-09-05 19:06:40 +0800152 job_links += "LAVA link: {}\n".format(lava_id_to_url(job, user_args))
Xinyu Zhange9033f62022-10-08 11:15:27 +0800153 job_links += "TFM LOG: {}artifact/{}/target_log.txt\n\n".format(os.getenv("BUILD_URL"), info['job_dir'])
Xinyu Zhang97ee3fd2020-12-14 14:45:06 +0800154 print(job_links)
155
Xinyu Zhang1b8f5152020-11-13 16:10:58 +0800156def csv_report(jobs):
157 lava_jobs = []
158 for job, info in jobs.items():
159 exist = False
160 for record in lava_jobs:
161 if info['metadata']['platform'] == record["Platform"] and \
162 info['metadata']['compiler'] == record["Compiler"] and \
163 info['metadata']['build_type'] == record["Build Type"]:
164 if record[info['metadata']['name']] != "FAIL":
165 record[info['metadata']['name']] = generateTestResult(info)
166 exist = True
167 break
168 if not exist:
169 record = {}
170 record["Platform"] = info['metadata']['platform']
171 record["Compiler"] = info['metadata']['compiler']
172 record["Build Type"] = info['metadata']['build_type']
173 record["Config Name"] = info['metadata']['name']
174 for cfg in cfgs:
175 record[cfg] = "N.A."
176 record[info['metadata']['name']] = generateTestResult(info)
177 lava_jobs.append(record)
178 lava_jobs.sort(key=lambda x: x["Platform"] + x["Compiler"] + x["Build Type"])
179 with open("test_results.csv", "w", newline="") as csvfile:
180 fieldnames = ["Platform", "Compiler", "Build Type"] + cfgs
181 writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore')
182
183 writer.writeheader()
184 writer.writerows(lava_jobs)
185
Matthew Hartfb6fd362020-03-04 21:03:59 +0000186def boot_report(jobs, user_args):
187 incomplete_jobs = []
188 for job, info in jobs.items():
189 if info['health'] != 'Complete':
190 if info['error_reason'] == 'Infrastructure':
191 info_print("Job {} failed with Infrastructure error".format(job))
192 incomplete_jobs.append(job)
193 incomplete_output = [lava_id_to_url(x, user_args) for x in incomplete_jobs];
194 if len(incomplete_jobs) > 0:
195 print("BOOT_RESULT: -1 Failed: {}".format(incomplete_output))
196 else:
197 print("BOOT_RESULT: +1")
198
Xinyu Zhang38a18872020-11-23 16:45:28 +0800199def failure_report(jobs, user_args):
200 failed_report = "FAILURE_TESTS:"
201 for job, info in jobs.items():
202 if info['health'] != "Complete" or info['state'] != "Finished":
Xinyu Zhange9033f62022-10-08 11:15:27 +0800203 failed_report += " {}:{}artifact/{}/target_log.txt\n".format(info['metadata']['build_name'],
204 os.getenv("BUILD_URL"),
205 info['job_dir'])
Xinyu Zhang38a18872020-11-23 16:45:28 +0800206 print(failed_report)
207
Matthew Hartfb6fd362020-03-04 21:03:59 +0000208def remove_lava_dupes(results):
209 for result in results:
210 if result['result'] != 'pass':
211 if result['suite'] == "lava":
212 for other in [x for x in results if x != result]:
213 if other['name'] == result['name']:
214 if other['result'] == 'pass':
215 results.remove(result)
216 return(results)
217
Paul Sokolovsky451f67b2022-03-08 19:44:41 +0300218def test_report(jobs, user_args):
Matthew Hartfb6fd362020-03-04 21:03:59 +0000219 # parsing of test results is WIP
220 fail_j = []
221 jinja_data = []
222 for job, info in jobs.items():
Matthew Hart4a4f1202020-06-12 15:52:46 +0100223 results_file = os.path.join(info['job_dir'], 'results.yaml')
224 if not os.path.exists(results_file) or (os.path.getsize(results_file) == 0):
225 fail_j.append(job)
226 continue
227 with open(results_file, "r") as F:
228 res_data = F.read()
Paul Sokolovskyf2f385d2022-01-11 00:36:31 +0300229 results = yaml.safe_load(res_data)
Paul Sokolovsky07f6dfb2022-07-15 12:26:24 +0300230 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 +0000231 info['lava_url'] = lava_id_to_url(job, user_args)
Arthur She38d5f5a2022-09-02 17:32:14 -0700232 info['artifacts_dir'] = info['job_dir']
Matthew Hartfb6fd362020-03-04 21:03:59 +0000233 jinja_data.append({job: [info, non_lava_results]})
234 for result in non_lava_results:
Paul Sokolovsky58f00de2022-02-01 00:26:32 +0300235 if result['result'] == 'fail':
Matthew Hartfb6fd362020-03-04 21:03:59 +0000236 fail_j.append(job) if job not in fail_j else fail_j
237 time.sleep(0.5) # be friendly to LAVA
238 fail_output = [lava_id_to_url(x, user_args) for x in fail_j]
239 if len(fail_j) > 0:
240 print("TEST_RESULT: -1 Failed: {}".format(fail_output))
241 else:
242 print("TEST_RESULT: +1")
243 data = {}
244 data['jobs'] = jinja_data
245 render_jinja(data)
246
247def render_jinja(data):
248 work_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "jinja2_templates")
249 template_loader = FileSystemLoader(searchpath=work_dir)
250 template_env = Environment(loader=template_loader)
251 html = template_env.get_template("test_summary.jinja2").render(data)
252 csv = template_env.get_template("test_summary_csv.jinja2").render(data)
253 with open('test_summary.html', "w") as F:
254 F.write(html)
255 with open('test_summary.csv', "w") as F:
256 F.write(csv)
257
258def print_lava_urls(jobs, user_args):
259 output = [lava_id_to_url(x, user_args) for x in jobs]
Xinyu Zhang78c146a2022-09-05 19:06:40 +0800260 info_print("LAVA jobs triggered for this build: {}".format(output))
Matthew Hartfb6fd362020-03-04 21:03:59 +0000261
262
Xinyu Zhang78c146a2022-09-05 19:06:40 +0800263def info_print(line, silent=True):
264 if not silent:
265 print("INFO: {}".format(line))
Matthew Hartfb6fd362020-03-04 21:03:59 +0000266
267def main(user_args):
268 """ Main logic """
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800269 for try_time in range(3):
270 try:
Paul Sokolovsky451f67b2022-03-08 19:44:41 +0300271 finished_jobs = wait_for_jobs(user_args)
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800272 break
273 except Exception as e:
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800274 if try_time < 2:
Paul Sokolovskycc51ea92022-02-02 19:34:02 +0300275 print("Exception in wait_for_jobs: {!r}".format(e))
276 print("Trying to get LAVA jobs again...")
Xinyu Zhang3e8f6602021-04-28 10:57:32 +0800277 else:
278 raise e
Paul Sokolovsky451f67b2022-03-08 19:44:41 +0300279 process_finished_jobs(finished_jobs, user_args)
Matthew Hartfb6fd362020-03-04 21:03:59 +0000280
281def get_cmd_args():
282 """ Parse command line arguments """
283
284 # Parse command line arguments to override config
285 parser = argparse.ArgumentParser(description="Lava Wait Jobs")
286 cmdargs = parser.add_argument_group("Lava Wait Jobs")
287
288 # Configuration control
289 cmdargs.add_argument(
290 "--lava-url", dest="lava_url", action="store", help="LAVA lab URL (without RPC2)"
291 )
292 cmdargs.add_argument(
293 "--job-ids", dest="job_ids", action="store", required=True, help="Comma separated list of job IDS"
294 )
295 cmdargs.add_argument(
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +0800296 "--lava-token", dest="lava_token", action="store", help="LAVA auth token"
Matthew Hartfb6fd362020-03-04 21:03:59 +0000297 )
298 cmdargs.add_argument(
Xinyu Zhangf2b7cbf2021-05-18 20:17:34 +0800299 "--lava-user", dest="lava_user", action="store", help="LAVA username"
Matthew Hartfb6fd362020-03-04 21:03:59 +0000300 )
301 cmdargs.add_argument(
302 "--use-env", dest="token_from_env", action="store_true", default=False, help="Use LAVA auth info from environment"
303 )
304 cmdargs.add_argument(
305 "--lava-timeout", dest="dispatch_timeout", action="store", type=int, default=3600, help="Time in seconds to wait for all jobs"
306 )
307 cmdargs.add_argument(
308 "--artifacts-path", dest="artifacts_path", action="store", help="Download LAVA artifacts to this directory"
309 )
310 return parser.parse_args()
311
312
313if __name__ == "__main__":
314 main(get_cmd_args())