Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 1 | # |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 2 | # Copyright (C) 2016 Intel Corporation |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 3 | # |
| 4 | # SPDX-License-Identifier: MIT |
| 5 | # |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 6 | |
| 7 | import os |
| 8 | import time |
| 9 | import unittest |
| 10 | import logging |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 11 | import re |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 12 | import json |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 13 | import sys |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 14 | |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 15 | from unittest import TextTestResult as _TestResult |
| 16 | from unittest import TextTestRunner as _TestRunner |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 17 | |
| 18 | class OEStreamLogger(object): |
| 19 | def __init__(self, logger): |
| 20 | self.logger = logger |
| 21 | self.buffer = "" |
| 22 | |
| 23 | def write(self, msg): |
| 24 | if len(msg) > 1 and msg[0] != '\n': |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 25 | if '...' in msg: |
| 26 | self.buffer += msg |
| 27 | elif self.buffer: |
| 28 | self.buffer += msg |
| 29 | self.logger.log(logging.INFO, self.buffer) |
| 30 | self.buffer = "" |
| 31 | else: |
| 32 | self.logger.log(logging.INFO, msg) |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 33 | |
| 34 | def flush(self): |
| 35 | for handler in self.logger.handlers: |
| 36 | handler.flush() |
| 37 | |
| 38 | class OETestResult(_TestResult): |
| 39 | def __init__(self, tc, *args, **kwargs): |
| 40 | super(OETestResult, self).__init__(*args, **kwargs) |
| 41 | |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 42 | self.successes = [] |
Brad Bishop | 1a4b7ee | 2018-12-16 17:11:34 -0800 | [diff] [blame] | 43 | self.starttime = {} |
| 44 | self.endtime = {} |
| 45 | self.progressinfo = {} |
Brad Bishop | 79641f2 | 2019-09-10 07:20:22 -0400 | [diff] [blame] | 46 | self.extraresults = {} |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 47 | |
| 48 | # Inject into tc so that TestDepends decorator can see results |
| 49 | tc.results = self |
| 50 | |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 51 | self.tc = tc |
| 52 | |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 53 | # stdout and stderr for each test case |
| 54 | self.logged_output = {} |
| 55 | |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 56 | def startTest(self, test): |
Brad Bishop | 1a4b7ee | 2018-12-16 17:11:34 -0800 | [diff] [blame] | 57 | # May have been set by concurrencytest |
| 58 | if test.id() not in self.starttime: |
| 59 | self.starttime[test.id()] = time.time() |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 60 | super(OETestResult, self).startTest(test) |
| 61 | |
Brad Bishop | 1a4b7ee | 2018-12-16 17:11:34 -0800 | [diff] [blame] | 62 | def stopTest(self, test): |
| 63 | self.endtime[test.id()] = time.time() |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 64 | if self.buffer: |
| 65 | self.logged_output[test.id()] = ( |
| 66 | sys.stdout.getvalue(), sys.stderr.getvalue()) |
Brad Bishop | 1a4b7ee | 2018-12-16 17:11:34 -0800 | [diff] [blame] | 67 | super(OETestResult, self).stopTest(test) |
| 68 | if test.id() in self.progressinfo: |
| 69 | self.tc.logger.info(self.progressinfo[test.id()]) |
| 70 | |
| 71 | # Print the errors/failures early to aid/speed debugging, its a pain |
| 72 | # to wait until selftest finishes to see them. |
| 73 | for t in ['failures', 'errors', 'skipped', 'expectedFailures']: |
| 74 | for (scase, msg) in getattr(self, t): |
| 75 | if test.id() == scase.id(): |
| 76 | self.tc.logger.info(str(msg)) |
| 77 | break |
| 78 | |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 79 | def logSummary(self, component, context_msg=''): |
| 80 | elapsed_time = self.tc._run_end_time - self.tc._run_start_time |
| 81 | self.tc.logger.info("SUMMARY:") |
| 82 | self.tc.logger.info("%s (%s) - Ran %d test%s in %.3fs" % (component, |
| 83 | context_msg, self.testsRun, self.testsRun != 1 and "s" or "", |
| 84 | elapsed_time)) |
| 85 | |
| 86 | if self.wasSuccessful(): |
| 87 | msg = "%s - OK - All required tests passed" % component |
| 88 | else: |
| 89 | msg = "%s - FAIL - Required tests failed" % component |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 90 | msg += " (successes=%d, skipped=%d, failures=%d, errors=%d)" % (len(self.successes), len(self.skipped), len(self.failures), len(self.errors)) |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 91 | self.tc.logger.info(msg) |
| 92 | |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 93 | def _getTestResultDetails(self, case): |
| 94 | result_types = {'failures': 'FAILED', 'errors': 'ERROR', 'skipped': 'SKIPPED', |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 95 | 'expectedFailures': 'EXPECTEDFAIL', 'successes': 'PASSED', |
| 96 | 'unexpectedSuccesses' : 'PASSED'} |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 97 | |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 98 | for rtype in result_types: |
| 99 | found = False |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 100 | for resultclass in getattr(self, rtype): |
| 101 | # unexpectedSuccesses are just lists, not lists of tuples |
| 102 | if isinstance(resultclass, tuple): |
| 103 | scase, msg = resultclass |
| 104 | else: |
| 105 | scase, msg = resultclass, None |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 106 | if case.id() == scase.id(): |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 107 | found = True |
| 108 | break |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 109 | scase_str = str(scase.id()) |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 110 | |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 111 | # When fails at module or class level the class name is passed as string |
| 112 | # so figure out to see if match |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 113 | m = re.search(r"^setUpModule \((?P<module_name>.*)\).*$", scase_str) |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 114 | if m: |
| 115 | if case.__class__.__module__ == m.group('module_name'): |
| 116 | found = True |
| 117 | break |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 118 | |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 119 | m = re.search(r"^setUpClass \((?P<class_name>.*)\).*$", scase_str) |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 120 | if m: |
| 121 | class_name = "%s.%s" % (case.__class__.__module__, |
| 122 | case.__class__.__name__) |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 123 | |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 124 | if class_name == m.group('class_name'): |
| 125 | found = True |
| 126 | break |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 127 | |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 128 | if found: |
| 129 | return result_types[rtype], msg |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 130 | |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 131 | return 'UNKNOWN', None |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 132 | |
Brad Bishop | 79641f2 | 2019-09-10 07:20:22 -0400 | [diff] [blame] | 133 | def extractExtraResults(self, test, details = None): |
| 134 | extraresults = None |
| 135 | if details is not None and "extraresults" in details: |
| 136 | extraresults = details.get("extraresults", {}) |
| 137 | elif hasattr(test, "extraresults"): |
| 138 | extraresults = test.extraresults |
| 139 | |
| 140 | if extraresults is not None: |
| 141 | for k, v in extraresults.items(): |
| 142 | # handle updating already existing entries (e.g. ptestresults.sections) |
| 143 | if k in self.extraresults: |
| 144 | self.extraresults[k].update(v) |
| 145 | else: |
| 146 | self.extraresults[k] = v |
| 147 | |
| 148 | def addError(self, test, *args, details = None): |
| 149 | self.extractExtraResults(test, details = details) |
| 150 | return super(OETestResult, self).addError(test, *args) |
| 151 | |
| 152 | def addFailure(self, test, *args, details = None): |
| 153 | self.extractExtraResults(test, details = details) |
| 154 | return super(OETestResult, self).addFailure(test, *args) |
| 155 | |
| 156 | def addSuccess(self, test, details = None): |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 157 | #Added so we can keep track of successes too |
| 158 | self.successes.append((test, None)) |
Brad Bishop | 79641f2 | 2019-09-10 07:20:22 -0400 | [diff] [blame] | 159 | self.extractExtraResults(test, details = details) |
| 160 | return super(OETestResult, self).addSuccess(test) |
| 161 | |
| 162 | def addExpectedFailure(self, test, *args, details = None): |
| 163 | self.extractExtraResults(test, details = details) |
| 164 | return super(OETestResult, self).addExpectedFailure(test, *args) |
| 165 | |
| 166 | def addUnexpectedSuccess(self, test, details = None): |
| 167 | self.extractExtraResults(test, details = details) |
| 168 | return super(OETestResult, self).addUnexpectedSuccess(test) |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 169 | |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 170 | def logDetails(self, json_file_dir=None, configuration=None, result_id=None, |
| 171 | dump_streams=False): |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 172 | self.tc.logger.info("RESULTS:") |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 173 | |
Brad Bishop | 79641f2 | 2019-09-10 07:20:22 -0400 | [diff] [blame] | 174 | result = self.extraresults |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 175 | logs = {} |
| 176 | if hasattr(self.tc, "extraresults"): |
Brad Bishop | 79641f2 | 2019-09-10 07:20:22 -0400 | [diff] [blame] | 177 | result.update(self.tc.extraresults) |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 178 | |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 179 | for case_name in self.tc._registry['cases']: |
| 180 | case = self.tc._registry['cases'][case_name] |
| 181 | |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 182 | (status, log) = self._getTestResultDetails(case) |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 183 | |
Brad Bishop | 1a4b7ee | 2018-12-16 17:11:34 -0800 | [diff] [blame] | 184 | t = "" |
Andrew Geissler | 1e34c2d | 2020-05-29 16:02:59 -0500 | [diff] [blame] | 185 | duration = 0 |
Brad Bishop | 1a4b7ee | 2018-12-16 17:11:34 -0800 | [diff] [blame] | 186 | if case.id() in self.starttime and case.id() in self.endtime: |
Andrew Geissler | 1e34c2d | 2020-05-29 16:02:59 -0500 | [diff] [blame] | 187 | duration = self.endtime[case.id()] - self.starttime[case.id()] |
| 188 | t = " (" + "{0:.2f}".format(duration) + "s)" |
Brad Bishop | 1a4b7ee | 2018-12-16 17:11:34 -0800 | [diff] [blame] | 189 | |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 190 | if status not in logs: |
| 191 | logs[status] = [] |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 192 | logs[status].append("RESULTS - %s: %s%s" % (case.id(), status, t)) |
| 193 | report = {'status': status} |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 194 | if log: |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 195 | report['log'] = log |
Andrew Geissler | 1e34c2d | 2020-05-29 16:02:59 -0500 | [diff] [blame] | 196 | if duration: |
| 197 | report['duration'] = duration |
Andrew Geissler | 635e0e4 | 2020-08-21 15:58:33 -0500 | [diff] [blame] | 198 | |
| 199 | alltags = [] |
| 200 | # pull tags from the case class |
| 201 | if hasattr(case, "__oeqa_testtags"): |
| 202 | alltags.extend(getattr(case, "__oeqa_testtags")) |
| 203 | # pull tags from the method itself |
| 204 | test_name = case._testMethodName |
| 205 | if hasattr(case, test_name): |
| 206 | method = getattr(case, test_name) |
| 207 | if hasattr(method, "__oeqa_testtags"): |
| 208 | alltags.extend(getattr(method, "__oeqa_testtags")) |
| 209 | if alltags: |
| 210 | report['oetags'] = alltags |
| 211 | |
Brad Bishop | c342db3 | 2019-05-15 21:57:59 -0400 | [diff] [blame] | 212 | if dump_streams and case.id() in self.logged_output: |
| 213 | (stdout, stderr) = self.logged_output[case.id()] |
| 214 | report['stdout'] = stdout |
| 215 | report['stderr'] = stderr |
| 216 | result[case.id()] = report |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 217 | |
| 218 | for i in ['PASSED', 'SKIPPED', 'EXPECTEDFAIL', 'ERROR', 'FAILED', 'UNKNOWN']: |
| 219 | if i not in logs: |
| 220 | continue |
| 221 | for l in logs[i]: |
| 222 | self.tc.logger.info(l) |
| 223 | |
| 224 | if json_file_dir: |
| 225 | tresultjsonhelper = OETestResultJSONHelper() |
| 226 | tresultjsonhelper.dump_testresult_file(json_file_dir, configuration, result_id, result) |
| 227 | |
| 228 | def wasSuccessful(self): |
| 229 | # Override as we unexpected successes aren't failures for us |
| 230 | return (len(self.failures) == len(self.errors) == 0) |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 231 | |
| 232 | class OEListTestsResult(object): |
| 233 | def wasSuccessful(self): |
| 234 | return True |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 235 | |
| 236 | class OETestRunner(_TestRunner): |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 237 | streamLoggerClass = OEStreamLogger |
| 238 | |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 239 | def __init__(self, tc, *args, **kwargs): |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 240 | kwargs['stream'] = self.streamLoggerClass(tc.logger) |
Brad Bishop | 6e60e8b | 2018-02-01 10:27:11 -0500 | [diff] [blame] | 241 | super(OETestRunner, self).__init__(*args, **kwargs) |
| 242 | self.tc = tc |
| 243 | self.resultclass = OETestResult |
| 244 | |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 245 | def _makeResult(self): |
| 246 | return self.resultclass(self.tc, self.stream, self.descriptions, |
| 247 | self.verbosity) |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 248 | |
| 249 | def _walk_suite(self, suite, func): |
| 250 | for obj in suite: |
| 251 | if isinstance(obj, unittest.suite.TestSuite): |
| 252 | if len(obj._tests): |
| 253 | self._walk_suite(obj, func) |
| 254 | elif isinstance(obj, unittest.case.TestCase): |
| 255 | func(self.tc.logger, obj) |
| 256 | self._walked_cases = self._walked_cases + 1 |
| 257 | |
| 258 | def _list_tests_name(self, suite): |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 259 | self._walked_cases = 0 |
| 260 | |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 261 | def _list_cases(logger, case): |
Brad Bishop | 79641f2 | 2019-09-10 07:20:22 -0400 | [diff] [blame] | 262 | oetags = [] |
| 263 | if hasattr(case, '__oeqa_testtags'): |
| 264 | oetags = getattr(case, '__oeqa_testtags') |
| 265 | if oetags: |
| 266 | logger.info("%s (%s)" % (case.id(), ",".join(oetags))) |
| 267 | else: |
| 268 | logger.info("%s" % (case.id())) |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 269 | |
| 270 | self.tc.logger.info("Listing all available tests:") |
| 271 | self._walked_cases = 0 |
Brad Bishop | 79641f2 | 2019-09-10 07:20:22 -0400 | [diff] [blame] | 272 | self.tc.logger.info("test (tags)") |
Brad Bishop | d7bf8c1 | 2018-02-25 22:55:05 -0500 | [diff] [blame] | 273 | self.tc.logger.info("-" * 80) |
| 274 | self._walk_suite(suite, _list_cases) |
| 275 | self.tc.logger.info("-" * 80) |
| 276 | self.tc.logger.info("Total found:\t%s" % self._walked_cases) |
| 277 | |
| 278 | def _list_tests_class(self, suite): |
| 279 | self._walked_cases = 0 |
| 280 | |
| 281 | curr = {} |
| 282 | def _list_classes(logger, case): |
| 283 | if not 'module' in curr or curr['module'] != case.__module__: |
| 284 | curr['module'] = case.__module__ |
| 285 | logger.info(curr['module']) |
| 286 | |
| 287 | if not 'class' in curr or curr['class'] != \ |
| 288 | case.__class__.__name__: |
| 289 | curr['class'] = case.__class__.__name__ |
| 290 | logger.info(" -- %s" % curr['class']) |
| 291 | |
| 292 | logger.info(" -- -- %s" % case._testMethodName) |
| 293 | |
| 294 | self.tc.logger.info("Listing all available test classes:") |
| 295 | self._walk_suite(suite, _list_classes) |
| 296 | |
| 297 | def _list_tests_module(self, suite): |
| 298 | self._walked_cases = 0 |
| 299 | |
| 300 | listed = [] |
| 301 | def _list_modules(logger, case): |
| 302 | if not case.__module__ in listed: |
| 303 | if case.__module__.startswith('_'): |
| 304 | logger.info("%s (hidden)" % case.__module__) |
| 305 | else: |
| 306 | logger.info(case.__module__) |
| 307 | listed.append(case.__module__) |
| 308 | |
| 309 | self.tc.logger.info("Listing all available test modules:") |
| 310 | self._walk_suite(suite, _list_modules) |
| 311 | |
| 312 | def list_tests(self, suite, display_type): |
| 313 | if display_type == 'name': |
| 314 | self._list_tests_name(suite) |
| 315 | elif display_type == 'class': |
| 316 | self._list_tests_class(suite) |
| 317 | elif display_type == 'module': |
| 318 | self._list_tests_module(suite) |
| 319 | |
| 320 | return OEListTestsResult() |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 321 | |
| 322 | class OETestResultJSONHelper(object): |
| 323 | |
| 324 | testresult_filename = 'testresults.json' |
| 325 | |
| 326 | def _get_existing_testresults_if_available(self, write_dir): |
| 327 | testresults = {} |
| 328 | file = os.path.join(write_dir, self.testresult_filename) |
| 329 | if os.path.exists(file): |
| 330 | with open(file, "r") as f: |
| 331 | testresults = json.load(f) |
| 332 | return testresults |
| 333 | |
| 334 | def _write_file(self, write_dir, file_name, file_content): |
| 335 | file_path = os.path.join(write_dir, file_name) |
| 336 | with open(file_path, 'w') as the_file: |
| 337 | the_file.write(file_content) |
| 338 | |
| 339 | def dump_testresult_file(self, write_dir, configuration, result_id, test_result): |
Andrew Geissler | 82c905d | 2020-04-13 13:39:40 -0500 | [diff] [blame] | 340 | try: |
| 341 | import bb |
| 342 | has_bb = True |
| 343 | bb.utils.mkdirhier(write_dir) |
| 344 | lf = bb.utils.lockfile(os.path.join(write_dir, 'jsontestresult.lock')) |
| 345 | except ImportError: |
| 346 | has_bb = False |
| 347 | os.makedirs(write_dir, exist_ok=True) |
Brad Bishop | f86d055 | 2018-12-04 14:18:15 -0800 | [diff] [blame] | 348 | test_results = self._get_existing_testresults_if_available(write_dir) |
| 349 | test_results[result_id] = {'configuration': configuration, 'result': test_result} |
| 350 | json_testresults = json.dumps(test_results, sort_keys=True, indent=4) |
| 351 | self._write_file(write_dir, self.testresult_filename, json_testresults) |
Andrew Geissler | 82c905d | 2020-04-13 13:39:40 -0500 | [diff] [blame] | 352 | if has_bb: |
| 353 | bb.utils.unlockfile(lf) |