Improved Primitive support and better testing
[osm/N2VC.git] / modules / libjuju / tests / integration / test_controller.py
index d559313..93e2883 100644 (file)
@@ -1,11 +1,16 @@
 import asyncio
 import asyncio
-import pytest
+import subprocess
 import uuid
 
 import uuid
 
-from .. import base
+from juju.client.connection import Connection
+from juju.client.jujudata import FileJujuData
 from juju.controller import Controller
 from juju.errors import JujuAPIError
 
 from juju.controller import Controller
 from juju.errors import JujuAPIError
 
+import pytest
+
+from .. import base
+
 
 @base.bootstrapped
 @pytest.mark.asyncio
 
 @base.bootstrapped
 @pytest.mark.asyncio
@@ -57,14 +62,18 @@ async def test_change_user_password(event_loop):
         username = 'test-password{}'.format(uuid.uuid4())
         user = await controller.add_user(username)
         await user.set_password('password')
         username = 'test-password{}'.format(uuid.uuid4())
         user = await controller.add_user(username)
         await user.set_password('password')
+        # Check that we can connect with the new password.
+        new_connection = None
         try:
         try:
-            new_controller = Controller()
-            await new_controller.connect(
-                controller.connection.endpoint, username, 'password')
+            kwargs = controller.connection().connect_params()
+            kwargs['username'] = username
+            kwargs['password'] = 'password'
+            new_connection = await Connection.connect(**kwargs)
         except JujuAPIError:
             raise AssertionError('Unable to connect with new password')
         finally:
         except JujuAPIError:
             raise AssertionError('Unable to connect with new password')
         finally:
-            await new_controller.disconnect()
+            if new_connection:
+                await new_connection.close()
 
 
 @base.bootstrapped
 
 
 @base.bootstrapped
@@ -77,10 +86,10 @@ async def test_grant_revoke(event_loop):
         assert user.access == 'superuser'
         fresh = await controller.get_user(username)  # fetch fresh copy
         assert fresh.access == 'superuser'
         assert user.access == 'superuser'
         fresh = await controller.get_user(username)  # fetch fresh copy
         assert fresh.access == 'superuser'
-        await user.grant('login')
-        assert user.access == 'login'
+        await user.grant('login')  # already has 'superuser', so no-op
+        assert user.access == 'superuser'
         fresh = await controller.get_user(username)  # fetch fresh copy
         fresh = await controller.get_user(username)  # fetch fresh copy
-        assert fresh.access == 'login'
+        assert fresh.access == 'superuser'
         await user.revoke()
         assert user.access is ''
         fresh = await controller.get_user(username)  # fetch fresh copy
         await user.revoke()
         assert user.access is ''
         fresh = await controller.get_user(username)  # fetch fresh copy
@@ -120,6 +129,11 @@ async def test_get_model(event_loop):
             await controller.destroy_model(model_name)
 
 
             await controller.destroy_model(model_name)
 
 
+async def _wait_for_model(controller, model_name):
+    while model_name not in await controller.list_models():
+        await asyncio.sleep(0.5, loop=controller.loop)
+
+
 async def _wait_for_model_gone(controller, model_name):
     while model_name in await controller.list_models():
         await asyncio.sleep(0.5, loop=controller.loop)
 async def _wait_for_model_gone(controller, model_name):
     while model_name in await controller.list_models():
         await asyncio.sleep(0.5, loop=controller.loop)
@@ -132,6 +146,9 @@ async def test_destroy_model_by_name(event_loop):
         model_name = 'test-{}'.format(uuid.uuid4())
         model = await controller.add_model(model_name)
         await model.disconnect()
         model_name = 'test-{}'.format(uuid.uuid4())
         model = await controller.add_model(model_name)
         await model.disconnect()
+        await asyncio.wait_for(_wait_for_model(controller,
+                                               model_name),
+                               timeout=60)
         await controller.destroy_model(model_name)
         await asyncio.wait_for(_wait_for_model_gone(controller,
                                                     model_name),
         await controller.destroy_model(model_name)
         await asyncio.wait_for(_wait_for_model_gone(controller,
                                                     model_name),
@@ -146,7 +163,38 @@ async def test_add_destroy_model_by_uuid(event_loop):
         model = await controller.add_model(model_name)
         model_uuid = model.info.uuid
         await model.disconnect()
         model = await controller.add_model(model_name)
         model_uuid = model.info.uuid
         await model.disconnect()
+        await asyncio.wait_for(_wait_for_model(controller,
+                                               model_name),
+                               timeout=60)
         await controller.destroy_model(model_uuid)
         await asyncio.wait_for(_wait_for_model_gone(controller,
                                                     model_name),
                                timeout=60)
         await controller.destroy_model(model_uuid)
         await asyncio.wait_for(_wait_for_model_gone(controller,
                                                     model_name),
                                timeout=60)
+
+
+# this test must be run serially because it modifies the login password
+@pytest.mark.serial
+@base.bootstrapped
+@pytest.mark.asyncio
+async def test_macaroon_auth(event_loop):
+    jujudata = FileJujuData()
+    account = jujudata.accounts()[jujudata.current_controller()]
+    with base.patch_file('~/.local/share/juju/accounts.yaml'):
+        if 'password' in account:
+            # force macaroon auth by "changing" password to current password
+            result = subprocess.run(
+                ['juju', 'change-user-password'],
+                input='{0}\n{0}\n'.format(account['password']),
+                universal_newlines=True,
+                stderr=subprocess.PIPE)
+            assert result.returncode == 0, ('Failed to change password: '
+                                            '{}'.format(result.stderr))
+        controller = Controller()
+        try:
+            await controller.connect()
+            assert controller.is_connected()
+        finally:
+            if controller.is_connected():
+                await controller.disconnect()
+        async with base.CleanModel():
+            pass  # create and login to model works