TestVimConnectivity improvement and UTs 77/13277/5
authorPatricia Reinoso <patricia.reinoso@canonical.com>
Wed, 26 Apr 2023 08:16:19 +0000 (08:16 +0000)
committerGulsum Atici <gulsum.atici@canonical.com>
Wed, 26 Apr 2023 10:51:56 +0000 (13:51 +0300)
Move get_controller method from N2VC to
juju paas activitities.

Change-Id: Id3b8e79055690536746bd2a04578bf6de8dde3e1
Signed-off-by: Patricia Reinoso <patricia.reinoso@canonical.com>
osm_lcm/temporal/juju_paas_activities.py
osm_lcm/temporal/vnf_workflows.py
osm_lcm/tests/test_juju_paas_activities.py
osm_lcm/tests/test_vdu_workflow.py
osm_lcm/tests/test_vnf_workflows.py

index f2b9a16..d86f1c2 100644 (file)
 import asyncio
 import base64
 import logging
+from dataclasses import dataclass
 from juju.application import Application
 from juju.controller import Controller
 from n2vc.config import EnvironConfig
-from n2vc.temporal_libjuju import ConnectionInfo, Libjuju
 from osm_common.dataclasses.temporal_dataclasses import (
     CharmInfo,
     CheckCharmStatusInput,
@@ -29,14 +29,30 @@ from osm_common.dataclasses.temporal_dataclasses import (
 )
 from osm_common.temporal_constants import (
     ACTIVITY_TEST_VIM_CONNECTIVITY,
+    ACTIVITY_CHECK_CHARM_STATUS,
     ACTIVITY_CREATE_MODEL,
     ACTIVITY_DEPLOY_CHARM,
-    ACTIVITY_CHECK_CHARM_STATUS,
 )
 from osm_lcm.data_utils.database.database import Database
 from temporalio import activity
 
 
+@dataclass
+class ConnectionInfo:
+    """Information to connect to juju controller"""
+
+    endpoint: str
+    user: str
+    password: str
+    cacert: str
+
+    def __repr__(self):
+        return f"{self.__class__.__name__}(endpoint: {self.endpoint}, user: {self.user}, password: ******, cacert: ******)"
+
+    def __str__(self):
+        return f"{self.__class__.__name__}(endpoint: {self.endpoint}, user: {self.user}, password: ******, cacert: ******)"
+
+
 class JujuPaasConnector:
     """Handles Juju Controller operations.
 
@@ -77,16 +93,8 @@ class JujuPaasConnector:
         username = vim_content["vim_user"]
         vim_config = vim_content["config"]
         cacert = vim_config["ca_cert_content"]
-        cloud_name = vim_config["cloud"]
-        cloud_credentials = vim_config["cloud_credentials"]
         password = self._decrypt_password(vim_content)
-        return ConnectionInfo(
-            endpoint, username, password, cacert, cloud_name, cloud_credentials
-        )
-
-    def _get_libjuju(self, vim_uuid):
-        connection_info = self._get_connection_info(vim_uuid)
-        return Libjuju(connection_info)
+        return ConnectionInfo(endpoint, username, password, cacert)
 
     async def _get_controller(self, vim_uuid) -> Controller:
         connection_info = self._get_connection_info(vim_uuid)
@@ -126,14 +134,9 @@ class JujuPaasConnector:
             and wait on each connection attempt.
         """
         vim_id = test_connectivity_input.vim_uuid
-        controller = None
-        try:
-            libjuju = self._get_libjuju(vim_id)
-            controller = await libjuju.get_controller()
-            message = f"Connection to juju controller succeeded for {vim_id}"
-            self.logger.info(message)
-        finally:
-            await libjuju.disconnect_controller(controller)
+        self._get_controller(vim_id)
+        message = f"Connection to juju controller succeeded for {vim_id}"
+        self.logger.info(message)
 
     @activity.defn(name=ACTIVITY_CREATE_MODEL)
     async def create_model(self, create_model_input: ModelInfo) -> None:
index ed81a8e..d2d6d71 100644 (file)
@@ -186,7 +186,7 @@ class VnfInstantiateWorkflow:
         vim_id = vnfr.get("vim-account-id")
         sw_image_descs = vnfd.get("sw-image-desc")
         vdu_info = CharmInfoUtils.get_charm_info(vdu, sw_image_descs)
-        vdu_instantiate_input = VduInstantiateInput(vim_id, model_name, vdu_info)
+        vdu_instantiate_input = VduInstantiateInput(vim_id, model_name, vdu_info, None)
         vdu_instantiate_workflow_id = (
             vdu_instantiate_input.model_name
             + "-"
index ddafd54..1aee12b 100644 (file)
@@ -23,24 +23,21 @@ from juju.controller import Controller
 from juju.model import Model
 from juju.errors import JujuError
 from juju.unit import Unit
-from n2vc.temporal_libjuju import ConnectionInfo
 from osm_common.dataclasses.temporal_dataclasses import (
     CharmInfo,
     CheckCharmStatusInput,
     ModelInfo,
+    TestVimConnectivityInput,
+    VduComputeConstraints,
     VduInstantiateInput,
 )
+from osm_common.dbbase import DbException
 from osm_lcm.temporal.juju_paas_activities import JujuPaasConnector
 from parameterized import parameterized
 from temporalio.testing import ActivityEnvironment
 from unittest.mock import ANY, AsyncMock, Mock
 
-vim_id = "some-vim-uuid"
 namespace = "some-namespace"
-model_info = ModelInfo(vim_id, namespace)
-connection_info = ConnectionInfo(
-    "1.2.3.4:17070", "user", "password", "cacert", "cloud_name", "cloud_credentials"
-)
 vim_content = {
     "_id": "82258772-0145-47cf-9a56-98a83aab38cc",
     "name": "juju-with-key",
@@ -60,50 +57,50 @@ vim_content = {
 }
 
 
+@asynctest.mock.patch("juju.controller.Controller.connect")
 class TestJujuPaasConnector(asynctest.TestCase):
     def setUp(self):
         self.db = Mock()
-        self.env = ActivityEnvironment()
         self.juju_paas_connector = JujuPaasConnector(self.db)
-        self.controller = AsyncMock(spec=Controller)
-
-        async def get_controller(_: str):
-            return self.controller
-
-        self.juju_paas_connector._get_controller = get_controller
-        self._api_endpoints = []
-        self.controller.api_endpoints = self.api_endpoints
+        self.juju_paas_connector._decrypt_password = Mock()
+        self.juju_paas_connector._decrypt_password.side_effect = ["password"]
 
-    @property
-    async def api_endpoints(self):
-        return self._api_endpoints
+    async def test_get_controller_nominal_case(self, mock_connect):
+        self.db.get_one.side_effect = [vim_content]
+        controller = await self.juju_paas_connector._get_controller(vim_content["_id"])
+        self.assertIsInstance(controller, Controller)
+        mock_connect.assert_called_once_with(
+            endpoint=vim_content["vim_url"],
+            username=vim_content["vim_user"],
+            password="password",
+            cacert=vim_content["config"]["ca_cert_content"],
+        )
 
-    async def test_create_model_nominal_case(self):
+    async def test_get_controller_raises_juju_error(self, mock_connect):
         self.db.get_one.side_effect = [vim_content]
-        self.juju_paas_connector._decrypt_password = Mock()
-        self.juju_paas_connector._decrypt_password.side_effect = ["password"]
-        await self.env.run(self.juju_paas_connector.create_model, model_info)
-        self.controller.add_model.assert_called_once_with(
-            model_info.model_name,
-            config=ANY,
-            cloud_name=vim_content["config"]["cloud"],
-            credential_name=vim_content["config"]["cloud_credentials"],
+        mock_connect.side_effect = JujuError()
+        with self.assertRaises(JujuError):
+            await self.juju_paas_connector._get_controller(vim_content["_id"])
+        mock_connect.assert_called_once_with(
+            endpoint=vim_content["vim_url"],
+            username=vim_content["vim_user"],
+            password="password",
+            cacert=vim_content["config"]["ca_cert_content"],
         )
 
-    async def test_create_model_already_exists(self):
-        self.controller.list_models.return_value = [model_info.model_name]
-        await self.env.run(self.juju_paas_connector.create_model, model_info)
-        self.controller.add_model.assert_not_called()
+    async def test_get_controller_raises_db_error(self, mock_connect):
+        self.db.get_one.side_effect = DbException("DB Exception")
+        with self.assertRaises(DbException):
+            await self.juju_paas_connector._get_controller(vim_content["_id"])
+        mock_connect.assert_not_called()
 
 
 class TestJujuPaasActivitiesBase(asynctest.TestCase):
     def setUp(self) -> None:
         self.db = Mock()
         self.env = ActivityEnvironment()
-        self.controller = AsyncMock()
-        self.model = Mock(spec=Model)
-        self.model.applications = {}
-        self.controller.get_model.return_value = self.model
+        self.controller = AsyncMock(spec=Controller)
+        self.mock_model()
 
         async def get_controller(_: str):
             return self.controller
@@ -111,6 +108,11 @@ class TestJujuPaasActivitiesBase(asynctest.TestCase):
         self.juju_paas = JujuPaasConnector(self.db)
         self.juju_paas._get_controller = get_controller
 
+    def mock_model(self) -> None:
+        self.model = Mock(spec=Model)
+        self.model.applications = {}
+        self.controller.get_model.return_value = self.model
+
     def add_application(self, application_name) -> None:
         self.application_name = application_name
         self.application = Mock(spec=Application)
@@ -118,6 +120,36 @@ class TestJujuPaasActivitiesBase(asynctest.TestCase):
         self.model.applications = {self.application_name: self.application}
 
 
+class TestCreateModel(TestJujuPaasActivitiesBase):
+    model_info = ModelInfo(vim_content["_id"], namespace)
+
+    def setUp(self):
+        super().setUp()
+        self._api_endpoints = []
+        self.controller.api_endpoints = self.api_endpoints
+
+    @property
+    async def api_endpoints(self):
+        return self._api_endpoints
+
+    async def test_create_model_nominal_case(self):
+        self.db.get_one.side_effect = [vim_content]
+        self.juju_paas._decrypt_password = Mock()
+        self.juju_paas._decrypt_password.side_effect = ["password"]
+        await self.env.run(self.juju_paas.create_model, self.model_info)
+        self.controller.add_model.assert_called_once_with(
+            self.model_info.model_name,
+            config=ANY,
+            cloud_name=vim_content["config"]["cloud"],
+            credential_name=vim_content["config"]["cloud_credentials"],
+        )
+
+    async def test_create_model_already_exists(self):
+        self.controller.list_models.return_value = [self.model_info.model_name]
+        await self.env.run(self.juju_paas.create_model, self.model_info)
+        self.controller.add_model.assert_not_called()
+
+
 class TestCheckCharmStatus(TestJujuPaasActivitiesBase):
     def setUp(self) -> None:
         super().setUp()
@@ -225,7 +257,10 @@ class TestDeployCharm(TestJujuPaasActivitiesBase):
     channel = "latest"
     entity_url = "ch:my-charm"
     charm_info = CharmInfo(app_name, channel, entity_url)
-    vdu_instantiate_input = VduInstantiateInput(vim_id, namespace, charm_info)
+    constraints = VduComputeConstraints(1, 2, "")
+    vdu_instantiate_input = VduInstantiateInput(
+        vim_content["_id"], namespace, charm_info, constraints
+    )
 
     async def test_deploy_charm_nominal_case(self):
         await self.env.run(self.juju_paas.deploy_charm, self.vdu_instantiate_input)
@@ -250,3 +285,20 @@ class TestDeployCharm(TestJujuPaasActivitiesBase):
         with self.assertRaises(JujuError):
             await self.env.run(self.juju_paas.deploy_charm, self.vdu_instantiate_input)
         self.model.deploy.assert_not_called()
+
+
+class TestTestVimConnectivity(TestJujuPaasActivitiesBase):
+    test_vim_connectivity_input = TestVimConnectivityInput(vim_content["_id"])
+
+    async def test_connectivity_nominal_case(self):
+        await self.env.run(
+            self.juju_paas.test_vim_connectivity, self.test_vim_connectivity_input
+        )
+
+    async def test_connectivity_raises_exception(self):
+        self.juju_paas._get_controller = Mock()
+        self.juju_paas._get_controller.side_effect = JujuError()
+        with self.assertRaises(JujuError):
+            await self.env.run(
+                self.juju_paas.test_vim_connectivity, self.test_vim_connectivity_input
+            )
index 23de701..c5b2adc 100644 (file)
 
 import asynctest
 
-from osm_common.dataclasses.temporal_dataclasses import CharmInfo, VduInstantiateInput
+from osm_common.dataclasses.temporal_dataclasses import (
+    CharmInfo,
+    VduInstantiateInput,
+    VduComputeConstraints,
+)
 from osm_common.temporal_constants import (
     ACTIVITY_DEPLOY_CHARM,
     ACTIVITY_CHECK_CHARM_STATUS,
@@ -58,8 +62,12 @@ class TestVduWorkflows(asynctest.TestCase):
     app_name = "my_app_name"
     channel = "latest"
     entity_url = "ch:my-charm"
+    cloud = "microk8s"
+    constraints = VduComputeConstraints(mem=1, cores=1, cloud=cloud)
     charm_info = CharmInfo(app_name, channel, entity_url)
-    vdu_instantiate_input = VduInstantiateInput(vim_id, namespace, charm_info)
+    vdu_instantiate_input = VduInstantiateInput(
+        vim_id, namespace, charm_info, constraints
+    )
     worflow_id = namespace + "-" + app_name
 
     async def setUp(self):
index 633d113..912f5d0 100644 (file)
@@ -30,6 +30,7 @@ from osm_common.dataclasses.temporal_dataclasses import (
     GetTaskQueueOutput,
     GetVnfDetailsInput,
     GetVnfDetailsOutput,
+    VduComputeConstraints,
     VduInstantiateInput,
     VnfInstantiateInput,
     VnfInstantiationState,
@@ -52,6 +53,7 @@ wf_input = VnfInstantiateInput(
     vnfr_uuid="86b53d92-4f5a-402e-8ac2-585ec6b64698",
     model_name="a-model-name",
 )
+cloud = "microk8s"
 juju_task_queue = "juju_task_queue"
 vnfr_uuid = "9f472177-95c0-4335-b357-5cdc17a79965"
 sample_vnfr = {
@@ -481,6 +483,7 @@ class TestVnfInstantiateWorkflow(asynctest.TestCase):
                 charm_info=CharmInfo(
                     app_name="my-app", channel="latest", entity_url="my-url"
                 ),
+                constraints=VduComputeConstraints(cores=1, mem=1, cloud=cloud),
             ),
             "vdu_instantiate_workflow_id",
         )