Brad Bishop | 40320b1 | 2019-03-26 16:08:25 -0400 | [diff] [blame] | 1 | # resulttool - common library/utility functions |
| 2 | # |
| 3 | # Copyright (c) 2019, Intel Corporation. |
| 4 | # Copyright (c) 2019, Linux Foundation |
| 5 | # |
| 6 | # This program is free software; you can redistribute it and/or modify it |
| 7 | # under the terms and conditions of the GNU General Public License, |
| 8 | # version 2, as published by the Free Software Foundation. |
| 9 | # |
| 10 | # This program is distributed in the hope it will be useful, but WITHOUT |
| 11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 13 | # more details. |
| 14 | # |
| 15 | import os |
| 16 | import json |
| 17 | import scriptpath |
Brad Bishop | 1932369 | 2019-04-05 15:28:33 -0400 | [diff] [blame] | 18 | import copy |
Brad Bishop | 40320b1 | 2019-03-26 16:08:25 -0400 | [diff] [blame] | 19 | scriptpath.add_oe_lib_path() |
| 20 | |
| 21 | flatten_map = { |
| 22 | "oeselftest": [], |
| 23 | "runtime": [], |
| 24 | "sdk": [], |
| 25 | "sdkext": [], |
| 26 | "manual": [] |
| 27 | } |
| 28 | regression_map = { |
| 29 | "oeselftest": ['TEST_TYPE', 'MACHINE'], |
| 30 | "runtime": ['TESTSERIES', 'TEST_TYPE', 'IMAGE_BASENAME', 'MACHINE', 'IMAGE_PKGTYPE', 'DISTRO'], |
| 31 | "sdk": ['TESTSERIES', 'TEST_TYPE', 'IMAGE_BASENAME', 'MACHINE', 'SDKMACHINE'], |
| 32 | "sdkext": ['TESTSERIES', 'TEST_TYPE', 'IMAGE_BASENAME', 'MACHINE', 'SDKMACHINE'], |
| 33 | "manual": ['TEST_TYPE', 'TEST_MODULE', 'IMAGE_BASENAME', 'MACHINE'] |
| 34 | } |
| 35 | store_map = { |
| 36 | "oeselftest": ['TEST_TYPE'], |
| 37 | "runtime": ['TEST_TYPE', 'DISTRO', 'MACHINE', 'IMAGE_BASENAME'], |
| 38 | "sdk": ['TEST_TYPE', 'MACHINE', 'SDKMACHINE', 'IMAGE_BASENAME'], |
| 39 | "sdkext": ['TEST_TYPE', 'MACHINE', 'SDKMACHINE', 'IMAGE_BASENAME'], |
| 40 | "manual": ['TEST_TYPE', 'TEST_MODULE', 'MACHINE', 'IMAGE_BASENAME'] |
| 41 | } |
| 42 | |
| 43 | # |
| 44 | # Load the json file and append the results data into the provided results dict |
| 45 | # |
| 46 | def append_resultsdata(results, f, configmap=store_map): |
| 47 | if type(f) is str: |
| 48 | with open(f, "r") as filedata: |
| 49 | data = json.load(filedata) |
| 50 | else: |
| 51 | data = f |
| 52 | for res in data: |
| 53 | if "configuration" not in data[res] or "result" not in data[res]: |
| 54 | raise ValueError("Test results data without configuration or result section?") |
| 55 | if "TESTSERIES" not in data[res]["configuration"]: |
| 56 | data[res]["configuration"]["TESTSERIES"] = os.path.basename(os.path.dirname(f)) |
| 57 | testtype = data[res]["configuration"].get("TEST_TYPE") |
| 58 | if testtype not in configmap: |
| 59 | raise ValueError("Unknown test type %s" % testtype) |
| 60 | configvars = configmap[testtype] |
| 61 | testpath = "/".join(data[res]["configuration"].get(i) for i in configmap[testtype]) |
| 62 | if testpath not in results: |
| 63 | results[testpath] = {} |
Brad Bishop | 40320b1 | 2019-03-26 16:08:25 -0400 | [diff] [blame] | 64 | results[testpath][res] = data[res] |
| 65 | |
| 66 | # |
| 67 | # Walk a directory and find/load results data |
| 68 | # or load directly from a file |
| 69 | # |
| 70 | def load_resultsdata(source, configmap=store_map): |
| 71 | results = {} |
| 72 | if os.path.isfile(source): |
| 73 | append_resultsdata(results, source, configmap) |
| 74 | return results |
| 75 | for root, dirs, files in os.walk(source): |
| 76 | for name in files: |
| 77 | f = os.path.join(root, name) |
| 78 | if name == "testresults.json": |
| 79 | append_resultsdata(results, f, configmap) |
| 80 | return results |
| 81 | |
| 82 | def filter_resultsdata(results, resultid): |
| 83 | newresults = {} |
| 84 | for r in results: |
| 85 | for i in results[r]: |
| 86 | if i == resultsid: |
| 87 | newresults[r] = {} |
| 88 | newresults[r][i] = results[r][i] |
| 89 | return newresults |
| 90 | |
Brad Bishop | 1932369 | 2019-04-05 15:28:33 -0400 | [diff] [blame] | 91 | def strip_ptestresults(results): |
| 92 | newresults = copy.deepcopy(results) |
| 93 | #for a in newresults2: |
| 94 | # newresults = newresults2[a] |
| 95 | for res in newresults: |
| 96 | if 'result' not in newresults[res]: |
| 97 | continue |
| 98 | if 'ptestresult.rawlogs' in newresults[res]['result']: |
| 99 | del newresults[res]['result']['ptestresult.rawlogs'] |
| 100 | if 'ptestresult.sections' in newresults[res]['result']: |
| 101 | for i in newresults[res]['result']['ptestresult.sections']: |
| 102 | if 'log' in newresults[res]['result']['ptestresult.sections'][i]: |
| 103 | del newresults[res]['result']['ptestresult.sections'][i]['log'] |
| 104 | return newresults |
| 105 | |
| 106 | def save_resultsdata(results, destdir, fn="testresults.json", ptestjson=False, ptestlogs=False): |
Brad Bishop | 40320b1 | 2019-03-26 16:08:25 -0400 | [diff] [blame] | 107 | for res in results: |
| 108 | if res: |
| 109 | dst = destdir + "/" + res + "/" + fn |
| 110 | else: |
| 111 | dst = destdir + "/" + fn |
| 112 | os.makedirs(os.path.dirname(dst), exist_ok=True) |
Brad Bishop | 1932369 | 2019-04-05 15:28:33 -0400 | [diff] [blame] | 113 | resultsout = results[res] |
| 114 | if not ptestjson: |
| 115 | resultsout = strip_ptestresults(results[res]) |
Brad Bishop | 40320b1 | 2019-03-26 16:08:25 -0400 | [diff] [blame] | 116 | with open(dst, 'w') as f: |
Brad Bishop | 1932369 | 2019-04-05 15:28:33 -0400 | [diff] [blame] | 117 | f.write(json.dumps(resultsout, sort_keys=True, indent=4)) |
| 118 | for res2 in results[res]: |
| 119 | if ptestlogs and 'result' in results[res][res2]: |
| 120 | if 'ptestresult.rawlogs' in results[res][res2]['result']: |
| 121 | with open(dst.replace(fn, "ptest-raw.log"), "w+") as f: |
| 122 | f.write(results[res][res2]['result']['ptestresult.rawlogs']['log']) |
| 123 | if 'ptestresult.sections' in results[res][res2]['result']: |
| 124 | for i in results[res][res2]['result']['ptestresult.sections']: |
| 125 | if 'log' in results[res][res2]['result']['ptestresult.sections'][i]: |
| 126 | with open(dst.replace(fn, "ptest-%s.log" % i), "w+") as f: |
| 127 | f.write(results[res][res2]['result']['ptestresult.sections'][i]['log']) |
Brad Bishop | 40320b1 | 2019-03-26 16:08:25 -0400 | [diff] [blame] | 128 | |
| 129 | def git_get_result(repo, tags): |
| 130 | git_objs = [] |
| 131 | for tag in tags: |
| 132 | files = repo.run_cmd(['ls-tree', "--name-only", "-r", tag]).splitlines() |
| 133 | git_objs.extend([tag + ':' + f for f in files if f.endswith("testresults.json")]) |
| 134 | |
| 135 | def parse_json_stream(data): |
| 136 | """Parse multiple concatenated JSON objects""" |
| 137 | objs = [] |
| 138 | json_d = "" |
| 139 | for line in data.splitlines(): |
| 140 | if line == '}{': |
| 141 | json_d += '}' |
| 142 | objs.append(json.loads(json_d)) |
| 143 | json_d = '{' |
| 144 | else: |
| 145 | json_d += line |
| 146 | objs.append(json.loads(json_d)) |
| 147 | return objs |
| 148 | |
| 149 | # Optimize by reading all data with one git command |
| 150 | results = {} |
| 151 | for obj in parse_json_stream(repo.run_cmd(['show'] + git_objs + ['--'])): |
| 152 | append_resultsdata(results, obj) |
| 153 | |
| 154 | return results |