Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
S2-group
GitHub Repository: S2-group/android-runner
Path: blob/master/tests/unit/test_main.py
908 views
1
import importlib
2
import logging
3
import os.path as op
4
import sys
5
6
import pytest
7
8
import paths
9
from mock import patch, Mock, call
10
from AndroidRunner.util import makedirs
11
12
# Suggested imp.load_source replacement, since python 3.12 (https://docs.python.org/3/whatsnew/3.12.html#imp)
13
def load_source(modname, filename):
14
loader = importlib.machinery.SourceFileLoader(modname, filename)
15
spec = importlib.util.spec_from_file_location(modname, filename, loader=loader)
16
module = importlib.util.module_from_spec(spec)
17
# The module is always executed and not cached in sys.modules.
18
# Uncomment the following line to cache the module.
19
sys.modules[module.__name__] = module
20
loader.exec_module(module)
21
return module
22
23
main = load_source('runner_main', op.join(op.dirname(paths.__file__), '__main__.py'))
24
25
class TestRunnerMain(object):
26
27
@patch('runner_main.set_stdout_logger')
28
@patch('runner_main.set_file_logger')
29
@patch('logging.getLogger')
30
def test_setup_logger(self, get_logger_mock, set_file_logger_mock, set_stdout_logger_mock):
31
test_filename = "asdfvgbnsaq"
32
logger_mock = Mock()
33
get_logger_mock.return_value = logger_mock
34
file_logger_mock = Mock()
35
set_file_logger_mock.return_value = file_logger_mock
36
stdout_logger_mock = Mock()
37
set_stdout_logger_mock.return_value = stdout_logger_mock
38
39
result_logger = main.setup_logger(test_filename)
40
41
logger_mock.setLevel.assert_called_once_with(logging.DEBUG)
42
expected_calls = [call(file_logger_mock), call(stdout_logger_mock)]
43
assert logger_mock.addHandler.mock_calls == expected_calls
44
set_file_logger_mock.assert_called_once_with(op.join(test_filename, 'experiment.log'))
45
set_stdout_logger_mock.assert_called_once_with()
46
assert result_logger == logger_mock
47
48
@patch('logging.Formatter')
49
@patch('logging.FileHandler')
50
def test_set_file_logger(self, filehandler_mock, formatter_mock):
51
test_filename = "asdfvgbnsaq"
52
handler_mock = Mock()
53
filehandler_mock.return_value = handler_mock
54
formatter_result_mock = Mock()
55
formatter_mock.return_value = formatter_result_mock
56
57
result_file_handler = main.set_file_logger(test_filename)
58
59
assert result_file_handler == handler_mock
60
handler_mock.setLevel.assert_called_once_with(logging.DEBUG)
61
handler_mock.setFormatter.assert_called_once_with(formatter_result_mock)
62
filehandler_mock.assert_called_once_with(test_filename)
63
64
@patch('logging.Formatter')
65
@patch('logging.StreamHandler')
66
def test_set_stdout_logger(self, streamhandler_mock, formatter_mock):
67
handler_mock = Mock()
68
streamhandler_mock.return_value = handler_mock
69
formatter_result_mock = Mock()
70
formatter_mock.return_value = formatter_result_mock
71
72
result_file_handler = main.set_stdout_logger()
73
74
assert result_file_handler == handler_mock
75
handler_mock.setLevel.assert_called_once_with(logging.INFO)
76
handler_mock.setFormatter.assert_called_once_with(formatter_result_mock)
77
streamhandler_mock.assert_called_once_with(sys.stdout)
78
79
def test_setup_paths(self, tmpdir):
80
temp_config_dir = op.join(str(tmpdir), 'config')
81
makedirs(temp_config_dir)
82
temp_config_file = op.join(temp_config_dir, 'config.json')
83
open(temp_config_file, "w+")
84
temp_log_dir = op.join(str(tmpdir), 'log')
85
86
main.setup_paths(temp_config_file, temp_log_dir)
87
88
assert paths.CONFIG_DIR == op.dirname(temp_config_file)
89
assert op.isdir(temp_log_dir)
90
assert paths.OUTPUT_DIR == temp_log_dir
91
assert paths.BASE_OUTPUT_DIR == temp_log_dir
92
assert op.join(paths.ROOT_DIR, 'AndroidRunner') in sys.path
93
94
def test_parse_arguments_empty_args(self, capsys):
95
with pytest.raises(SystemExit) as pytest_wrapped_e:
96
main.parse_arguments([])
97
capsys.readouterr() # Catch print
98
assert pytest_wrapped_e.type == SystemExit
99
assert pytest_wrapped_e.value.code == 2
100
101
def test_parse_arguments_one_args(self, capsys):
102
fake_filename = 'test/file/name'
103
result_args = main.parse_arguments([fake_filename])
104
105
assert len(result_args) == 1
106
assert result_args.get('file') == fake_filename
107
108
def test_parse_arguments_both_args(self, capsys):
109
fake_filename = 'test/file/name'
110
fake_progress_file = 'path/to/progress'
111
result_args = main.parse_arguments([fake_filename, '--progress', fake_progress_file])
112
113
assert len(result_args) == 2
114
assert result_args.get('file') == fake_filename
115
assert result_args.get('progress') == fake_progress_file
116
117
def test_set_progress_new(self, tmpdir):
118
temp_config_file = op.join(str(tmpdir), 'fake_config.json')
119
open(temp_config_file, "w+")
120
args = {"file": temp_config_file}
121
result_progress, result_log_dir = main.set_progress(args)
122
assert result_progress is None
123
assert result_log_dir.startswith(op.join(op.dirname(temp_config_file), 'output'))
124
125
@patch('AndroidRunner.Progress.Progress.get_output_dir')
126
@patch('AndroidRunner.Progress.Progress.__init__')
127
def test_set_progress_restart(self, mock_progress_init, mock_progress_get_output, tmpdir):
128
temp_config_file = op.join(str(tmpdir), 'fake_config.json')
129
temp_progress_file = op.join(str(tmpdir), 'fake_progress.xml')
130
open(temp_config_file, "w+")
131
open(temp_progress_file, "w+")
132
mock_progress_init.return_value = None
133
mock_output_dir = Mock()
134
mock_progress_get_output.return_value = mock_output_dir
135
args = {"file": temp_config_file, "progress": temp_progress_file}
136
137
result_progress, result_log_dir = main.set_progress(args)
138
139
mock_progress_init.assert_called_once_with(progress_file=temp_progress_file,
140
config_file=temp_config_file, load_progress=True)
141
assert result_log_dir == mock_output_dir
142
143
@patch('runner_main.parse_arguments')
144
@patch('runner_main.set_progress')
145
@patch('runner_main.setup_paths')
146
@patch('runner_main.setup_logger')
147
@patch('AndroidRunner.ExperimentFactory.ExperimentFactory.from_json')
148
def test_main_exception(self, from_json_mock, setup_logger_mock, setup_paths_mock, set_progress_mock,
149
parse_arguments_mock, tmpdir):
150
setup_paths_mock.return_value = None
151
temp_progress_file = op.join(str(tmpdir), 'fake_progress.xml')
152
open(temp_progress_file, "w+")
153
from_json_mock.side_effect = Exception()
154
parse_arguments_mock.return_value = {'file': temp_progress_file}
155
set_progress_mock.return_value = None, None
156
mock_logger = Mock()
157
setup_logger_mock.return_value = mock_logger
158
159
main.main()
160
161
from_json_mock.assert_called_once_with(temp_progress_file, None)
162
assert mock_logger.error.call_count == 2
163
assert mock_logger.error.mock_calls[1] == call('An error occurred, the experiment has been stopped. '
164
'To continue, add progress file argument to experiment startup: '
165
'--progress No progress file created')
166
167
@patch('runner_main.parse_arguments')
168
@patch('runner_main.set_progress')
169
@patch('runner_main.setup_paths')
170
@patch('runner_main.setup_logger')
171
@patch('AndroidRunner.ExperimentFactory.ExperimentFactory.from_json')
172
def test_main_interrupt(self, from_json_mock, setup_logger_mock, setup_paths_mock, set_progress_mock,
173
parse_arguments_mock, tmpdir):
174
setup_paths_mock.return_value = None
175
temp_progress_file = op.join(str(tmpdir), 'fake_progress.xml')
176
open(temp_progress_file, "w+")
177
from_json_mock.side_effect = KeyboardInterrupt
178
parse_arguments_mock.return_value = {'file': temp_progress_file}
179
mock_progress = Mock()
180
mock_progress.get_progress_xml_file.return_value = "path/to/progress.xml"
181
set_progress_mock.return_value = mock_progress, None
182
mock_logger = Mock()
183
setup_logger_mock.return_value = mock_logger
184
185
main.main()
186
187
from_json_mock.assert_called_once_with(temp_progress_file, mock_progress)
188
assert mock_logger.error.call_count == 1
189
assert mock_logger.error.mock_calls[0] == call('Experiment stopped by user. To continue,'
190
' add progress file argument to experiment startup: '
191
'--progress path/to/progress.xml')
192
193
@patch('runner_main.parse_arguments')
194
@patch('runner_main.set_progress')
195
@patch('runner_main.setup_paths')
196
@patch('runner_main.setup_logger')
197
@patch('AndroidRunner.ExperimentFactory.ExperimentFactory.from_json')
198
def test_main_succes(self, from_json_mock, setup_logger_mock, setup_paths_mock, set_progress_mock,
199
parse_arguments_mock, tmpdir):
200
setup_paths_mock.return_value = None
201
temp_progress_file = op.join(str(tmpdir), 'fake_progress.xml')
202
open(temp_progress_file, "w+")
203
mock_experiment = Mock()
204
from_json_mock.return_value = mock_experiment
205
parse_arguments_mock.return_value = {'file': temp_progress_file}
206
set_progress_mock.return_value = None, None
207
mock_logger = Mock()
208
setup_logger_mock.return_value = mock_logger
209
210
main.main()
211
212
from_json_mock.assert_called_once_with(temp_progress_file, None)
213
mock_experiment.start.assert_called_once_with()
214
assert mock_logger.error.call_count == 0
215
216