Skip to content

Commit 17c9380

Browse files
author
anon
committed
add utests
1 parent b3f15f5 commit 17c9380

1 file changed

Lines changed: 152 additions & 6 deletions

File tree

qubesadmin/tests/tools/qvm_shutdown.py

Lines changed: 152 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,6 @@ def test_004_multiple_vms(self):
8383
app=self.app)
8484
self.assertAllCalled()
8585

86-
@unittest.skipUnless(qubesadmin.tools.qvm_shutdown.have_events,
87-
'Events not present')
8886
def test_010_wait(self):
8987
'''test --wait option'''
9088
loop = asyncio.new_event_loop()
@@ -114,8 +112,6 @@ def test_010_wait(self):
114112
qubesadmin.tools.qvm_shutdown.main(['--wait', 'some-vm'], app=self.app)
115113
self.assertAllCalled()
116114

117-
@unittest.skipUnless(qubesadmin.tools.qvm_shutdown.have_events,
118-
'Events not present')
119115
def test_012_wait_all(self):
120116
'''test --wait option, with multiple VMs'''
121117
loop = asyncio.new_event_loop()
@@ -161,8 +157,6 @@ def test_012_wait_all(self):
161157
qubesadmin.tools.qvm_shutdown.main(['--wait', '--all'], app=self.app)
162158
self.assertAllCalled()
163159

164-
@unittest.skipUnless(qubesadmin.tools.qvm_shutdown.have_events,
165-
'Events not present')
166160
def test_015_wait_all_kill_timeout(self):
167161
'''test --wait option, with multiple VMs and killing on timeout'''
168162
loop = asyncio.new_event_loop()
@@ -251,3 +245,155 @@ def test_017_all_exclude_force_explicit(self):
251245
'--force'],
252246
app=self.app)
253247
self.assertAllCalled()
248+
249+
def test_005_force(self):
250+
'''test --force sends force flag to shutdown call'''
251+
self.app.expected_calls[
252+
('dom0', 'admin.vm.List', None, None)] = \
253+
b'0\x00some-vm class=AppVM state=Running\n'
254+
self.app.expected_calls[
255+
('some-vm', 'admin.vm.Shutdown', 'force', None)] = b'0\x00'
256+
qubesadmin.tools.qvm_shutdown.main(
257+
['--force', 'some-vm'], app=self.app)
258+
self.assertAllCalled()
259+
260+
def test_006_dry_run(self):
261+
'''test --dry-run skips shutdown calls'''
262+
self.app.expected_calls[
263+
('dom0', 'admin.vm.List', None, None)] = \
264+
b'0\x00some-vm class=AppVM state=Running\n'
265+
qubesadmin.tools.qvm_shutdown.main(
266+
['--dry-run', 'some-vm'], app=self.app)
267+
self.assertAllCalled()
268+
269+
def test_011_wait_retry(self):
270+
'''test --wait retries VMs whose shutdown request failed'''
271+
loop = asyncio.new_event_loop()
272+
asyncio.set_event_loop(loop)
273+
274+
mock_events = unittest.mock.AsyncMock()
275+
patch = unittest.mock.patch(
276+
'qubesadmin.events.EventsDispatcher._get_events_reader',
277+
mock_events)
278+
patch.start()
279+
self.addCleanup(patch.stop)
280+
mock_events.side_effect = qubesadmin.tests.tools.MockEventsReader([
281+
# round 1: wait for some-vm
282+
b'1\0\0connection-established\0\0',
283+
b'1\0some-vm\0domain-shutdown\0\0',
284+
# round 2: wait for other-vm
285+
b'1\0\0connection-established\0\0',
286+
b'1\0other-vm\0domain-shutdown\0\0',
287+
])
288+
289+
self.app.expected_calls[
290+
('dom0', 'admin.vm.List', None, None)] = \
291+
b'0\x00' \
292+
b'some-vm class=AppVM state=Running\n' \
293+
b'other-vm class=AppVM state=Running\n'
294+
self.app.expected_calls[
295+
('some-vm', 'admin.vm.Shutdown', None, None)] = \
296+
b'0\x00'
297+
# other-vm fails first attempt, succeeds on retry
298+
self.app.expected_calls[
299+
('other-vm', 'admin.vm.Shutdown', None, None)] = [
300+
b'2\x00QubesException\x00\x00Shutdown refused\x00',
301+
b'0\x00',
302+
]
303+
self.app.expected_calls[
304+
('some-vm', 'admin.vm.CurrentState', None, None)] = [
305+
b'0\x00power_state=Running',
306+
b'0\x00power_state=Halted',
307+
]
308+
self.app.expected_calls[
309+
('other-vm', 'admin.vm.CurrentState', None, None)] = [
310+
b'0\x00power_state=Running',
311+
b'0\x00power_state=Halted',
312+
]
313+
qubesadmin.tools.qvm_shutdown.main(
314+
['--wait', 'some-vm', 'other-vm'], app=self.app)
315+
self.assertAllCalled()
316+
317+
def test_013_wait_all_shutdown_fail(self):
318+
'''test --wait exits with error when all shutdown requests fail'''
319+
self.app.expected_calls[
320+
('dom0', 'admin.vm.List', None, None)] = \
321+
b'0\x00some-vm class=AppVM state=Running\n'
322+
self.app.expected_calls[
323+
('some-vm', 'admin.vm.Shutdown', None, None)] = \
324+
b'2\x00QubesException\x00\x00Shutdown refused\x00'
325+
self.app.expected_calls[
326+
('some-vm', 'admin.vm.CurrentState', None, None)] = \
327+
b'0\x00power_state=Running'
328+
with self.assertRaises(SystemExit):
329+
qubesadmin.tools.qvm_shutdown.main(
330+
['--wait', 'some-vm'], app=self.app)
331+
self.assertAllCalled()
332+
333+
def test_016_wait_kill_exception(self):
334+
'''test --wait timeout where kill raises QubesException'''
335+
loop = asyncio.new_event_loop()
336+
asyncio.set_event_loop(loop)
337+
338+
mock_events = unittest.mock.AsyncMock()
339+
patch = unittest.mock.patch(
340+
'qubesadmin.events.EventsDispatcher._get_events_reader',
341+
mock_events)
342+
patch.start()
343+
self.addCleanup(patch.stop)
344+
mock_events.side_effect = qubesadmin.tests.tools.MockEventsReader([
345+
b'1\0\0connection-established\0\0',
346+
])
347+
348+
self.app.expected_calls[
349+
('dom0', 'admin.vm.List', None, None)] = \
350+
b'0\x00some-vm class=AppVM state=Running\n'
351+
self.app.expected_calls[
352+
('some-vm', 'admin.vm.Shutdown', None, None)] = \
353+
b'0\x00'
354+
self.app.expected_calls[
355+
('some-vm', 'admin.vm.Kill', None, None)] = \
356+
b'2\x00QubesException\x00\x00Kill failed\x00'
357+
self.app.expected_calls[
358+
('some-vm', 'admin.vm.CurrentState', None, None)] = [
359+
b'0\x00power_state=Running',
360+
b'0\x00power_state=Running',
361+
]
362+
with self.assertRaises(SystemExit):
363+
qubesadmin.tools.qvm_shutdown.main(
364+
['--wait', '--timeout=1', 'some-vm'], app=self.app)
365+
self.assertAllCalled()
366+
367+
def test_017_wait_dispvm_na(self):
368+
'''test --wait treats DispVM with NA power state as shut down'''
369+
loop = asyncio.new_event_loop()
370+
asyncio.set_event_loop(loop)
371+
372+
mock_events = unittest.mock.AsyncMock()
373+
patch = unittest.mock.patch(
374+
'qubesadmin.events.EventsDispatcher._get_events_reader',
375+
mock_events)
376+
patch.start()
377+
self.addCleanup(patch.stop)
378+
mock_events.side_effect = qubesadmin.tests.tools.MockEventsReader([
379+
b'1\0\0connection-established\0\0',
380+
b'1\0disp123\0domain-shutdown\0\0',
381+
])
382+
383+
self.app.expected_calls[
384+
('dom0', 'admin.vm.List', None, None)] = \
385+
b'0\x00disp123 class=DispVM state=Running\n'
386+
self.app.expected_calls[
387+
('disp123', 'admin.vm.Shutdown', None, None)] = \
388+
b'0\x00'
389+
self.app.expected_calls[
390+
('disp123', 'admin.vm.CurrentState', None, None)] = [
391+
b'0\x00power_state=Running',
392+
# failed_domains: first get_power_state() != 'Halted',
393+
# then klass == 'DispVM' triggers second get_power_state()
394+
b'0\x00power_state=NA',
395+
b'0\x00power_state=NA',
396+
]
397+
qubesadmin.tools.qvm_shutdown.main(
398+
['--wait', 'disp123'], app=self.app)
399+
self.assertAllCalled()

0 commit comments

Comments
 (0)