OSMENG-1048 Implement day1 configuration for VDU

Day1 config implementation, arranging existing unit tests and imports
adding task and execution timeout policy for workflows in tests.

Change-Id: Ie5a2626eec01176723d8130576facbf4934d5285
Signed-off-by: Gulsum Atici <gulsum.atici@canonical.com>
diff --git a/osm_lcm/tests/test_vnf_activities.py b/osm_lcm/tests/test_vnf_activities.py
index 02fad62..0c346ee 100644
--- a/osm_lcm/tests/test_vnf_activities.py
+++ b/osm_lcm/tests/test_vnf_activities.py
@@ -14,19 +14,22 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-
 import asynctest
-from asyncio.exceptions import CancelledError
 from copy import deepcopy
+from unittest import TestCase
+from unittest.mock import Mock, patch
+
 from osm_common.dataclasses.temporal_dataclasses import (
     ChangeVnfInstantiationStateInput,
     ChangeVnfStateInput,
     GetTaskQueueInput,
     GetVimCloudInput,
-    GetVnfDetailsInput,
-    VnfInstantiateInput,
+    GetVnfDescriptorInput,
+    GetVnfRecordInput,
+    SetVnfModelInput,
     VnfInstantiationState,
     VnfState,
+    VduComputeConstraints,
 )
 from osm_common.dbbase import DbException
 from osm_common.temporal_constants import (
@@ -34,29 +37,17 @@
 )
 from osm_lcm.temporal.vnf_activities import VnfDbActivity, VnfOperations
 from temporalio.testing import ActivityEnvironment
-from unittest.mock import Mock
 
-vnfr_uuid = "d08d2da5-2120-476c-8538-deaeb4e88b3e"
-model_name = "a-model-name"
-vnf_instantiate_input = VnfInstantiateInput(vnfr_uuid=vnfr_uuid, model_name=model_name)
+
+vnfr_uuid = "9f472177-95c0-4335-b357-5cdc17a79965"
+vnfd_uuid = "97784f19-d254-4252-946c-cf92d85443ca"
+vim_uuid = "a64f7c6c-bc27-4ec8-b664-5500a3324eca"
+model_name = "my-model-name"
+set_vnf_model_input = SetVnfModelInput(vnfr_uuid=vnfr_uuid, model_name=model_name)
 cloud = "microk8s"
-sample_vnfr = {
-    "_id": "9f472177-95c0-4335-b357-5cdc17a79965",
-    "id": "9f472177-95c0-4335-b357-5cdc17a79965",
-    "nsr-id-ref": "dcf4c922-5a73-41bf-a6ca-870c22d6336c",
-    "vnfd-ref": "jar_vnfd_scalable",
-    "vnfd-id": "f1b38eac-190c-485d-9a74-c6e169c929d8",
-    "vim-account-id": "9b0bedc3-ea8e-42fd-acc9-dd03f4dee73c",
-}
-sample_vnfd = {
-    "_id": "97784f19-d254-4252-946c-cf92d85443ca",
-    "id": "sol006-vnf",
-    "provider": "Canonical",
-    "product-name": "test-vnf",
-    "software-version": "1.0",
-}
+nsr_uuid = "583726d4-957d-47f5-8df5-199456f7afd0"
 sample_vim_record = {
-    "_id": "a64f7c6c-bc27-4ec8-b664-5500a3324eca",
+    "_id": vim_uuid,
     "name": "juju",
     "vim_type": "paas",
     "vim_url": "192.168.1.100:17070",
@@ -70,6 +61,72 @@
         "ca_cert_content": "-----BEGIN-----",
     },
 }
+vim_account_id = "9b0bedc3-ea8e-42fd-acc9-dd03f4dee73c"
+vdu_id = "hackfest_basic-VM"
+vnf_index = "vnf-profile-id"
+sample_vnfr = {
+    "_id": vnfr_uuid,
+    "id": vnfr_uuid,
+    "nsr-id-ref": "dcf4c922-5a73-41bf-a6ca-870c22d6336c",
+    "vnfd-ref": "jar_vnfd_scalable",
+    "vnfd-id": "f1b38eac-190c-485d-9a74-c6e169c929d8",
+    "vim-account-id": vim_account_id,
+    "namespace": model_name,
+    "member-vnf-index-ref": vnf_index,
+}
+vnf_config = {
+    "member-vnf-index": vnf_index,
+    "vdu": [
+        {
+            "id": vdu_id,
+            "configurable-properties": {
+                "config::redirect-map": "https://osm.instantiation.params"
+            },
+        }
+    ],
+}
+app_config = {"domain_name1": "osm.org", "domain_name2": "osm.com"}
+config = [
+    {"key": "config::domain_name1", "value": "osm.org"},
+    {"key": "config::domain_name2", "value": "osm.com"},
+    {"key": "track", "value": "latest"},
+    {"key": "channel", "value": "stable"},
+]
+vdu = {
+    "id": vdu_id,
+    "name": "hackfest_basic-VM",
+    "sw-image-desc": "ubuntu18.04",
+    "virtual-compute-desc": "hackfest_basic-VM-compute",
+    "virtual-storage-desc": ["hackfest_basic-VM-storage"],
+    "configurable-properties": config,
+}
+vnfd_id = "97784f19-d254-4252-946c-cf92d85443ca"
+flavor_1 = {
+    "id": "compute-id-1",
+    "virtual-memory": {"size": "4"},
+    "virtual-cpu": {"cpu-architecture": "x86", "num-virtual-cpu": 2},
+}
+flavor_2 = {
+    "id": "compute-id-2",
+    "virtual-cpu": {"cpu-architecture": "x86", "num-virtual-cpu": 2},
+}
+flavor_3 = {
+    "id": "compute-id-2",
+    "virtual-memory": {"size": "4"},
+}
+sample_vnfd = {
+    "_id": vnfd_id,
+    "id": "sol006-vnf",
+    "provider": "Canonical",
+    "product-name": "test-vnf",
+    "software-version": "1.0",
+    "vdu": [vdu],
+    "virtual-compute-desc": [flavor_1, flavor_2],
+}
+
+
+class TestException(Exception):
+    pass
 
 
 class TestVnfDbActivity(asynctest.TestCase):
@@ -78,7 +135,7 @@
         self.env = ActivityEnvironment()
         self.vnf_db_activity = VnfDbActivity(self.db)
 
-    async def test_change_vnf_state_nominal_case(self):
+    async def test_change_vnf_state__successful__db_updated_as_expected(self):
         vnf_state = VnfState.STOPPED
         change_vnf_state_input = ChangeVnfStateInput(vnfr_uuid, vnf_state)
         await self.env.run(
@@ -88,7 +145,7 @@
             "vnfrs", {"_id": vnfr_uuid}, {"vnfState": vnf_state.name}
         )
 
-    async def test_change_vnf_state_db_raises_exception(self):
+    async def test_change_vnf_state__failed__raises_db_exception(self):
         change_vnf_state_input = ChangeVnfStateInput(vnfr_uuid, VnfState.STARTED)
         self.db.set_one.side_effect = DbException("not found")
         with self.assertRaises(DbException):
@@ -96,7 +153,9 @@
                 self.vnf_db_activity.change_vnf_state, change_vnf_state_input
             )
 
-    async def test_change_vnf_instantiation_state_nominal_case(self):
+    async def test_change_vnf_instantiation_state__successful__db_updated_as_expected(
+        self,
+    ):
         instantiation_state = VnfInstantiationState.NOT_INSTANTIATED
         change_instantiation_input = ChangeVnfInstantiationStateInput(
             vnfr_uuid, instantiation_state
@@ -111,28 +170,27 @@
             {"instantiationState": instantiation_state.name},
         )
 
-    async def test_change_vnf_instantiation_state_db_raises_exception(self):
+    async def test_change_vnf_instantiation_state__failed__raises_db_exception(self):
         change_instantiation_input = ChangeVnfInstantiationStateInput(
             vnfr_uuid, VnfInstantiationState.INSTANTIATED
         )
         self.db.set_one.side_effect = DbException("not found")
         with self.assertRaises(DbException):
             await self.env.run(
-                self.vnf_db_activity.change_vnf_state, change_instantiation_input
+                self.vnf_db_activity.change_vnf_instantiation_state,
+                change_instantiation_input,
             )
 
-    async def test_set_vnf_model_nominal_case(self):
-        await self.env.run(self.vnf_db_activity.set_vnf_model, vnf_instantiate_input)
+    async def test_set_vnf_model__successful__db_updated_as_expected(self):
+        await self.env.run(self.vnf_db_activity.set_vnf_model, set_vnf_model_input)
         self.db.set_one.assert_called_with(
             "vnfrs", {"_id": vnfr_uuid}, {"namespace": model_name}
         )
 
-    async def test_set_vnf_model_db_raises_exception(self):
+    async def test_set_vnf_model__failed__raises_db_exception(self):
         self.db.set_one.side_effect = DbException("not found")
         with self.assertRaises(DbException):
-            await self.env.run(
-                self.vnf_db_activity.set_vnf_model, vnf_instantiate_input
-            )
+            await self.env.run(self.vnf_db_activity.set_vnf_model, set_vnf_model_input)
 
 
 class TestGetTaskQueue(asynctest.TestCase):
@@ -142,7 +200,7 @@
         self.env = ActivityEnvironment()
         self.get_task_queue_input = GetTaskQueueInput(vnfr_uuid=sample_vnfr["id"])
 
-    async def test_activity_succeeded(self):
+    async def test_activity__succeeded__get_expected_task_queue(self):
         self.db.get_one.side_effect = [sample_vnfr, sample_vim_record]
         activity_result = await self.env.run(
             self.vnf_operations_instance.get_task_queue,
@@ -150,7 +208,7 @@
         )
         self.assertEqual(activity_result.task_queue, LCM_TASK_QUEUE)
 
-    async def test_db_raises_exception(self):
+    async def test_activity__failed__raises_db_exception(self):
         self.db.get_one.side_effect = DbException("not found")
         with self.assertRaises(DbException):
             await self.env.run(
@@ -158,7 +216,7 @@
                 self.get_task_queue_input,
             )
 
-    async def test_invalid_task_queue(self):
+    async def test_activity__invalid_task_queue__raises_key_error(self):
         vim_record = deepcopy(sample_vim_record)
         vim_record["vim_type"] = "some-vim-type"
         self.db.get_one.side_effect = [sample_vnfr, vim_record]
@@ -168,65 +226,51 @@
                 self.get_task_queue_input,
             )
 
-    async def test_activity_cancelled(self):
-        self.env._cancelled = True
-        self.db.get_one.side_effect = [sample_vnfr, sample_vim_record]
-        with self.assertRaises(CancelledError):
-            activity_result = await self.env.run(
-                self.vnf_operations_instance.get_task_queue,
-                self.get_task_queue_input,
-            )
-            self.assertEqual(activity_result, None)
 
-
-class TestVnfDetails(asynctest.TestCase):
+class TestGetVnfDescriptor(asynctest.TestCase):
     async def setUp(self):
         self.db = Mock()
         self.vnf_operations_instance = VnfOperations(self.db)
         self.env = ActivityEnvironment()
 
-    async def test_activity_succeeded(self):
-        self.db.get_one.side_effect = [sample_vnfr, sample_vnfd]
+    async def test_activity__succeeded__get_expected_vnfd(self):
+        self.db.get_one.return_value = sample_vnfd
         activity_result = await self.env.run(
-            self.vnf_operations_instance.get_vnf_details,
-            GetVnfDetailsInput(vnfr_uuid=sample_vnfr["id"]),
+            self.vnf_operations_instance.get_vnf_descriptor,
+            GetVnfDescriptorInput(vnfd_uuid=vnfd_uuid),
         )
         self.assertEqual(activity_result.vnfd, sample_vnfd)
+
+    async def test_activity__failed__raises_db_exception(self):
+        self.db.get_one.side_effect = DbException("Can not connect to Database.")
+        with self.assertRaises(DbException):
+            await self.env.run(
+                self.vnf_operations_instance.get_vnf_descriptor,
+                GetVnfDescriptorInput(vnfd_uuid=vnfd_uuid),
+            )
+
+
+class TestGetVnfRecord(asynctest.TestCase):
+    async def setUp(self):
+        self.db = Mock()
+        self.vnf_operations_instance = VnfOperations(self.db)
+        self.env = ActivityEnvironment()
+
+    async def test_activity__succeeded__get_expected_vnfr(self):
+        self.db.get_one.return_value = sample_vnfr
+        activity_result = await self.env.run(
+            self.vnf_operations_instance.get_vnf_record,
+            GetVnfRecordInput(vnfr_uuid=vnfr_uuid),
+        )
         self.assertEqual(activity_result.vnfr, sample_vnfr)
 
-    async def test_activity_failed_db_exception(self):
+    async def test_activity__failed__raise_db_exception(self):
         self.db.get_one.side_effect = DbException("Can not connect to Database.")
-        with self.assertRaises(DbException) as err:
-            activity_result = await self.env.run(
-                self.vnf_operations_instance.get_vnf_details,
-                GetVnfDetailsInput(vnfr_uuid=sample_vnfr["id"]),
+        with self.assertRaises(DbException):
+            await self.env.run(
+                self.vnf_operations_instance.get_vnf_record,
+                GetVnfRecordInput(vnfr_uuid=vnfr_uuid),
             )
-            self.assertEqual(activity_result, None)
-        self.assertEqual(
-            str(err.exception), "database exception Can not connect to Database."
-        )
-
-    async def test_activity_failed_key_error(self):
-        vnfr = deepcopy(sample_vnfr)
-        vnfr.pop("vnfd-id")
-        self.db.get_one.side_effect = [vnfr, sample_vnfd]
-        with self.assertRaises(KeyError) as err:
-            activity_result = await self.env.run(
-                self.vnf_operations_instance.get_vnf_details,
-                GetVnfDetailsInput(vnfr_uuid=sample_vnfr["id"]),
-            )
-            self.assertEqual(activity_result, None)
-        self.assertEqual(str(err.exception.args[0]), "vnfd-id")
-
-    async def test_activity_cancelled(self):
-        self.env._cancelled = True
-        self.db.get_one.side_effect = [sample_vnfr, sample_vnfd]
-        with self.assertRaises(CancelledError):
-            activity_result = await self.env.run(
-                self.vnf_operations_instance.get_vnf_details,
-                GetVnfDetailsInput(vnfr_uuid=sample_vnfr["id"]),
-            )
-            self.assertEqual(activity_result, None)
 
 
 class TestGetVimCloud(asynctest.TestCase):
@@ -235,7 +279,7 @@
         self.vnf_operations_instance = VnfOperations(self.db)
         self.env = ActivityEnvironment()
 
-    async def test_activity_succeeded(self):
+    async def test_activity__succeeded__get_vim_cloud(self):
         self.db.get_one.side_effect = [sample_vnfr, sample_vim_record]
         activity_result = await self.env.run(
             self.vnf_operations_instance.get_vim_cloud,
@@ -243,7 +287,7 @@
         )
         self.assertEqual(activity_result.cloud, cloud)
 
-    async def test_activity_vim_record_without_cloud(self):
+    async def test_activity__vim_record_without_cloud__no_cloud_info(self):
         vim_record = deepcopy(sample_vim_record)
         vim_record["config"].pop("cloud")
         self.db.get_one.side_effect = [sample_vnfr, vim_record]
@@ -253,39 +297,205 @@
         )
         self.assertEqual(activity_result.cloud, "")
 
-    async def test_activity_failed_db_exception(self):
+    async def test_activity__failed__raise_db_exception(self):
         self.db.get_one.side_effect = DbException("Can not connect to Database.")
-        with self.assertRaises(DbException) as err:
-            activity_result = await self.env.run(
+        with self.assertRaises(DbException):
+            await self.env.run(
                 self.vnf_operations_instance.get_vim_cloud,
                 GetVimCloudInput(vnfr_uuid=sample_vnfr["id"]),
             )
-            self.assertEqual(activity_result, None)
-        self.assertEqual(
-            str(err.exception), "database exception Can not connect to Database."
-        )
 
-    async def test_activity_failed_key_error(self):
+    async def test_activity__wrong_vim_record__raise_key_error(self):
         vim_record = deepcopy(sample_vim_record)
         vim_record.pop("config")
         self.db.get_one.side_effect = [sample_vnfr, vim_record]
-        with self.assertRaises(KeyError) as err:
-            activity_result = await self.env.run(
+        with self.assertRaises(KeyError):
+            await self.env.run(
                 self.vnf_operations_instance.get_vim_cloud,
                 GetVimCloudInput(vnfr_uuid=sample_vnfr["id"]),
             )
-            self.assertEqual(activity_result, None)
-        self.assertEqual(str(err.exception.args[0]), "config")
 
-    async def test_activity_cancelled(self):
-        self.env._cancelled = True
-        self.db.get_one.side_effect = [sample_vnfr, sample_vim_record]
-        with self.assertRaises(CancelledError):
-            activity_result = await self.env.run(
-                self.vnf_operations_instance.get_vim_cloud,
-                GetVimCloudInput(vnfr_uuid=sample_vnfr["id"]),
-            )
-            self.assertEqual(activity_result, None)
+
+class TestGetVduInstantiateInfoMethods(TestCase):
+    def test_get_flavor_details__successful__get_flavor(self):
+        compute_desc_id = "compute-id-1"
+        result = VnfOperations._get_flavor_details(compute_desc_id, sample_vnfd)
+        self.assertEqual(result, flavor_1)
+
+    def test_get_flavor_details__empty_compute_desc__flavor_is_none(self):
+        compute_desc_id = ""
+        result = VnfOperations._get_flavor_details(compute_desc_id, sample_vnfd)
+        self.assertEqual(result, None)
+
+    def test_get_flavor_details__compute_desc_not_found__flavor_is_none(self):
+        compute_desc_id = "compute-id-5"
+        result = VnfOperations._get_flavor_details(compute_desc_id, sample_vnfd)
+        self.assertEqual(result, None)
+
+    def test_get_flavor_details__empty_vnfd__flavor_is_none(self):
+        compute_desc_id = "compute-id-5"
+        result = VnfOperations._get_flavor_details(compute_desc_id, {})
+        self.assertEqual(result, None)
+
+    def test_get_flavor_details__wrong_vnfd_format__flavor_is_none(self):
+        compute_desc_id = "compute-id-2"
+        sample_vnfd = {
+            "_id": vnfd_id,
+            "vdu": [vdu],
+            "virtual-compute-desc": [
+                {
+                    "virtual-memory": {"size": "4"},
+                }
+            ],
+        }
+        result = VnfOperations._get_flavor_details(compute_desc_id, sample_vnfd)
+        self.assertEqual(result, None)
+
+    @patch("osm_lcm.temporal.vnf_activities.VnfOperations._get_flavor_details")
+    def test_get_compute_constraints__succeeded__get_constraints(
+        self, mock_get_flavor_details
+    ):
+        mock_get_flavor_details.return_value = flavor_1
+        result = VnfOperations.get_compute_constraints(vdu, sample_vnfd)
+        self.assertEqual(VduComputeConstraints(cores=2, mem=4), result)
+
+    @patch("osm_lcm.temporal.vnf_activities.VnfOperations._get_flavor_details")
+    def test_get_compute_constraints__empty_flavor_details__no_constraints(
+        self, mock_get_flavor_details
+    ):
+        mock_get_flavor_details.return_value = {}
+        result = VnfOperations.get_compute_constraints(vdu, sample_vnfd)
+        self.assertEqual(VduComputeConstraints(cores=0, mem=0), result)
+
+    @patch("osm_lcm.temporal.vnf_activities.VnfOperations._get_flavor_details")
+    def test_get_compute_constraints__flavor_details_is_none__no_constraints(
+        self, mock_get_flavor_details
+    ):
+        mock_get_flavor_details.return_value = None
+        result = VnfOperations.get_compute_constraints(vdu, sample_vnfd)
+        self.assertEqual(VduComputeConstraints(cores=0, mem=0), result)
+
+    @patch("osm_lcm.temporal.vnf_activities.VnfOperations._get_flavor_details")
+    def test_get_compute_constraints__flavor_has_only_cpu__get_cpu_constraint(
+        self, mock_get_flavor_details
+    ):
+        mock_get_flavor_details.return_value = flavor_2
+        result = VnfOperations.get_compute_constraints(vdu, sample_vnfd)
+        self.assertEqual(VduComputeConstraints(cores=2, mem=0), result)
+
+    @patch("osm_lcm.temporal.vnf_activities.VnfOperations._get_flavor_details")
+    def test_get_compute_constraints__flavor_has_only_memory__get_memory_constraint(
+        self, mock_get_flavor_details
+    ):
+        mock_get_flavor_details.return_value = flavor_3
+        result = VnfOperations.get_compute_constraints(vdu, sample_vnfd)
+        self.assertEqual(VduComputeConstraints(cores=0, mem=4), result)
+
+    def test_list_to_dict__config_has_several_items__get_expected_dict(self):
+        config = [
+            {"key": "config::domain_name1", "value": "osm.org"},
+            {"key": "domain_name2", "value": "osm.com"},
+        ]
+        result = VnfOperations._list_to_dict(config)
+        self.assertEqual(
+            result, {"config::domain_name1": "osm.org", "domain_name2": "osm.com"}
+        )
+
+    def test_list_to_dict__empty_input__get_empty_dict(self):
+        config = []
+        result = VnfOperations._list_to_dict(config)
+        self.assertEqual(result, {})
+
+    def test_get_only_config_items__with_identifier__get_expected_config(self):
+        config = {"config::redirect-map": "https://osm.instantiation.params"}
+        result = VnfOperations._get_only_config_items(config)
+        self.assertEqual(result, {"redirect-map": "https://osm.instantiation.params"})
+
+    def test_get_only_config_items__without_identifier__no_config(self):
+        config = {"key": "domain_name1", "value": "osm.org"}
+        result = VnfOperations._get_only_config_items(config)
+        self.assertEqual(result, {})
+
+    def test_get_only_config_items__empty_input__no_config(self):
+        config = {}
+        result = VnfOperations._get_only_config_items(config)
+        self.assertEqual(result, {})
+
+    def test_get_vdu_instantiation_params__empty_vnf_config__get_params(self):
+        result = VnfOperations.get_vdu_instantiation_params(vdu_id, vnf_config)
+        self.assertEqual(
+            result, {"config::redirect-map": "https://osm.instantiation.params"}
+        )
+
+    def test_get_vdu_instantiation_params__empty_vnf_config__no_params(self):
+        result = VnfOperations.get_vdu_instantiation_params(vdu_id, {})
+        self.assertEqual(result, {})
+
+    def test_get_vdu_instantiation_params__vdu_id_mismatch__no_params(self):
+        config = deepcopy(vnf_config)
+        config["vdu"][0]["id"] = "other-vdu-id"
+        result = VnfOperations.get_vdu_instantiation_params(vdu_id, config)
+        self.assertEqual(result, {})
+
+    def test_get_vdu_instantiation_params__empty_configurable_properties__no_params(
+        self,
+    ):
+        config = deepcopy(vnf_config)
+        config["vdu"][0]["configurable-properties"] = {}
+        result = VnfOperations.get_vdu_instantiation_params(vdu_id, config)
+        self.assertEqual(result, {})
+
+    @patch("osm_lcm.temporal.vnf_activities.VnfOperations._get_only_config_items")
+    @patch("osm_lcm.temporal.vnf_activities.VnfOperations._list_to_dict")
+    def test_get_application_config__instantiate_config_overrides_vdu_config__get_expected_application_config(
+        self,
+        mock_list_to_dict,
+        mock_get_only_config_items,
+    ):
+        vdu_instantiate_config = {"config::domain_name1": "osm.public"}
+        mock_get_only_config_items.side_effect = [
+            {
+                "domain_name1": "osm.org",
+                "domain_name2": "osm.com",
+            },
+            {"domain_name1": "osm.public"},
+        ]
+        result = VnfOperations.get_application_config(vdu, vdu_instantiate_config)
+        self.assertEqual(
+            result, {"domain_name1": "osm.public", "domain_name2": "osm.com"}
+        )
+
+    @patch("osm_lcm.temporal.vnf_activities.VnfOperations._get_only_config_items")
+    @patch("osm_lcm.temporal.vnf_activities.VnfOperations._list_to_dict")
+    def test_get_application_config__empty_instantiate_config__get_descriptor_config(
+        self,
+        mock_list_to_dict,
+        mock_get_only_config_items,
+    ):
+        vdu_instantiate_config = {}
+        mock_get_only_config_items.side_effect = [
+            {
+                "domain_name1": "osm.org",
+                "domain_name2": "osm.com",
+            },
+            {},
+        ]
+        result = VnfOperations.get_application_config(vdu, vdu_instantiate_config)
+        self.assertEqual(result, app_config)
+
+    @patch("osm_lcm.temporal.vnf_activities.VnfOperations._get_only_config_items")
+    @patch("osm_lcm.temporal.vnf_activities.VnfOperations._list_to_dict")
+    def test_get_application_config__no_config__empty_application_config(
+        self,
+        mock_list_to_dict,
+        mock_get_only_config_items,
+    ):
+        vdu_instantiate_config = {}
+        vdu_copy = deepcopy(vdu)
+        vdu_copy["configurable-properties"] = []
+        mock_get_only_config_items.side_effect = [{}, {}]
+        result = VnfOperations.get_application_config(vdu_copy, vdu_instantiate_config)
+        self.assertEqual(result, {})
 
 
 if __name__ == "__main__":