It was suggested that we replace TestCase with NoDBTestCase [1]. This does two things. First it prevents the test case setup from running the database schema migrations unnecessarily which should improve performance. Second it will cause the test to fail if the code does touch the DB when the developer is claiming that it shouldn't. [1] https://review.openstack.org/#/c/409404/46/nova/tests/unit/virt/powervm/test_media.py Change-Id: I8bcc9cbdcadd9fe89a4450ca405387899baa9fc3
198 lines
8.1 KiB
Python
198 lines
8.1 KiB
Python
# Copyright 2015 IBM Corp.
|
|
#
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import mock
|
|
|
|
from nova.compute import task_states
|
|
from nova import exception
|
|
from nova import test
|
|
|
|
from nova_powervm.virt.powervm.tasks import vm as tf_vm
|
|
|
|
from pypowervm import const as pvmc
|
|
from taskflow import engines as tf_eng
|
|
from taskflow.patterns import linear_flow as tf_lf
|
|
from taskflow import task as tf_tsk
|
|
|
|
|
|
class TestVMTasks(test.NoDBTestCase):
|
|
def setUp(self):
|
|
super(TestVMTasks, self).setUp()
|
|
self.apt = mock.Mock()
|
|
self.instance = mock.Mock(uuid='fake-uuid')
|
|
|
|
@mock.patch('pypowervm.utils.transaction.FeedTask')
|
|
@mock.patch('pypowervm.tasks.partition.build_active_vio_feed_task')
|
|
@mock.patch('pypowervm.tasks.storage.add_lpar_storage_scrub_tasks')
|
|
@mock.patch('nova_powervm.virt.powervm.vm.create_lpar')
|
|
def test_create(self, mock_vm_crt, mock_stg, mock_bld, mock_ftsk):
|
|
nvram_mgr = mock.Mock()
|
|
nvram_mgr.fetch.return_value = 'data'
|
|
lpar_entry = mock.Mock()
|
|
|
|
# Test create with normal (non-recreate) ftsk
|
|
crt = tf_vm.Create(self.apt, 'host_wrapper', self.instance,
|
|
stg_ftsk=mock_ftsk, nvram_mgr=nvram_mgr,
|
|
slot_mgr='slot_mgr')
|
|
mock_vm_crt.return_value = lpar_entry
|
|
crt_entry = crt.execute()
|
|
|
|
mock_ftsk.execute.assert_not_called()
|
|
mock_vm_crt.assert_called_once_with(
|
|
self.apt, 'host_wrapper', self.instance, nvram='data',
|
|
slot_mgr='slot_mgr')
|
|
self.assertEqual(lpar_entry, crt_entry)
|
|
nvram_mgr.fetch.assert_called_once_with(self.instance)
|
|
|
|
mock_ftsk.name = 'create_scrubber'
|
|
mock_bld.return_value = mock_ftsk
|
|
# Test create with recreate ftsk
|
|
rcrt = tf_vm.Create(self.apt, 'host_wrapper', self.instance,
|
|
stg_ftsk=None, nvram_mgr=nvram_mgr,
|
|
slot_mgr='slot_mgr')
|
|
mock_bld.assert_called_once_with(
|
|
self.apt, name='create_scrubber',
|
|
xag={pvmc.XAG.VIO_SMAP, pvmc.XAG.VIO_FMAP})
|
|
rcrt.execute()
|
|
mock_ftsk.execute.assert_called_once_with()
|
|
|
|
@mock.patch('nova_powervm.virt.powervm.vm.get_pvm_uuid')
|
|
@mock.patch('nova_powervm.virt.powervm.tasks.vm.Create.execute')
|
|
@mock.patch('nova_powervm.virt.powervm.vm.delete_lpar')
|
|
def test_create_revert(self, mock_vm_dlt, mock_crt_exc,
|
|
mock_get_pvm_uuid):
|
|
|
|
mock_crt_exc.side_effect = exception.NovaException()
|
|
crt = tf_vm.Create(self.apt, 'host_wrapper', self.instance, 'stg_ftsk',
|
|
None)
|
|
|
|
# Assert that a failure while building does not revert
|
|
crt.instance.task_state = task_states.SPAWNING
|
|
flow_test = tf_lf.Flow("test_revert")
|
|
flow_test.add(crt)
|
|
self.assertRaises(exception.NovaException, tf_eng.run, flow_test)
|
|
mock_vm_dlt.assert_not_called()
|
|
|
|
# Assert that a failure when rebuild results in revert
|
|
crt.instance.task_state = task_states.REBUILD_SPAWNING
|
|
flow_test = tf_lf.Flow("test_revert")
|
|
flow_test.add(crt)
|
|
self.assertRaises(exception.NovaException, tf_eng.run, flow_test)
|
|
mock_vm_dlt.assert_called()
|
|
|
|
@mock.patch('nova_powervm.virt.powervm.vm.power_on')
|
|
def test_power_on(self, mock_pwron):
|
|
pwron = tf_vm.PowerOn(self.apt, self.instance, pwr_opts='opt')
|
|
pwron.execute()
|
|
mock_pwron.assert_called_once_with(self.apt, self.instance, opts='opt')
|
|
|
|
@mock.patch('nova_powervm.virt.powervm.vm.power_on')
|
|
@mock.patch('nova_powervm.virt.powervm.vm.power_off')
|
|
def test_power_on_revert(self, mock_pwroff, mock_pwron):
|
|
flow = tf_lf.Flow('revert_power_on')
|
|
pwron = tf_vm.PowerOn(self.apt, self.instance, pwr_opts='opt')
|
|
flow.add(pwron)
|
|
|
|
# Dummy Task that fails, triggering flow revert
|
|
def failure(*a, **k):
|
|
raise ValueError()
|
|
flow.add(tf_tsk.FunctorTask(failure))
|
|
|
|
# When PowerOn.execute doesn't fail, revert calls power_off
|
|
self.assertRaises(ValueError, tf_eng.run, flow)
|
|
mock_pwron.assert_called_once_with(self.apt, self.instance, opts='opt')
|
|
mock_pwroff.assert_called_once_with(self.apt, self.instance,
|
|
force_immediate=True)
|
|
|
|
mock_pwron.reset_mock()
|
|
mock_pwroff.reset_mock()
|
|
|
|
# When PowerOn.execute fails, revert doesn't call power_off
|
|
mock_pwron.side_effect = exception.NovaException()
|
|
self.assertRaises(exception.NovaException, tf_eng.run, flow)
|
|
mock_pwron.assert_called_once_with(self.apt, self.instance, opts='opt')
|
|
mock_pwroff.assert_not_called()
|
|
|
|
@mock.patch('nova_powervm.virt.powervm.vm.power_off')
|
|
def test_power_off(self, mock_pwroff):
|
|
# Default force_immediate
|
|
pwroff = tf_vm.PowerOff(self.apt, self.instance)
|
|
pwroff.execute()
|
|
mock_pwroff.assert_called_once_with(self.apt, self.instance,
|
|
force_immediate=False)
|
|
|
|
mock_pwroff.reset_mock()
|
|
|
|
# Explicit force_immediate
|
|
pwroff = tf_vm.PowerOff(self.apt, self.instance, force_immediate=True)
|
|
pwroff.execute()
|
|
mock_pwroff.assert_called_once_with(self.apt, self.instance,
|
|
force_immediate=True)
|
|
|
|
@mock.patch('nova_powervm.virt.powervm.vm.delete_lpar')
|
|
def test_delete(self, mock_dlt):
|
|
delete = tf_vm.Delete(self.apt, self.instance)
|
|
delete.execute()
|
|
mock_dlt.assert_called_once_with(self.apt, self.instance)
|
|
|
|
@mock.patch('nova_powervm.virt.powervm.vm.update')
|
|
def test_resize(self, mock_vm_update):
|
|
|
|
resize = tf_vm.Resize(self.apt, 'host_wrapper', self.instance,
|
|
name='new_name')
|
|
mock_vm_update.return_value = 'resized_entry'
|
|
resized_entry = resize.execute()
|
|
mock_vm_update.assert_called_once_with(
|
|
self.apt, 'host_wrapper', self.instance, entry=None,
|
|
name='new_name')
|
|
self.assertEqual('resized_entry', resized_entry)
|
|
|
|
@mock.patch('nova_powervm.virt.powervm.vm.rename')
|
|
def test_rename(self, mock_vm_rename):
|
|
mock_vm_rename.return_value = 'new_entry'
|
|
rename = tf_vm.Rename(self.apt, self.instance, 'new_name')
|
|
new_entry = rename.execute()
|
|
mock_vm_rename.assert_called_once_with(
|
|
self.apt, self.instance, 'new_name')
|
|
self.assertEqual('new_entry', new_entry)
|
|
|
|
def test_store_nvram(self):
|
|
nvram_mgr = mock.Mock()
|
|
store_nvram = tf_vm.StoreNvram(nvram_mgr, self.instance,
|
|
immediate=True)
|
|
store_nvram.execute()
|
|
nvram_mgr.store.assert_called_once_with(self.instance,
|
|
immediate=True)
|
|
|
|
# No exception is raised if the NVRAM could not be stored.
|
|
nvram_mgr.reset_mock()
|
|
nvram_mgr.store.side_effect = ValueError('Not Available')
|
|
store_nvram.execute()
|
|
nvram_mgr.store.assert_called_once_with(self.instance,
|
|
immediate=True)
|
|
|
|
def test_delete_nvram(self):
|
|
nvram_mgr = mock.Mock()
|
|
delete_nvram = tf_vm.DeleteNvram(nvram_mgr, self.instance)
|
|
delete_nvram.execute()
|
|
nvram_mgr.remove.assert_called_once_with(self.instance)
|
|
|
|
# No exception is raised if the NVRAM could not be stored.
|
|
nvram_mgr.reset_mock()
|
|
nvram_mgr.remove.side_effect = ValueError('Not Available')
|
|
delete_nvram.execute()
|
|
nvram_mgr.remove.assert_called_once_with(self.instance)
|