blob: 30a7168a319af06b0a34bb01a06de504f8d19288 [file] [log] [blame]
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +00001"""Template test runner class for running TOSA tests."""
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +01002# Copyright (c) 2020-2023, ARM Limited.
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +00003# SPDX-License-Identifier: Apache-2.0
Eric Kunzee5e26762020-10-13 16:11:07 -07004import json
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +00005from enum import IntEnum
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +00006
Jeremy Johnsone2b5e872023-09-14 17:02:09 +01007import conformance.model_files as cmf
8import schemavalidation.schemavalidation as sch
9from checker.color_print import LogColors
10from checker.color_print import print_color
11from checker.color_print import set_print_in_color
12from checker.tosa_result_checker import set_print_result
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000013from checker.tosa_result_checker import test_check
14from json2fbbin import json2fbbin
Jeremy Johnsone2b5e872023-09-14 17:02:09 +010015from runner.tosa_test_presets import TOSA_REFCOMPLIANCE_RUNNER
16
17
18def isComplianceModeDotProduct(testDesc):
19 """Checks the test descriptor for DOT_PRODUCT compliance mode."""
20 if (
21 "meta" in testDesc
22 and "compliance" in testDesc["meta"]
23 and "tensors" in testDesc["meta"]["compliance"]
24 ):
25 for _, t in testDesc["meta"]["compliance"]["tensors"].items():
26 if "mode" in t and t["mode"] == "DOT_PRODUCT":
27 return True
28 return False
29
30
31def getRunnerResultFilePath(resultFilePath, sutModule):
32 """Return the result file path with the runner specific naming."""
33 return resultFilePath.with_suffix(f".{sutModule}{resultFilePath.suffix}")
34
35
36def getBoundsResultFilePath(resultFilePath, sutModule=None):
37 """Return the bounds result file with/without runner specific naming."""
38 boundsFilePath = resultFilePath.parent / f"bounds_{resultFilePath.name}"
39 if sutModule is not None:
40 boundsFilePath = boundsFilePath.with_suffix(
41 f".{sutModule}{boundsFilePath.suffix}"
42 )
43 return boundsFilePath
Eric Kunzee5e26762020-10-13 16:11:07 -070044
Kevin Cheng550ccc52021-03-03 11:21:43 -080045
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000046class TosaTestInvalid(Exception):
47 """Exception raised for errors loading test description.
Eric Kunzee5e26762020-10-13 16:11:07 -070048
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000049 Attributes:
50 path - full path to missing test description file
51 exception = underlying exception
52 """
Eric Kunzee5e26762020-10-13 16:11:07 -070053
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000054 def __init__(self, path, exception):
55 """Initialize test not found error."""
56 self.path = path
57 self.exception = exception
58 self.message = "Invalid test, could not read test description {}: {}".format(
59 self.path, str(self.exception)
60 )
61 super().__init__(self.message)
Kevin Cheng550ccc52021-03-03 11:21:43 -080062
Eric Kunzee5e26762020-10-13 16:11:07 -070063
64class TosaTestRunner:
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000065 """TOSA Test Runner template class for systems under test."""
Eric Kunzee5e26762020-10-13 16:11:07 -070066
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010067 def __init__(self, args, runnerArgs, testDirPath):
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000068 """Initialize and load JSON meta data file."""
Eric Kunzee5e26762020-10-13 16:11:07 -070069 self.args = args
70 self.runnerArgs = runnerArgs
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010071 self.testDir = str(testDirPath)
72 self.testDirPath = testDirPath
73 self.testName = self.testDirPath.name
Jeremy Johnsone2b5e872023-09-14 17:02:09 +010074 self.verify_lib_path = cmf.find_tosa_file(
75 cmf.TosaFileType.VERIFY_LIBRARY, args.ref_model_path
76 )
Eric Kunzee5e26762020-10-13 16:11:07 -070077
Jeremy Johnson015c3552022-02-23 12:15:03 +000078 set_print_in_color(not args.no_color)
Jeremy Johnsone2b5e872023-09-14 17:02:09 +010079 # Stop the result checker printing anything - we will do it
80 set_print_result(False)
Jeremy Johnson015c3552022-02-23 12:15:03 +000081
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000082 # Check if we want to run binary and if its already converted
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010083 descFilePath = testDirPath / "desc.json"
84 descBinFilePath = testDirPath / "desc_binary.json"
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000085 if args.binary:
86 if descBinFilePath.is_file():
87 descFilePath = descBinFilePath
Eric Kunzee5e26762020-10-13 16:11:07 -070088
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000089 try:
90 # Load the json test file
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010091 with descFilePath.open("r") as fd:
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000092 self.testDesc = json.load(fd)
Jeremy Johnsone2b5e872023-09-14 17:02:09 +010093 # Validate the json with the schema
94 sch.TestDescSchemaValidator().validate_config(self.testDesc)
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000095 except Exception as e:
96 raise TosaTestInvalid(str(descFilePath), e)
97
98 # Convert to binary if needed
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010099 tosaFilePath = testDirPath / self.testDesc["tosa_file"]
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000100 if args.binary and tosaFilePath.suffix == ".json":
101 # Convert tosa JSON to binary
102 json2fbbin.json_to_fbbin(
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100103 args.flatc_path,
104 args.schema_path,
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000105 tosaFilePath,
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100106 testDirPath,
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000107 )
108 # Write new desc_binary file
109 self.testDesc["tosa_file"] = tosaFilePath.stem + ".tosa"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100110 with descBinFilePath.open("w") as fd:
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000111 json.dump(self.testDesc, fd, indent=2)
112 descFilePath = descBinFilePath
113
114 # Set location of desc.json (or desc_binary.json) file in use
115 self.descFile = str(descFilePath)
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100116 self.descFilePath = descFilePath
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000117
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100118 # Check for compliance mode - need to run refmodel to get results
119 if "meta" in self.testDesc and "compliance" in self.testDesc["meta"]:
120 self.complianceMode = True
121 if "expected_result" in self.testDesc:
122 if self.args.verbose:
123 print("Warning: fixing conflicting compliance mode in test.desc")
124 self.testDesc.pop("expected_result")
125 else:
126 self.complianceMode = False
127
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000128 def skipTest(self):
Jeremy Johnson88588622022-07-12 16:42:29 +0100129 """Check if the test is skipped due to test type or profile selection."""
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000130 expectedFailure = self.testDesc["expected_failure"]
131 if self.args.test_type == "negative" and not expectedFailure:
Jeremy Johnson88588622022-07-12 16:42:29 +0100132 return True, "non-negative type"
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000133 elif self.args.test_type == "positive" and expectedFailure:
Jeremy Johnson88588622022-07-12 16:42:29 +0100134 return True, "non-positive type"
135 if self.args.profile:
136 profile = self.testDesc["profile"] if "profile" in self.testDesc else []
137 if self.args.profile not in profile:
138 return True, "non-{} profile".format(self.args.profile)
139 return False, ""
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000140
141 def runTestGraph(self):
142 """Override with function that calls system under test."""
Eric Kunzee5e26762020-10-13 16:11:07 -0700143 pass
144
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000145 def testResult(self, tosaGraphResult, graphMessage=None):
146 """Work out test result based on graph result and output files."""
147 expectedFailure = self.testDesc["expected_failure"]
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100148 print_check_result = False
149
150 sutModule = self.__module__
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000151
152 if tosaGraphResult == TosaTestRunner.TosaGraphResult.TOSA_VALID:
153 if expectedFailure:
154 result = TosaTestRunner.Result.UNEXPECTED_PASS
155 resultMessage = "Expected failure test incorrectly passed"
156 else:
157 # Work through all the results produced by the testing, assuming success
158 # but overriding this with any failures found
159 result = TosaTestRunner.Result.EXPECTED_PASS
160 messages = []
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100161
162 # Go through each output result checking it
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000163 for resultNum, resultFileName in enumerate(self.testDesc["ofm_file"]):
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100164 resultFilePath = self.testDirPath / resultFileName
165
166 # Work out the file to check against (if any)
167 if self.complianceMode and sutModule != TOSA_REFCOMPLIANCE_RUNNER:
168 conformanceFilePath = getRunnerResultFilePath(
169 resultFilePath, TOSA_REFCOMPLIANCE_RUNNER
170 )
171 if isComplianceModeDotProduct(self.testDesc):
172 conformanceBoundsPath = getBoundsResultFilePath(
173 resultFilePath, TOSA_REFCOMPLIANCE_RUNNER
174 )
175 else:
176 # Not expecting a bounds file for this test
177 conformanceBoundsPath = None
178 elif "expected_result_file" in self.testDesc:
179 conformanceBoundsPath = None
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000180 try:
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100181 conformanceFilePath = (
182 self.testDirPath
183 / self.testDesc["expected_result_file"][resultNum]
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000184 )
185 except IndexError:
186 result = TosaTestRunner.Result.INTERNAL_ERROR
187 msg = "Internal error: Missing expected_result_file {} in {}".format(
188 resultNum, self.descFile
189 )
190 messages.append(msg)
191 print(msg)
192 break
193 else:
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100194 # Nothing to check against
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100195 conformanceFilePath = None
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100196 conformanceBoundsPath = None
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000197
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100198 if conformanceFilePath:
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100199 print_check_result = True # Result from checker
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000200 chkResult, tolerance, msg = test_check(
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100201 conformanceFilePath,
202 resultFilePath,
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000203 test_name=self.testName,
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100204 test_desc=self.testDesc,
205 bnd_result_path=conformanceBoundsPath,
206 ofm_name=self.testDesc["ofm_name"][resultNum],
207 verify_lib_path=self.verify_lib_path,
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000208 )
209 # Change EXPECTED_PASS assumption if we have any failures
210 if chkResult != 0:
211 result = TosaTestRunner.Result.UNEXPECTED_FAILURE
212 messages.append(msg)
213 if self.args.verbose:
214 print(msg)
215 else:
216 # No conformance file to verify, just check results file exists
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100217 if not resultFilePath.is_file():
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000218 result = TosaTestRunner.Result.UNEXPECTED_FAILURE
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100219 msg = f"Results file is missing: {resultFilePath}"
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000220 messages.append(msg)
221 print(msg)
222
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100223 if resultFilePath.is_file():
224 # Move the resultFilePath to allow subsequent system under
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000225 # tests to create them and to test they have been created
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100226 # and to enable compliance testing against refmodel results
227 resultFilePath.rename(
228 getRunnerResultFilePath(resultFilePath, sutModule)
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000229 )
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100230 if (
231 isComplianceModeDotProduct(self.testDesc)
232 and sutModule == TOSA_REFCOMPLIANCE_RUNNER
233 ):
234 boundsFilePath = getBoundsResultFilePath(resultFilePath)
235 if boundsFilePath.is_file():
236 boundsFilePath = boundsFilePath.rename(
237 getBoundsResultFilePath(resultFilePath, sutModule)
238 )
239 else:
240 result = TosaTestRunner.Result.INTERNAL_ERROR
241 msg = f"Internal error: Missing expected dot product compliance bounds file {boundsFilePath}"
242 messages.append(msg)
243 print(msg)
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000244
245 resultMessage = "\n".join(messages) if len(messages) > 0 else None
246 else:
247 if (
248 expectedFailure
249 and tosaGraphResult == TosaTestRunner.TosaGraphResult.TOSA_ERROR
250 ):
251 result = TosaTestRunner.Result.EXPECTED_FAILURE
252 resultMessage = None
253 else:
254 result = TosaTestRunner.Result.UNEXPECTED_FAILURE
255 resultMessage = graphMessage
256
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100257 status = "Result" if print_check_result else "Result code"
258 if (
259 result == TosaTestRunner.Result.EXPECTED_FAILURE
260 or result == TosaTestRunner.Result.EXPECTED_PASS
261 ):
262 print_color(LogColors.GREEN, f"{sutModule}: {status} PASS {self.testName}")
263 else:
264 print_color(LogColors.RED, f"{sutModule}: {status} FAIL {self.testName}")
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000265
266 return result, resultMessage
267
Eric Kunzee5e26762020-10-13 16:11:07 -0700268 class Result(IntEnum):
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000269 """Test result codes."""
270
Eric Kunzee5e26762020-10-13 16:11:07 -0700271 EXPECTED_PASS = 0
272 EXPECTED_FAILURE = 1
273 UNEXPECTED_PASS = 2
274 UNEXPECTED_FAILURE = 3
275 INTERNAL_ERROR = 4
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000276 SKIPPED = 5
277
278 class TosaGraphResult(IntEnum):
279 """The tosa_graph_result codes."""
280
281 TOSA_VALID = 0
282 TOSA_UNPREDICTABLE = 1
283 TOSA_ERROR = 2
284 OTHER_ERROR = 3