Skip to content

Commit 1894a27

Browse files
committed
Reworking mocks classes
1 parent 4d45a5c commit 1894a27

File tree

10 files changed

+305
-265
lines changed

10 files changed

+305
-265
lines changed

test/test/host_test_black_box.py

Lines changed: 3 additions & 265 deletions
Original file line numberDiff line numberDiff line change
@@ -17,277 +17,15 @@
1717
import unittest
1818
import os
1919
import re
20-
21-
import threading
22-
import shutil
23-
import tempfile
2420
from builtins import super
2521
from copy import copy
2622
from mbed_os_tools.test import init_host_test_cli_params
2723
from mbed_os_tools.test.host_tests_runner.host_test_default import DefaultTestSelector
2824
from mock import patch, MagicMock
2925

30-
31-
class MockThread(threading.Thread):
32-
def __init__(self, target=None, args=None):
33-
super().__init__(target=target, args=args)
34-
self._terminates = 0
35-
self.exitcode = 0 # TODO maybe this needs to be setable? Mock sys.exit
36-
37-
def terminate(self):
38-
self._terminates += 1
39-
40-
class MockSerial(object):
41-
def __init__(self, *args, **kwargs):
42-
super().__init__(*args, **kwargs)
43-
self._args = args
44-
self._kwargs = kwargs
45-
self._open = True
46-
self._rx_counter = 0
47-
self._tx_buffer = b""
48-
self._rx_buffer = b""
49-
self._upstream_write_cb = None
50-
51-
def read(self, count):
52-
contents = self._rx_buffer[self._rx_counter:count]
53-
self._rx_counter += len(contents)
54-
return contents
55-
56-
def write(self, data):
57-
self._tx_buffer += data
58-
if self._upstream_write_cb:
59-
# TODO this may not work...
60-
self._upstream_write_cb(data)
61-
62-
def close(self):
63-
self._open = False
64-
65-
def downstream_write(self, data):
66-
self._rx_buffer += data.encode("utf-8")
67-
68-
def downstream_write_bytes(self, data):
69-
self._rx_buffer += data
70-
71-
def on_upstream_write(self, func):
72-
self._upstream_write_cb = func
73-
74-
kv_regex = re.compile("\{\{([\w\d_-]+);([^\}]+)\}\}")
75-
76-
class MockMbedDevice(object):
77-
def __init__(self, serial):
78-
self._synced = False
79-
self._kvs = []
80-
self._serial = serial
81-
self._serial.on_upstream_write(self.on_write)
82-
83-
def handle_kv(self, key, value):
84-
if not self._synced:
85-
if key == "__sync":
86-
self._synced = True
87-
self.send_kv(key, value)
88-
self.on_sync()
89-
else:
90-
pass
91-
92-
def send_kv(self, key, value):
93-
self._serial.downstream_write("{{{{{};{}}}}}\r\n".format(key, value))
94-
95-
def on_write(self, data):
96-
kvs = kv_regex.findall(data.decode("utf-8"))
97-
98-
for key, value in kvs:
99-
self.handle_kv(key, value)
100-
self._kvs.append((key, value))
101-
102-
def on_sync(self):
103-
self._serial.downstream_write(
104-
"{{__timeout;15}}\r\n"
105-
"{{__host_test_name;default_auto}}\r\n"
106-
"{{end;success}}\n"
107-
"{{__exit;0}}\r\n"
108-
)
109-
110-
111-
def _process_side_effect(target=None, args=None):
112-
return MockThread(target=target, args=args)
113-
114-
class MockTestEnvironment(object):
115-
116-
def __init__(self, test_case, platform_info, image_path):
117-
self._test_case = test_case
118-
self._tempdir = tempfile.mkdtemp()
119-
self._platform_info = copy(platform_info)
120-
self._platform_info['mount_point'] = os.path.join(self._tempdir, self._platform_info['mount_point'])
121-
self._platform_info['serial_port'] = os.path.join(self._tempdir, self._platform_info['serial_port'])
122-
self._image_path = os.path.join(self._tempdir, image_path)
123-
124-
self._patch_definitions = []
125-
self.patches = {}
126-
127-
args = (
128-
'mbedhtrun -m {} -p {}:9600 -f '
129-
'"{}" -e "TESTS/host_tests" -d {} -c default '
130-
'-t {} -r default '
131-
'-C 4 --sync 5 -P 60'
132-
).format(
133-
self._platform_info['platform_name'],
134-
self._platform_info['serial_port'],
135-
self._image_path,
136-
self._platform_info['mount_point'],
137-
self._platform_info['target_id']
138-
).split()
139-
self.patch('sys.argv', new=args)
140-
141-
# Mock detect
142-
detect_mock = MagicMock()
143-
detect_mock.return_value.list_mbeds.return_value = [
144-
self._platform_info
145-
]
146-
self.patch('mbed_os_tools.detect.create', new=detect_mock)
147-
148-
# Mock process
149-
self.patch(
150-
'mbed_os_tools.test.host_tests_runner.host_test_default.Process',
151-
new=MagicMock(side_effect=_process_side_effect)
152-
)
153-
self.patch(
154-
'mbed_os_tools.test.host_tests_plugins.host_test_plugins.call',
155-
new=MagicMock(return_value=0)
156-
)
157-
158-
# Mock serial
159-
mock_serial = MockSerial()
160-
mock_device = MockMbedDevice(mock_serial)
161-
self.patch(
162-
'mbed_os_tools.test.host_tests_conn_proxy.conn_primitive_serial.Serial',
163-
new=MagicMock(return_value=mock_serial)
164-
)
165-
166-
167-
def patch(self, path, **kwargs):
168-
self._patch_definitions.append((path, patch(path, **kwargs)))
169-
170-
def __enter__(self):
171-
os.makedirs(os.path.dirname(self._image_path))
172-
with open(self._image_path, 'w') as _:
173-
pass
174-
175-
os.makedirs(self._platform_info['mount_point'])
176-
177-
for path, patcher in self._patch_definitions:
178-
self.patches[path] = patcher.start()
179-
180-
def __exit__(self, type, value, traceback):
181-
for _, patcher in self._patch_definitions:
182-
patcher.stop()
183-
184-
shutil.rmtree(self._tempdir)
185-
186-
class MockTestEnvironmentPosix(MockTestEnvironment):
187-
188-
def __init__(self, test_case, platform_info, image_path):
189-
super().__init__(test_case, platform_info, image_path)
190-
191-
self.patch('os.name', new='posix')
192-
193-
def __exit__(self, type, value, traceback):
194-
super().__exit__(type, value, traceback)
195-
196-
# Assert for proper image copy
197-
mocked_call = self.patches[
198-
'mbed_os_tools.test.host_tests_plugins.host_test_plugins.call'
199-
]
200-
201-
first_call_args = mocked_call.call_args_list[0][0][0]
202-
self._test_case.assertEqual(first_call_args[0], "cp")
203-
self._test_case.assertEqual(first_call_args[1], self._image_path)
204-
self._test_case.assertTrue(first_call_args[2].startswith(self._platform_info["mount_point"]))
205-
self._test_case.assertTrue(first_call_args[2].endswith(os.path.splitext(self._image_path)[1]))
206-
207-
208-
class MockTestEnvironmentLinux(MockTestEnvironmentPosix):
209-
210-
def __init__(self, test_case, platform_info, image_path):
211-
super().__init__(test_case, platform_info, image_path)
212-
213-
self.patch(
214-
'os.uname',
215-
new=MagicMock(return_value=('Linux',)),
216-
create=True
217-
)
218-
219-
def __exit__(self, type, value, traceback):
220-
super().__exit__(type, value, traceback)
221-
222-
# Assert for proper image copy
223-
mocked_call = self.patches[
224-
'mbed_os_tools.test.host_tests_plugins.host_test_plugins.call'
225-
]
226-
227-
second_call_args = mocked_call.call_args_list[1][0][0]
228-
destination_path = os.path.normpath(
229-
os.path.join(
230-
self._platform_info["mount_point"],
231-
os.path.basename(self._image_path)
232-
)
233-
)
234-
235-
self._test_case.assertEqual(
236-
second_call_args,
237-
["sync", "-f", destination_path]
238-
)
239-
240-
# Ensure only two subprocesses were started
241-
self._test_case.assertEqual(len(mocked_call.call_args_list), 2)
242-
243-
class MockTestEnvironmentDarwin(MockTestEnvironmentPosix):
244-
245-
def __init__(self, test_case, platform_info, image_path):
246-
super().__init__(test_case, platform_info, image_path)
247-
248-
self.patch(
249-
'os.uname',
250-
new=MagicMock(return_value=('Darwin',)),
251-
create=True
252-
)
253-
254-
def __exit__(self, type, value, traceback):
255-
super().__exit__(type, value, traceback)
256-
257-
# Assert for proper image copy
258-
mocked_call = self.patches[
259-
'mbed_os_tools.test.host_tests_plugins.host_test_plugins.call'
260-
]
261-
262-
second_call_args = mocked_call.call_args_list[1][0][0]
263-
self._test_case.assertEqual(second_call_args, ["sync"])
264-
265-
# Ensure only two subprocesses were started
266-
self._test_case.assertEqual(len(mocked_call.call_args_list), 2)
267-
268-
class MockTestEnvironmentWindows(MockTestEnvironment):
269-
270-
def __init__(self, test_case, platform_info, image_path):
271-
super().__init__(test_case, platform_info, image_path)
272-
273-
self.patch('os.name', new='nt')
274-
275-
def __exit__(self, type, value, traceback):
276-
super().__exit__(type, value, traceback)
277-
278-
# Assert for proper image copy
279-
mocked_call = self.patches[
280-
'mbed_os_tools.test.host_tests_plugins.host_test_plugins.call'
281-
]
282-
283-
first_call_args = mocked_call.call_args_list[0][0][0]
284-
self._test_case.assertEqual(first_call_args[0], "copy")
285-
self._test_case.assertEqual(first_call_args[1], self._image_path)
286-
self._test_case.assertTrue(first_call_args[2].startswith(self._platform_info["mount_point"]))
287-
self._test_case.assertTrue(first_call_args[2].endswith(os.path.splitext(self._image_path)[1]))
288-
289-
# Ensure only one subprocess was started
290-
self._test_case.assertEqual(len(mocked_call.call_args_list), 1)
26+
from .mocks.environment.linux import MockTestEnvironmentLinux
27+
from .mocks.environment.darwin import MockTestEnvironmentDarwin
28+
from .mocks.environment.windows import MockTestEnvironmentWindows
29129

29230
mock_platform_info = {
29331
"platform_name": "K64F",

test/test/mocks/__init__.py

Whitespace-only changes.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import tempfile
2+
import os
3+
import shutil
4+
5+
from mock import patch, MagicMock
6+
from copy import copy
7+
from ..serial import MockSerial
8+
from ..mbed_device import MockMbedDevice
9+
from ..thread import MockThread
10+
11+
class MockTestEnvironment(object):
12+
13+
def __init__(self, test_case, platform_info, image_path):
14+
self._test_case = test_case
15+
self._tempdir = tempfile.mkdtemp()
16+
self._platform_info = copy(platform_info)
17+
self._platform_info['mount_point'] = os.path.splitdrive(os.path.join(self._tempdir, self._platform_info['mount_point']))[1]
18+
self._platform_info['serial_port'] = os.path.splitdrive(os.path.join(self._tempdir, self._platform_info['serial_port']))[1]
19+
self._image_path = os.path.splitdrive(os.path.join(self._tempdir, image_path))[1]
20+
21+
self._patch_definitions = []
22+
self.patches = {}
23+
24+
args = (
25+
'mbedhtrun -m {} -p {}:9600 -f '
26+
'"{}" -e "TESTS/host_tests" -d {} -c default '
27+
'-t {} -r default '
28+
'-C 4 --sync 5 -P 60'
29+
).format(
30+
self._platform_info['platform_name'],
31+
self._platform_info['serial_port'],
32+
self._image_path,
33+
self._platform_info['mount_point'],
34+
self._platform_info['target_id']
35+
).split()
36+
self.patch('sys.argv', new=args)
37+
38+
# Mock detect
39+
detect_mock = MagicMock()
40+
detect_mock.return_value.list_mbeds.return_value = [
41+
self._platform_info
42+
]
43+
self.patch('mbed_os_tools.detect.create', new=detect_mock)
44+
45+
# Mock process
46+
self.patch(
47+
'mbed_os_tools.test.host_tests_runner.host_test_default.Process',
48+
new=MagicMock(side_effect=self._process_side_effect)
49+
)
50+
self.patch(
51+
'mbed_os_tools.test.host_tests_plugins.host_test_plugins.call',
52+
new=MagicMock(return_value=0)
53+
)
54+
55+
# Mock serial
56+
mock_serial = MockSerial()
57+
mock_device = MockMbedDevice(mock_serial)
58+
self.patch(
59+
'mbed_os_tools.test.host_tests_conn_proxy.conn_primitive_serial.Serial',
60+
new=MagicMock(return_value=mock_serial)
61+
)
62+
63+
@staticmethod
64+
def _process_side_effect(target=None, args=None):
65+
return MockThread(target=target, args=args)
66+
67+
def patch(self, path, **kwargs):
68+
self._patch_definitions.append((path, patch(path, **kwargs)))
69+
70+
def __enter__(self):
71+
os.makedirs(os.path.dirname(self._image_path))
72+
with open(self._image_path, 'w') as _:
73+
pass
74+
75+
os.makedirs(self._platform_info['mount_point'])
76+
77+
for path, patcher in self._patch_definitions:
78+
self.patches[path] = patcher.start()
79+
80+
def __exit__(self, type, value, traceback):
81+
for _, patcher in self._patch_definitions:
82+
patcher.stop()
83+
84+
shutil.rmtree(self._tempdir)

test/test/mocks/environment/darwin.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from builtins import super
2+
from mock import MagicMock
3+
4+
from .posix import MockTestEnvironmentPosix
5+
6+
class MockTestEnvironmentDarwin(MockTestEnvironmentPosix):
7+
8+
def __init__(self, test_case, platform_info, image_path):
9+
super().__init__(test_case, platform_info, image_path)
10+
11+
self.patch(
12+
'os.uname',
13+
new=MagicMock(return_value=('Darwin',)),
14+
create=True
15+
)
16+
17+
def __exit__(self, type, value, traceback):
18+
super().__exit__(type, value, traceback)
19+
20+
if value:
21+
return False
22+
23+
# Assert for proper image copy
24+
mocked_call = self.patches[
25+
'mbed_os_tools.test.host_tests_plugins.host_test_plugins.call'
26+
]
27+
28+
second_call_args = mocked_call.call_args_list[1][0][0]
29+
self._test_case.assertEqual(second_call_args, ["sync"])
30+
31+
# Ensure only two subprocesses were started
32+
self._test_case.assertEqual(len(mocked_call.call_args_list), 2)

0 commit comments

Comments
 (0)