blob: 92e85e0b5d0797c9fe5336d8f4e526653b6f9c83 [file] [log] [blame]
Andrew Scullbc7189d2018-08-14 09:35:13 +01001#!/usr/bin/env python
Andrew Scull18834872018-10-12 11:48:09 +01002#
3# Copyright 2018 Google LLC
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# https://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
Andrew Scullbc7189d2018-08-14 09:35:13 +010017"""Run tests.
18
19Runs tests on QEMU.
20"""
21
22from __future__ import print_function
23
Andrew Scull3b62f2b2018-08-21 14:26:12 +010024import xml.etree.ElementTree as ET
25
Andrew Scullbc7189d2018-08-14 09:35:13 +010026import argparse
Andrew Scull04502e42018-09-03 14:54:52 +010027import datetime
Andrew Scullbc7189d2018-08-14 09:35:13 +010028import json
29import os
30import re
31import subprocess
32import sys
33
34
35def qemu(hafnium, initrd, args, log):
36 qemu_args = [
37 "timeout", "--foreground", "5s",
38 "./prebuilts/linux-x64/qemu/qemu-system-aarch64", "-M", "virt", "-cpu",
Andrew Scullabcf1fa2018-10-05 17:45:21 +010039 "cortex-a57", "-m", "16M", "-machine", "virtualization=true",
Andrew Scullbc7189d2018-08-14 09:35:13 +010040 "-nographic", "-nodefaults", "-serial", "stdio", "-kernel", hafnium,
41 "-initrd", initrd
42 ]
43 if args:
44 qemu_args += ["-append", args]
45 # Save the log to a file.
46 with open(log, "w") as f:
47 f.write("$ {}\r\n".format(" ".join(qemu_args)))
48 f.flush()
49 subprocess.check_call(qemu_args, stdout=f, stderr=f)
50 # Return that log for processing.
51 with open(log, "r") as f:
52 return f.read()
53
54
55def ensure_dir(path):
56 try:
57 os.makedirs(path)
58 except OSError:
59 if not os.path.isdir(path):
60 raise
61
62
63def hftest_lines(raw):
64 prefix = "[hftest] "
65 return [
66 line[len(prefix):]
67 for line in raw.splitlines()
68 if line.startswith(prefix)
69 ]
70
71
72def Main():
73 parser = argparse.ArgumentParser()
74 parser.add_argument("--out", required=True)
Andrew Scull23e93a82018-10-26 14:56:04 +010075 parser.add_argument("--log", required=True)
Andrew Scullbc7189d2018-08-14 09:35:13 +010076 parser.add_argument("--initrd", required=True)
77 parser.add_argument("--suite")
78 parser.add_argument("--test")
79 args = parser.parse_args()
80 # Resolve some paths.
81 hafnium = os.path.join(args.out, "hafnium.bin")
82 initrd = os.path.join(args.out, "initrd", args.initrd + ".img")
Andrew Scull23e93a82018-10-26 14:56:04 +010083 log = os.path.join(args.log, args.initrd)
Andrew Scullbc7189d2018-08-14 09:35:13 +010084 ensure_dir(log)
85 print("Logs saved under", log)
Andrew Scull3b62f2b2018-08-21 14:26:12 +010086 log_file = os.path.join(log, "sponge_log.log")
87 with open(log_file, "w") as sponge_log:
88 # Query the tests in the image.
89 out = qemu(hafnium, initrd, "json", os.path.join(log, "json.log"))
90 sponge_log.write(out)
91 sponge_log.write("\r\n\r\n")
92 hftest_json = "\n".join(hftest_lines(out))
93 tests = json.loads(hftest_json)
94 # Run the selected tests.
95 tests_run = 0
96 failures = 0
97 suite_re = re.compile(args.suite or ".*")
98 test_re = re.compile(args.test or ".*")
99 sponge = ET.Element("testsuites")
100 sponge.set("name", args.initrd)
Andrew Scull04502e42018-09-03 14:54:52 +0100101 sponge.set(
102 "timestamp",
103 datetime.datetime.now().replace(microsecond=0).isoformat())
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100104 for suite in tests["suites"]:
105 if not suite_re.match(suite["name"]):
Andrew Scullbc7189d2018-08-14 09:35:13 +0100106 continue
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100107 tests_run_from_suite = 0
108 failures_from_suite = 0
109 sponge_suite = ET.SubElement(sponge, "testsuite")
110 sponge_suite.set("name", suite["name"])
111 for test in suite["tests"]:
112 if not test_re.match(test):
113 continue
114 sponge_test = ET.SubElement(sponge_suite, "testcase")
115 sponge_test.set("name", test)
Andrew Scull04502e42018-09-03 14:54:52 +0100116 sponge_test.set("classname", suite['name'])
Andrew Scull3b62f2b2018-08-21 14:26:12 +0100117 sponge_test.set("status", "run")
118 tests_run_from_suite += 1
119 if tests_run_from_suite == 1:
120 print(" SUITE", suite["name"])
121 print(" RUN", test)
122 test_log = os.path.join(log,
123 suite["name"] + "." + test + ".log")
124 out = qemu(hafnium, initrd, "run {} {}".format(
125 suite["name"], test), test_log)
126 sponge_log.write(out)
127 sponge_log.write("\r\n\r\n")
128 hftest_out = hftest_lines(out)
129 if hftest_out[-1] == "PASS":
130 print(" PASS")
131 else:
132 failures_from_suite += 1
133 sponge_failure = ET.SubElement(sponge_test, "failure")
134 # TODO: set a meaningful message and put log in CDATA
135 sponge_failure.set("message", "Test failed")
136 print("[x] FAIL --", test_log)
137 tests_run += tests_run_from_suite
138 failures += failures_from_suite
139 sponge_suite.set("tests", str(tests_run_from_suite))
140 sponge_suite.set("failures", str(failures_from_suite))
141 sponge.set("tests", str(tests_run))
142 sponge.set("failures", str(failures))
143 with open(os.path.join(log, "sponge_log.xml"), "w") as f:
144 ET.ElementTree(sponge).write(f, encoding='utf-8', xml_declaration=True)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100145 # If none were run, this is probably a mistake.
146 if tests_run == 0:
147 print("Error: no tests match")
148 return 10
149 # Exit with 0 on success and 1 if any test failed.
150 if failures:
151 print("[x] FAIL:", failures, "of", tests_run, "tests failed")
152 return 1
153 else:
154 print(" PASS: all", tests_run, "tests passed")
155 return 0
156
157
158if __name__ == "__main__":
159 sys.exit(Main())