forked from nevillegrech/gigahorse-toolchain
-
Notifications
You must be signed in to change notification settings - Fork 0
/
run_tests.py
executable file
·177 lines (127 loc) · 5.25 KB
/
run_tests.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/usr/bin/env python3
import argparse
import subprocess
import unittest
import json
import re
from os.path import abspath, dirname, join, isdir, isfile
from os import listdir, makedirs
from typing import Mapping, MutableMapping, Any, List, Iterator, Tuple
GIGAHORSE_TOOLCHAIN_ROOT = dirname(abspath(__file__))
DEFAULT_TEST_DIR = join(GIGAHORSE_TOOLCHAIN_ROOT, 'tests')
TEST_WORKING_DIR = join(GIGAHORSE_TOOLCHAIN_ROOT, '.tests')
class LogicTestCase(unittest.TestCase):
def __init__(self, name: str, test_root:str, test_path: str, test_config: Mapping[str, Any]):
super(LogicTestCase, self).__init__()
self.name = name
client_path = test_config.get('client_path', None)
self.client_path = abspath(join(dirname(test_root), client_path)) if client_path else None
self.test_path = test_path
self.working_dir = abspath(f'{TEST_WORKING_DIR}/{self.name}')
self.results_file = join(self.working_dir, f'results.json')
self.gigahorse_args = test_config.get('gigahorse_args', [])
self.expected_results: List[Tuple[str, int, float]] = test_config.get("expected_results", [])
def id(self) -> str:
return self.name
def __str__(self) -> str:
return self.name
def __repr__(self) -> str:
return self.name
def __run(self) -> subprocess.CompletedProcess:
client_arg = ['-C', self.client_path] if self.client_path else []
return subprocess.run(
[
'python3',
join(GIGAHORSE_TOOLCHAIN_ROOT, 'gigahorse.py'),
self.test_path,
'--restart',
'--jobs', '1',
'--results_file', self.results_file,
'--working_dir', self.working_dir,
*client_arg,
*self.gigahorse_args
],
capture_output=True
)
def __relation_size(self, name: str) -> int:
hex_name = self.test_path.split('/')[-1].split('.')[-2]
if isfile(join(self.working_dir, hex_name, 'out', f'{name}.csv')):
path = join(self.working_dir, hex_name, 'out', f'{name}.csv')
else:
path = join(self.working_dir, hex_name, f'{name}.csv')
with open(path) as f:
return len(f.readlines())
def runTest(self):
def within_margin(actual: int, expected: int, margin: float) -> bool:
return (1 - margin) * expected <= actual <= (1 + margin) * expected
result = self.__run()
with open(join(self.working_dir, 'stdout'), 'wb') as f:
f.write(result.stdout)
with open(join(self.working_dir, 'stderr'), 'wb') as f:
f.write(result.stderr)
self.assertTrue(result.returncode == 0)
with open(self.results_file) as f:
(_, _, _, temp_analytics), = json.load(f)
analytics = {}
for x, y in temp_analytics.items():
if isinstance(y, str):
analytics[x] = len(y.splitlines()) if y else 0
else:
analytics[x] = y
self.assertTrue(all(within_margin(analytics[metric], expected, margin) for metric, expected, margin in self.expected_results))
def discover_logic_tests(current_config: MutableMapping[str, Any], directory: str) -> Iterator[Tuple[Mapping[str, Any], str]]:
def update_config(config_path: str) -> MutableMapping:
if isfile(config_path):
with open(config_path) as f:
new_config = dict(**current_config)
new_config.update(json.load(f))
return new_config
else:
return current_config
current_config = update_config(join(directory, 'config.json'))
for entry in listdir(directory):
entry_path = join(directory, entry)
if entry.endswith('.hex') and isfile(entry_path):
yield update_config(join(directory, f'{entry[:-4]}.json')), entry_path
elif isdir(entry_path):
yield from discover_logic_tests(current_config, entry_path)
def run_tests(test_dirs: List[str]):
makedirs(TEST_WORKING_DIR, exist_ok=True)
for test_dir in (abspath(x) for x in test_dirs):
print(f'Running testcases under {test_dir}')
test_suite = unittest.TestSuite()
for config, hex_path in discover_logic_tests({}, test_dir):
test_id = hex_path[len(test_dir) + 1:-4].replace('/', '.')
if config:
test_suite.addTest(LogicTestCase(test_id, test_dir, hex_path, config))
unittest.TextTestRunner().run(test_suite)
def main():
def check_arg_is_regex(val: str) -> str:
try:
re.compile(val)
except re.error:
raise argparse.ArgumentTypeError
return val
parser = argparse.ArgumentParser(
description="Gigahorse unit test driver"
)
parser.add_argument(
'dirs',
metavar='D',
type=str,
nargs='*',
default=[DEFAULT_TEST_DIR],
help='Test directories'
)
parser.add_argument(
"-p",
"--pattern",
default=".*",
metavar="REGEX",
type=check_arg_is_regex,
help="A regular expression. Used to choose specific unit tests"
)
args = parser.parse_args()
run_tests(args.dirs)
if __name__ == "__main__":
main()