blob: 32521a8f93ce73a3fe909f78a2ae4559482a67f7 [file] [log] [blame]
Mohammad Azim Khan7a0d84f2017-04-01 03:18:20 +01001"""
2mbed SDK
3Copyright (c) 2011-2013 ARM Limited
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16"""
17
18import re
19import os
20import time
21from mbed_host_tests import BaseHostTest, event_callback
22
23
24class TestDataParser(object):
25 """
26 parser for mbedtls test data files.
27 """
28
29 def __init__(self):
30 """
31 Constructor
32 """
33 self.tests = []
34
35 def parse(self, data_file):
36 """
37
38 """
39 with open(data_file, 'r') as f:
40 self.__parse(f)
41
42 @staticmethod
43 def __escaped_split(str, ch):
44 """
45 """
46 if len(ch) > 1:
47 raise ValueError('Expected split character. Found string!')
48 out = []
49 part = ''
50 escape = False
51 for i in range(len(str)):
52 if not escape and str[i] == ch:
53 out.append(part)
54 part = ''
55 else:
56 part += str[i]
57 escape = not escape and str[i] == '\\'
58 if len(part):
59 out.append(part)
60 return out
61
62 def __parse(self, file):
63 """
64 """
65 line = file.readline().strip()
66 while line:
67 line = line.strip()
68 if len(line) == 0:
69 line = file.readline()
70 continue
71 # Read test name
72 name = line
73
74 # Check dependencies
75 deps = []
76 line = file.readline().strip()
77 m = re.search('depends_on\:(.*)', line)
78 if m:
79 deps = [int(x) for x in m.group(1).split(':')]
80 line = file.readline().strip()
81
82 # Read test vectors
83 line = line.replace('\\n', '\n#')
84 parts = self.__escaped_split(line, ':')
85 function = int(parts[0])
86 x = parts[1:]
87 l = len(x)
88 assert l % 2 == 0, "Number of test arguments should be even: %s" % line
89 args = [(x[i * 2], x[(i * 2) + 1]) for i in range(len(x)/2)]
90 self.tests.append((name, function, deps, args))
91 line = file.readline()
92
93 def get_test_data(self):
94 """
95 """
96 return self.tests
97
98
99class MbedTlsTest(BaseHostTest):
100 """
101 Host test for mbed-tls target tests.
102 """
103 # From suites/helpers.function
104 DEPENDENCY_SUPPORTED = 0
105 KEY_VALUE_MAPPING_FOUND = DEPENDENCY_SUPPORTED
106 DISPATCH_TEST_SUCCESS = DEPENDENCY_SUPPORTED
107
108 KEY_VALUE_MAPPING_NOT_FOUND = -1
109 DEPENDENCY_NOT_SUPPORTED = -2
110 DISPATCH_TEST_FN_NOT_FOUND = -3
111 DISPATCH_INVALID_TEST_DATA = -4
112 DISPATCH_UNSUPPORTED_SUITE = -5
113
114 def __init__(self):
115 """
116 """
117 super(MbedTlsTest, self).__init__()
118 self.tests = []
119 self.test_index = -1
120 self.dep_index = 0
121 self.error_str = dict()
122 self.error_str[self.DEPENDENCY_SUPPORTED] = 'DEPENDENCY_SUPPORTED'
123 self.error_str[self.KEY_VALUE_MAPPING_NOT_FOUND] = 'KEY_VALUE_MAPPING_NOT_FOUND'
124 self.error_str[self.DEPENDENCY_NOT_SUPPORTED] = 'DEPENDENCY_NOT_SUPPORTED'
125 self.error_str[self.DISPATCH_TEST_FN_NOT_FOUND] = 'DISPATCH_TEST_FN_NOT_FOUND'
126 self.error_str[self.DISPATCH_INVALID_TEST_DATA] = 'DISPATCH_INVALID_TEST_DATA'
127 self.error_str[self.DISPATCH_UNSUPPORTED_SUITE] = 'DISPATCH_UNSUPPORTED_SUITE'
128
129 def setup(self):
130 """
131 """
132 binary_path = self.get_config_item('image_path')
133 script_dir = os.path.split(os.path.abspath(__file__))[0]
134 suite_name = os.path.splitext(os.path.basename(binary_path))[0]
135 data_file = ".".join((suite_name, 'data'))
136 data_file = os.path.join(script_dir, '..', 'mbedtls', suite_name, data_file)
137 if os.path.exists(data_file):
138 self.log("Running tests from %s" % data_file)
139 parser = TestDataParser()
140 parser.parse(data_file)
141 self.tests = parser.get_test_data()
142 self.print_test_info()
143 else:
144 self.log("Data file not found: %s" % data_file)
145 self.notify_complete(False)
146
147 def print_test_info(self):
148 """
149 """
150 self.log('{{__testcase_count;%d}}' % len(self.tests))
151 for name, _, _, _ in self.tests:
152 self.log('{{__testcase_name;%s}}' % name)
153
154 @staticmethod
155 def align_32bit(b):
156 """
157 4 byte aligns byte array.
158
159 :return:
160 """
161 b += bytearray((4 - (len(b))) % 4)
162
163 def parameters_to_bytes(self, b, parameters):
164 for typ, param in parameters:
165 if typ == 'int' or typ == 'exp':
166 i = int(param)
167 b += 'I' if typ == 'int' else 'E'
168 self.align_32bit(b)
169 b += bytearray([((i >> x) & 0xff) for x in [24, 16, 8, 0]])
170 elif typ == 'char*':
171 param = param.strip('"')
172 i = len(param) + 1 # + 1 for null termination
173 b += 'S'
174 self.align_32bit(b)
175 b += bytearray([((i >> x) & 0xff) for x in [24, 16, 8, 0]])
176 b += bytearray(list(param))
177 b += '\0' # Null terminate
178 return b
179
180 def run_next_test(self):
181 """
182 Send next test function to the target.
183
184 """
185 self.test_index += 1
186 self.dep_index = 0
187 if self.test_index < len(self.tests):
188 name, function, deps, args = self.tests[self.test_index]
189 self.log("Running: %s" % name)
190 bytes = bytearray([len(deps)])
191 if len(deps):
192 bytes += bytearray(deps)
193 bytes += bytearray([function, len(args)])
194 self.parameters_to_bytes(bytes, args)
195 key = bytearray([((len(bytes) >> x) & 0xff) for x in [24, 16, 8, 0]])
196 #self.log("Bytes: " + " ".join(["%x '%c'" % (x, x) for x in bytes]))
197 self.send_kv(key, bytes)
198 else:
199 self.notify_complete(True)
200
201 @staticmethod
202 def get_result(value):
203 try:
204 return int(value)
205 except ValueError:
206 ValueError("Result should return error number. Instead received %s" % value)
207 return 0
208
209 @event_callback('GO')
210 def on_go(self, key, value, timestamp):
211 self.run_next_test()
212
213 @event_callback("R")
214 def on_result(self, key, value, timestamp):
215 """
216 Handle result.
217
218 """
219 int_val = self.get_result(value)
220 name, function, deps, args = self.tests[self.test_index]
221 self.log('{{__testcase_finish;%s;%d;%d}}' % (name, int_val == 0,
222 int_val != 0))
223 self.run_next_test()
224
225 @event_callback("F")
226 def on_failure(self, key, value, timestamp):
227 """
228 Handles test execution failure. Hence marking test as skipped.
229
230 :param key:
231 :param value:
232 :param timestamp:
233 :return:
234 """
235 int_val = self.get_result(value)
236 name, function, deps, args = self.tests[self.test_index]
237 if int_val in self.error_str:
238 err = self.error_str[int_val]
239 else:
240 err = 'Unknown error'
241 # For skip status, do not write {{__testcase_finish;...}}
242 self.log("Error: %s" % err)
243 self.run_next_test()