diff --git a/magnum/conductor/api.py b/magnum/conductor/api.py index 0dca1a89e2..b33d4cad96 100644 --- a/magnum/conductor/api.py +++ b/magnum/conductor/api.py @@ -22,9 +22,10 @@ from magnum import objects # API to trigger operations on the conductors class API(rpc_service.API): - def __init__(self, transport=None, context=None): - cfg.CONF.import_opt('topic', 'magnum.conductor.config', - group='conductor') + def __init__(self, transport=None, context=None, topic=None): + if topic is None: + cfg.CONF.import_opt('topic', 'magnum.conductor.config', + group='conductor') super(API, self).__init__(transport, context, topic=cfg.CONF.conductor.topic) diff --git a/magnum/tests/conductor/test_rpcapi.py b/magnum/tests/conductor/test_rpcapi.py new file mode 100644 index 0000000000..618b1fba8e --- /dev/null +++ b/magnum/tests/conductor/test_rpcapi.py @@ -0,0 +1,123 @@ +# 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. +""" +Unit Tests for :py:class:`magnum.conductor.rpcapi.API`. +""" + +import copy + +import mock + +from magnum.conductor import api as conductor_rpcapi +from magnum.tests.db import base +from magnum.tests.db import utils as dbutils + + +class RPCAPITestCase(base.DbTestCase): + + def setUp(self): + super(RPCAPITestCase, self).setUp() + self.fake_bay = dbutils.get_test_bay(driver='fake-driver') + self.fake_pod = dbutils.get_test_pod(driver='fake-driver') + self.fake_rc = dbutils.get_test_rc(driver='fake-driver') + self.fake_service = dbutils.get_test_service(driver='fake-driver') + + def _test_rpcapi(self, method, rpc_method, **kwargs): + rpcapi = conductor_rpcapi.API(topic='fake-topic') + + expected_retval = 'hello world' if rpc_method == 'call' else None + + expected_topic = 'fake-topic' + if 'host' in kwargs: + expected_topic += ".%s" % kwargs['host'] + + target = { + "topic": expected_topic, + "version": kwargs.pop('version', 1.0) + } + expected_msg = copy.deepcopy(kwargs) + + self.fake_args = None + self.fake_kwargs = None + + def _fake_prepare_method(*args, **kwargs): + for kwd in kwargs: + self.assertEqual(kwargs[kwd], target[kwd]) + return rpcapi._client + + def _fake_rpc_method(*args, **kwargs): + self.fake_args = args + self.fake_kwargs = kwargs + if expected_retval: + return expected_retval + + with mock.patch.object(rpcapi._client, "prepare") as mock_prepared: + mock_prepared.side_effect = _fake_prepare_method + + with mock.patch.object(rpcapi._client, rpc_method) as mock_method: + mock_method.side_effect = _fake_rpc_method + retval = getattr(rpcapi, method)(**kwargs) + self.assertEqual(retval, expected_retval) + expected_args = [None, method, expected_msg] + for arg, expected_arg in zip(self.fake_args, expected_args): + self.assertEqual(arg, expected_arg) + + def test_bay_create(self): + self._test_rpcapi('bay_create', + 'call', + version='1.0', + bay=self.fake_bay) + + def test_bay_delete(self): + self._test_rpcapi('bay_delete', + 'call', + version='1.0', + uuid=self.fake_bay['uuid']) + + def test_service_create(self): + self._test_rpcapi('service_create', + 'call', + version='1.0', + service=self.fake_service) + + # TODO(sdake) the parameters to delete operations are highly suspect + def test_service_delete(self): + self._test_rpcapi('service_delete', + 'call', + version='1.0', + service=self.fake_service) + + def test_pod_create(self): + self._test_rpcapi('pod_create', + 'call', + version='1.0', + pod=self.fake_pod) + + # TODO(sdake) the parameters to delete operations are highly suspect + def test_pod_delete(self): + self._test_rpcapi('pod_delete', + 'call', + version='1.0', + pod=self.fake_pod) + + def test_rc_create(self): + self._test_rpcapi('rc_create', + 'call', + version='1.0', + rc=self.fake_rc) + + # TODO(sdake) the parameters to delete operations are highly suspect + def test_rc_delete(self): + self._test_rpcapi('rc_delete', + 'call', + version='1.0', + rc=self.fake_rc) diff --git a/magnum/tests/db/utils.py b/magnum/tests/db/utils.py index 9be1687963..754f104eed 100644 --- a/magnum/tests/db/utils.py +++ b/magnum/tests/db/utils.py @@ -119,4 +119,34 @@ def create_test_service(**kw): if 'id' not in kw: del service['id'] dbapi = db_api.get_instance() - return dbapi.create_service(service) \ No newline at end of file + return dbapi.create_service(service) + + +def get_test_rc(**kw): + return { + 'id': kw.get('id', 42), + 'uuid': kw.get('uuid', '10a47dd1-4874-4298-91cf-eff046dbdb8d'), + 'name': kw.get('name', 'service1'), + 'images': kw.get('images', ['steak/for-dinner']), + 'bay_uuid': kw.get('bay_uuid', '10a47dd1-4874-4298-91cf-eff046dbdb8e'), + 'selector': kw.get('selector', {'name': 'foo'}), + 'replicas': kw.get('replicas', 3), + 'rc_definition_url': kw.get('file:///tmp/rc.yaml'), + 'created_at': kw.get('created_at'), + 'updated_at': kw.get('updated_at'), + } + + +def create_test_rc(**kw): + """Create test rc entry in DB and return ReplicationController DB object. + Function to be used to create test ReplicationController objects in the + database. + :param kw: kwargs with overriding values for service's attributes. + :returns: Test Service DB object. + """ + service = get_test_rc(**kw) + # Let DB generate ID if it isn't specified explicitly + if 'id' not in kw: + del service['id'] + dbapi = db_api.get_instance() + return dbapi.create_rc(service)