From 6144551809c939570e47bab288604b25aa3cab21 Mon Sep 17 00:00:00 2001 From: licanwei Date: Sat, 16 Jul 2016 12:11:26 +0800 Subject: [PATCH] Add unit tests for nova_helper.py The nova helper does not have a sufficient code coverage. This commit raises its coverage from 39% to 89%. And unit tests find two bugs. Closes-Bug: #1607198 Change-Id: Iebb693cd09e512ce44702eddca8ead0c7310b263 Closes-Bug: #1599849 --- watcher/common/nova_helper.py | 5 + watcher/tests/common/test_nova_helper.py | 168 +++++++++++++++++++---- 2 files changed, 144 insertions(+), 29 deletions(-) diff --git a/watcher/common/nova_helper.py b/watcher/common/nova_helper.py index 99c7aa709..6b2e78113 100644 --- a/watcher/common/nova_helper.py +++ b/watcher/common/nova_helper.py @@ -72,6 +72,7 @@ class NovaHelper(object): else: raise Exception("Volume %s did not reach status %s after %d s" % (volume.id, status, timeout)) + return volume.status == status def watcher_non_live_migrate_instance(self, instance_id, node_id, keep_original_image_name=True): @@ -426,6 +427,8 @@ class NovaHelper(object): metadata) image = self.glance.images.get(image_uuid) + if not image: + return None # Waiting for the new image to be officially in ACTIVE state # in order to make sure it can be used @@ -436,6 +439,8 @@ class NovaHelper(object): retry -= 1 # Retrieve the instance again so the status field updates image = self.glance.images.get(image_uuid) + if not image: + break status = image.status LOG.debug("Current image status: %s" % status) diff --git a/watcher/tests/common/test_nova_helper.py b/watcher/tests/common/test_nova_helper.py index 62b509a79..38bda9837 100644 --- a/watcher/tests/common/test_nova_helper.py +++ b/watcher/tests/common/test_nova_helper.py @@ -39,47 +39,79 @@ class TestNovaHelper(base.TestCase): self.source_node = "ldev-indeedsrv005" self.destination_node = "ldev-indeedsrv006" + @staticmethod + def fake_server(*args, **kwargs): + server = mock.MagicMock() + server.id = args[0] + server.status = 'ACTIVE' + + return server + + @staticmethod + def fake_nova_find_list(nova_util, find=None, list=None): + nova_util.nova.servers.find.return_value = find + if list is None: + nova_util.nova.servers.list.return_value = [] + else: + nova_util.nova.servers.list.return_value = [list] + + @mock.patch.object(time, 'sleep', mock.Mock()) def test_stop_instance(self, mock_glance, mock_cinder, mock_neutron, mock_nova): nova_util = nova_helper.NovaHelper() instance_id = utils.generate_uuid() - server = mock.MagicMock() - server.id = instance_id + server = self.fake_server(instance_id) setattr(server, 'OS-EXT-STS:vm_state', 'stopped') - nova_util.nova.servers = mock.MagicMock() - nova_util.nova.servers.find.return_value = server - nova_util.nova.servers.list.return_value = [server] + self.fake_nova_find_list(nova_util, find=server, list=server) result = nova_util.stop_instance(instance_id) self.assertTrue(result) + setattr(server, 'OS-EXT-STS:vm_state', 'active') + result = nova_util.stop_instance(instance_id) + self.assertFalse(result) + + self.fake_nova_find_list(nova_util, find=server, list=None) + + result = nova_util.stop_instance(instance_id) + self.assertFalse(result) + def test_set_host_offline(self, mock_glance, mock_cinder, mock_neutron, mock_nova): - nova_util = nova_helper.NovaHelper() host = mock.MagicMock() + nova_util = nova_helper.NovaHelper() nova_util.nova.hosts = mock.MagicMock() nova_util.nova.hosts.get.return_value = host result = nova_util.set_host_offline("rennes") self.assertTrue(result) + nova_util.nova.hosts.get.return_value = None + result = nova_util.set_host_offline("rennes") + self.assertFalse(result) + @mock.patch.object(time, 'sleep', mock.Mock()) def test_live_migrate_instance(self, mock_glance, mock_cinder, mock_neutron, mock_nova): nova_util = nova_helper.NovaHelper() - server = mock.MagicMock() - server.id = self.instance_uuid - nova_util.nova.servers = mock.MagicMock() - nova_util.nova.servers.list.return_value = [server] - instance = nova_util.live_migrate_instance( + server = self.fake_server(self.instance_uuid) + setattr(server, 'OS-EXT-SRV-ATTR:host', + self.destination_node) + self.fake_nova_find_list(nova_util, find=server, list=server) + is_success = nova_util.live_migrate_instance( self.instance_uuid, self.destination_node ) - self.assertIsNotNone(instance) + self.assertTrue(is_success) + + self.fake_nova_find_list(nova_util, find=server, list=None) + is_success = nova_util.live_migrate_instance( + self.instance_uuid, self.destination_node + ) + self.assertFalse(is_success) def test_watcher_non_live_migrate_instance_not_found( self, mock_glance, mock_cinder, mock_neutron, mock_nova): nova_util = nova_helper.NovaHelper() - nova_util.nova.servers.list.return_value = [] - nova_util.nova.servers.find.return_value = None + self.fake_nova_find_list(nova_util, find=None, list=None) is_success = nova_util.watcher_non_live_migrate_instance( self.instance_uuid, @@ -91,21 +123,35 @@ class TestNovaHelper(base.TestCase): def test_watcher_non_live_migrate_instance_volume( self, mock_glance, mock_cinder, mock_neutron, mock_nova): nova_util = nova_helper.NovaHelper() - instance = mock.MagicMock(id=self.instance_uuid) - setattr(instance, 'OS-EXT-SRV-ATTR:host', self.source_node) - nova_util.nova.servers.list.return_value = [instance] - nova_util.nova.servers.find.return_value = instance - instance = nova_util.watcher_non_live_migrate_instance( + nova_servers = nova_util.nova.servers + instance = self.fake_server(self.instance_uuid) + setattr(instance, 'OS-EXT-SRV-ATTR:host', + self.source_node) + setattr(instance, 'OS-EXT-STS:vm_state', "stopped") + attached_volumes = [{'id': str(utils.generate_uuid())}] + setattr(instance, "os-extended-volumes:volumes_attached", + attached_volumes) + self.fake_nova_find_list(nova_util, find=instance, list=instance) + nova_servers.create_image.return_value = utils.generate_uuid() + nova_util.glance.images.get.return_value = mock.MagicMock( + status='active') + nova_util.cinder.volumes.get.return_value = mock.MagicMock( + status='available') + + is_success = nova_util.watcher_non_live_migrate_instance( self.instance_uuid, self.destination_node) - self.assertIsNotNone(instance) + self.assertTrue(is_success) @mock.patch.object(time, 'sleep', mock.Mock()) def test_watcher_non_live_migrate_keep_image( self, mock_glance, mock_cinder, mock_neutron, mock_nova): nova_util = nova_helper.NovaHelper() - instance = mock.MagicMock(id=self.instance_uuid) - setattr(instance, 'OS-EXT-SRV-ATTR:host', self.source_node) + nova_servers = nova_util.nova.servers + instance = self.fake_server(self.instance_uuid) + setattr(instance, 'OS-EXT-SRV-ATTR:host', + self.source_node) + setattr(instance, 'OS-EXT-STS:vm_state', "stopped") addresses = mock.MagicMock() network_type = mock.MagicMock() networks = [] @@ -115,22 +161,24 @@ class TestNovaHelper(base.TestCase): setattr(instance, 'addresses', addresses) setattr(instance, "os-extended-volumes:volumes_attached", attached_volumes) - nova_util.nova.servers.list.return_value = [instance] - nova_util.nova.servers.find.return_value = instance - instance = nova_util.watcher_non_live_migrate_instance( + self.fake_nova_find_list(nova_util, find=instance, list=instance) + nova_servers.create_image.return_value = utils.generate_uuid() + nova_util.glance.images.get.return_value = mock.MagicMock( + status='active') + is_success = nova_util.watcher_non_live_migrate_instance( self.instance_uuid, self.destination_node, keep_original_image_name=False) - self.assertIsNotNone(instance) + self.assertTrue(is_success) @mock.patch.object(time, 'sleep', mock.Mock()) def test_create_image_from_instance(self, mock_glance, mock_cinder, mock_neutron, mock_nova): nova_util = nova_helper.NovaHelper() - instance = mock.MagicMock() + instance = self.fake_server(self.instance_uuid) image = mock.MagicMock() setattr(instance, 'OS-EXT-SRV-ATTR:host', self.source_node) - nova_util.nova.servers.list.return_value = [instance] - nova_util.nova.servers.find.return_value = instance + setattr(instance, 'OS-EXT-STS:vm_state', "stopped") + self.fake_nova_find_list(nova_util, find=instance, list=instance) image_uuid = 'fake-image-uuid' nova_util.nova.servers.create_image.return_value = image @@ -141,4 +189,66 @@ class TestNovaHelper(base.TestCase): instance = nova_util.create_image_from_instance( self.instance_uuid, "Cirros" ) + self.assertIsNotNone(instance) + + nova_util.glance.images.get.return_value = None + instance = nova_util.create_image_from_instance( + self.instance_uuid, "Cirros" + ) self.assertIsNone(instance) + + def test_enable_service_nova_compute(self, mock_glance, mock_cinder, + mock_neutron, mock_nova): + nova_util = nova_helper.NovaHelper() + nova_services = nova_util.nova.services + nova_services.enable.return_value = mock.MagicMock( + status='enabled') + + result = nova_util.enable_service_nova_compute('nanjing') + self.assertTrue(result) + + nova_services.enable.return_value = mock.MagicMock( + status='disabled') + + result = nova_util.enable_service_nova_compute('nanjing') + self.assertFalse(result) + + def test_disable_service_nova_compute(self, mock_glance, mock_cinder, + mock_neutron, mock_nova): + nova_util = nova_helper.NovaHelper() + nova_services = nova_util.nova.services + nova_services.disable.return_value = mock.MagicMock( + status='enabled') + + result = nova_util.disable_service_nova_compute('nanjing') + self.assertFalse(result) + + nova_services.disable.return_value = mock.MagicMock( + status='disabled') + + result = nova_util.disable_service_nova_compute('nanjing') + self.assertTrue(result) + + @mock.patch.object(time, 'sleep', mock.Mock()) + def test_create_instance(self, mock_glance, mock_cinder, + mock_neutron, mock_nova): + nova_util = nova_helper.NovaHelper() + instance = self.fake_server(self.instance_uuid) + nova_util.nova.services.create.return_value = instance + nova_util.nova.services.get.return_value = instance + + instance = nova_util.create_instance(self.source_node) + self.assertIsNotNone(instance) + + def test_get_flavor_instance(self, mock_glance, mock_cinder, + mock_neutron, mock_nova): + nova_util = nova_helper.NovaHelper() + instance = self.fake_server(self.instance_uuid) + flavor = {'id': 1, 'name': 'm1.tiny', 'ram': 512, 'vcpus': 1, + 'disk': 0, 'ephemeral': 0} + instance.flavor = flavor + nova_util.nova.flavors.get.return_value = flavor + cache = flavor + + nova_util.get_flavor_instance(instance, cache) + self.assertEqual(instance.flavor['name'], cache['name'])