Feature 10908: LCM process NS update request
[osm/LCM.git] / osm_lcm / tests / test_ns.py
index ef87a4c..86e2136 100644 (file)
@@ -27,7 +27,11 @@ 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.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
 from uuid import uuid4
+from unittest.mock import Mock, patch
 
 from osm_lcm.tests import test_db_descriptors as descriptors
 
@@ -168,6 +172,10 @@ class TestMyNS(asynctest.TestCase):
             self.db.create_list(
                 "vnfds", yaml.load(descriptors.db_vnfds_text, Loader=yaml.Loader)
             )
+            self.db.create_list(
+                "vnfds_revisions",
+                yaml.load(descriptors.db_vnfds_revisions_text, Loader=yaml.Loader),
+            )
             self.db.create_list(
                 "nsds", yaml.load(descriptors.db_nsds_text, Loader=yaml.Loader)
             )
@@ -855,6 +863,748 @@ 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/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/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},
+            )
+
+            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_charm_upgrade = asynctest.Mock(autospec=True)
+            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",
+            ]
+
+            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 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"
+
+            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
+            ):
+
+                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",
+                },
+            )
+
+            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",
+                },
+            )
+
+            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_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": [],
+                },
+            )
+
+            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}
+            )
+
+            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"
+            )
+
+        with self.subTest(
+            i=2, t="Find software version, VNFD includes software version"
+        ):
+            # Testing method find_software_version
+
+            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")
+
+        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"
+            fs = Mock(autospec=True)
+            fs.path.__add__ = Mock()
+            fs.path.side_effect = ["/", "/", "/", "/"]
+
+            mock_path = Mock(autospec=True)
+            mock_path.exists.side_effect = [True, True]
+
+            mock_checksumdir = Mock(autospec=True)
+            mock_checksumdir.dirhash.side_effect = ["hash_value", "hash_value"]
+
+            instance = self.my_ns
+            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_checksumdir.dirhash.call_count, 2)
+
+            mock_reset()
+
+        with self.subTest(i=4, t="Check charm hash, Hash has changed"):
+            # Testing method check_charm_hash_changed
+
+            current_path, target_path = "/tmp/charm1", "/tmp/charm2"
+            fs = Mock(autospec=True)
+            fs.path.__add__ = Mock()
+            fs.path.side_effect = ["/", "/", "/", "/"]
+
+            mock_path = Mock(autospec=True)
+            mock_path.exists.side_effect = [True, True]
+
+            mock_checksumdir = Mock(autospec=True)
+            mock_checksumdir.dirhash.side_effect = ["hash_value", "another_hash_value"]
+
+            instance = self.my_ns
+            expected_result = True
+
+            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_checksumdir.dirhash.call_count, 2)
+
+            mock_reset()
+
+        with self.subTest(i=5, t="Check charm hash, Charm path does not exists"):
+            # Testing method check_charm_hash_changed
+
+            current_path, target_path = "/tmp/charm1", "/tmp/charm2"
+            fs = Mock(autospec=True)
+            fs.path.__add__ = Mock()
+            fs.path.side_effect = ["/", "/", "/", "/"]
+
+            mock_path = Mock(autospec=True)
+            mock_path.exists.side_effect = [True, False]
+
+            mock_checksumdir = Mock(autospec=True)
+            mock_checksumdir.dirhash.side_effect = ["hash_value", "hash_value"]
+
+            instance = self.my_ns
+
+            with patch.object(instance, "fs", fs), patch(
+                "checksumdir.dirhash", mock_checksumdir.dirhash
+            ), patch("os.path.exists", mock_path.exists):
+
+                with self.assertRaises(LcmException):
+
+                    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)
+
+            mock_reset()
+
+        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"}
+            )
+
+            expected_result = None
+            result = check_juju_bundle_existence(test_vnfd1)
+            self.assertEqual(result, expected_result, "Wrong juju bundle name")
+
+            expected_result = "stable/native-kdu"
+            result = check_juju_bundle_existence(test_vnfd2)
+            self.assertEqual(result, expected_result, "Wrong juju bundle name")
+
+        with self.subTest(i=7, t="Check charm artifacts"):
+            # Testing method check_juju_bundle_existence
+
+            base_folder = {
+                "folder": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77",
+                "pkg-dir": "hackfest_3charmed_vnfd",
+            }
+            charm_name = "simple"
+            charm_type = "lxc_proxy_charm"
+            revision = 3
+
+            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")
+
+            # SOL004 packages
+            base_folder = {
+                "folder": "7637bcf8-cf14-42dc-ad70-c66fcf1e6e77",
+            }
+            charm_name = "basic"
+            charm_type = ""
+            revision = ""
+
+            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")
+
 
 if __name__ == "__main__":
     asynctest.main()