diff --git a/unit_tests/test_zaza_controller.py b/unit_tests/test_zaza_controller.py new file mode 100644 index 0000000..13a5108 --- /dev/null +++ b/unit_tests/test_zaza_controller.py @@ -0,0 +1,80 @@ +import mock + +import unit_tests.utils as ut_utils + +import zaza.controller as controller + + +class TestController(ut_utils.BaseTestCase): + + def setUp(self): + super(TestController, self).setUp() + + async def _disconnect(): + return + + async def _connect(): + return + + async def _list_models(): + return self.models + + async def _add_model(model_name): + return self.model1 + + async def _destroy_model(model_name): + return + + async def _get_cloud(): + return self.cloud + + # Cloud + self.cloud = "FakeCloud" + + # Model + self.Model_mock = mock.MagicMock() + self.Model_mock.connect.side_effect = _connect + self.Model_mock.disconnect.side_effect = _disconnect + self.Model_mock.disconnect.side_effect = _disconnect + self.model1 = self.Model_mock + self.model2 = mock.MagicMock() + self.model1.info.name = "model1" + self.model2.info.name = "model2" + self.models = [self.model1.info.name, self.model2.info.name] + + # Controller + self.Controller_mock = mock.MagicMock() + self.Controller_mock.connect.side_effect = _connect + self.Controller_mock.disconnect.side_effect = _disconnect + self.Controller_mock.add_model.side_effect = _add_model + self.Controller_mock.destroy_model.side_effect = _destroy_model + self.Controller_mock.list_models.side_effect = _list_models + self.Controller_mock.get_cloud.side_effect = _get_cloud + self.controller_name = "testcontroller" + self.Controller_mock.info.name = self.controller_name + self.patch_object(controller, 'Controller') + self.Controller.return_value = self.Controller_mock + + def test_add_model(self): + self.assertEqual(controller.add_model(self.model1.info.name), + self.model1.info.name) + self.Controller_mock.add_model.assert_called_once_with( + self.model1.info.name) + self.model1.connect.assert_called_once() + + def test_destroy_model(self): + controller.destroy_model(self.model1.info.name) + self.Controller_mock.destroy_model.assert_called_once_with( + self.model1.info.name) + + def test_get_cloud(self): + self.assertEqual( + controller.get_cloud(), + self.cloud) + self.Controller_mock.get_cloud.assert_called_once() + + def test_list_models(self): + self.assertEqual( + controller.list_models(), + self.models) + self.Controller_mock.list_models.assert_called_once() diff --git a/zaza/__init__.py b/zaza/__init__.py index e69de29..5ffaf45 100644 --- a/zaza/__init__.py +++ b/zaza/__init__.py @@ -0,0 +1,30 @@ +import asyncio + + +def run(*steps): + """Run the given steps in an asyncio loop + + :returns: The result of the asyncio.Task + :rtype: Any + """ + if not steps: + return + loop = asyncio.get_event_loop() + + for step in steps: + task = loop.create_task(step) + loop.run_until_complete(asyncio.wait([task], loop=loop)) + return task.result() + + +def sync_wrapper(f): + """Convert the given async function into a sync function + + :returns: The de-async'd function + :rtype: function + """ + def _wrapper(*args, **kwargs): + async def _run_it(): + return await f(*args, **kwargs) + return run(_run_it()) + return _wrapper diff --git a/zaza/controller.py b/zaza/controller.py new file mode 100644 index 0000000..4eb4630 --- /dev/null +++ b/zaza/controller.py @@ -0,0 +1,47 @@ +import logging +from juju.controller import Controller +from zaza import sync_wrapper + + +async def async_add_model(model_name): + controller = Controller() + await controller.connect() + logging.debug("Adding model {}".format(model_name)) + model = await controller.add_model(model_name) + await model.connect() + model_name = model.info.name + await model.disconnect() + await controller.disconnect() + return model_name + +add_model = sync_wrapper(async_add_model) + + +async def async_destroy_model(model_name): + controller = Controller() + await controller.connect() + logging.debug("Destroying model {}".format(model_name)) + await controller.destroy_model(model_name) + await controller.disconnect() + +destroy_model = sync_wrapper(async_destroy_model) + + +async def async_get_cloud(): + controller = Controller() + await controller.connect() + cloud = await controller.get_cloud() + await controller.disconnect() + return cloud + +get_cloud = sync_wrapper(async_get_cloud) + + +async def async_list_models(): + controller = Controller() + await controller.connect() + models = await controller.list_models() + await controller.disconnect() + return models + +list_models = sync_wrapper(async_list_models) diff --git a/zaza/model.py b/zaza/model.py index 295a3d1..8deda72 100644 --- a/zaza/model.py +++ b/zaza/model.py @@ -10,6 +10,8 @@ from juju import loop from juju.errors import JujuError from juju.model import Model +from zaza import sync_wrapper + async def deployed(filter=None): # Create a Model instance. We need to connect our Model to a Juju api @@ -46,35 +48,6 @@ def get_unit_from_name(unit_name, model): return unit -def run(*steps): - """Run the given steps in an asyncio loop - - :returns: The result of the asyncio.Task - :rtype: Any - """ - if not steps: - return - loop = asyncio.get_event_loop() - - for step in steps: - task = loop.create_task(step) - loop.run_until_complete(asyncio.wait([task], loop=loop)) - return task.result() - - -def sync_wrapper(f): - """Convert the given async function into a sync function - - :returns: The de-async'd function - :rtype: function - """ - def _wrapper(*args, **kwargs): - async def _run_it(): - return await f(*args, **kwargs) - return run(_run_it()) - return _wrapper - - @asynccontextmanager @async_generator async def run_in_model(model_name):