Feature 11002: Deorecate helmv2
[osm/LCM.git] / osm_lcm / tests / test_ns.py
index 5e248a2..d2062d3 100644 (file)
 
 import asynctest  # pip3 install asynctest --user
 import asyncio
+from copy import deepcopy
 import yaml
 import copy
+from n2vc.exceptions import N2VCException
 from os import getenv
 from osm_lcm import ns
 from osm_common.msgkafka import MsgKafka
+
+from osm_lcm.data_utils.lcm_config import LcmCfg
 from osm_lcm.lcm_utils import TaskRegistry
 from osm_lcm.ng_ro import NgRoClient
 from osm_lcm.data_utils.database.database import Database
 from osm_lcm.data_utils.filesystem.filesystem import Filesystem
+from osm_lcm.data_utils.vca import Relation, EERelation, DeployedVCA
 from osm_lcm.data_utils.vnfd import find_software_version
 from osm_lcm.lcm_utils import check_juju_bundle_existence, get_charm_artifact_path
 from osm_lcm.lcm_utils import LcmException
@@ -53,7 +58,7 @@ It allows, if some testing ENV are supplied, testing without mocking some extern
     OSMLCM_RO_XXX: configuration of RO
 """
 
-lcm_config = {
+lcm_config_dict = {
     "global": {"loglevel": "DEBUG"},
     "timeout": {},
     "VCA": {  # TODO replace with os.get_env to get other configurations
@@ -65,7 +70,7 @@ lcm_config = {
         "ca_cert": getenv("OSMLCM_VCA_CACERT", None),
         "apiproxy": getenv("OSMLCM_VCA_APIPROXY", "192.168.1.1"),
     },
-    "ro_config": {
+    "RO": {
         "uri": "http://{}:{}/openmano".format(
             getenv("OSMLCM_RO_HOST", "ro"), getenv("OSMLCM_RO_PORT", "9090")
         ),
@@ -76,8 +81,25 @@ lcm_config = {
     },
 }
 
+lcm_config = LcmCfg()
+lcm_config.set_from_dict(lcm_config_dict)
+lcm_config.transform()
+
+nsr_id = descriptors.test_ids["TEST-A"]["ns"]
+nslcmop_id = descriptors.test_ids["TEST-A"]["update"]
+vnfr_id = "6421c7c9-d865-4fb4-9a13-d4275d243e01"
+vnfd_id = "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77"
+update_fs = Mock(autospec=True)
+update_fs.path.__add__ = Mock()
+update_fs.path.side_effect = ["/", "/", "/", "/"]
+update_fs.sync.side_effect = [None, None]
+
+
+def callable(a):
+    return a
 
-class TestMyNS(asynctest.TestCase):
+
+class TestBaseNS(asynctest.TestCase):
     async def _n2vc_DeployCharms(
         self,
         model_name,
@@ -87,7 +109,7 @@ class TestMyNS(asynctest.TestCase):
         params={},
         machine_spec={},
         callback=None,
-        *callback_args
+        *callback_args,
     ):
         if callback:
             for status, message in (
@@ -95,7 +117,7 @@ class TestMyNS(asynctest.TestCase):
                 ("active", "Ready!"),
             ):
                 # call callback after some time
-                asyncio.sleep(5, loop=self.loop)
+                asyncio.sleep(5)
                 callback(model_name, application_name, status, message, *callback_args)
 
     @staticmethod
@@ -122,19 +144,15 @@ class TestMyNS(asynctest.TestCase):
         print("kwargs > {}".format(kwargs))
         if args:
             if "update" in args:
-                ro_ns_desc = yaml.load(
-                    descriptors.ro_update_action_text, Loader=yaml.Loader
-                )
+                ro_ns_desc = yaml.safe_load(descriptors.ro_update_action_text)
                 while True:
                     yield ro_ns_desc
         if kwargs.get("delete"):
-            ro_ns_desc = yaml.load(
-                descriptors.ro_delete_action_text, Loader=yaml.Loader
-            )
+            ro_ns_desc = yaml.safe_load(descriptors.ro_delete_action_text)
             while True:
                 yield ro_ns_desc
 
-        ro_ns_desc = yaml.load(descriptors.ro_ns_text, Loader=yaml.Loader)
+        ro_ns_desc = yaml.safe_load(descriptors.ro_ns_text)
 
         # if ip address provided, replace descriptor
         ip_addresses = getenv("OSMLCMTEST_NS_IPADDRESS", "")
@@ -169,48 +187,44 @@ class TestMyNS(asynctest.TestCase):
         return str(uuid4())
 
     async def setUp(self):
-
-        # Mock DB
+        self.mock_db()
+        self.mock_kafka()
+        self.mock_filesystem()
+        self.mock_task_registry()
+        self.mock_vca_k8s()
+        self.create_nslcm_class()
+        self.mock_logging()
+        self.mock_vca_n2vc()
+        self.mock_ro()
+
+    def mock_db(self):
         if not getenv("OSMLCMTEST_DB_NOMOCK"):
             # Cleanup singleton Database instance
             Database.instance = None
 
             self.db = Database({"database": {"driver": "memory"}}).instance.db
+            self.db.create_list("vnfds", yaml.safe_load(descriptors.db_vnfds_text))
             self.db.create_list(
-                "vnfds", yaml.load(descriptors.db_vnfds_text, Loader=yaml.Loader)
+                "vnfds_revisions", yaml.safe_load(descriptors.db_vnfds_revisions_text)
             )
+            self.db.create_list("nsds", yaml.safe_load(descriptors.db_nsds_text))
+            self.db.create_list("nsrs", yaml.safe_load(descriptors.db_nsrs_text))
             self.db.create_list(
-                "vnfds_revisions",
-                yaml.load(descriptors.db_vnfds_revisions_text, Loader=yaml.Loader),
+                "vim_accounts", yaml.safe_load(descriptors.db_vim_accounts_text)
             )
             self.db.create_list(
-                "nsds", yaml.load(descriptors.db_nsds_text, Loader=yaml.Loader)
+                "k8sclusters", yaml.safe_load(descriptors.db_k8sclusters_text)
             )
             self.db.create_list(
-                "nsrs", yaml.load(descriptors.db_nsrs_text, Loader=yaml.Loader)
-            )
-            self.db.create_list(
-                "vim_accounts",
-                yaml.load(descriptors.db_vim_accounts_text, Loader=yaml.Loader),
-            )
-            self.db.create_list(
-                "k8sclusters",
-                yaml.load(descriptors.db_k8sclusters_text, Loader=yaml.Loader),
-            )
-            self.db.create_list(
-                "nslcmops", yaml.load(descriptors.db_nslcmops_text, Loader=yaml.Loader)
-            )
-            self.db.create_list(
-                "vnfrs", yaml.load(descriptors.db_vnfrs_text, Loader=yaml.Loader)
-            )
-            self.db_vim_accounts = yaml.load(
-                descriptors.db_vim_accounts_text, Loader=yaml.Loader
+                "nslcmops", yaml.safe_load(descriptors.db_nslcmops_text)
             )
+            self.db.create_list("vnfrs", yaml.safe_load(descriptors.db_vnfrs_text))
+            self.db_vim_accounts = yaml.safe_load(descriptors.db_vim_accounts_text)
 
-        # Mock kafka
+    def mock_kafka(self):
         self.msg = asynctest.Mock(MsgKafka())
 
-        # Mock filesystem
+    def mock_filesystem(self):
         if not getenv("OSMLCMTEST_FS_NOMOCK"):
             self.fs = asynctest.Mock(
                 Filesystem({"storage": {"driver": "local", "path": "/"}}).instance.fs
@@ -222,33 +236,33 @@ class TestMyNS(asynctest.TestCase):
             # self.fs.file_open.return_value.__enter__.return_value = asynctest.MagicMock()  # called on a python "with"
             # self.fs.file_open.return_value.__enter__.return_value.read.return_value = ""   # empty file
 
-        # Mock TaskRegistry
+    def mock_task_registry(self):
         self.lcm_tasks = asynctest.Mock(TaskRegistry())
         self.lcm_tasks.lock_HA.return_value = True
         self.lcm_tasks.waitfor_related_HA.return_value = None
         self.lcm_tasks.lookfor_related.return_value = ("", [])
 
-        # Mock VCA - K8s
+    def mock_vca_k8s(self):
         if not getenv("OSMLCMTEST_VCA_K8s_NOMOCK"):
             ns.K8sJujuConnector = asynctest.MagicMock(ns.K8sJujuConnector)
-            ns.K8sHelmConnector = asynctest.MagicMock(ns.K8sHelmConnector)
+            ns.K8sHelmConnector = asynctest.MagicMock(ns.K8sHelmConnector)
             ns.K8sHelm3Connector = asynctest.MagicMock(ns.K8sHelm3Connector)
 
         if not getenv("OSMLCMTEST_VCA_NOMOCK"):
             ns.N2VCJujuConnector = asynctest.MagicMock(ns.N2VCJujuConnector)
             ns.LCMHelmConn = asynctest.MagicMock(ns.LCMHelmConn)
 
-        # Create NsLCM class
-        self.my_ns = ns.NsLcm(self.msg, self.lcm_tasks, lcm_config, self.loop)
+    def create_nslcm_class(self):
+        self.my_ns = ns.NsLcm(self.msg, self.lcm_tasks, lcm_config)
         self.my_ns.fs = self.fs
         self.my_ns.db = self.db
         self.my_ns._wait_dependent_n2vc = asynctest.CoroutineMock()
 
-        # Mock logging
+    def mock_logging(self):
         if not getenv("OSMLCMTEST_LOGGING_NOMOCK"):
             self.my_ns.logger = asynctest.Mock(self.my_ns.logger)
 
-        # Mock VCA - N2VC
+    def mock_vca_n2vc(self):
         if not getenv("OSMLCMTEST_VCA_NOMOCK"):
             pub_key = getenv("OSMLCMTEST_NS_PUBKEY", "ssh-rsa test-pub-key t@osm.com")
             # self.my_ns.n2vc = asynctest.Mock(N2VC())
@@ -292,12 +306,13 @@ class TestMyNS(asynctest.TestCase):
             self.my_ns.n2vc.delete_namespace = asynctest.CoroutineMock(
                 return_value=None
             )
+            self.my_ns.n2vc.register_execution_environment = asynctest.CoroutineMock(
+                return_value="model-name.application-name.k8s"
+            )
 
-        # Mock RO
+    def mock_ro(self):
         if not getenv("OSMLCMTEST_RO_NOMOCK"):
-            self.my_ns.RO = asynctest.Mock(
-                NgRoClient(self.loop, **lcm_config["ro_config"])
-            )
+            self.my_ns.RO = asynctest.Mock(NgRoClient(**lcm_config.RO.to_dict()))
             # TODO first time should be empty list, following should return a dict
             # self.my_ns.RO.get_list = asynctest.CoroutineMock(self.my_ns.RO.get_list, return_value=[])
             self.my_ns.RO.deploy = asynctest.CoroutineMock(
@@ -309,86 +324,39 @@ class TestMyNS(asynctest.TestCase):
             #                                                                              "description": "done"}})
             self.my_ns.RO.delete = asynctest.CoroutineMock(self.my_ns.RO.delete)
 
-    # @asynctest.fail_on(active_handles=True)   # all async tasks must be completed
-    # async def test_instantiate(self):
-    #     nsr_id = descriptors.test_ids["TEST-A"]["ns"]
-    #     nslcmop_id = descriptors.test_ids["TEST-A"]["instantiate"]
-    #     # print("Test instantiate started")
-
-    #     # delete deployed information of database
-    #     if not getenv("OSMLCMTEST_DB_NOMOCK"):
-    #         if self.db.get_list("nsrs")[0]["_admin"].get("deployed"):
-    #             del self.db.get_list("nsrs")[0]["_admin"]["deployed"]
-    #         for db_vnfr in self.db.get_list("vnfrs"):
-    #             db_vnfr.pop("ip_address", None)
-    #             for db_vdur in db_vnfr["vdur"]:
-    #                 db_vdur.pop("ip_address", None)
-    #                 db_vdur.pop("mac_address", None)
-    #         if getenv("OSMLCMTEST_RO_VIMID"):
-    #             self.db.get_list("vim_accounts")[0]["_admin"]["deployed"]["RO"] = getenv("OSMLCMTEST_RO_VIMID")
-    #         if getenv("OSMLCMTEST_RO_VIMID"):
-    #             self.db.get_list("nsrs")[0]["_admin"]["deployed"]["RO"] = getenv("OSMLCMTEST_RO_VIMID")
 
-    #     await self.my_ns.instantiate(nsr_id, nslcmop_id)
+class TestMyNS(TestBaseNS):
+    @asynctest.fail_on(active_handles=True)
+    async def test_start_stop_rebuild_pass(self):
+        nsr_id = descriptors.test_ids["TEST-OP-VNF"]["ns"]
+        nslcmop_id = descriptors.test_ids["TEST-OP-VNF"]["nslcmops"]
+        vnf_id = descriptors.test_ids["TEST-OP-VNF"]["vnfrs"]
+        additional_param = {"count-index": "0"}
+        operation_type = "start"
+        await self.my_ns.rebuild_start_stop(
+            nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
+        )
+        expected_value = "COMPLETED"
+        return_value = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "operationState"
+        )
+        self.assertEqual(return_value, expected_value)
 
-    #     self.msg.aiowrite.assert_called_once_with("ns", "instantiated",
-    #                                               {"nsr_id": nsr_id, "nslcmop_id": nslcmop_id,
-    #                                                "operationState": "COMPLETED"},
-    #                                               loop=self.loop)
-    #     self.lcm_tasks.lock_HA.assert_called_once_with('ns', 'nslcmops', nslcmop_id)
-    #     if not getenv("OSMLCMTEST_LOGGING_NOMOCK"):
-    #         self.assertTrue(self.my_ns.logger.debug.called, "Debug method not called")
-    #         self.my_ns.logger.error.assert_not_called()
-    #         self.my_ns.logger.exception().assert_not_called()
-
-    #     if not getenv("OSMLCMTEST_DB_NOMOCK"):
-    #         self.assertTrue(self.db.set_one.called, "db.set_one not called")
-    #         db_nsr = self.db.get_one("nsrs", {"_id": nsr_id})
-    #         db_vnfrs_list = self.db.get_list("vnfrs", {"nsr-id-ref": nsr_id})
-    #         self.assertEqual(db_nsr["_admin"].get("nsState"), "INSTANTIATED", "Not instantiated")
-    #         for vnfr in db_vnfrs_list:
-    #             self.assertEqual(vnfr["_admin"].get("nsState"), "INSTANTIATED", "Not instantiated")
-
-    #     if not getenv("OSMLCMTEST_VCA_NOMOCK"):
-    #         # check intial-primitives called
-    #         self.assertTrue(self.my_ns.n2vc.exec_primitive.called,
-    #                         "Exec primitive not called for initial config primitive")
-    #         for _call in self.my_ns.n2vc.exec_primitive.call_args_list:
-    #             self.assertIn(_call[1]["primitive_name"], ("config", "touch"),
-    #                           "called exec primitive with a primitive different than config or touch")
-
-    #     # TODO add more checks of called methods
-    #     # TODO add a terminate
-
-    # async def test_instantiate_ee_list(self):
-    #     # Using modern IM where configuration is in the new format of execution_environment_list
-    #     ee_descriptor_id = "charm_simple"
-    #     non_used_initial_primitive = {
-    #         "name": "not_to_be_called",
-    #         "seq": 3,
-    #         "execution-environment-ref": "not_used_ee"
-    #     }
-    #     ee_list = [
-    #         {
-    #             "id": ee_descriptor_id,
-    #             "juju": {"charm": "simple"},
-
-    #         },
-    #     ]
-
-    #     self.db.set_one(
-    #         "vnfds",
-    #         q_filter={"_id": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77"},
-    #         update_dict={"vnf-configuration.0.execution-environment-list": ee_list,
-    #                      "vnf-configuration.0.initial-config-primitive.0.execution-environment-ref": ee_descriptor_id,
-    #                      "vnf-configuration.0.initial-config-primitive.1.execution-environment-ref": ee_descriptor_id,
-    #                      "vnf-configuration.0.initial-config-primitive.2": non_used_initial_primitive,
-    #                      "vnf-configuration.0.config-primitive.0.execution-environment-ref": ee_descriptor_id,
-    #                      "vnf-configuration.0.config-primitive.0.execution-environment-primitive": "touch_charm",
-    #                      },
-    #         unset={"vnf-configuration.juju": None})
-    #     await self.test_instantiate()
-    #     # this will check that the initial-congig-primitive 'not_to_be_called' is not called
+    @asynctest.fail_on(active_handles=True)
+    async def test_start_stop_rebuild_fail(self):
+        nsr_id = descriptors.test_ids["TEST-OP-VNF"]["ns"]
+        nslcmop_id = descriptors.test_ids["TEST-OP-VNF"]["nslcmops1"]
+        vnf_id = descriptors.test_ids["TEST-OP-VNF"]["vnfrs"]
+        additional_param = {"count-index": "0"}
+        operation_type = "stop"
+        await self.my_ns.rebuild_start_stop(
+            nsr_id, nslcmop_id, vnf_id, additional_param, operation_type
+        )
+        expected_value = "Error"
+        return_value = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "operationState"
+        )
+        self.assertEqual(return_value, expected_value)
 
     # Test scale() and related methods
     @asynctest.fail_on(active_handles=True)  # all async tasks must be completed
@@ -463,13 +431,16 @@ class TestMyNS(asynctest.TestCase):
                         ):
                             if (
                                 v.get("execution-environment-list")
-                                and "juju" in v["execution-environment-list"][k]
+                                and "juju" in v["execution-environment-list"][0]
                             ):
                                 expected_value = self.db.get_list("nsrs")[i][
                                     "vcaStatus"
                                 ]
                                 await self.my_ns._on_update_n2vc_db(
-                                    "nsrs", {"_id": nsr_id}, "_admin.deployed.VCA.0", {}
+                                    "nsrs",
+                                    {"_id": nsr_id},
+                                    "_admin.deployed.VCA.{}".format(k),
+                                    {},
                                 )
                                 return_value = self.db.get_list("nsrs")[i]["vcaStatus"]
         self.assertEqual(return_value, expected_value)
@@ -807,7 +778,43 @@ class TestMyNS(asynctest.TestCase):
             self.assertEqual(return_value, expected_value)
             with self.assertRaises(Exception) as context:
                 self.db.get_one("vnfrs", {"_id": vnf_instance_id})
-            self.assertTrue("database exception Not found entry with filter" in str(context.exception))
+            self.assertTrue(
+                "database exception Not found entry with filter"
+                in str(context.exception)
+            )
+
+    # test vertical scale executes sucessfully
+    # @patch("osm_lcm.ng_ro.status.response")
+    @asynctest.fail_on(active_handles=True)
+    async def test_vertical_scaling(self):
+        nsr_id = descriptors.test_ids["TEST-V-SCALE"]["ns"]
+        nslcmop_id = descriptors.test_ids["TEST-V-SCALE"]["instantiate"]
+
+        # calling the vertical scale fucntion
+        # self.my_ns.RO.status = asynctest.CoroutineMock(self.my_ns.RO.status, side_effect=self._ro_status("update"))
+        mock_wait_ng_ro = asynctest.CoroutineMock()
+        with patch("osm_lcm.ns.NsLcm._wait_ng_ro", mock_wait_ng_ro):
+            await self.my_ns.vertical_scale(nsr_id, nslcmop_id)
+            return_value = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+                "operationState"
+            )
+            expected_value = "COMPLETED"
+            self.assertEqual(return_value, expected_value)
+
+    # test vertical scale executes fail
+    @asynctest.fail_on(active_handles=True)
+    async def test_vertical_scaling_fail(self):
+        # get th nsr nad nslcmops id from descriptors
+        nsr_id = descriptors.test_ids["TEST-V-SCALE"]["ns"]
+        nslcmop_id = descriptors.test_ids["TEST-V-SCALE"]["instantiate-1"]
+
+        # calling the vertical scale fucntion
+        await self.my_ns.vertical_scale(nsr_id, nslcmop_id)
+        return_value = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "operationState"
+        )
+        expected_value = "FAILED"
+        self.assertEqual(return_value, expected_value)
 
     # async def test_instantiate_pdu(self):
     #     nsr_id = descriptors.test_ids["TEST-A"]["ns"]
@@ -889,747 +896,711 @@ class TestMyNS(asynctest.TestCase):
     #     self.assertEqual(db_nsr.get("errorDescription "), None, "errorDescription different than None")
     #     self.assertEqual(db_nsr.get("errorDetail"), None, "errorDetail different than None")
 
-    # Test update method
-
-    async def test_update(self):
-
-        nsr_id = descriptors.test_ids["TEST-A"]["ns"]
-        nslcmop_id = descriptors.test_ids["TEST-A"]["update"]
-        vnfr_id = "6421c7c9-d865-4fb4-9a13-d4275d243e01"
-        vnfd_id = "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77"
-
-        def mock_reset():
-            mock_charm_hash.reset_mock()
-            mock_juju_bundle.reset_mock()
-            fs.sync.reset_mock()
-            mock_charm_upgrade.reset_mock()
-            mock_software_version.reset_mock()
-
-        with self.subTest(
-            i=1,
-            t="Update type: CHANGE_VNFPKG, latest_vnfd revision changed,"
-            "Charm package changed, sw-version is not changed.",
-        ):
-
-            self.db.set_one(
-                "vnfds",
-                q_filter={"_id": vnfd_id},
-                update_dict={"_admin.revision": 3, "kdu": []},
-            )
-
-            self.db.set_one(
-                "vnfds_revisions",
-                q_filter={"_id": vnfd_id + ":1"},
-                update_dict={"_admin.revision": 1, "kdu": []},
-            )
-
-            self.db.set_one(
-                "vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1}
-            )
-
-            mock_charm_hash = Mock(autospec=True)
-            mock_charm_hash.return_value = True
-
-            mock_juju_bundle = Mock(return_value=None)
-
-            mock_software_version = Mock(autospec=True)
-            mock_software_version.side_effect = ["1.0", "1.0"]
-
-            mock_charm_upgrade = asynctest.Mock(autospec=True)
-            task = asyncio.Future()
-            task.set_result(("COMPLETED", "some_output"))
-            mock_charm_upgrade.return_value = task
-
-            fs = Mock(autospec=True)
-            fs.path.__add__ = Mock()
-            fs.path.side_effect = ["/", "/", "/", "/"]
-            fs.sync.side_effect = [None, None]
-
-            instance = self.my_ns
-
-            expected_operation_state = "COMPLETED"
-            expected_operation_error = ""
-            expected_vnfr_revision = 3
-            expected_ns_state = "INSTANTIATED"
-            expected_ns_operational_state = "running"
-
-            with patch.object(instance, "fs", fs), patch(
-                "osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed", mock_charm_hash
-            ), patch("osm_lcm.ns.NsLcm._ns_charm_upgrade", mock_charm_upgrade), patch(
-                "osm_lcm.data_utils.vnfd.find_software_version", mock_software_version
-            ), patch(
-                "osm_lcm.lcm_utils.check_juju_bundle_existence", mock_juju_bundle
-            ):
-
-                await instance.update(nsr_id, nslcmop_id)
-                return_operation_state = self.db.get_one(
-                    "nslcmops", {"_id": nslcmop_id}
-                ).get("operationState")
-                return_operation_error = self.db.get_one(
-                    "nslcmops", {"_id": nslcmop_id}
-                ).get("errorMessage")
-                return_ns_operational_state = self.db.get_one(
-                    "nsrs", {"_id": nsr_id}
-                ).get("operational-status")
-
-                return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
-                    "revision"
-                )
-
-                return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
-                    "nsState"
-                )
-
-                mock_charm_hash.assert_called_with(
-                    "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:1/hackfest_3charmed_vnfd/charms/simple",
-                    "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:3/hackfest_3charmed_vnfd/charms/simple",
-                )
-
-                self.assertEqual(fs.sync.call_count, 2)
-                self.assertEqual(return_ns_state, expected_ns_state)
-                self.assertEqual(return_operation_state, expected_operation_state)
-                self.assertEqual(return_operation_error, expected_operation_error)
-                self.assertEqual(
-                    return_ns_operational_state, expected_ns_operational_state
-                )
-                self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
-
-            mock_reset()
-
-        with self.subTest(
-            i=2, t="Update type: CHANGE_VNFPKG, latest_vnfd revision not changed"
-        ):
-
-            self.db.set_one(
-                "vnfds", q_filter={"_id": vnfd_id}, update_dict={"_admin.revision": 1}
-            )
-
-            self.db.set_one(
-                "vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1}
-            )
-
-            mock_charm_hash = Mock(autospec=True)
-            mock_charm_hash.return_value = True
-
-            mock_juju_bundle = Mock(return_value=None)
-            mock_software_version = Mock(autospec=True)
-
-            mock_charm_upgrade = asynctest.Mock(autospec=True)
-            task = asyncio.Future()
-            task.set_result(("COMPLETED", "some_output"))
-            mock_charm_upgrade.return_value = task
-
-            fs = Mock(autospec=True)
-            fs.path.__add__ = Mock()
-            fs.path.side_effect = ["/", "/", "/", "/"]
-            fs.sync.side_effect = [None, None]
-
-            instance = self.my_ns
-
-            expected_operation_state = "COMPLETED"
-            expected_operation_error = ""
-            expected_vnfr_revision = 1
-            expected_ns_state = "INSTANTIATED"
-            expected_ns_operational_state = "running"
-
-            with patch.object(instance, "fs", fs), patch(
-                "osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed", mock_charm_hash
-            ), patch("osm_lcm.ns.NsLcm._ns_charm_upgrade", mock_charm_upgrade), patch(
-                "osm_lcm.lcm_utils.check_juju_bundle_existence", mock_juju_bundle
-            ):
-
-                await instance.update(nsr_id, nslcmop_id)
-
-                return_operation_state = self.db.get_one(
-                    "nslcmops", {"_id": nslcmop_id}
-                ).get("operationState")
-
-                return_operation_error = self.db.get_one(
-                    "nslcmops", {"_id": nslcmop_id}
-                ).get("errorMessage")
-
-                return_ns_operational_state = self.db.get_one(
-                    "nsrs", {"_id": nsr_id}
-                ).get("operational-status")
-
-                return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
-                    "nsState"
-                )
-
-                return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
-                    "revision"
-                )
-
-                mock_charm_hash.assert_not_called()
-                mock_software_version.assert_not_called()
-                mock_juju_bundle.assert_not_called()
-                mock_charm_upgrade.assert_not_called()
-                fs.sync.assert_not_called()
-
-                self.assertEqual(return_ns_state, expected_ns_state)
-                self.assertEqual(return_operation_state, expected_operation_state)
-                self.assertEqual(return_operation_error, expected_operation_error)
-                self.assertEqual(
-                    return_ns_operational_state, expected_ns_operational_state
-                )
-                self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
-
-            mock_reset()
-
-        with self.subTest(
-            i=3,
-            t="Update type: CHANGE_VNFPKG, latest_vnfd revision changed, "
-            "Charm package is not changed, sw-version is not changed.",
-        ):
-
-            self.db.set_one(
-                "vnfds", q_filter={"_id": vnfd_id}, update_dict={"_admin.revision": 3}
-            )
-
-            self.db.set_one(
-                "vnfds_revisions",
-                q_filter={"_id": vnfd_id + ":1"},
-                update_dict={"_admin.revision": 1},
-            )
-
-            self.db.set_one(
-                "vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1}
-            )
-
-            mock_charm_hash = Mock(autospec=True)
-            mock_charm_hash.return_value = False
-
-            mock_juju_bundle = Mock(return_value=None)
-
-            mock_software_version = Mock(autospec=True)
-
-            mock_charm_upgrade = asynctest.Mock(autospec=True)
-            task = asyncio.Future()
-            task.set_result(("COMPLETED", "some_output"))
-            mock_charm_upgrade.return_value = task
-            mock_software_version.side_effect = ["1.0", "1.0"]
-
-            fs = Mock(autospec=True)
-            fs.path.__add__ = Mock()
-            fs.path.side_effect = ["/", "/", "/", "/"]
-            fs.sync.side_effect = [None, None]
-
-            instance = self.my_ns
-
-            expected_operation_state = "COMPLETED"
-            expected_operation_error = ""
-            expected_vnfr_revision = 3
-            expected_ns_state = "INSTANTIATED"
-            expected_ns_operational_state = "running"
-
-            with patch.object(instance, "fs", fs), patch(
-                "osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed", mock_charm_hash
-            ), patch("osm_lcm.ns.NsLcm._ns_charm_upgrade", mock_charm_upgrade), patch(
-                "osm_lcm.lcm_utils.check_juju_bundle_existence", mock_juju_bundle
-            ):
-
-                await instance.update(nsr_id, nslcmop_id)
-
-                return_operation_state = self.db.get_one(
-                    "nslcmops", {"_id": nslcmop_id}
-                ).get("operationState")
-
-                return_operation_error = self.db.get_one(
-                    "nslcmops", {"_id": nslcmop_id}
-                ).get("errorMessage")
-
-                return_ns_operational_state = self.db.get_one(
-                    "nsrs", {"_id": nsr_id}
-                ).get("operational-status")
-
-                return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
-                    "revision"
-                )
-
-                return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
-                    "nsState"
-                )
-
-                mock_charm_hash.assert_called_with(
-                    "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:1/hackfest_3charmed_vnfd/charms/simple",
-                    "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:3/hackfest_3charmed_vnfd/charms/simple",
-                )
-
-                self.assertEqual(fs.sync.call_count, 2)
-                self.assertEqual(mock_charm_hash.call_count, 1)
-
-                mock_juju_bundle.assert_not_called()
-                mock_charm_upgrade.assert_not_called()
-
-                self.assertEqual(return_ns_state, expected_ns_state)
-                self.assertEqual(return_operation_state, expected_operation_state)
-                self.assertEqual(return_operation_error, expected_operation_error)
-                self.assertEqual(
-                    return_ns_operational_state, expected_ns_operational_state
-                )
-                self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
-
-            mock_reset()
-
-        with self.subTest(
-            i=4,
-            t="Update type: CHANGE_VNFPKG, latest_vnfd revision changed, "
-            "Charm package exists, sw-version changed.",
-        ):
-
-            self.db.set_one(
-                "vnfds",
-                q_filter={"_id": vnfd_id},
-                update_dict={"_admin.revision": 3, "software-version": "3.0"},
-            )
-
-            self.db.set_one(
-                "vnfds_revisions",
-                q_filter={"_id": vnfd_id + ":1"},
-                update_dict={"_admin.revision": 1},
-            )
+    @patch("osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed")
+    @patch(
+        "osm_lcm.ns.NsLcm._ns_charm_upgrade", new_callable=asynctest.Mock(autospec=True)
+    )
+    @patch("osm_lcm.data_utils.vnfd.find_software_version")
+    @patch("osm_lcm.lcm_utils.check_juju_bundle_existence")
+    async def test_update_change_vnfpkg_sw_version_not_changed(
+        self,
+        mock_juju_bundle,
+        mock_software_version,
+        mock_charm_upgrade,
+        mock_charm_hash,
+    ):
+        """Update type: CHANGE_VNFPKG, latest_vnfd revision changed,
+        Charm package changed, sw-version is not changed"""
+        self.db.set_one(
+            "vnfds",
+            q_filter={"_id": vnfd_id},
+            update_dict={"_admin.revision": 3, "kdu": []},
+        )
 
-            self.db.set_one(
-                "vnfrs",
-                q_filter={"_id": vnfr_id},
-                update_dict={"revision": 1},
-            )
+        self.db.set_one(
+            "vnfds_revisions",
+            q_filter={"_id": vnfd_id + ":1"},
+            update_dict={"_admin.revision": 1, "kdu": []},
+        )
 
-            mock_charm_hash = Mock(autospec=True)
-            mock_charm_hash.return_value = False
+        self.db.set_one("vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1})
 
-            mock_juju_bundle = Mock(return_value=None)
+        mock_charm_hash.return_value = True
+        mock_software_version.side_effect = ["1.0", "1.0"]
 
-            mock_charm_upgrade = asynctest.Mock(autospec=True)
-            task = asyncio.Future()
-            task.set_result(("COMPLETED", "some_output"))
-            mock_charm_upgrade.return_value = task
+        task = asyncio.Future()
+        task.set_result(("COMPLETED", "some_output"))
+        mock_charm_upgrade.return_value = task
 
-            mock_charm_artifact = Mock(autospec=True)
-            mock_charm_artifact.side_effect = [
-                "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:1/hackfest_3charmed_vnfd/charms/simple",
-                "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77/hackfest_3charmed_vnfd/charms/simple",
-            ]
+        instance = self.my_ns
+        fs = deepcopy(update_fs)
+        instance.fs = fs
 
-            fs = Mock(autospec=True)
-            fs.path.__add__ = Mock()
-            fs.path.side_effect = ["/", "/", "/", "/"]
-            fs.sync.side_effect = [None, None]
+        expected_operation_state = "COMPLETED"
+        expected_operation_error = ""
+        expected_vnfr_revision = 3
+        expected_ns_state = "INSTANTIATED"
+        expected_ns_operational_state = "running"
 
-            instance = self.my_ns
+        await instance.update(nsr_id, nslcmop_id)
+        return_operation_state = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "operationState"
+        )
+        return_operation_error = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "errorMessage"
+        )
+        return_ns_operational_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
+            "operational-status"
+        )
+        return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
+            "revision"
+        )
+        return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get("nsState")
+        mock_charm_hash.assert_called_with(
+            f"{vnfd_id}:1/hackfest_3charmed_vnfd/charms/simple",
+            f"{vnfd_id}:3/hackfest_3charmed_vnfd/charms/simple",
+        )
+        self.assertEqual(fs.sync.call_count, 2)
+        self.assertEqual(return_ns_state, expected_ns_state)
+        self.assertEqual(return_operation_state, expected_operation_state)
+        self.assertEqual(return_operation_error, expected_operation_error)
+        self.assertEqual(return_ns_operational_state, expected_ns_operational_state)
+        self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
+
+    @patch("osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed")
+    @patch(
+        "osm_lcm.ns.NsLcm._ns_charm_upgrade", new_callable=asynctest.Mock(autospec=True)
+    )
+    @patch("osm_lcm.data_utils.vnfd.find_software_version")
+    @patch("osm_lcm.lcm_utils.check_juju_bundle_existence")
+    async def test_update_change_vnfpkg_vnfd_revision_not_changed(
+        self,
+        mock_juju_bundle,
+        mock_software_version,
+        mock_charm_upgrade,
+        mock_charm_hash,
+    ):
+        """Update type: CHANGE_VNFPKG, latest_vnfd revision not changed"""
+        self.db.set_one(
+            "vnfds", q_filter={"_id": vnfd_id}, update_dict={"_admin.revision": 1}
+        )
+        self.db.set_one("vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1})
 
-            expected_operation_state = "FAILED"
-            expected_operation_error = "FAILED Checking if existing VNF has charm: Software version change is not supported as VNF instance 6421c7c9-d865-4fb4-9a13-d4275d243e01 has charm."
-            expected_vnfr_revision = 1
-            expected_ns_state = "INSTANTIATED"
-            expected_ns_operational_state = "running"
+        mock_charm_hash.return_value = True
 
-            with patch.object(instance, "fs", fs), patch(
-                "osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed", mock_charm_hash
-            ), patch("osm_lcm.ns.NsLcm._ns_charm_upgrade", mock_charm_upgrade), patch(
-                "osm_lcm.lcm_utils.get_charm_artifact_path", mock_charm_artifact
-            ):
+        task = asyncio.Future()
+        task.set_result(("COMPLETED", "some_output"))
+        mock_charm_upgrade.return_value = task
 
-                await instance.update(nsr_id, nslcmop_id)
-
-                return_operation_state = self.db.get_one(
-                    "nslcmops", {"_id": nslcmop_id}
-                ).get("operationState")
-
-                return_operation_error = self.db.get_one(
-                    "nslcmops", {"_id": nslcmop_id}
-                ).get("errorMessage")
-
-                return_ns_operational_state = self.db.get_one(
-                    "nsrs", {"_id": nsr_id}
-                ).get("operational-status")
-
-                return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
-                    "revision"
-                )
-
-                return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
-                    "nsState"
-                )
-
-                self.assertEqual(fs.sync.call_count, 2)
-                mock_charm_hash.assert_not_called()
-
-                mock_juju_bundle.assert_not_called()
-                mock_charm_upgrade.assert_not_called()
-
-                self.assertEqual(return_ns_state, expected_ns_state)
-                self.assertEqual(return_operation_state, expected_operation_state)
-                self.assertEqual(return_operation_error, expected_operation_error)
-                self.assertEqual(
-                    return_ns_operational_state, expected_ns_operational_state
-                )
-                self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
-
-            mock_reset()
-
-        with self.subTest(
-            i=5,
-            t="Update type: CHANGE_VNFPKG, latest_vnfd revision changed,"
-            "Charm package exists, sw-version not changed, juju-bundle exists",
-        ):
-
-            self.db.set_one(
-                "vnfds",
-                q_filter={"_id": vnfd_id},
-                update_dict={
-                    "_admin.revision": 3,
-                    "software-version": "1.0",
-                    "kdu.0.juju-bundle": "stable/native-kdu",
-                },
-            )
+        instance = self.my_ns
 
-            self.db.set_one(
-                "vnfds_revisions",
-                q_filter={"_id": vnfd_id + ":1"},
-                update_dict={
-                    "_admin.revision": 1,
-                    "software-version": "1.0",
-                    "kdu.0.juju-bundle": "stable/native-kdu",
-                },
-            )
+        expected_operation_state = "COMPLETED"
+        expected_operation_error = ""
+        expected_vnfr_revision = 1
+        expected_ns_state = "INSTANTIATED"
+        expected_ns_operational_state = "running"
 
-            self.db.set_one(
-                "vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1}
-            )
+        await instance.update(nsr_id, nslcmop_id)
+        return_operation_state = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "operationState"
+        )
+        return_operation_error = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "errorMessage"
+        )
+        return_ns_operational_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
+            "operational-status"
+        )
+        return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get("nsState")
+        return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
+            "revision"
+        )
+        mock_charm_hash.assert_not_called()
+        mock_software_version.assert_not_called()
+        mock_juju_bundle.assert_not_called()
+        mock_charm_upgrade.assert_not_called()
+        update_fs.sync.assert_not_called()
+        self.assertEqual(return_ns_state, expected_ns_state)
+        self.assertEqual(return_operation_state, expected_operation_state)
+        self.assertEqual(return_operation_error, expected_operation_error)
+        self.assertEqual(return_ns_operational_state, expected_ns_operational_state)
+        self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
+
+    @patch("osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed")
+    @patch(
+        "osm_lcm.ns.NsLcm._ns_charm_upgrade", new_callable=asynctest.Mock(autospec=True)
+    )
+    @patch("osm_lcm.data_utils.vnfd.find_software_version")
+    @patch("osm_lcm.lcm_utils.check_juju_bundle_existence")
+    async def test_update_change_vnfpkg_charm_is_not_changed(
+        self,
+        mock_juju_bundle,
+        mock_software_version,
+        mock_charm_upgrade,
+        mock_charm_hash,
+    ):
+        """Update type: CHANGE_VNFPKG, latest_vnfd revision changed
+        Charm package is not changed, sw-version is not changed"""
+        self.db.set_one(
+            "vnfds",
+            q_filter={"_id": vnfd_id},
+            update_dict={"_admin.revision": 3, "kdu": []},
+        )
+        self.db.set_one(
+            "vnfds_revisions",
+            q_filter={"_id": vnfd_id + ":1"},
+            update_dict={"_admin.revision": 1, "kdu": []},
+        )
+        self.db.set_one("vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1})
+
+        mock_charm_hash.return_value = False
+        mock_software_version.side_effect = ["1.0", "1.0"]
+
+        instance = self.my_ns
+        fs = deepcopy(update_fs)
+        instance.fs = fs
+        expected_operation_state = "COMPLETED"
+        expected_operation_error = ""
+        expected_vnfr_revision = 3
+        expected_ns_state = "INSTANTIATED"
+        expected_ns_operational_state = "running"
+
+        await instance.update(nsr_id, nslcmop_id)
+        return_operation_state = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "operationState"
+        )
+        return_operation_error = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "errorMessage"
+        )
+        return_ns_operational_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
+            "operational-status"
+        )
+        return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
+            "revision"
+        )
+        return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get("nsState")
+        mock_charm_hash.assert_called_with(
+            f"{vnfd_id}:1/hackfest_3charmed_vnfd/charms/simple",
+            f"{vnfd_id}:3/hackfest_3charmed_vnfd/charms/simple",
+        )
+        self.assertEqual(fs.sync.call_count, 2)
+        self.assertEqual(mock_charm_hash.call_count, 1)
+        mock_juju_bundle.assert_not_called()
+        mock_charm_upgrade.assert_not_called()
+        self.assertEqual(return_ns_state, expected_ns_state)
+        self.assertEqual(return_operation_state, expected_operation_state)
+        self.assertEqual(return_operation_error, expected_operation_error)
+        self.assertEqual(return_ns_operational_state, expected_ns_operational_state)
+        self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
+
+    @patch("osm_lcm.lcm_utils.check_juju_bundle_existence")
+    @patch("osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed")
+    @patch(
+        "osm_lcm.ns.NsLcm._ns_charm_upgrade", new_callable=asynctest.Mock(autospec=True)
+    )
+    @patch("osm_lcm.lcm_utils.get_charm_artifact_path")
+    async def test_update_change_vnfpkg_sw_version_changed(
+        self, mock_charm_artifact, mock_charm_upgrade, mock_charm_hash, mock_juju_bundle
+    ):
+        """Update type: CHANGE_VNFPKG, latest_vnfd revision changed
+        Charm package exists, sw-version changed."""
+        self.db.set_one(
+            "vnfds",
+            q_filter={"_id": vnfd_id},
+            update_dict={"_admin.revision": 3, "software-version": "3.0", "kdu": []},
+        )
+        self.db.set_one(
+            "vnfds_revisions",
+            q_filter={"_id": vnfd_id + ":1"},
+            update_dict={"_admin.revision": 1, "kdu": []},
+        )
+        self.db.set_one("vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1})
+        mock_charm_hash.return_value = False
 
-            mock_charm_hash = Mock(autospec=True)
-            mock_charm_hash.return_value = True
-
-            mock_charm_artifact = Mock(autospec=True)
-            mock_charm_artifact.side_effect = [
-                "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:1/hackfest_3charmed_vnfd/charms/simple",
-                "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77/hackfest_3charmed_vnfd/charms/simple",
-            ]
-
-            fs = Mock(autospec=True)
-            fs.path.__add__ = Mock()
-            fs.path.side_effect = ["/", "/", "/", "/"]
-            fs.sync.side_effect = [None, None]
-
-            instance = self.my_ns
-
-            expected_operation_state = "FAILED"
-            expected_operation_error = "FAILED Checking whether VNF uses juju bundle: Charm upgrade is not supported for the instance which uses juju-bundle: stable/native-kdu"
-            expected_vnfr_revision = 1
-            expected_ns_state = "INSTANTIATED"
-            expected_ns_operational_state = "running"
-
-            with patch.object(instance, "fs", fs), patch(
-                "osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed", mock_charm_hash
-            ), patch("osm_lcm.lcm_utils.get_charm_artifact_path", mock_charm_artifact):
-
-                await instance.update(nsr_id, nslcmop_id)
-
-                return_operation_state = self.db.get_one(
-                    "nslcmops", {"_id": nslcmop_id}
-                ).get("operationState")
-
-                return_operation_error = self.db.get_one(
-                    "nslcmops", {"_id": nslcmop_id}
-                ).get("errorMessage")
-
-                return_ns_operational_state = self.db.get_one(
-                    "nsrs", {"_id": nsr_id}
-                ).get("operational-status")
-
-                return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
-                    "revision"
-                )
-
-                return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
-                    "nsState"
-                )
-
-                self.assertEqual(fs.sync.call_count, 2)
-                self.assertEqual(mock_charm_hash.call_count, 1)
-                self.assertEqual(mock_charm_hash.call_count, 1)
-
-                mock_charm_upgrade.assert_not_called()
-
-                self.assertEqual(return_ns_state, expected_ns_state)
-                self.assertEqual(return_operation_state, expected_operation_state)
-                self.assertEqual(return_operation_error, expected_operation_error)
-                self.assertEqual(
-                    return_ns_operational_state, expected_ns_operational_state
-                )
-                self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
-
-            mock_reset()
-
-        with self.subTest(
-            i=6,
-            t="Update type: CHANGE_VNFPKG, latest_vnfd revision changed,"
-            "Charm package exists, sw-version not changed, charm-upgrade failed",
-        ):
-
-            self.db.set_one(
-                "vnfds",
-                q_filter={"_id": vnfd_id},
-                update_dict={
-                    "_admin.revision": 3,
-                    "software-version": "1.0",
-                    "kdu": [],
-                },
-            )
+        mock_charm_artifact.side_effect = [
+            f"{vnfd_id}:1/hackfest_3charmed_vnfd/charms/simple",
+            f"{vnfd_id}:3/hackfest_3charmed_vnfd/charms/simple",
+        ]
 
-            self.db.set_one(
-                "vnfds_revisions",
-                q_filter={"_id": vnfd_id + ":1"},
-                update_dict={
-                    "_admin.revision": 1,
-                    "software-version": "1.0",
-                    "kdu": [],
-                },
-            )
+        instance = self.my_ns
+        fs = deepcopy(update_fs)
+        instance.fs = fs
+        expected_operation_state = "FAILED"
+        expected_operation_error = "FAILED Checking if existing VNF has charm: Software version change is not supported as VNF instance 6421c7c9-d865-4fb4-9a13-d4275d243e01 has charm."
+        expected_vnfr_revision = 1
+        expected_ns_state = "INSTANTIATED"
+        expected_ns_operational_state = "running"
+
+        await instance.update(nsr_id, nslcmop_id)
+        return_operation_state = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "operationState"
+        )
+        return_operation_error = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "errorMessage"
+        )
+        return_ns_operational_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
+            "operational-status"
+        )
+        return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
+            "revision"
+        )
+        return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get("nsState")
+        self.assertEqual(fs.sync.call_count, 2)
+        mock_charm_hash.assert_not_called()
+        mock_juju_bundle.assert_not_called()
+        mock_charm_upgrade.assert_not_called()
+        self.assertEqual(return_ns_state, expected_ns_state)
+        self.assertEqual(return_operation_state, expected_operation_state)
+        self.assertEqual(return_operation_error, expected_operation_error)
+        self.assertEqual(return_ns_operational_state, expected_ns_operational_state)
+        self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
+
+    @patch("osm_lcm.lcm_utils.check_juju_bundle_existence")
+    @patch("osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed")
+    @patch(
+        "osm_lcm.ns.NsLcm._ns_charm_upgrade", new_callable=asynctest.Mock(autospec=True)
+    )
+    @patch("osm_lcm.data_utils.vnfd.find_software_version")
+    async def test_update_change_vnfpkg_juju_bundle_exists(
+        self,
+        mock_software_version,
+        mock_charm_upgrade,
+        mock_charm_hash,
+        mock_juju_bundle,
+    ):
+        """Update type: CHANGE_VNFPKG, latest_vnfd revision changed
+        Charm package exists, sw-version not changed, juju-bundle exists"""
+        # Upgrade is not allowed with juju bundles, this will cause TypeError
+        self.db.set_one(
+            "vnfds",
+            q_filter={"_id": vnfd_id},
+            update_dict={
+                "_admin.revision": 5,
+                "software-version": "1.0",
+                "kdu": [{"kdu_name": "native-kdu", "juju-bundle": "stable/native-kdu"}],
+            },
+        )
+        self.db.set_one(
+            "vnfds_revisions",
+            q_filter={"_id": vnfd_id + ":1"},
+            update_dict={
+                "_admin.revision": 1,
+                "software-version": "1.0",
+                "kdu": [{"kdu_name": "native-kdu", "juju-bundle": "stable/native-kdu"}],
+            },
+        )
+        self.db.set_one(
+            "nsrs",
+            q_filter={"_id": nsr_id},
+            update_dict={"_admin.deployed.VCA.0.kdu_name": "native-kdu"},
+        )
+        self.db.set_one("vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1})
+
+        mock_charm_hash.side_effect = [True]
+        mock_software_version.side_effect = ["1.0", "1.0"]
+        mock_juju_bundle.return_value = True
+        instance = self.my_ns
+        fs = deepcopy(update_fs)
+        instance.fs = fs
+
+        expected_vnfr_revision = 1
+        expected_ns_state = "INSTANTIATED"
+        expected_ns_operational_state = "running"
+
+        await instance.update(nsr_id, nslcmop_id)
+        return_ns_operational_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
+            "operational-status"
+        )
+        return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
+            "revision"
+        )
+        return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get("nsState")
+        self.assertEqual(fs.sync.call_count, 2)
+        mock_charm_upgrade.assert_not_called()
+        mock_charm_hash.assert_not_called()
+        self.assertEqual(return_ns_state, expected_ns_state)
+        self.assertEqual(return_ns_operational_state, expected_ns_operational_state)
+        self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
+
+    @patch("osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed")
+    @patch(
+        "osm_lcm.ns.NsLcm._ns_charm_upgrade", new_callable=asynctest.Mock(autospec=True)
+    )
+    async def test_update_change_vnfpkg_charm_upgrade_failed(
+        self, mock_charm_upgrade, mock_charm_hash
+    ):
+        """ "Update type: CHANGE_VNFPKG, latest_vnfd revision changed"
+        Charm package exists, sw-version not changed, charm-upgrade failed"""
+        self.db.set_one(
+            "vnfds",
+            q_filter={"_id": vnfd_id},
+            update_dict={"_admin.revision": 3, "software-version": "1.0", "kdu": []},
+        )
+        self.db.set_one(
+            "vnfds_revisions",
+            q_filter={"_id": vnfd_id + ":1"},
+            update_dict={"_admin.revision": 1, "software-version": "1.0", "kdu": []},
+        )
+        self.db.set_one("vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1})
 
-            self.db.set_one(
-                "vnfrs", q_filter={"_id": vnfr_id}, update_dict={"revision": 1}
-            )
+        mock_charm_hash.return_value = True
 
-            mock_charm_hash = Mock(autospec=True)
-            mock_charm_hash.return_value = True
-
-            mock_charm_upgrade = asynctest.Mock(autospec=True)
-            task = asyncio.Future()
-            task.set_result(("FAILED", "some_error"))
-            mock_charm_upgrade.return_value = task
-
-            mock_charm_artifact = Mock(autospec=True)
-            mock_charm_artifact.side_effect = [
-                "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:1/hackfest_3charmed_vnfd/charms/simple",
-                "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77/hackfest_3charmed_vnfd/charms/simple",
-            ]
-
-            fs = Mock(autospec=True)
-            fs.path.__add__ = Mock()
-            fs.path.side_effect = ["/", "/", "/", "/"]
-            fs.sync.side_effect = [None, None]
-
-            instance = self.my_ns
-
-            expected_operation_state = "FAILED"
-            expected_operation_error = "some_error"
-            expected_vnfr_revision = 1
-            expected_ns_state = "INSTANTIATED"
-            expected_ns_operational_state = "running"
-
-            with patch.object(instance, "fs", fs), patch(
-                "osm_lcm.lcm_utils.LcmBase.check_charm_hash_changed", mock_charm_hash
-            ), patch("osm_lcm.ns.NsLcm._ns_charm_upgrade", mock_charm_upgrade):
-
-                await instance.update(nsr_id, nslcmop_id)
-
-                return_operation_state = self.db.get_one(
-                    "nslcmops", {"_id": nslcmop_id}
-                ).get("operationState")
-
-                return_operation_error = self.db.get_one(
-                    "nslcmops", {"_id": nslcmop_id}
-                ).get("errorMessage")
-
-                return_ns_operational_state = self.db.get_one(
-                    "nsrs", {"_id": nsr_id}
-                ).get("operational-status")
-
-                return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
-                    "revision"
-                )
-
-                return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
-                    "nsState"
-                )
-
-                self.assertEqual(fs.sync.call_count, 2)
-                self.assertEqual(mock_charm_hash.call_count, 1)
-                self.assertEqual(mock_charm_upgrade.call_count, 1)
-
-                self.assertEqual(return_ns_state, expected_ns_state)
-                self.assertEqual(return_operation_state, expected_operation_state)
-                self.assertEqual(return_operation_error, expected_operation_error)
-                self.assertEqual(
-                    return_ns_operational_state, expected_ns_operational_state
-                )
-                self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
-
-            mock_reset()
-
-    def test_ns_update_helper_methods(self):
-        def mock_reset():
-            fs.mock_reset()
-            mock_path.mock_reset()
-            mock_checksumdir.mock_reset()
-
-        with self.subTest(
-            i=1, t="Find software version, VNFD does not have have software version"
-        ):
-            # Testing method find_software_version
-
-            db_vnfd = self.db.get_one(
-                "vnfds", {"_id": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77"}
-            )
-            expected_result = "1.0"
-            result = find_software_version(db_vnfd)
-            self.assertEqual(
-                result, expected_result, "Default sw version should be 1.0"
-            )
+        task = asyncio.Future()
+        task.set_result(("FAILED", "some_error"))
+        mock_charm_upgrade.return_value = task
 
-        with self.subTest(
-            i=2, t="Find software version, VNFD includes software version"
-        ):
-            # Testing method find_software_version
+        instance = self.my_ns
+        fs = deepcopy(update_fs)
+        instance.fs = fs
+        expected_operation_state = "FAILED"
+        expected_operation_error = "some_error"
+        expected_vnfr_revision = 1
+        expected_ns_state = "INSTANTIATED"
+        expected_ns_operational_state = "running"
 
-            db_vnfd = self.db.get_one(
-                "vnfds", {"_id": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77"}
-            )
-            db_vnfd["software-version"] = "3.1"
-            expected_result = "3.1"
-            result = find_software_version(db_vnfd)
-            self.assertEqual(result, expected_result, "VNFD software version is wrong")
+        await instance.update(nsr_id, nslcmop_id)
+        return_operation_state = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "operationState"
+        )
+        return_operation_error = self.db.get_one("nslcmops", {"_id": nslcmop_id}).get(
+            "errorMessage"
+        )
+        return_ns_operational_state = self.db.get_one("nsrs", {"_id": nsr_id}).get(
+            "operational-status"
+        )
+        return_vnfr_revision = self.db.get_one("vnfrs", {"_id": vnfr_id}).get(
+            "revision"
+        )
+        return_ns_state = self.db.get_one("nsrs", {"_id": nsr_id}).get("nsState")
+        self.assertEqual(fs.sync.call_count, 2)
+        self.assertEqual(mock_charm_hash.call_count, 1)
+        self.assertEqual(mock_charm_upgrade.call_count, 1)
+        self.assertEqual(return_ns_state, expected_ns_state)
+        self.assertEqual(return_operation_state, expected_operation_state)
+        self.assertEqual(return_operation_error, expected_operation_error)
+        self.assertEqual(return_ns_operational_state, expected_ns_operational_state)
+        self.assertEqual(return_vnfr_revision, expected_vnfr_revision)
+
+    def test_ns_update_find_sw_version_vnfd_not_includes(self):
+        """Find software version, VNFD does not have software version"""
+
+        db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
+        expected_result = "1.0"
+        result = find_software_version(db_vnfd)
+        self.assertEqual(result, expected_result, "Default sw version should be 1.0")
+
+    def test_ns_update_find_sw_version_vnfd_includes(self):
+        """Find software version, VNFD includes software version"""
+
+        db_vnfd = self.db.get_one("vnfds", {"_id": vnfd_id})
+        db_vnfd["software-version"] = "3.1"
+        expected_result = "3.1"
+        result = find_software_version(db_vnfd)
+        self.assertEqual(result, expected_result, "VNFD software version is wrong")
+
+    @patch("os.path.exists")
+    @patch("osm_lcm.lcm_utils.LcmBase.compare_charmdir_hash")
+    @patch("osm_lcm.lcm_utils.LcmBase.compare_charm_hash")
+    def test_ns_update_check_charm_hash_not_changed(
+        self, mock_compare_charm_hash, mock_compare_charmdir_hash, mock_path_exists
+    ):
+        """Check charm hash, Hash did not change"""
 
-        with self.subTest(i=3, t="Check charm hash, Hash has did not change"):
-            # Testing method check_charm_hash_changed
+        current_path, target_path = "/tmp/charm1", "/tmp/charm1"
 
-            current_path, target_path = "/tmp/charm1", "/tmp/charm1"
-            fs = Mock(autospec=True)
-            fs.path.__add__ = Mock()
-            fs.path.side_effect = ["/", "/", "/", "/"]
+        fs = Mock()
+        fs.path.__add__ = Mock()
+        fs.path.side_effect = [current_path, target_path]
+        fs.path.__add__.side_effect = [current_path, target_path]
 
-            mock_path = Mock(autospec=True)
-            mock_path.exists.side_effect = [True, True]
+        mock_path_exists.side_effect = [True, True]
 
-            mock_checksumdir = Mock(autospec=True)
-            mock_checksumdir.dirhash.side_effect = ["hash_value", "hash_value"]
+        mock_compare_charmdir_hash.return_value = callable(False)
+        mock_compare_charm_hash.return_value = callable(False)
 
-            instance = self.my_ns
-            expected_result = False
+        instance = self.my_ns
+        instance.fs = fs
+        expected_result = False
 
-            with patch.object(instance, "fs", fs), patch(
-                "checksumdir.dirhash", mock_checksumdir.dirhash
-            ), patch("os.path.exists", mock_path.exists):
+        result = instance.check_charm_hash_changed(current_path, target_path)
+        self.assertEqual(result, expected_result, "Wrong charm hash control value")
+        self.assertEqual(mock_path_exists.call_count, 2)
+        self.assertEqual(mock_compare_charmdir_hash.call_count, 1)
+        self.assertEqual(mock_compare_charm_hash.call_count, 0)
 
-                result = instance.check_charm_hash_changed(current_path, target_path)
-                self.assertEqual(
-                    result, expected_result, "Wrong charm hash control value"
-                )
-                self.assertEqual(mock_path.exists.call_count, 2)
-                self.assertEqual(mock_checksumdir.dirhash.call_count, 2)
+    @patch("os.path.exists")
+    @patch("osm_lcm.lcm_utils.LcmBase.compare_charmdir_hash")
+    @patch("osm_lcm.lcm_utils.LcmBase.compare_charm_hash")
+    def test_ns_update_check_charm_hash_changed(
+        self, mock_compare_charm_hash, mock_compare_charmdir_hash, mock_path_exists
+    ):
+        """Check charm hash, Hash has changed"""
+
+        current_path, target_path = "/tmp/charm1", "/tmp/charm2"
+
+        fs = Mock()
+        fs.path.__add__ = Mock()
+        fs.path.side_effect = [current_path, target_path, current_path, target_path]
+        fs.path.__add__.side_effect = [
+            current_path,
+            target_path,
+            current_path,
+            target_path,
+        ]
 
-            mock_reset()
+        mock_path_exists.side_effect = [True, True]
+        mock_compare_charmdir_hash.return_value = callable(True)
+        mock_compare_charm_hash.return_value = callable(True)
+
+        instance = self.my_ns
+        instance.fs = fs
+        expected_result = True
+
+        result = instance.check_charm_hash_changed(current_path, target_path)
+        self.assertEqual(result, expected_result, "Wrong charm hash control value")
+        self.assertEqual(mock_path_exists.call_count, 2)
+        self.assertEqual(mock_compare_charmdir_hash.call_count, 1)
+        self.assertEqual(mock_compare_charm_hash.call_count, 0)
+
+    @patch("os.path.exists")
+    @patch("osm_lcm.lcm_utils.LcmBase.compare_charmdir_hash")
+    @patch("osm_lcm.lcm_utils.LcmBase.compare_charm_hash")
+    def test_ns_update_check_no_charm_path(
+        self, mock_compare_charm_hash, mock_compare_charmdir_hash, mock_path_exists
+    ):
+        """Check charm hash, Charm path does not exist"""
+
+        current_path, target_path = "/tmp/charm1", "/tmp/charm2"
+
+        fs = Mock()
+        fs.path.__add__ = Mock()
+        fs.path.side_effect = [current_path, target_path, current_path, target_path]
+        fs.path.__add__.side_effect = [
+            current_path,
+            target_path,
+            current_path,
+            target_path,
+        ]
 
-        with self.subTest(i=4, t="Check charm hash, Hash has changed"):
-            # Testing method check_charm_hash_changed
+        mock_path_exists.side_effect = [True, False]
 
-            current_path, target_path = "/tmp/charm1", "/tmp/charm2"
-            fs = Mock(autospec=True)
-            fs.path.__add__ = Mock()
-            fs.path.side_effect = ["/", "/", "/", "/"]
+        mock_compare_charmdir_hash.return_value = callable(False)
+        mock_compare_charm_hash.return_value = callable(False)
+        instance = self.my_ns
+        instance.fs = fs
 
-            mock_path = Mock(autospec=True)
-            mock_path.exists.side_effect = [True, True]
+        with self.assertRaises(LcmException):
+            instance.check_charm_hash_changed(current_path, target_path)
+            self.assertEqual(mock_path_exists.call_count, 2)
+            self.assertEqual(mock_compare_charmdir_hash.call_count, 0)
+            self.assertEqual(mock_compare_charm_hash.call_count, 0)
 
-            mock_checksumdir = Mock(autospec=True)
-            mock_checksumdir.dirhash.side_effect = ["hash_value", "another_hash_value"]
+    def test_ns_update_check_juju_bundle_existence_bundle_exists(self):
+        """Check juju bundle existence"""
+        test_vnfd2 = self.db.get_one(
+            "vnfds", {"_id": "d96b1cdf-5ad6-49f7-bf65-907ada989293"}
+        )
+        expected_result = "stable/native-kdu"
+        result = check_juju_bundle_existence(test_vnfd2)
+        self.assertEqual(result, expected_result, "Wrong juju bundle name")
+
+    def test_ns_update_check_juju_bundle_existence_bundle_does_not_exist(self):
+        """Check juju bundle existence"""
+        test_vnfd1 = self.db.get_one("vnfds", {"_id": vnfd_id})
+        expected_result = None
+        result = check_juju_bundle_existence(test_vnfd1)
+        self.assertEqual(result, expected_result, "Wrong juju bundle name")
+
+    def test_ns_update_check_juju_bundle_existence_empty_vnfd(self):
+        """Check juju bundle existence"""
+        test_vnfd1 = {}
+        expected_result = None
+        result = check_juju_bundle_existence(test_vnfd1)
+        self.assertEqual(result, expected_result, "Wrong juju bundle name")
+
+    def test_ns_update_check_juju_bundle_existence_invalid_vnfd(self):
+        """Check juju bundle existence"""
+        test_vnfd1 = [{"_id": vnfd_id}]
+        with self.assertRaises(AttributeError):
+            check_juju_bundle_existence(test_vnfd1)
+
+    def test_ns_update_check_juju_charm_artifacts_base_folder_wth_pkgdir(self):
+        """Check charm artifacts"""
+        base_folder = {"folder": vnfd_id, "pkg-dir": "hackfest_3charmed_vnfd"}
+        charm_name = "simple"
+        charm_type = "lxc_proxy_charm"
+        revision = 3
+        expected_result = f"{vnfd_id}:3/hackfest_3charmed_vnfd/charms/simple"
+        result = get_charm_artifact_path(base_folder, charm_name, charm_type, revision)
+        self.assertEqual(result, expected_result, "Wrong charm artifact path")
+
+    def test_ns_update_check_juju_charm_artifacts_base_folder_wthout_pkgdir(self):
+        """Check charm artifacts, SOL004 packages"""
+        base_folder = {"folder": vnfd_id}
+        charm_name = "basic"
+        charm_type, revision = "", ""
+        expected_result = f"{vnfd_id}/Scripts/helm-charts/basic"
+        result = get_charm_artifact_path(base_folder, charm_name, charm_type, revision)
+        self.assertEqual(result, expected_result, "Wrong charm artifact path")
+
+
+class TestInstantiateN2VC(TestBaseNS):
+    async def setUp(self):
+        await super().setUp()
+        self.db_nsr = yaml.safe_load(descriptors.db_nsrs_text)[0]
+        self.db_vnfr = yaml.safe_load(descriptors.db_vnfrs_text)[0]
+        self.vca_index = 1
+        self.my_ns._write_configuration_status = Mock()
+
+    async def call_instantiate_N2VC(self):
+        logging_text = "N2VC Instantiation"
+        config_descriptor = {"config-access": {"ssh-access": {"default-user": "admin"}}}
+        base_folder = {"pkg-dir": "", "folder": "~"}
+        stage = ["Stage", "Message"]
+
+        await self.my_ns.instantiate_N2VC(
+            logging_text=logging_text,
+            vca_index=self.vca_index,
+            nsi_id="nsi_id",
+            db_nsr=self.db_nsr,
+            db_vnfr=self.db_vnfr,
+            vdu_id=None,
+            kdu_name=None,
+            vdu_index=None,
+            kdu_index=None,
+            config_descriptor=config_descriptor,
+            deploy_params={},
+            base_folder=base_folder,
+            nslcmop_id="nslcmop_id",
+            stage=stage,
+            vca_type="native_charm",
+            vca_name="vca_name",
+            ee_config_descriptor={},
+        )
 
-            instance = self.my_ns
-            expected_result = True
+    def check_config_status(self, expected_status):
+        self.my_ns._write_configuration_status.assert_called_with(
+            nsr_id=self.db_nsr["_id"], vca_index=self.vca_index, status=expected_status
+        )
 
-            with patch.object(instance, "fs", fs), patch(
-                "checksumdir.dirhash", mock_checksumdir.dirhash
-            ), patch("os.path.exists", mock_path.exists):
+    async def call_ns_add_relation(self):
+        ee_relation = EERelation(
+            {
+                "nsr-id": self.db_nsr["_id"],
+                "vdu-profile-id": None,
+                "kdu-resource-profile-id": None,
+                "vnf-profile-id": "hackfest_vnf1",
+                "execution-environment-ref": "f48163a6-c807-47bc-9682-f72caef5af85.alf-c-ab",
+                "endpoint": "127.0.0.1",
+            }
+        )
 
-                result = instance.check_charm_hash_changed(current_path, target_path)
-                self.assertEqual(
-                    result, expected_result, "Wrong charm hash control value"
-                )
-                self.assertEqual(mock_path.exists.call_count, 2)
-                self.assertEqual(mock_checksumdir.dirhash.call_count, 2)
+        relation = Relation("relation-name", ee_relation, ee_relation)
+        cached_vnfrs = {"hackfest_vnf1": self.db_vnfr}
 
-            mock_reset()
+        return await self.my_ns._add_relation(
+            relation=relation,
+            vca_type="native_charm",
+            db_nsr=self.db_nsr,
+            cached_vnfds={},
+            cached_vnfrs=cached_vnfrs,
+        )
 
-        with self.subTest(i=5, t="Check charm hash, Charm path does not exists"):
-            # Testing method check_charm_hash_changed
+    async def test_add_relation_ok(self):
+        await self.call_instantiate_N2VC()
+        self.check_config_status(expected_status="READY")
 
-            current_path, target_path = "/tmp/charm1", "/tmp/charm2"
-            fs = Mock(autospec=True)
-            fs.path.__add__ = Mock()
-            fs.path.side_effect = ["/", "/", "/", "/"]
+    async def test_add_relation_returns_false_raises_exception(self):
+        self.my_ns._add_vca_relations = asynctest.CoroutineMock(return_value=False)
 
-            mock_path = Mock(autospec=True)
-            mock_path.exists.side_effect = [True, False]
+        with self.assertRaises(LcmException) as exception:
+            await self.call_instantiate_N2VC()
 
-            mock_checksumdir = Mock(autospec=True)
-            mock_checksumdir.dirhash.side_effect = ["hash_value", "hash_value"]
+        exception_msg = "Relations could not be added to VCA."
+        self.assertTrue(exception_msg in str(exception.exception))
+        self.check_config_status(expected_status="BROKEN")
 
-            instance = self.my_ns
+    async def test_add_relation_raises_lcm_exception(self):
+        exception_msg = "Relations FAILED"
+        self.my_ns._add_vca_relations = asynctest.CoroutineMock(
+            side_effect=LcmException(exception_msg)
+        )
 
-            with patch.object(instance, "fs", fs), patch(
-                "checksumdir.dirhash", mock_checksumdir.dirhash
-            ), patch("os.path.exists", mock_path.exists):
+        with self.assertRaises(LcmException) as exception:
+            await self.call_instantiate_N2VC()
 
-                with self.assertRaises(LcmException):
+        self.assertTrue(exception_msg in str(exception.exception))
+        self.check_config_status(expected_status="BROKEN")
 
-                    instance.check_charm_hash_changed(current_path, target_path)
-                    self.assertEqual(mock_path.exists.call_count, 2)
-                    self.assertEqual(mock_checksumdir.dirhash.call_count, 0)
+    async def test_n2vc_add_relation_fails_raises_exception(self):
+        exception_msg = "N2VC failed to add relations"
+        self.my_ns.n2vc.add_relation = asynctest.CoroutineMock(
+            side_effect=N2VCException(exception_msg)
+        )
+        with self.assertRaises(LcmException) as exception:
+            await self.call_ns_add_relation()
+        self.assertTrue(exception_msg in str(exception.exception))
 
-            mock_reset()
+    async def test_n2vc_add_relation_ok_returns_true(self):
+        self.my_ns.n2vc.add_relation = asynctest.CoroutineMock(return_value=None)
+        self.assertTrue(await self.call_ns_add_relation())
 
-        with self.subTest(i=6, t="Check juju bundle existence"):
-            # Testing method check_juju_bundle_existence
 
-            test_vnfd1 = self.db.get_one(
-                "vnfds", {"_id": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77"}
-            )
-            test_vnfd2 = self.db.get_one(
-                "vnfds", {"_id": "d96b1cdf-5ad6-49f7-bf65-907ada989293"}
-            )
+class TestGetVNFRelations(TestBaseNS):
+    async def setUp(self):
+        await super().setUp()
+        self.db_nsd = yaml.safe_load(descriptors.db_nsds_text)[0]
 
-            expected_result = None
-            result = check_juju_bundle_existence(test_vnfd1)
-            self.assertEqual(result, expected_result, "Wrong juju bundle name")
+    def test_ns_charm_vca_returns_empty_relations(self):
+        ns_charm_vca = {"member-vnf-index": None, "target_element": "ns"}
+        nsr_id = self.db_nsd["id"]
+        deployed_vca = DeployedVCA(nsr_id, ns_charm_vca)
 
-            expected_result = "stable/native-kdu"
-            result = check_juju_bundle_existence(test_vnfd2)
-            self.assertEqual(result, expected_result, "Wrong juju bundle name")
+        expected_relations = []
+        self.assertEqual(
+            expected_relations,
+            self.my_ns._get_vnf_relations(
+                nsr_id=nsr_id, nsd=self.db_nsd, vca=deployed_vca, cached_vnfds={}
+            ),
+        )
 
-        with self.subTest(i=7, t="Check charm artifacts"):
-            # Testing method check_juju_bundle_existence
+    def test_vnf_returns_relation(self):
+        vnf_vca = {
+            "member-vnf-index": "1",
+            "target_element": "vnf/0",
+            "ee_descriptor_id": "simple-ee",
+            "vdu_id": "mgmtVM",
+        }
+        nsr_id = self.db_nsd["id"]
+        deployed_vca = DeployedVCA(nsr_id, vnf_vca)
+
+        provider_dict = {
+            "nsr-id": nsr_id,
+            "vnf-profile-id": "1",
+            "vdu-profile-id": "mgmtVM",
+            "kdu-resource-profile-id": None,
+            "execution-environment-ref": "simple-ee",
+            "endpoint": "interface",
+        }
 
-            base_folder = {
-                "folder": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77",
-                "pkg-dir": "hackfest_3charmed_vnfd",
-            }
-            charm_name = "simple"
-            charm_type = "lxc_proxy_charm"
-            revision = 3
+        requirer_dict = {
+            "nsr-id": nsr_id,
+            "vnf-profile-id": "1",
+            "vdu-profile-id": "dataVM",
+            "kdu-resource-profile-id": None,
+            "execution-environment-ref": "simple-ee",
+            "endpoint": "interface",
+        }
 
-            expected_result = "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77:3/hackfest_3charmed_vnfd/charms/simple"
-            result = get_charm_artifact_path(
-                base_folder, charm_name, charm_type, revision
-            )
-            self.assertEqual(result, expected_result, "Wrong charm artifact path")
+        provider = EERelation(provider_dict)
+        requirer = EERelation(requirer_dict)
+        relation = Relation("relation", provider, requirer)
 
-            # SOL004 packages
-            base_folder = {
-                "folder": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77",
-            }
-            charm_name = "basic"
-            charm_type = ""
-            revision = ""
+        relations_found = self.my_ns._get_vnf_relations(
+            nsr_id=nsr_id, nsd=self.db_nsd, vca=deployed_vca, cached_vnfds={}
+        )
 
-            expected_result = (
-                "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77/Scripts/helm-charts/basic"
-            )
-            result = get_charm_artifact_path(
-                base_folder, charm_name, charm_type, revision
-            )
-            self.assertEqual(result, expected_result, "Wrong charm artifact path")
+        self.assertEqual(1, len(relations_found))
+        self.assertEqual(relation, relations_found[0])
 
 
 if __name__ == "__main__":