#!/usr/bin/env vpython3 # Copyright (c) 2021 The Brave Authors. All rights reserved. # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at https://mozilla.org/MPL/2.0/. """ On Android the `--output' switch to `npm run test', which produces xunit reports, doesn't work (https://github.com/brave/brave-browser/issues/15595). This script reads json on stdin (`--json-results-file') and prints xunit xml on stdout. This is a temporary hack until `--output' on Android is fixed. Only one global test iteration is supported (it seems only one is used anyway). In per-test iterations, only one is reported - a successful one, if it exists, otherwise a failed one. """ import collections import re import sys import json from operator import add from string import printable from functools import reduce def pick_iteration(test_case, iterations): """Pick the test iteration that provides the most relevant feedback""" def score(iteration): score = 1000000 if iteration['status'] == 'SUCCESS' else 0 score += len(iteration['output_snippet']) started_this_test = re.compile(r'\[ RUN \] [\w/#\.]*' + re.escape(test_case) + '\\n') score += 7500 if started_this_test.match( iteration['output_snippet']) else 0 for string in ['Stack Trace:', 'Expected:', 'Actual:']: score += 2500 if string in iteration['output_snippet'] else 0 return score return sorted(iterations, key=score, reverse=True)[0] def transform(input_json): """Read json input and return a dictionary with information necessary to produce the xunit output""" output = collections.defaultdict(lambda: { 'xml': '', 'test_count': 0, 'failure_count': 0 }) if not input_json['per_iteration_data']: return output test_results = input_json['per_iteration_data'][0] for test_fullname, iterations in test_results.items(): delim = ('#' if '#' in test_fullname else '/' if '/' in test_fullname else '.') test_suite, test_case = test_fullname.rsplit(delim, maxsplit=1) iteration = pick_iteration(test_case, iterations) output[test_suite]['test_count'] += 1 elapsed_time_ms = int(iteration["elapsed_time_ms"] ) if iteration["elapsed_time_ms"] else 0 output[test_suite]['xml'] += (f'') if iteration['status'] == 'SUCCESS': if iteration['output_snippet']: sanitized_output = ''.join( filter(lambda x: x in printable, iteration['output_snippet'])) output[test_suite]['xml'] += ( f"") else: output[test_suite]['failure_count'] += 1 sanitized_output = ''.join( filter(lambda x: x in printable, iteration['output_snippet'])) output[test_suite]['xml'] += ( f'') output[test_suite]['xml'] += "" return output def main(): """Read json on stdin and print xunit on stdout""" output = transform(json.load(sys.stdin)) test_count = reduce(add, (ts['test_count'] for ts in output.values()), 0) failure_count = reduce(add, (ts['failure_count'] for ts in output.values()), 0) print( f'\n', end='') for test_suite in output.keys(): print( f'{output[test_suite]["xml"]}', end='') print('', end='') if __name__ == "__main__": main()