diff options
Diffstat (limited to 'scripts/lib/resulttool/resultutils.py')
-rw-r--r-- | scripts/lib/resulttool/resultutils.py | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/scripts/lib/resulttool/resultutils.py b/scripts/lib/resulttool/resultutils.py new file mode 100644 index 0000000000..06cceef796 --- /dev/null +++ b/scripts/lib/resulttool/resultutils.py | |||
@@ -0,0 +1,127 @@ | |||
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 | ||
18 | scriptpath.add_oe_lib_path() | ||
19 | |||
20 | flatten_map = { | ||
21 | "oeselftest": [], | ||
22 | "runtime": [], | ||
23 | "sdk": [], | ||
24 | "sdkext": [] | ||
25 | } | ||
26 | regression_map = { | ||
27 | "oeselftest": ['TEST_TYPE', 'MACHINE'], | ||
28 | "runtime": ['TESTSERIES', 'TEST_TYPE', 'IMAGE_BASENAME', 'MACHINE', 'IMAGE_PKGTYPE', 'DISTRO'], | ||
29 | "sdk": ['TESTSERIES', 'TEST_TYPE', 'IMAGE_BASENAME', 'MACHINE', 'SDKMACHINE'], | ||
30 | "sdkext": ['TESTSERIES', 'TEST_TYPE', 'IMAGE_BASENAME', 'MACHINE', 'SDKMACHINE'] | ||
31 | } | ||
32 | store_map = { | ||
33 | "oeselftest": ['TEST_TYPE'], | ||
34 | "runtime": ['TEST_TYPE', 'DISTRO', 'MACHINE', 'IMAGE_BASENAME'], | ||
35 | "sdk": ['TEST_TYPE', 'MACHINE', 'SDKMACHINE', 'IMAGE_BASENAME'], | ||
36 | "sdkext": ['TEST_TYPE', 'MACHINE', 'SDKMACHINE', 'IMAGE_BASENAME'] | ||
37 | } | ||
38 | |||
39 | # | ||
40 | # Load the json file and append the results data into the provided results dict | ||
41 | # | ||
42 | def append_resultsdata(results, f, configmap=store_map): | ||
43 | if type(f) is str: | ||
44 | with open(f, "r") as filedata: | ||
45 | data = json.load(filedata) | ||
46 | else: | ||
47 | data = f | ||
48 | for res in data: | ||
49 | if "configuration" not in data[res] or "result" not in data[res]: | ||
50 | raise ValueError("Test results data without configuration or result section?") | ||
51 | if "TESTSERIES" not in data[res]["configuration"]: | ||
52 | data[res]["configuration"]["TESTSERIES"] = os.path.basename(os.path.dirname(f)) | ||
53 | testtype = data[res]["configuration"].get("TEST_TYPE") | ||
54 | if testtype not in configmap: | ||
55 | raise ValueError("Unknown test type %s" % testtype) | ||
56 | configvars = configmap[testtype] | ||
57 | testpath = "/".join(data[res]["configuration"].get(i) for i in configmap[testtype]) | ||
58 | if testpath not in results: | ||
59 | results[testpath] = {} | ||
60 | if 'ptestresult.rawlogs' in data[res]['result']: | ||
61 | del data[res]['result']['ptestresult.rawlogs'] | ||
62 | if 'ptestresult.sections' in data[res]['result']: | ||
63 | for i in data[res]['result']['ptestresult.sections']: | ||
64 | del data[res]['result']['ptestresult.sections'][i]['log'] | ||
65 | results[testpath][res] = data[res] | ||
66 | |||
67 | # | ||
68 | # Walk a directory and find/load results data | ||
69 | # or load directly from a file | ||
70 | # | ||
71 | def load_resultsdata(source, configmap=store_map): | ||
72 | results = {} | ||
73 | if os.path.isfile(source): | ||
74 | append_resultsdata(results, source, configmap) | ||
75 | return results | ||
76 | for root, dirs, files in os.walk(source): | ||
77 | for name in files: | ||
78 | f = os.path.join(root, name) | ||
79 | if name == "testresults.json": | ||
80 | append_resultsdata(results, f, configmap) | ||
81 | return results | ||
82 | |||
83 | def filter_resultsdata(results, resultid): | ||
84 | newresults = {} | ||
85 | for r in results: | ||
86 | for i in results[r]: | ||
87 | if i == resultsid: | ||
88 | newresults[r] = {} | ||
89 | newresults[r][i] = results[r][i] | ||
90 | return newresults | ||
91 | |||
92 | def save_resultsdata(results, destdir, fn="testresults.json"): | ||
93 | for res in results: | ||
94 | if res: | ||
95 | dst = destdir + "/" + res + "/" + fn | ||
96 | else: | ||
97 | dst = destdir + "/" + fn | ||
98 | os.makedirs(os.path.dirname(dst), exist_ok=True) | ||
99 | with open(dst, 'w') as f: | ||
100 | f.write(json.dumps(results[res], sort_keys=True, indent=4)) | ||
101 | |||
102 | def git_get_result(repo, tags): | ||
103 | git_objs = [] | ||
104 | for tag in tags: | ||
105 | files = repo.run_cmd(['ls-tree', "--name-only", "-r", tag]).splitlines() | ||
106 | git_objs.extend([tag + ':' + f for f in files if f.endswith("testresults.json")]) | ||
107 | |||
108 | def parse_json_stream(data): | ||
109 | """Parse multiple concatenated JSON objects""" | ||
110 | objs = [] | ||
111 | json_d = "" | ||
112 | for line in data.splitlines(): | ||
113 | if line == '}{': | ||
114 | json_d += '}' | ||
115 | objs.append(json.loads(json_d)) | ||
116 | json_d = '{' | ||
117 | else: | ||
118 | json_d += line | ||
119 | objs.append(json.loads(json_d)) | ||
120 | return objs | ||
121 | |||
122 | # Optimize by reading all data with one git command | ||
123 | results = {} | ||
124 | for obj in parse_json_stream(repo.run_cmd(['show'] + git_objs + ['--'])): | ||
125 | append_resultsdata(results, obj) | ||
126 | |||
127 | return results | ||