d6e7552457
Python3 have a standard library for mock in the unittest module, let's drop the mock requirement and switch tests to unittest mock. Change-Id: I4f1b3e25c8adbc24cdda51c73da3b66967f7ef23
558 lines
24 KiB
Python
558 lines
24 KiB
Python
# 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.
|
|
|
|
"""Test class for Ironic BaseConductorManager."""
|
|
|
|
import collections
|
|
from unittest import mock
|
|
import uuid
|
|
|
|
import eventlet
|
|
import futurist
|
|
from futurist import periodics
|
|
from ironic_lib import mdns
|
|
from oslo_config import cfg
|
|
from oslo_db import exception as db_exception
|
|
from oslo_utils import uuidutils
|
|
|
|
from ironic.common import driver_factory
|
|
from ironic.common import exception
|
|
from ironic.common import states
|
|
from ironic.conductor import base_manager
|
|
from ironic.conductor import manager
|
|
from ironic.conductor import notification_utils
|
|
from ironic.conductor import task_manager
|
|
from ironic.drivers import fake_hardware
|
|
from ironic.drivers import generic
|
|
from ironic.drivers.modules import deploy_utils
|
|
from ironic.drivers.modules import fake
|
|
from ironic import objects
|
|
from ironic.objects import fields
|
|
from ironic.tests import base as tests_base
|
|
from ironic.tests.unit.conductor import mgr_utils
|
|
from ironic.tests.unit.db import base as db_base
|
|
from ironic.tests.unit.objects import utils as obj_utils
|
|
|
|
|
|
CONF = cfg.CONF
|
|
|
|
|
|
@mgr_utils.mock_record_keepalive
|
|
class StartStopTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
|
|
def test_start_registers_conductor(self):
|
|
self.assertRaises(exception.ConductorNotFound,
|
|
objects.Conductor.get_by_hostname,
|
|
self.context, self.hostname)
|
|
self._start_service()
|
|
res = objects.Conductor.get_by_hostname(self.context, self.hostname)
|
|
self.assertEqual(self.hostname, res['hostname'])
|
|
|
|
def test_start_clears_conductor_locks(self):
|
|
node = obj_utils.create_test_node(self.context,
|
|
reservation=self.hostname)
|
|
node.save()
|
|
self._start_service()
|
|
node.refresh()
|
|
self.assertIsNone(node.reservation)
|
|
|
|
def test_stop_clears_conductor_locks(self):
|
|
node = obj_utils.create_test_node(self.context,
|
|
reservation=self.hostname)
|
|
node.save()
|
|
self._start_service()
|
|
res = objects.Conductor.get_by_hostname(self.context, self.hostname)
|
|
self.assertEqual(self.hostname, res['hostname'])
|
|
self.service.del_host()
|
|
node.refresh()
|
|
self.assertIsNone(node.reservation)
|
|
|
|
def test_stop_unregisters_conductor(self):
|
|
self._start_service()
|
|
res = objects.Conductor.get_by_hostname(self.context, self.hostname)
|
|
self.assertEqual(self.hostname, res['hostname'])
|
|
self.service.del_host()
|
|
self.assertRaises(exception.ConductorNotFound,
|
|
objects.Conductor.get_by_hostname,
|
|
self.context, self.hostname)
|
|
|
|
def test_stop_doesnt_unregister_conductor(self):
|
|
self._start_service()
|
|
res = objects.Conductor.get_by_hostname(self.context, self.hostname)
|
|
self.assertEqual(self.hostname, res['hostname'])
|
|
self.service.del_host(deregister=False)
|
|
res = objects.Conductor.get_by_hostname(self.context, self.hostname)
|
|
self.assertEqual(self.hostname, res['hostname'])
|
|
|
|
@mock.patch.object(manager.ConductorManager, 'init_host')
|
|
def test_stop_uninitialized_conductor(self, mock_init):
|
|
self._start_service()
|
|
self.service.del_host()
|
|
|
|
@mock.patch.object(driver_factory.HardwareTypesFactory, '__getitem__',
|
|
lambda *args: mock.MagicMock())
|
|
@mock.patch.object(driver_factory, 'default_interface', autospec=True)
|
|
def test_start_registers_driver_names(self, mock_def_iface):
|
|
init_names = ['fake1', 'fake2']
|
|
restart_names = ['fake3', 'fake4']
|
|
|
|
mock_def_iface.return_value = 'fake'
|
|
|
|
df = driver_factory.HardwareTypesFactory()
|
|
with mock.patch.object(df._extension_manager, 'names') as mock_names:
|
|
# verify driver names are registered
|
|
self.config(enabled_hardware_types=init_names)
|
|
mock_names.return_value = init_names
|
|
self._start_service()
|
|
res = objects.Conductor.get_by_hostname(self.context,
|
|
self.hostname)
|
|
self.assertEqual(init_names, res['drivers'])
|
|
self._stop_service()
|
|
|
|
# verify that restart registers new driver names
|
|
self.config(enabled_hardware_types=restart_names)
|
|
mock_names.return_value = restart_names
|
|
self._start_service()
|
|
res = objects.Conductor.get_by_hostname(self.context,
|
|
self.hostname)
|
|
self.assertEqual(restart_names, res['drivers'])
|
|
|
|
@mock.patch.object(base_manager.BaseConductorManager,
|
|
'_register_and_validate_hardware_interfaces',
|
|
autospec=True)
|
|
@mock.patch.object(driver_factory, 'all_interfaces', autospec=True)
|
|
@mock.patch.object(driver_factory, 'hardware_types', autospec=True)
|
|
def test_start_registers_driver_specific_tasks(self,
|
|
mock_hw_types, mock_ifaces,
|
|
mock_reg_hw_ifaces):
|
|
class TestHwType(generic.GenericHardware):
|
|
@property
|
|
def supported_management_interfaces(self):
|
|
return []
|
|
|
|
@property
|
|
def supported_power_interfaces(self):
|
|
return []
|
|
|
|
# This should not be collected, since we don't collect periodic
|
|
# tasks from hardware types
|
|
@periodics.periodic(spacing=100500)
|
|
def task(self):
|
|
pass
|
|
|
|
class TestInterface(object):
|
|
@periodics.periodic(spacing=100500)
|
|
def iface(self):
|
|
pass
|
|
|
|
class TestInterface2(object):
|
|
@periodics.periodic(spacing=100500)
|
|
def iface(self):
|
|
pass
|
|
|
|
hw_type = TestHwType()
|
|
iface1 = TestInterface()
|
|
iface2 = TestInterface2()
|
|
expected = [iface1.iface, iface2.iface]
|
|
|
|
mock_hw_types.return_value = {'fake1': hw_type}
|
|
mock_ifaces.return_value = {
|
|
'management': {'fake1': iface1},
|
|
'power': {'fake2': iface2}
|
|
}
|
|
|
|
self._start_service(start_periodic_tasks=True)
|
|
|
|
tasks = {c[0] for c in self.service._periodic_task_callables}
|
|
for item in expected:
|
|
self.assertTrue(periodics.is_periodic(item))
|
|
self.assertIn(item, tasks)
|
|
|
|
# no periodic tasks from the hardware type
|
|
self.assertTrue(periodics.is_periodic(hw_type.task))
|
|
self.assertNotIn(hw_type.task, tasks)
|
|
|
|
@mock.patch.object(driver_factory.HardwareTypesFactory, '__init__')
|
|
def test_start_fails_on_missing_driver(self, mock_df):
|
|
mock_df.side_effect = exception.DriverNotFound('test')
|
|
with mock.patch.object(self.dbapi, 'register_conductor') as mock_reg:
|
|
self.assertRaises(exception.DriverNotFound,
|
|
self.service.init_host)
|
|
self.assertTrue(mock_df.called)
|
|
self.assertFalse(mock_reg.called)
|
|
|
|
def test_start_fails_on_no_enabled_interfaces(self):
|
|
self.config(enabled_boot_interfaces=[])
|
|
self.assertRaisesRegex(exception.ConfigInvalid,
|
|
'options enabled_boot_interfaces',
|
|
self.service.init_host)
|
|
|
|
@mock.patch.object(base_manager, 'LOG')
|
|
@mock.patch.object(driver_factory, 'HardwareTypesFactory')
|
|
def test_start_fails_on_hw_types(self, ht_mock, log_mock):
|
|
driver_factory_mock = mock.MagicMock(names=[])
|
|
ht_mock.return_value = driver_factory_mock
|
|
self.assertRaises(exception.NoDriversLoaded,
|
|
self.service.init_host)
|
|
self.assertTrue(log_mock.error.called)
|
|
ht_mock.assert_called_once_with()
|
|
|
|
@mock.patch.object(base_manager, 'LOG')
|
|
@mock.patch.object(base_manager.BaseConductorManager,
|
|
'_register_and_validate_hardware_interfaces')
|
|
@mock.patch.object(base_manager.BaseConductorManager, 'del_host')
|
|
def test_start_fails_hw_type_register(self, del_mock, reg_mock, log_mock):
|
|
reg_mock.side_effect = exception.DriverNotFound('hw-type')
|
|
self.assertRaises(exception.DriverNotFound,
|
|
self.service.init_host)
|
|
self.assertTrue(log_mock.error.called)
|
|
del_mock.assert_called_once_with()
|
|
|
|
def test_prevent_double_start(self):
|
|
self._start_service()
|
|
self.assertRaisesRegex(RuntimeError, 'already running',
|
|
self.service.init_host)
|
|
|
|
def test_start_recover_nodes_stuck(self):
|
|
state_trans = [
|
|
(states.DEPLOYING, states.DEPLOYFAIL),
|
|
(states.CLEANING, states.CLEANFAIL),
|
|
(states.VERIFYING, states.ENROLL),
|
|
(states.INSPECTING, states.INSPECTFAIL),
|
|
(states.ADOPTING, states.ADOPTFAIL),
|
|
(states.RESCUING, states.RESCUEFAIL),
|
|
(states.UNRESCUING, states.UNRESCUEFAIL),
|
|
]
|
|
nodes = [obj_utils.create_test_node(self.context, uuid=uuid.uuid4(),
|
|
driver='fake-hardware',
|
|
provision_state=state[0])
|
|
for state in state_trans]
|
|
|
|
self._start_service()
|
|
for node, state in zip(nodes, state_trans):
|
|
node.refresh()
|
|
self.assertEqual(state[1], node.provision_state,
|
|
'Test failed when recovering from %s' % state[0])
|
|
|
|
@mock.patch.object(base_manager, 'LOG')
|
|
def test_warning_on_low_workers_pool(self, log_mock):
|
|
CONF.set_override('workers_pool_size', 3, 'conductor')
|
|
self._start_service()
|
|
self.assertTrue(log_mock.warning.called)
|
|
|
|
@mock.patch.object(eventlet.greenpool.GreenPool, 'waitall')
|
|
def test_del_host_waits_on_workerpool(self, wait_mock):
|
|
self._start_service()
|
|
self.service.del_host()
|
|
self.assertTrue(wait_mock.called)
|
|
|
|
def test_conductor_shutdown_flag(self):
|
|
self._start_service()
|
|
self.assertFalse(self.service._shutdown)
|
|
self.service.del_host()
|
|
self.assertTrue(self.service._shutdown)
|
|
|
|
@mock.patch.object(deploy_utils, 'get_ironic_api_url', autospec=True)
|
|
@mock.patch.object(mdns, 'Zeroconf', autospec=True)
|
|
def test_start_with_mdns(self, mock_zc, mock_api_url):
|
|
CONF.set_override('debug', False)
|
|
CONF.set_override('enable_mdns', True, 'conductor')
|
|
self._start_service()
|
|
res = objects.Conductor.get_by_hostname(self.context, self.hostname)
|
|
self.assertEqual(self.hostname, res['hostname'])
|
|
mock_zc.return_value.register_service.assert_called_once_with(
|
|
'baremetal',
|
|
mock_api_url.return_value,
|
|
params={})
|
|
|
|
@mock.patch.object(deploy_utils, 'get_ironic_api_url', autospec=True)
|
|
@mock.patch.object(mdns, 'Zeroconf', autospec=True)
|
|
def test_start_with_mdns_and_debug(self, mock_zc, mock_api_url):
|
|
CONF.set_override('debug', True)
|
|
CONF.set_override('enable_mdns', True, 'conductor')
|
|
self._start_service()
|
|
res = objects.Conductor.get_by_hostname(self.context, self.hostname)
|
|
self.assertEqual(self.hostname, res['hostname'])
|
|
mock_zc.return_value.register_service.assert_called_once_with(
|
|
'baremetal',
|
|
mock_api_url.return_value,
|
|
params={'ipa_debug': True})
|
|
|
|
def test_del_host_with_mdns(self):
|
|
mock_zc = mock.Mock(spec=mdns.Zeroconf)
|
|
self.service._zeroconf = mock_zc
|
|
self._start_service()
|
|
self.service.del_host()
|
|
mock_zc.close.assert_called_once_with()
|
|
self.assertIsNone(self.service._zeroconf)
|
|
|
|
|
|
class CheckInterfacesTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
|
|
def test__check_enabled_interfaces_success(self):
|
|
base_manager._check_enabled_interfaces()
|
|
|
|
def test__check_enabled_interfaces_failure(self):
|
|
self.config(enabled_boot_interfaces=[])
|
|
self.assertRaisesRegex(exception.ConfigInvalid,
|
|
'options enabled_boot_interfaces',
|
|
base_manager._check_enabled_interfaces)
|
|
|
|
|
|
class KeepAliveTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
|
|
def test__conductor_service_record_keepalive(self):
|
|
self._start_service()
|
|
# avoid wasting time at the event.wait()
|
|
CONF.set_override('heartbeat_interval', 0, 'conductor')
|
|
with mock.patch.object(self.dbapi, 'touch_conductor') as mock_touch:
|
|
with mock.patch.object(self.service._keepalive_evt,
|
|
'is_set') as mock_is_set:
|
|
mock_is_set.side_effect = [False, True]
|
|
self.service._conductor_service_record_keepalive()
|
|
mock_touch.assert_called_once_with(self.hostname)
|
|
|
|
def test__conductor_service_record_keepalive_failed_db_conn(self):
|
|
self._start_service()
|
|
# avoid wasting time at the event.wait()
|
|
CONF.set_override('heartbeat_interval', 0, 'conductor')
|
|
with mock.patch.object(self.dbapi, 'touch_conductor') as mock_touch:
|
|
mock_touch.side_effect = [None, db_exception.DBConnectionError(),
|
|
None]
|
|
with mock.patch.object(self.service._keepalive_evt,
|
|
'is_set') as mock_is_set:
|
|
mock_is_set.side_effect = [False, False, False, True]
|
|
self.service._conductor_service_record_keepalive()
|
|
self.assertEqual(3, mock_touch.call_count)
|
|
|
|
def test__conductor_service_record_keepalive_failed_error(self):
|
|
self._start_service()
|
|
# avoid wasting time at the event.wait()
|
|
CONF.set_override('heartbeat_interval', 0, 'conductor')
|
|
with mock.patch.object(self.dbapi, 'touch_conductor') as mock_touch:
|
|
mock_touch.side_effect = [None, Exception(),
|
|
None]
|
|
with mock.patch.object(self.service._keepalive_evt,
|
|
'is_set') as mock_is_set:
|
|
mock_is_set.side_effect = [False, False, False, True]
|
|
self.service._conductor_service_record_keepalive()
|
|
self.assertEqual(3, mock_touch.call_count)
|
|
|
|
|
|
class ManagerSpawnWorkerTestCase(tests_base.TestCase):
|
|
def setUp(self):
|
|
super(ManagerSpawnWorkerTestCase, self).setUp()
|
|
self.service = manager.ConductorManager('hostname', 'test-topic')
|
|
self.executor = mock.Mock(spec=futurist.GreenThreadPoolExecutor)
|
|
self.service._executor = self.executor
|
|
|
|
def test__spawn_worker(self):
|
|
self.service._spawn_worker('fake', 1, 2, foo='bar', cat='meow')
|
|
|
|
self.executor.submit.assert_called_once_with(
|
|
'fake', 1, 2, foo='bar', cat='meow')
|
|
|
|
def test__spawn_worker_none_free(self):
|
|
self.executor.submit.side_effect = futurist.RejectedSubmission()
|
|
|
|
self.assertRaises(exception.NoFreeConductorWorker,
|
|
self.service._spawn_worker, 'fake')
|
|
|
|
|
|
@mock.patch.object(objects.Conductor, 'unregister_all_hardware_interfaces',
|
|
autospec=True)
|
|
@mock.patch.object(objects.Conductor, 'register_hardware_interfaces',
|
|
autospec=True)
|
|
@mock.patch.object(driver_factory, 'default_interface', autospec=True)
|
|
@mock.patch.object(driver_factory, 'enabled_supported_interfaces',
|
|
autospec=True)
|
|
@mgr_utils.mock_record_keepalive
|
|
class RegisterInterfacesTestCase(mgr_utils.ServiceSetUpMixin,
|
|
db_base.DbTestCase):
|
|
def setUp(self):
|
|
super(RegisterInterfacesTestCase, self).setUp()
|
|
self._start_service()
|
|
|
|
def test__register_and_validate_hardware_interfaces(self,
|
|
esi_mock,
|
|
default_mock,
|
|
reg_mock,
|
|
unreg_mock):
|
|
# these must be same order as esi_mock side effect
|
|
hardware_types = collections.OrderedDict((
|
|
('fake-hardware', fake_hardware.FakeHardware()),
|
|
('manual-management', generic.ManualManagementHardware),
|
|
))
|
|
esi_mock.side_effect = [
|
|
collections.OrderedDict((
|
|
('management', ['fake', 'noop']),
|
|
('deploy', ['agent', 'iscsi']),
|
|
)),
|
|
collections.OrderedDict((
|
|
('management', ['fake']),
|
|
('deploy', ['agent', 'fake']),
|
|
)),
|
|
]
|
|
default_mock.side_effect = ('fake', 'agent', 'fake', 'agent')
|
|
expected_calls = [
|
|
mock.call(mock.ANY, 'fake-hardware', 'management',
|
|
['fake', 'noop'], 'fake'),
|
|
mock.call(mock.ANY, 'fake-hardware', 'deploy', ['agent', 'iscsi'],
|
|
'agent'),
|
|
mock.call(mock.ANY, 'manual-management', 'management', ['fake'],
|
|
'fake'),
|
|
mock.call(mock.ANY, 'manual-management', 'deploy',
|
|
['agent', 'fake'], 'agent'),
|
|
]
|
|
|
|
self.service._register_and_validate_hardware_interfaces(hardware_types)
|
|
|
|
unreg_mock.assert_called_once_with(mock.ANY)
|
|
# we're iterating over dicts, don't worry about order
|
|
reg_mock.assert_has_calls(expected_calls)
|
|
|
|
def test__register_and_validate_no_valid_default(self,
|
|
esi_mock,
|
|
default_mock,
|
|
reg_mock,
|
|
unreg_mock):
|
|
# these must be same order as esi_mock side effect
|
|
hardware_types = collections.OrderedDict((
|
|
('fake-hardware', fake_hardware.FakeHardware()),
|
|
))
|
|
esi_mock.side_effect = [
|
|
collections.OrderedDict((
|
|
('management', ['fake', 'noop']),
|
|
('deploy', ['agent', 'iscsi']),
|
|
)),
|
|
]
|
|
default_mock.side_effect = exception.NoValidDefaultForInterface("boo")
|
|
|
|
self.assertRaises(
|
|
exception.NoValidDefaultForInterface,
|
|
self.service._register_and_validate_hardware_interfaces,
|
|
hardware_types)
|
|
|
|
default_mock.assert_called_once_with(
|
|
hardware_types['fake-hardware'],
|
|
mock.ANY, driver_name='fake-hardware')
|
|
unreg_mock.assert_called_once_with(mock.ANY)
|
|
self.assertFalse(reg_mock.called)
|
|
|
|
|
|
@mock.patch.object(fake.FakeConsole, 'start_console', autospec=True)
|
|
@mock.patch.object(notification_utils, 'emit_console_notification')
|
|
class StartConsolesTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
|
|
def test__start_consoles(self, mock_notify, mock_start_console):
|
|
obj_utils.create_test_node(self.context,
|
|
driver='fake-hardware',
|
|
console_enabled=True)
|
|
obj_utils.create_test_node(
|
|
self.context,
|
|
uuid=uuidutils.generate_uuid(),
|
|
driver='fake-hardware',
|
|
console_enabled=True
|
|
)
|
|
obj_utils.create_test_node(
|
|
self.context,
|
|
uuid=uuidutils.generate_uuid(),
|
|
driver='fake-hardware'
|
|
)
|
|
self._start_service()
|
|
self.service._start_consoles(self.context)
|
|
self.assertEqual(2, mock_start_console.call_count)
|
|
mock_notify.assert_has_calls(
|
|
[mock.call(mock.ANY, 'console_restore',
|
|
fields.NotificationStatus.START),
|
|
mock.call(mock.ANY, 'console_restore',
|
|
fields.NotificationStatus.END)])
|
|
|
|
def test__start_consoles_no_console_enabled(self, mock_notify,
|
|
mock_start_console):
|
|
obj_utils.create_test_node(self.context,
|
|
driver='fake-hardware',
|
|
console_enabled=False)
|
|
self._start_service()
|
|
self.service._start_consoles(self.context)
|
|
self.assertFalse(mock_start_console.called)
|
|
self.assertFalse(mock_notify.called)
|
|
|
|
def test__start_consoles_failed(self, mock_notify, mock_start_console):
|
|
test_node = obj_utils.create_test_node(self.context,
|
|
driver='fake-hardware',
|
|
console_enabled=True)
|
|
self._start_service()
|
|
mock_start_console.side_effect = Exception()
|
|
self.service._start_consoles(self.context)
|
|
mock_start_console.assert_called_once_with(mock.ANY, mock.ANY)
|
|
test_node.refresh()
|
|
self.assertFalse(test_node.console_enabled)
|
|
self.assertIsNotNone(test_node.last_error)
|
|
mock_notify.assert_has_calls(
|
|
[mock.call(mock.ANY, 'console_restore',
|
|
fields.NotificationStatus.START),
|
|
mock.call(mock.ANY, 'console_restore',
|
|
fields.NotificationStatus.ERROR)])
|
|
|
|
@mock.patch.object(base_manager, 'LOG')
|
|
def test__start_consoles_node_locked(self, log_mock, mock_notify,
|
|
mock_start_console):
|
|
test_node = obj_utils.create_test_node(self.context,
|
|
driver='fake-hardware',
|
|
console_enabled=True,
|
|
reservation='fake-host')
|
|
self._start_service()
|
|
self.service._start_consoles(self.context)
|
|
self.assertFalse(mock_start_console.called)
|
|
test_node.refresh()
|
|
self.assertTrue(test_node.console_enabled)
|
|
self.assertIsNone(test_node.last_error)
|
|
self.assertTrue(log_mock.warning.called)
|
|
self.assertFalse(mock_notify.called)
|
|
|
|
@mock.patch.object(base_manager, 'LOG')
|
|
def test__start_consoles_node_not_found(self, log_mock, mock_notify,
|
|
mock_start_console):
|
|
test_node = obj_utils.create_test_node(self.context,
|
|
driver='fake-hardware',
|
|
console_enabled=True)
|
|
self._start_service()
|
|
with mock.patch.object(task_manager, 'acquire') as mock_acquire:
|
|
mock_acquire.side_effect = exception.NodeNotFound(node='not found')
|
|
self.service._start_consoles(self.context)
|
|
self.assertFalse(mock_start_console.called)
|
|
test_node.refresh()
|
|
self.assertTrue(test_node.console_enabled)
|
|
self.assertIsNone(test_node.last_error)
|
|
self.assertTrue(log_mock.warning.called)
|
|
self.assertFalse(mock_notify.called)
|
|
|
|
|
|
class MiscTestCase(mgr_utils.ServiceSetUpMixin, db_base.DbTestCase):
|
|
def setUp(self):
|
|
super(MiscTestCase, self).setUp()
|
|
self._start_service()
|
|
|
|
def test__fail_transient_state(self):
|
|
node = obj_utils.create_test_node(self.context,
|
|
driver='fake-hardware',
|
|
provision_state=states.DEPLOYING)
|
|
self.service._fail_transient_state(states.DEPLOYING, 'unknown err')
|
|
node.refresh()
|
|
self.assertEqual(states.DEPLOYFAIL, node.provision_state)
|
|
|
|
def test__fail_transient_state_maintenance(self):
|
|
node = obj_utils.create_test_node(self.context,
|
|
driver='fake-hardware',
|
|
maintenance=True,
|
|
provision_state=states.DEPLOYING)
|
|
self.service._fail_transient_state(states.DEPLOYING, 'unknown err')
|
|
node.refresh()
|
|
self.assertEqual(states.DEPLOYFAIL, node.provision_state)
|