-
Notifications
You must be signed in to change notification settings - Fork 0
/
test_base_shell.py
357 lines (274 loc) · 10 KB
/
test_base_shell.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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
from __future__ import unicode_literals
import logging
import sys
import os
from friendlyshell.base_shell import BaseShell
from friendlyshell.basic_logger_mixin import BasicLoggerMixin
from mock import patch
import pytest
from io import StringIO
def test_defaults():
class MyShell(BasicLoggerMixin, BaseShell):
pass
obj = MyShell()
assert obj.prompt == '> '
def test_basic_parseline():
class MyShell(BasicLoggerMixin, BaseShell):
pass
obj = MyShell()
exp_command = "MyCommand"
exp_param1 = "Fu"
exp_param2 = "Bar"
res = obj._parse_line('{0} {1} {2}'.format(exp_command, exp_param1, exp_param2))
assert res.command == exp_command
assert len(res.params) == 2
assert res.params[0] == exp_param1
assert res.params[1] == exp_param2
def test_find_exit_command():
class MyShell(BasicLoggerMixin, BaseShell):
pass
obj = MyShell()
res = obj._find_command('exit')
assert res is not None
assert res.__name__ == 'do_exit'
assert res == obj.do_exit
def test_find_missing_command():
class MyShell(BasicLoggerMixin, BaseShell):
pass
obj = MyShell()
res = obj._find_command('fubar')
assert res is None
@pytest.mark.timeout(5)
def test_simple_run_exit():
class MyShell(BasicLoggerMixin, BaseShell):
pass
obj = MyShell()
with patch('friendlyshell.base_shell.input') as MockInput:
MockInput.return_value = 'exit'
obj.run()
MockInput.assert_called_once()
@pytest.mark.timeout(5)
def test_simple_run_input_stream(caplog):
expected_message = "My output from my command"
class MyShell(BasicLoggerMixin, BaseShell):
def do_my_cmd(self):
self.info(expected_message)
obj = MyShell()
in_stream = StringIO("""my_cmd
exit""")
obj.run(input_stream=in_stream)
assert expected_message in caplog.text
@pytest.mark.timeout(5)
def test_run_input_stream_no_exit(caplog):
expected_message = "My output from my command"
class MyShell(BasicLoggerMixin, BaseShell):
def do_my_cmd(self):
self.info(expected_message)
obj = MyShell()
in_stream = StringIO("""my_cmd""")
obj.run(input_stream=in_stream)
assert expected_message in caplog.text
@pytest.mark.timeout(5)
def test_run_input_stream_nested_exit(caplog):
expected_message1 = "My output from my command"
expected_message2 = "My Subcommand Output"
class SubShell(BasicLoggerMixin, BaseShell):
def do_my_sub_op(self):
self.info(expected_message2)
class MyShell(BasicLoggerMixin, BaseShell):
def do_my_cmd(self):
self.info(expected_message1)
def do_my_subshell(self):
tmp = SubShell()
tmp.run(input_stream=self.input_stream)
obj = MyShell()
in_stream = StringIO("""my_cmd
my_subshell
my_sub_op
exit""")
obj.run(input_stream=in_stream)
assert expected_message1 in caplog.text
assert expected_message2 in caplog.text
@pytest.mark.timeout(5)
def test_run_input_stream_subshell_close(caplog):
expected_message1 = "My output from my command"
expected_message2 = "My Subcommand Output"
expected_message3 = "Here's the other parents output"
class SubShell(BasicLoggerMixin, BaseShell):
def do_my_sub_op(self):
self.info(expected_message2)
class MyShell(BasicLoggerMixin, BaseShell):
def do_my_cmd(self):
self.info(expected_message1)
def do_my_other_cmd(self):
self.info(expected_message3)
def do_my_subshell(self):
tmp = SubShell()
tmp.run(input_stream=self.input_stream)
obj = MyShell()
in_stream = StringIO("""my_cmd
my_subshell
my_sub_op
close
my_other_cmd
exit""")
obj.run(input_stream=in_stream)
assert expected_message1 in caplog.text
assert expected_message2 in caplog.text
assert expected_message3 in caplog.text
def test_simple_nested_exit():
class SubShell(BasicLoggerMixin, BaseShell):
pass
class MyShell(BasicLoggerMixin, BaseShell):
def do_mysubshell (self):
temp = SubShell(parent=self)
return temp.run()
obj = MyShell()
with patch('friendlyshell.base_shell.input') as MockInput:
MockInput.side_effect = ['mysubshell', 'exit']
obj.run()
assert MockInput.call_count == 2
def test_simple_run_close():
class MyShell(BasicLoggerMixin, BaseShell):
pass
obj = MyShell()
with patch('friendlyshell.base_shell.input') as MockInput:
MockInput.return_value = 'close'
obj.run()
MockInput.assert_called_once()
def test_invalid_run(caplog):
caplog.set_level(logging.INFO)
class MyShell(BasicLoggerMixin, BaseShell):
pass
obj = MyShell()
with patch('friendlyshell.base_shell.input') as MockInput:
# Return 2 different commands to execute - the first invalid, and the second to terminate the shell
MockInput.side_effect = ['exit!', 'exit']
obj.run()
assert MockInput.call_count == 2
assert 'Parsing error:' in caplog.text
def test_keyboard_interrupt():
class MyShell(BasicLoggerMixin, BaseShell):
pass
obj = MyShell()
with patch('friendlyshell.base_shell.input') as MockInput:
MockInput.side_effect = KeyboardInterrupt()
obj.run()
MockInput.assert_called_once()
def test_unhandled_exception(caplog):
caplog.set_level(logging.INFO)
class MyShell(BasicLoggerMixin, BaseShell):
pass
obj = MyShell()
with patch('friendlyshell.base_shell.input') as MockInput:
expected_error = "Some crazy error"
MockInput.side_effect = Exception(expected_error)
obj.run()
MockInput.assert_called_once()
msg = 'Unexpected error during input sequence: ' + expected_error
assert msg in caplog.text
def test_missing_command(caplog):
caplog.set_level(logging.INFO)
expected_error = "Command not found"
expected_command_name = "fubar"
class test_class(BasicLoggerMixin, BaseShell):
pass
obj = test_class()
with patch('friendlyshell.base_shell.input') as MockInput:
MockInput.side_effect = [expected_command_name, 'exit']
obj.run()
assert MockInput.call_count == 2
assert expected_error in caplog.text
assert expected_command_name in caplog.text
def test_command_exception(caplog):
caplog.set_level(logging.INFO)
expected_error = "Some weird thing just happened"
class test_class(BasicLoggerMixin, BaseShell):
def do_something(self):
raise Exception(expected_error)
obj = test_class()
with patch('friendlyshell.base_shell.input') as MockInput:
MockInput.side_effect = ['something', 'exit']
obj.run()
assert MockInput.call_count == 2
assert expected_error in caplog.text
def test_command_with_params():
expected_param = "FuBar"
class test_class(BasicLoggerMixin, BaseShell):
test_function_ran = False
def do_something(self, my_param):
assert my_param == expected_param
self.test_function_ran = True
obj = test_class()
with patch('friendlyshell.base_shell.input') as MockInput:
MockInput.side_effect = ['something ' + expected_param, 'exit']
obj.run()
assert MockInput.call_count == 2
assert obj.test_function_ran
def test_command_too_many_params():
expected_params = "Fu Bar"
class test_class(BasicLoggerMixin, BaseShell):
def do_something(self, my_param):
pytest.fail("Test method should not be invoked")
obj = test_class()
with patch('friendlyshell.base_shell.input') as MockInput:
MockInput.side_effect = ['something ' + expected_params, 'exit']
obj.run()
assert MockInput.call_count == 2
def test_command_missing_params(caplog):
caplog.set_level(logging.INFO)
class test_class(BasicLoggerMixin, BaseShell):
def do_something(self, my_param1, my_param2):
pytest.fail("Test method should not be invoked")
obj = test_class()
with patch('friendlyshell.base_shell.input') as MockInput:
MockInput.side_effect = ['something first', 'exit']
obj.run()
assert MockInput.call_count == 2
msg = "Command something requires 2 of 2 parameters but 1 were provided"
assert msg in caplog.text
def test_command_no_params(caplog):
caplog.set_level(logging.INFO)
class test_class(BasicLoggerMixin, BaseShell):
def do_something(self, my_param1, my_param2):
pytest.fail("Test method should not be invoked")
obj = test_class()
with patch('friendlyshell.base_shell.input') as MockInput:
MockInput.side_effect = ['something', 'exit']
obj.run()
assert MockInput.call_count == 2
msg = "Command something requires 2 of 2 parameters but 0 were provided"
assert msg in caplog.text
def test_shell_command(caplog):
caplog.set_level(logging.INFO)
class test_class(BasicLoggerMixin, BaseShell):
pass
obj = test_class()
if sys.platform.startswith("win"):
test_cmd = "dir /a"
else:
test_cmd = "ls -a"
in_stream = StringIO("""!{0}
exit""".format(test_cmd))
obj.run(input_stream=in_stream)
for cur_item in os.listdir("."):
assert cur_item in caplog.text
def test_shell_command_not_found(caplog):
caplog.set_level(logging.INFO)
expected_text = "Hello World"
class test_class(BasicLoggerMixin, BaseShell):
def do_something(self):
self.info(expected_text)
obj = test_class()
expected_command = "fubarasdf1234"
in_stream = StringIO("""!{0}
something
exit""".format(expected_command))
obj.run(input_stream=in_stream)
# Make sure the second command in the sequence rance
assert expected_text in caplog.text
if sys.platform.startswith("win"):
assert "not recognized" in caplog.text
assert expected_command in caplog.text
if __name__ == "__main__":
pytest.main([__file__, "-v", "-s"])