Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
S2-group
GitHub Repository: S2-group/android-runner
Path: blob/master/tests/unit/test_progress.py
908 views
1
import os
2
import os.path as op
3
from shutil import copyfile
4
5
import lxml.etree as et
6
import pytest
7
from mock import Mock, call, patch
8
9
import paths
10
from AndroidRunner.Progress import Progress
11
from AndroidRunner.util import load_json
12
13
14
class TestProgressSetup(object):
15
@pytest.fixture()
16
def test_config(self):
17
fixture_dir = op.join(op.dirname(op.realpath(__file__)), "fixtures")
18
return op.join(fixture_dir, "test_config.json")
19
20
@pytest.fixture()
21
def test_progress(self):
22
fixture_dir = op.join(op.dirname(op.realpath(__file__)), "fixtures")
23
return op.join(fixture_dir, 'test_progress.xml')
24
25
@patch('AndroidRunner.Progress.Progress.write_progress_to_file')
26
@patch('AndroidRunner.Progress.Progress.build_progress_xml')
27
def test_progress_init(self, build_progress_mock, write_to_file_mock, tmp_path, test_config, test_progress):
28
with open(test_progress, 'r') as f:
29
expected_xml = f.read()
30
paths.OUTPUT_DIR = tmp_path.as_posix()
31
build_progress_mock.return_value = et.fromstring(expected_xml)
32
mock_manager = Mock()
33
mock_manager.attach_mock(build_progress_mock, 'managed_build_progress')
34
mock_manager.attach_mock(write_to_file_mock, 'managed_write_to_file')
35
36
progress = Progress(config_file=test_config, config=load_json(test_config))
37
38
expected_calls = [call.managed_build_progress(load_json(test_config), test_config),
39
call.managed_write_to_file()]
40
assert mock_manager.mock_calls == expected_calls
41
expected_lxml = et.fromstring(expected_xml)
42
current_lxml = progress.progress_xml_content
43
assert self.elements_equal(current_lxml, expected_lxml)
44
45
@patch('AndroidRunner.Progress.Progress.check_config_hash')
46
def test_progress_init_resume(self, check_hash_mock, tmp_path, test_config, test_progress):
47
check_hash_mock.return_value = None
48
progress = Progress(config_file=test_config, progress_file=test_progress, load_progress=True)
49
with open(test_progress, 'r') as f:
50
expected_xml = f.read()
51
expected_lxml = et.fromstring(expected_xml)
52
current_lxml = progress.progress_xml_content
53
assert self.elements_equal(current_lxml, expected_lxml)
54
55
def elements_equal(self, e1, e2):
56
if e1.tag != e2.tag:
57
return False
58
if e1.text != e2.text:
59
return False
60
if e1.tail != e2.tail:
61
return False
62
if e1.attrib != e2.attrib:
63
return False
64
if len(e1) != len(e2):
65
return False
66
return all(self.elements_equal(c1, c2) for c1, c2 in zip(e1, e2))
67
68
69
class TestProgressMethods(object):
70
@pytest.fixture()
71
def test_config(self):
72
fixture_dir = op.join(op.dirname(op.realpath(__file__)), "fixtures")
73
return op.join(fixture_dir, "test_config.json")
74
75
@pytest.fixture()
76
def test_progress(self):
77
fixture_dir = op.join(op.dirname(op.realpath(__file__)), "fixtures")
78
return op.join(fixture_dir, 'test_progress.xml')
79
80
@pytest.fixture()
81
def current_progress(self, tmp_path, test_config, test_progress):
82
paths.OUTPUT_DIR = tmp_path.as_posix()
83
progress = Progress(config_file=test_config, progress_file=test_progress, load_progress=True)
84
progress.progress_xml_file = op.join(paths.OUTPUT_DIR, "progress.xml")
85
copyfile(test_progress, progress.progress_xml_file)
86
return progress
87
88
@pytest.fixture()
89
def config_web_dict(self):
90
return {'devices': ['device1'], 'paths': ['path1'], 'type': 'web', 'browsers': ['browser1'], 'repetitions': 1}
91
92
@pytest.fixture()
93
def config_native_dict(self):
94
return {'devices': ['device1'], 'paths': ['path1'], 'type': 'native', 'repetitions': 1}
95
96
def elements_equal(self, e1, e2):
97
if e1.tag != e2.tag:
98
return False
99
if e1.text != e2.text:
100
return False
101
if e1.tail != e2.tail:
102
return False
103
if e1.attrib != e2.attrib:
104
return False
105
if len(e1) != len(e2):
106
return False
107
return all(self.elements_equal(c1, c2) for c1, c2 in zip(e1, e2))
108
109
@patch('AndroidRunner.Progress.Progress.run_to_dict')
110
def test_ordered_next(self, run_to_dict, current_progress):
111
run_to_dict.return_value = 0
112
for _ in range(50):
113
current_progress.get_next_run()
114
unique_values = len(set(str(run_to_dict.mock_calls).
115
replace('[', '').replace(']', '').replace('\n', '').split(', ')))
116
assert unique_values == 1
117
118
@patch('AndroidRunner.Progress.Progress.run_to_dict')
119
def test_random_next(self, run_to_dict, current_progress):
120
for _ in range(50):
121
current_progress.get_random_run()
122
unique_values = len(set(str(run_to_dict.mock_calls).
123
replace('[', '').replace(']', '').replace('\n', '').split(', ')))
124
assert unique_values > 1
125
126
def test_get_progress_xml_file(self, current_progress, test_progress):
127
progress_file = current_progress.get_progress_xml_file()
128
assert op.isfile(progress_file)
129
assert progress_file[-3:] == "xml"
130
131
with open(test_progress, 'r') as f:
132
expected_xml = f.read()
133
with open(progress_file, 'r') as f:
134
progress_xml = f.read()
135
expected_stripped = expected_xml.split("<outputDir>")[0] + expected_xml.split("</outputDir>")[1]
136
result_stripped = progress_xml.split("<outputDir>")[0] + progress_xml.split("</outputDir>")[1]
137
138
assert expected_stripped == result_stripped
139
140
def test_write_progress_to_file(self, current_progress, test_progress):
141
os.remove(current_progress.progress_xml_file)
142
143
assert not op.isfile(current_progress.progress_xml_file)
144
current_progress.write_progress_to_file()
145
assert op.isfile(current_progress.progress_xml_file)
146
147
with open(test_progress, 'r') as f:
148
expected_xml = f.read()
149
with open(current_progress.progress_xml_file, 'r') as f:
150
progress_xml = f.read()
151
expected_stripped = expected_xml.split("<outputDir>")[0] + expected_xml.split("</outputDir>")[1]
152
result_stripped = progress_xml.split("<outputDir>")[0] + progress_xml.split("</outputDir>")[1]
153
154
assert expected_stripped == result_stripped
155
156
def test_file_to_hash(self, current_progress, test_config):
157
expected_hash = "8bbc52b2deb22e83ac40b01abb04c95a"
158
current_hash = current_progress.file_to_hash(test_config)
159
assert current_hash == expected_hash
160
161
@patch('AndroidRunner.Progress.Progress.file_to_hash')
162
def test_check_config_hash_fail(self, file_to_hash_mock, current_progress, capsys, test_config, test_progress):
163
file_to_hash_mock.return_value = '0'
164
with pytest.raises(SystemExit) as wrapper_result:
165
current_progress.check_config_hash(test_progress)
166
167
# Prevent output during testing
168
capsys.readouterr()
169
assert wrapper_result.type == SystemExit
170
171
@patch('AndroidRunner.Progress.Progress.file_to_hash')
172
def test_check_config_hash_succes(self, file_to_hash_mock, current_progress):
173
file_to_hash_mock.return_value = current_progress.progress_xml_content.find('configHash').text
174
current_progress.check_config_hash(current_progress.get_progress_xml_file())
175
176
@patch('AndroidRunner.Progress.Progress.get_run_count')
177
def test_run_to_dict(self, get_run_count, current_progress):
178
get_run_count.return_value = 1459
179
run_dict = current_progress.run_to_dict(et.fromstring('<run runId="0"><device>device</device><path>path</path>'
180
'<browser>browser</browser><runCount>1</runCount></run>'))
181
expected_dict = {'runId': '0', 'device': 'device', 'path': 'path', 'browser': 'browser', 'runCount': 1459}
182
assert run_dict == expected_dict
183
184
def test_build_subject_xml_web(self, current_progress):
185
device = 'device1'
186
path = 'path1'
187
browser = 'browser1'
188
subject_xml = current_progress.build_subject_xml(device, path, browser)
189
expected_xml = '<device>device1</device><path>path1</path><browser>browser1</browser>'
190
assert subject_xml == expected_xml
191
192
def test_build_subject_xml_native(self, current_progress):
193
device = 'device1'
194
path = 'path1'
195
subject_xml = current_progress.build_subject_xml(device, path)
196
expected_xml = '<device>device1</device><path>path1</path>'
197
assert subject_xml == expected_xml
198
199
@patch('AndroidRunner.Progress.Progress.build_runs_xml')
200
@patch('AndroidRunner.Progress.Progress.file_to_hash')
201
def test_build_progress_xml(self, file_to_hash_mock, build_runs_xml_mock, current_progress):
202
mock_config = Mock()
203
mock_config_file = Mock()
204
paths.OUTPUT_DIR = "test/dir"
205
file_to_hash_mock.return_value = 'hash123'
206
build_runs_xml_mock.return_value = "runs_xml"
207
expected_xml = "<experiment><configHash>hash123</configHash><outputDir>test/dir</outputDir>" \
208
"<runsToRun>runs_xml</runsToRun><runsDone></runsDone></experiment>"
209
expected_lxml = et.fromstring(expected_xml)
210
build_progress = current_progress.build_progress_xml(mock_config, mock_config_file)
211
assert self.elements_equal(expected_lxml, build_progress)
212
file_to_hash_mock.assert_called_once_with(mock_config_file)
213
build_runs_xml_mock.assert_called_once_with(mock_config)
214
215
@patch('AndroidRunner.Progress.Progress.build_subject_xml')
216
def test_build_runs_xml_web(self, build_subject_xml_mock, current_progress, config_web_dict):
217
build_subject_xml_mock.return_value = "<device>device1</device><path>path1</path><browser>browser1</browser>"
218
runs_xml_web = current_progress.build_runs_xml(config_web_dict)
219
expected_runs_web = '<run runId="0"><device>device1</device><path>path1</path><browser>browser1</browser>' \
220
'<runCount>1</runCount></run>'
221
assert runs_xml_web == expected_runs_web
222
223
@patch('AndroidRunner.Progress.Progress.build_subject_xml')
224
def test_build_runs_xml_non_web(self, build_subject_xml_mock, current_progress, config_native_dict):
225
build_subject_xml_mock.return_value = "<device>device1</device><path>path1</path>"
226
runs_xml_native = current_progress.build_runs_xml(config_native_dict)
227
expected_runs_native = '<run runId="0"><device>device1</device><path>path1</path><runCount>1</runCount></run>'
228
assert runs_xml_native == expected_runs_native
229
230
def test_get_output_dir(self, current_progress):
231
assert current_progress.get_output_dir() == "test/output/dir"
232
233
def test_subject_first_web_first(self, current_progress):
234
mock_find_return_value = Mock()
235
mock_find_return_value.xpath.return_value = []
236
mock_progress_xml = Mock()
237
mock_progress_xml.find.return_value = mock_find_return_value
238
current_progress.progress_xml_content = mock_progress_xml
239
subject_first = current_progress.subject_first('fake_device', 'fake_path', 'fake_browser')
240
assert subject_first is True
241
242
def test_subject_first_native_first(self, current_progress):
243
mock_find_return_value = Mock()
244
mock_find_return_value.xpath.return_value = []
245
mock_progress_xml = Mock()
246
mock_progress_xml.find.return_value = mock_find_return_value
247
current_progress.progress_xml_content = mock_progress_xml
248
subject_first = current_progress.subject_first('fake_device', 'fake_path')
249
assert subject_first is True
250
251
def test_subject_first_web_not_first(self, current_progress):
252
mock_find_return_value = Mock()
253
mock_find_return_value.xpath.return_value = ['not_empty']
254
mock_progress_xml = Mock()
255
mock_progress_xml.find.return_value = mock_find_return_value
256
current_progress.progress_xml_content = mock_progress_xml
257
subject_first = current_progress.subject_first('fake_device', 'fake_path', 'fake_browser')
258
assert subject_first is False
259
260
def test_subject_first_native_not_first(self, current_progress):
261
mock_find_return_value = Mock()
262
mock_find_return_value.xpath.return_value = ['not_empty']
263
mock_progress_xml = Mock()
264
mock_progress_xml.find.return_value = mock_find_return_value
265
current_progress.progress_xml_content = mock_progress_xml
266
subject_first = current_progress.subject_first('fake_device', 'fake_path')
267
assert subject_first is False
268
269
def test_subject_finished_web_finished(self, current_progress):
270
mock_find_return_value = Mock()
271
mock_find_return_value.xpath.return_value = []
272
mock_progress_xml = Mock()
273
mock_progress_xml.find.return_value = mock_find_return_value
274
current_progress.progress_xml_content = mock_progress_xml
275
subject_first = current_progress.subject_finished('fake_device', 'fake_path', 'fake_browser')
276
assert subject_first is True
277
278
def test_subject_finished_native_finished(self, current_progress):
279
mock_find_return_value = Mock()
280
mock_find_return_value.xpath.return_value = []
281
mock_progress_xml = Mock()
282
mock_progress_xml.find.return_value = mock_find_return_value
283
current_progress.progress_xml_content = mock_progress_xml
284
subject_first = current_progress.subject_finished('fake_device', 'fake_path')
285
assert subject_first is True
286
287
def test_subject_finished_web_not_finished(self, current_progress):
288
mock_find_return_value = Mock()
289
mock_find_return_value.xpath.return_value = ['not_empty']
290
mock_progress_xml = Mock()
291
mock_progress_xml.find.return_value = mock_find_return_value
292
current_progress.progress_xml_content = mock_progress_xml
293
subject_first = current_progress.subject_finished('fake_device', 'fake_path', 'fake_browser')
294
assert subject_first is False
295
296
def test_subject_finished_native_not_finished(self, current_progress):
297
mock_find_return_value = Mock()
298
mock_find_return_value.xpath.return_value = ['not_empty']
299
mock_progress_xml = Mock()
300
mock_progress_xml.find.return_value = mock_find_return_value
301
current_progress.progress_xml_content = mock_progress_xml
302
subject_first = current_progress.subject_finished('fake_device', 'fake_path')
303
assert subject_first is False
304
305
def test_run_finished(self, current_progress):
306
runs_to_run_mock = Mock()
307
runs_to_run_mock.findall.return_value = ['fake_element']
308
runs_done_mock = Mock()
309
mock_progress_xml = Mock()
310
mock_progress_xml.find.side_effect = [runs_to_run_mock, runs_done_mock]
311
current_progress.progress_xml_content = mock_progress_xml
312
313
current_progress.run_finished(0)
314
315
runs_to_run_mock.remove.assert_called_once_with('fake_element')
316
runs_done_mock.append.assert_called_once_with('fake_element')
317
318
def test_experiment_finished_check_true(self, current_progress):
319
mock_progress_xml = Mock()
320
mock_progress_xml.find.return_value = et.fromstring('<runsToRun></runsToRun>')
321
current_progress.progress_xml_content = mock_progress_xml
322
experiment_finished = current_progress.experiment_finished_check()
323
assert experiment_finished is True
324
325
def test_experiment_finished_check_false(self, current_progress):
326
experiment_finished = current_progress.experiment_finished_check()
327
assert experiment_finished is False
328
329
def test_device_first_true(self, current_progress):
330
device_first = current_progress.device_first('nexus6p')
331
assert device_first is True
332
333
def test_device_first_false(self, current_progress):
334
mock_progress_xml = Mock()
335
mock_progress_xml.find.return_value = et.fromstring('<runsDone><run><device>device1</device></run></runsDone>')
336
current_progress.progress_xml_content = mock_progress_xml
337
device_first = current_progress.device_first('device1')
338
assert device_first is False
339
340
def test_device_finished_false(self, current_progress):
341
device_finished = current_progress.device_finished('nexus6p')
342
assert device_finished is False
343
344
def test_device_finished_true(self, current_progress):
345
device_finished = current_progress.device_finished('device1')
346
assert device_finished is True
347
348
def test_get_run_count_web(self, current_progress):
349
device = 'nexus6p'
350
path = 'https://google.com/'
351
run_xml = et.fromstring('<run runId="0"><device>nexus6p</device>'
352
'<path>https://google.com/</path>'
353
'<browser>firefox</browser></run>')
354
assert current_progress.get_run_count(run_xml, device, path) == 1
355
356
for _ in range(2):
357
run = current_progress.get_next_run()
358
current_progress.run_finished(run['runId'])
359
360
assert current_progress.get_run_count(run_xml, device, path) == 3
361
362
def test_get_run_count_native(self, current_progress):
363
device = 'nexus6p'
364
path = 'https://google.com/'
365
run_xml = et.fromstring('<run runId="0"><device>nexus6p</device><path>https://google.com/</path></run>')
366
assert current_progress.get_run_count(run_xml, device, path) == 1
367
run = current_progress.get_next_run()
368
current_progress.run_finished(run['runId'])
369
assert current_progress.get_run_count(run_xml, device, path) == 2
370
371