nova/nova/tests/unit/compute/test_virtapi.py

234 lines
8.7 KiB
Python

# Copyright 2012 IBM Corp.
#
# 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 collections
import mock
import os_traits
from oslo_utils.fixture import uuidsentinel as uuids
from nova.compute import manager as compute_manager
from nova import context as nova_context
from nova import exception
from nova import objects
from nova.scheduler.client import report
from nova import test
from nova.virt import fake
from nova.virt import virtapi
class VirtAPIBaseTest(test.NoDBTestCase, test.APICoverage):
cover_api = virtapi.VirtAPI
def setUp(self):
super(VirtAPIBaseTest, self).setUp()
self.set_up_virtapi()
def set_up_virtapi(self):
self.virtapi = virtapi.VirtAPI()
def assertExpected(self, method, *args, **kwargs):
self.assertRaises(NotImplementedError,
getattr(self.virtapi, method),
*args, **kwargs)
def test_wait_for_instance_event(self):
self.assertExpected('wait_for_instance_event',
'instance', ['event'])
def test_exit_wait_early(self):
self.assertExpected('exit_wait_early', [])
def test_update_compute_provider_status(self):
self.assertExpected('update_compute_provider_status',
nova_context.get_admin_context(), uuids.rp_uuid,
enabled=False)
class FakeVirtAPITest(VirtAPIBaseTest):
cover_api = fake.FakeVirtAPI
def set_up_virtapi(self):
self.virtapi = fake.FakeVirtAPI()
def assertExpected(self, method, *args, **kwargs):
if method == 'wait_for_instance_event':
run = False
with self.virtapi.wait_for_instance_event(*args, **kwargs):
run = True
self.assertTrue(run)
elif method == 'exit_wait_early':
self.virtapi.exit_wait_early(*args, **kwargs)
elif method == 'update_compute_provider_status':
self.virtapi.update_compute_provider_status(*args, **kwargs)
else:
self.fail("Unhandled FakeVirtAPI method: %s" % method)
class FakeCompute(object):
def __init__(self):
self.conductor_api = mock.MagicMock()
self.db = mock.MagicMock()
self._events = []
self.instance_events = mock.MagicMock()
self.instance_events.prepare_for_instance_event.side_effect = \
self._prepare_for_instance_event
self.reportclient = mock.Mock(spec=report.SchedulerReportClient)
# Keep track of the traits set on each provider in the test.
self.provider_traits = collections.defaultdict(set)
self.reportclient.get_provider_traits.side_effect = (
self._get_provider_traits)
self.reportclient.set_traits_for_provider.side_effect = (
self._set_traits_for_provider)
def _get_provider_traits(self, context, rp_uuid):
return mock.Mock(traits=self.provider_traits[rp_uuid])
def _set_traits_for_provider(
self, context, rp_uuid, traits, generation=None):
self.provider_traits[rp_uuid] = traits
def _event_waiter(self):
event = mock.MagicMock()
event.status = 'completed'
return event
def _prepare_for_instance_event(self, instance, name, tag):
m = mock.MagicMock()
m.instance = instance
m.name = name
m.tag = tag
m.event_name = '%s-%s' % (name, tag)
m.wait.side_effect = self._event_waiter
self._events.append(m)
return m
class ComputeVirtAPITest(VirtAPIBaseTest):
cover_api = compute_manager.ComputeVirtAPI
def set_up_virtapi(self):
self.compute = FakeCompute()
self.virtapi = compute_manager.ComputeVirtAPI(self.compute)
def test_exit_wait_early(self):
self.assertRaises(self.virtapi._exit_early_exc,
self.virtapi.exit_wait_early,
[('foo', 'bar'),
('foo', 'baz')])
def test_wait_for_instance_event(self):
and_i_ran = ''
event_1_tag = objects.InstanceExternalEvent.make_key(
'event1')
event_2_tag = objects.InstanceExternalEvent.make_key(
'event2', 'tag')
events = {
('event1', None): event_1_tag,
('event2', 'tag'): event_2_tag,
}
with self.virtapi.wait_for_instance_event('instance', events.keys()):
and_i_ran = 'I ran so far a-waa-y'
self.assertEqual('I ran so far a-waa-y', and_i_ran)
self.assertEqual(2, len(self.compute._events))
for event in self.compute._events:
self.assertEqual('instance', event.instance)
self.assertIn((event.name, event.tag), events.keys())
event.wait.assert_called_once_with()
def test_wait_for_instance_event_failed(self):
def _failer():
event = mock.MagicMock()
event.status = 'failed'
return event
@mock.patch.object(self.virtapi._compute, '_event_waiter', _failer)
def do_test():
with self.virtapi.wait_for_instance_event('instance',
[('foo', 'bar')]):
pass
self.assertRaises(exception.NovaException, do_test)
def test_wait_for_instance_event_failed_callback(self):
def _failer():
event = mock.MagicMock()
event.status = 'failed'
return event
@mock.patch.object(self.virtapi._compute, '_event_waiter', _failer)
def do_test():
callback = mock.MagicMock()
with self.virtapi.wait_for_instance_event('instance',
[('foo', None)],
error_callback=callback):
pass
callback.assert_called_with('foo', 'instance')
do_test()
def test_wait_for_instance_event_timeout(self):
@mock.patch.object(self.virtapi._compute, '_event_waiter',
side_effect=test.TestingException())
@mock.patch('eventlet.timeout.Timeout')
def do_test(mock_timeout, mock_waiter):
with self.virtapi.wait_for_instance_event('instance',
[('foo', 'bar')]):
pass
self.assertRaises(test.TestingException, do_test)
def test_wait_for_instance_event_exit_early(self):
# Wait for two events, exit early skipping one.
# Make sure we waited for one and did not wait for the other
with self.virtapi.wait_for_instance_event('instance',
[('foo', 'bar'),
('foo', 'baz')]):
self.virtapi.exit_wait_early([('foo', 'baz')])
self.fail('never gonna happen')
self.assertEqual(2, len(self.compute._events))
for event in self.compute._events:
if event.tag == 'bar':
event.wait.assert_called_once_with()
else:
event.wait.assert_not_called()
def test_update_compute_provider_status(self):
"""Tests scenarios for adding/removing the COMPUTE_STATUS_DISABLED
trait on a given compute node resource provider.
"""
ctxt = nova_context.get_admin_context()
# Start by adding the trait to a disabled provider.
self.assertNotIn(uuids.rp_uuid, self.compute.provider_traits)
self.virtapi.update_compute_provider_status(
ctxt, uuids.rp_uuid, enabled=False)
self.assertEqual({os_traits.COMPUTE_STATUS_DISABLED},
self.compute.provider_traits[uuids.rp_uuid])
# Now run it again to make sure nothing changed.
with mock.patch.object(self.compute.reportclient,
'set_traits_for_provider',
new_callable=mock.NonCallableMock):
self.virtapi.update_compute_provider_status(
ctxt, uuids.rp_uuid, enabled=False)
# Now enable the provider and make sure the trait is removed.
self.virtapi.update_compute_provider_status(
ctxt, uuids.rp_uuid, enabled=True)
self.assertEqual(set(), self.compute.provider_traits[uuids.rp_uuid])