Merge "[DCAEGEN2] PMSH Response Event Handler Integration"
diff --git a/components/pm-subscription-handler/Changelog.md b/components/pm-subscription-handler/Changelog.md
index 89237c3..8e0ee2f 100755
--- a/components/pm-subscription-handler/Changelog.md
+++ b/components/pm-subscription-handler/Changelog.md
@@ -13,6 +13,7 @@
 * Added 2 new attributes to the subscription model (DCAEGEN2-2913)
 * Read subscription API by using subscription name (DCAEGEN2-2818)
 * Read All subscriptions API  (DCAEGEN2-2847)
+* PMSH Response Event Handler Integration (DCAEGEN2-2915)
 
 ## [1.3.2]
 ### Changed
diff --git a/components/pm-subscription-handler/pmsh_service/mod/api/services/measurement_group_service.py b/components/pm-subscription-handler/pmsh_service/mod/api/services/measurement_group_service.py
index 733d803..cc07cc0 100644
--- a/components/pm-subscription-handler/pmsh_service/mod/api/services/measurement_group_service.py
+++ b/components/pm-subscription-handler/pmsh_service/mod/api/services/measurement_group_service.py
@@ -18,8 +18,8 @@
 
 from mod.api.db_models import MeasurementGroupModel, NfMeasureGroupRelationalModel
 from mod import db, logger
-from mod.subscription import SubNfState
 from mod.api.services import nf_service
+from mod.network_function import NetworkFunction
 from mod.pmsh_config import MRTopic, AppConfig
 
 
@@ -47,18 +47,19 @@
     return new_measurement_group
 
 
-def apply_nf_to_measgroup(nf_name, measurement_group_name):
+def apply_nf_status_to_measurement_group(nf_name, measurement_group_name, status):
     """
     Associate and saves the measurement group with Network function
 
     Args:
         nf_name (string): Network function name.
         measurement_group_name (string): Measurement group name
+        status (string): nf status to apply on measurement group
     """
     new_nf_measure_grp_rel = NfMeasureGroupRelationalModel(
         measurement_grp_name=measurement_group_name,
         nf_name=nf_name,
-        nf_measure_grp_status=SubNfState.PENDING_CREATE.value
+        nf_measure_grp_status=status
     )
     db.session.add(new_nf_measure_grp_rel)
 
@@ -86,3 +87,51 @@
     }
     logger.debug(f'Event Body: {event_body}')
     AppConfig.get_instance().publish_to_topic(MRTopic.POLICY_PM_PUBLISHER.value, event_body)
+
+
+def update_measurement_group_nf_status(measurement_group_name, status, nf_name):
+    """ Updates the status of a measurement grp for a particular nf
+
+    Args:
+        measurement_group_name (string): Measurement group name
+        nf_name (string): The network function name
+        status (string): status of the network function for measurement group
+    """
+    try:
+        logger.info(f'Performing update for measurement group name: {measurement_group_name},'
+                    f' network function name: {nf_name} on status: {status}')
+        NfMeasureGroupRelationalModel.query.filter(
+            NfMeasureGroupRelationalModel.measurement_grp_name == measurement_group_name,
+            NfMeasureGroupRelationalModel.nf_name == nf_name). \
+            update({NfMeasureGroupRelationalModel.nf_measure_grp_status: status},
+                   synchronize_session='evaluate')
+        db.session.commit()
+    except Exception as e:
+        logger.error(f'Failed to update nf: {nf_name} for measurement group: '
+                     f'{measurement_group_name} due to: {e}')
+
+
+def delete_nf_to_measurement_group(nf_name, measurement_group_name, status):
+    """ Deletes a particular nf related to a measurement group name and
+        if no more relations of nf exist to measurement group then delete nf from PMSH
+
+    Args:
+        nf_name (string): The network function name
+        measurement_group_name (string): Measurement group name
+        status (string): status of the network function for measurement group
+    """
+    try:
+        logger.info(f'Performing delete for measurement group name: {measurement_group_name},'
+                    f' network function name: {nf_name} on status: {status}')
+        nf_measurement_group_rel = NfMeasureGroupRelationalModel.query.filter(
+            NfMeasureGroupRelationalModel.measurement_grp_name == measurement_group_name,
+            NfMeasureGroupRelationalModel.nf_name == nf_name).one_or_none()
+        db.session.delete(nf_measurement_group_rel)
+        db.session.commit()
+        nf_relations = NfMeasureGroupRelationalModel.query.filter(
+            NfMeasureGroupRelationalModel.nf_name == nf_name).all()
+        if not nf_relations:
+            NetworkFunction.delete(nf_name=nf_name)
+    except Exception as e:
+        logger.error(f'Failed to delete nf: {nf_name} for measurement group: '
+                     f'{measurement_group_name} due to: {e}')
diff --git a/components/pm-subscription-handler/pmsh_service/mod/api/services/subscription_service.py b/components/pm-subscription-handler/pmsh_service/mod/api/services/subscription_service.py
index 96d50c2..c33c82f 100644
--- a/components/pm-subscription-handler/pmsh_service/mod/api/services/subscription_service.py
+++ b/components/pm-subscription-handler/pmsh_service/mod/api/services/subscription_service.py
@@ -21,7 +21,7 @@
     NetworkFunctionFilterModel, NetworkFunctionModel
 from mod.api.services import measurement_group_service, nf_service
 from mod.api.custom_exception import InvalidDataException, DuplicateDataException
-from mod.subscription import AdministrativeState
+from mod.subscription import AdministrativeState, SubNfState
 from sqlalchemy.exc import IntegrityError
 from sqlalchemy.orm import joinedload
 
@@ -143,8 +143,9 @@
             for nf in filtered_nfs:
                 logger.info(f'Saving measurement group to nf name, measure_grp_name: {nf.nf_name},'
                             f'{measurement_group.measurement_group_name}')
-                measurement_group_service.apply_nf_to_measgroup(
-                    nf.nf_name, measurement_group.measurement_group_name)
+                measurement_group_service.apply_nf_status_to_measurement_group(
+                    nf.nf_name, measurement_group.measurement_group_name,
+                    SubNfState.PENDING_CREATE.value)
         else:
             logger.info(f'No nfs added as measure_grp_name: '
                         f'{measurement_group.measurement_group_name} is LOCKED')
diff --git a/components/pm-subscription-handler/pmsh_service/mod/policy_response_handler.py b/components/pm-subscription-handler/pmsh_service/mod/policy_response_handler.py
index 09c9704..1bc5808 100644
--- a/components/pm-subscription-handler/pmsh_service/mod/policy_response_handler.py
+++ b/components/pm-subscription-handler/pmsh_service/mod/policy_response_handler.py
@@ -1,5 +1,5 @@
 # ============LICENSE_START===================================================
-#  Copyright (C) 2020 Nordix Foundation.
+#  Copyright (C) 2020-2021 Nordix Foundation.
 # ============================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -15,33 +15,31 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 # ============LICENSE_END=====================================================
-
 import json
-
+from mod.pmsh_config import MRTopic, AppConfig
 from mod import logger
-from mod.network_function import NetworkFunction
-from mod.subscription import Subscription, AdministrativeState, subscription_nf_states
+from mod.subscription import AdministrativeState, subscription_nf_states
+from mod.api.db_models import MeasurementGroupModel
+from mod.api.services import measurement_group_service
 
 policy_response_handle_functions = {
     AdministrativeState.LOCKED.value: {
-        'success': NetworkFunction.delete,
-        'failed': Subscription.update_sub_nf_status
+        'success': measurement_group_service.delete_nf_to_measurement_group,
+        'failed': measurement_group_service.update_measurement_group_nf_status
     },
     AdministrativeState.UNLOCKED.value: {
-        'success': Subscription.update_sub_nf_status,
-        'failed': Subscription.update_sub_nf_status
+        'success': measurement_group_service.update_measurement_group_nf_status,
+        'failed': measurement_group_service.update_measurement_group_nf_status
     },
     AdministrativeState.LOCKING.value: {
-        'success': NetworkFunction.delete,
-        'failed': Subscription.update_sub_nf_status
+        'success': measurement_group_service.delete_nf_to_measurement_group,
+        'failed': measurement_group_service.update_measurement_group_nf_status
     }
 }
 
 
 class PolicyResponseHandler:
-    def __init__(self, mr_sub, app_conf, app):
-        self.mr_sub = mr_sub
-        self.app_conf = app_conf
+    def __init__(self, app):
         self.app = app
 
     def poll_policy_topic(self):
@@ -50,38 +48,49 @@
         relevant subscription and then handles the response
         """
         self.app.app_context().push()
-        administrative_state = self.app_conf.subscription.administrativeState
         logger.info('Polling MR for XNF activation/deactivation policy response events.')
         try:
-            response_data = self.mr_sub.get_from_topic('dcae_pmsh_policy_cl_input')
+            response_data = AppConfig.get_instance(). \
+                get_from_topic(MRTopic.POLICY_PM_SUBSCRIBER.value, 'dcae_pmsh_policy_cl_input')
             for data in response_data:
                 data = json.loads(data)
-                if data['status']['subscriptionName'] \
-                        == self.app_conf.subscription.subscriptionName:
-                    nf_name = data['status']['nfName']
-                    response_message = data['status']['message']
-                    self._handle_response(self.app_conf.subscription.subscriptionName,
-                                          administrative_state, nf_name, response_message)
+                measurement_group_name = data['status']['measurementGroupName']
+                subscription_name = data['status']['subscriptionName']
+                measurement_group = (MeasurementGroupModel.query.filter(
+                    MeasurementGroupModel.measurement_group_name == measurement_group_name,
+                    subscription_name == MeasurementGroupModel
+                    .subscription_name).one_or_none())
+                nf_name = data['status']['nfName']
+                response_message = data['status']['message']
+                if measurement_group:
+                    self._handle_response(measurement_group_name,
+                                          measurement_group.administrative_state,
+                                          nf_name, response_message)
+                else:
+                    logger.info(f'Polled MR response provides missing measurement '
+                                f'group name :  {measurement_group_name}')
         except Exception as err:
             logger.error(f'Error trying to poll policy response topic on MR: {err}', exc_info=True)
 
     @staticmethod
-    def _handle_response(subscription_name, administrative_state, nf_name, response_message):
+    def _handle_response(measurement_group_name, administrative_state, nf_name, response_message):
         """
         Handles the response from Policy, updating the DB
-
         Args:
-            subscription_name (str): The subscription name
-            administrative_state (str): The administrative state of the subscription
-            nf_name (str): The network function name
-            response_message (str): The message in the response regarding the state (success|failed)
+            measurement_group_name (string): The measurement group name
+            administrative_state (string): The administrative state of the measurement group
+            nf_name (string): The network function name
+            response_message (string): The message in the response
+                                        regarding the state (success|failed)
         """
-        logger.info(f'Response from MR: Sub: {subscription_name} for '
+        logger.info(f'Response from MR: measurement group name: {measurement_group_name} for '
                     f'NF: {nf_name} received, updating the DB')
         try:
-            sub_nf_status = subscription_nf_states[administrative_state][response_message].value
+            nf_measure_grp_status = subscription_nf_states[administrative_state][response_message]\
+                .value
             policy_response_handle_functions[administrative_state][response_message](
-                subscription_name=subscription_name, status=sub_nf_status, nf_name=nf_name)
+                measurement_group_name=measurement_group_name, status=nf_measure_grp_status,
+                nf_name=nf_name)
         except Exception as err:
             logger.error(f'Error changing nf_sub status in the DB: {err}')
             raise
diff --git a/components/pm-subscription-handler/pmsh_service/pmsh_service_main.py b/components/pm-subscription-handler/pmsh_service/pmsh_service_main.py
index 0b6544b..fe151c0 100755
--- a/components/pm-subscription-handler/pmsh_service/pmsh_service_main.py
+++ b/components/pm-subscription-handler/pmsh_service/pmsh_service_main.py
@@ -35,13 +35,12 @@
             app_conf = AppConfig()
             pmsh_app_conf = NewAppConfig()
             policy_mr_pub = app_conf.get_mr_pub('policy_pm_publisher')
-            policy_mr_sub = app_conf.get_mr_sub('policy_pm_subscriber')
             aai_event_mr_sub = app_conf.get_mr_sub('aai_subscriber')
         except Exception as e:
             logger.error(f'Failed to get config and create application: {e}', exc_info=True)
             sys.exit(e)
 
-        policy_response_handler = PolicyResponseHandler(policy_mr_sub, app_conf, app)
+        policy_response_handler = PolicyResponseHandler(app)
         policy_response_handler_thread = PeriodicTask(25, policy_response_handler.poll_policy_topic)
         policy_response_handler_thread.name = 'policy_event_thread'
         logger.info('Start polling PMSH_CL_INPUT topic on DMaaP MR.')
diff --git a/components/pm-subscription-handler/tests/services/test_measurement_group_service.py b/components/pm-subscription-handler/tests/services/test_measurement_group_service.py
index 46c4bac..97353af 100644
--- a/components/pm-subscription-handler/tests/services/test_measurement_group_service.py
+++ b/components/pm-subscription-handler/tests/services/test_measurement_group_service.py
@@ -23,9 +23,9 @@
 from mod.pmsh_config import AppConfig
 from mod import db
 from tests.base_setup import BaseClassSetup
-from mod.api.services import measurement_group_service
-from mod.api.db_models import MeasurementGroupModel, NfMeasureGroupRelationalModel,\
-    SubscriptionModel
+from mod.api.services import measurement_group_service, nf_service
+from mod.api.db_models import MeasurementGroupModel, NfMeasureGroupRelationalModel, \
+    SubscriptionModel, NetworkFunctionModel
 from mod.subscription import SubNfState
 
 
@@ -99,17 +99,94 @@
             MeasurementGroupModel.subscription_name == 'ExtraPM-All-gNB-R2B').one_or_none())
         self.assertIsNotNone(measurement_grp)
 
-    def test_apply_nf_to_measgroup(self):
-        measurement_group_service.apply_nf_to_measgroup("pnf_test", "measure_grp_name")
+    def test_apply_nf_to_measurement_group_status(self):
+        measurement_group_service.apply_nf_status_to_measurement_group(
+            "pnf_test", "measure_grp_name", SubNfState.PENDING_CREATE.value)
         db.session.commit()
         measurement_grp_rel = (NfMeasureGroupRelationalModel.query.filter(
             NfMeasureGroupRelationalModel.measurement_grp_name == 'measure_grp_name',
             NfMeasureGroupRelationalModel.nf_name == 'pnf_test').one_or_none())
-        db.session.commit()
         self.assertIsNotNone(measurement_grp_rel)
         self.assertEqual(measurement_grp_rel.nf_measure_grp_status,
                          SubNfState.PENDING_CREATE.value)
 
+    def test_update_measurement_group_nf_status(self):
+        measurement_group_service.apply_nf_status_to_measurement_group(
+            "pnf_test", "measure_grp_name", SubNfState.PENDING_CREATE.value)
+        measurement_group_service.update_measurement_group_nf_status(
+            "measure_grp_name", SubNfState.CREATED.value, "pnf_test")
+        db.session.commit()
+        measurement_grp_rel = (NfMeasureGroupRelationalModel.query.filter(
+            NfMeasureGroupRelationalModel.measurement_grp_name == 'measure_grp_name',
+            NfMeasureGroupRelationalModel.nf_name == 'pnf_test').one_or_none())
+        self.assertIsNotNone(measurement_grp_rel)
+        self.assertEqual(measurement_grp_rel.nf_measure_grp_status,
+                         SubNfState.CREATED.value)
+
+    def test_delete_nf_to_measurement_group_without_nf_delete(self):
+        nf = NetworkFunction(nf_name='pnf_test1')
+        nf_service.save_nf(nf)
+        db.session.commit()
+        measurement_group_service.apply_nf_status_to_measurement_group(
+            "pnf_test1", "measure_grp_name1", SubNfState.PENDING_CREATE.value)
+        measurement_group_service.apply_nf_status_to_measurement_group(
+            "pnf_test1", "measure_grp_name2", SubNfState.PENDING_CREATE.value)
+        measurement_group_service.delete_nf_to_measurement_group(
+            "pnf_test1", "measure_grp_name1", SubNfState.DELETED.value)
+        measurement_grp_rel = (NfMeasureGroupRelationalModel.query.filter(
+            NfMeasureGroupRelationalModel.measurement_grp_name == 'measure_grp_name1',
+            NfMeasureGroupRelationalModel.nf_name == 'pnf_test1').one_or_none())
+        self.assertIsNone(measurement_grp_rel)
+        network_function = (NetworkFunctionModel.query.filter(
+            NetworkFunctionModel.nf_name == 'pnf_test1').one_or_none())
+        self.assertIsNotNone(network_function)
+
+    def test_delete_nf_to_measurement_group_with_nf_delete(self):
+        nf = NetworkFunction(nf_name='pnf_test2')
+        nf_service.save_nf(nf)
+        db.session.commit()
+        measurement_group_service.apply_nf_status_to_measurement_group(
+            "pnf_test2", "measure_grp_name2", SubNfState.PENDING_CREATE.value)
+        measurement_group_service.delete_nf_to_measurement_group(
+            "pnf_test2", "measure_grp_name2", SubNfState.DELETED.value)
+        measurement_grp_rel = (NfMeasureGroupRelationalModel.query.filter(
+            NfMeasureGroupRelationalModel.measurement_grp_name == 'measure_grp_name2',
+            NfMeasureGroupRelationalModel.nf_name == 'pnf_test2').one_or_none())
+        self.assertIsNone(measurement_grp_rel)
+        network_function = (NetworkFunctionModel.query.filter(
+            NetworkFunctionModel.nf_name == 'pnf_test2').one_or_none())
+        self.assertIsNone(network_function)
+
+    @patch.object(NetworkFunction, 'delete')
+    @patch('mod.logger.error')
+    def test_delete_nf_to_measurement_group_failure(self, mock_logger, nf_delete_func):
+        nf = NetworkFunction(nf_name='pnf_test2')
+        nf_service.save_nf(nf)
+        db.session.commit()
+        measurement_group_service.apply_nf_status_to_measurement_group(
+            "pnf_test2", "measure_grp_name2", SubNfState.PENDING_CREATE.value)
+        nf_delete_func.side_effect = Exception('delete failed')
+        measurement_group_service.delete_nf_to_measurement_group(
+            "pnf_test2", "measure_grp_name2", SubNfState.DELETED.value)
+        measurement_grp_rel = (NfMeasureGroupRelationalModel.query.filter(
+            NfMeasureGroupRelationalModel.measurement_grp_name == 'measure_grp_name2',
+            NfMeasureGroupRelationalModel.nf_name == 'pnf_test2').one_or_none())
+        self.assertIsNone(measurement_grp_rel)
+        network_function = (NetworkFunctionModel.query.filter(
+            NetworkFunctionModel.nf_name == 'pnf_test2').one_or_none())
+        self.assertIsNotNone(network_function)
+        mock_logger.assert_called_with('Failed to delete nf: pnf_test2 for '
+                                       'measurement group: measure_grp_name2 due to: delete failed')
+
+    @patch.object(db.session, 'commit')
+    @patch('mod.logger.error')
+    def test_update_nf_to_measurement_group_failure(self, mock_logger, db_commit_call):
+        db_commit_call.side_effect = Exception('update failed')
+        measurement_group_service.update_measurement_group_nf_status(
+            "measure_grp_name2", SubNfState.CREATE_FAILED.value, "pnf_test2")
+        mock_logger.assert_called_with('Failed to update nf: pnf_test2 for '
+                                       'measurement group: measure_grp_name2 due to: update failed')
+
     def create_test_subs(self, new_sub_name, new_msrmt_grp_name):
         subscription = self.subscription_request.replace('ExtraPM-All-gNB-R2B', new_sub_name)
         subscription = subscription.replace('msrmt_grp_name', new_msrmt_grp_name)
diff --git a/components/pm-subscription-handler/tests/services/test_subscription_service.py b/components/pm-subscription-handler/tests/services/test_subscription_service.py
index 86bf263..8f3f0f4 100644
--- a/components/pm-subscription-handler/tests/services/test_subscription_service.py
+++ b/components/pm-subscription-handler/tests/services/test_subscription_service.py
@@ -171,7 +171,7 @@
 
     @patch.object(aai_client, '_get_all_aai_nf_data')
     @patch.object(aai_client, 'get_aai_model_data')
-    @patch.object(measurement_group_service, 'apply_nf_to_measgroup')
+    @patch.object(measurement_group_service, 'apply_nf_status_to_measurement_group')
     @patch.object(NetworkFunctionFilter, 'get_network_function_filter')
     def test_apply_measurement_grp_to_nfs(self, mock_filter_call, mock_apply_nf,
                                           mock_model_aai, mock_aai):
diff --git a/components/pm-subscription-handler/tests/test_policy_response_handler.py b/components/pm-subscription-handler/tests/test_policy_response_handler.py
index 9bf1593..3e6abf9 100644
--- a/components/pm-subscription-handler/tests/test_policy_response_handler.py
+++ b/components/pm-subscription-handler/tests/test_policy_response_handler.py
@@ -15,30 +15,26 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 # ============LICENSE_END=====================================================
-from unittest.mock import patch
+from unittest.mock import patch, MagicMock
 
-from mod.api.db_models import SubscriptionModel
+from mod import db
 from mod.network_function import NetworkFunction
 from mod.policy_response_handler import PolicyResponseHandler, policy_response_handle_functions
 from mod.subscription import AdministrativeState, SubNfState
-from tests.base_setup import BaseClassSetup
+from tests.base_setup import BaseClassSetup, create_subscription_data
 
 
 class PolicyResponseHandlerTest(BaseClassSetup):
-
     @classmethod
     def setUpClass(cls):
         super().setUpClass()
 
     @patch('mod.create_app')
-    @patch('mod.pmsh_utils._MrSub')
-    def setUp(self, mock_mr_sub, mock_app):
+    def setUp(self, mock_app):
         super().setUp()
-        self.mock_policy_mr_sub = mock_mr_sub
+        super().setUpAppConf()
         self.nf = NetworkFunction(nf_name='nf1')
-        self.policy_response_handler = PolicyResponseHandler(self.mock_policy_mr_sub,
-                                                             self.app_conf,
-                                                             mock_app)
+        self.policy_response_handler = PolicyResponseHandler(mock_app)
 
     def tearDown(self):
         super().tearDown()
@@ -52,46 +48,67 @@
         with patch.dict(policy_response_handle_functions,
                         {AdministrativeState.LOCKED.value: {'success': mock_delete}}):
             self.policy_response_handler._handle_response(
-                self.app_conf.subscription.subscriptionName,
+                'msr_grp_name',
                 AdministrativeState.LOCKED.value,
                 self.nf.nf_name, 'success')
-
             mock_delete.assert_called()
 
-    @patch('mod.subscription.Subscription.update_sub_nf_status')
+    @patch('mod.api.services.measurement_group_service.update_measurement_group_nf_status')
     def test_handle_response_locked_failed(self, mock_update_sub_nf):
         with patch.dict(policy_response_handle_functions,
                         {AdministrativeState.LOCKED.value: {'failed': mock_update_sub_nf}}):
             self.policy_response_handler._handle_response(
-                self.app_conf.subscription.subscriptionName,
+                'msr_grp_name',
                 AdministrativeState.LOCKED.value,
                 self.nf.nf_name, 'failed')
             mock_update_sub_nf.assert_called_with(
-                subscription_name=self.app_conf.subscription.subscriptionName,
+                measurement_group_name='msr_grp_name',
                 status=SubNfState.DELETE_FAILED.value, nf_name=self.nf.nf_name)
 
-    @patch('mod.subscription.Subscription.update_sub_nf_status')
+    @patch('mod.network_function.NetworkFunction.delete')
+    def test_handle_response_locking_success(self, mock_delete):
+        with patch.dict(policy_response_handle_functions,
+                        {AdministrativeState.LOCKING.value: {'success': mock_delete}}):
+            self.policy_response_handler._handle_response(
+                'msr_grp_name',
+                AdministrativeState.LOCKING.value,
+                self.nf.nf_name, 'success')
+            mock_delete.assert_called()
+
+    @patch('mod.api.services.measurement_group_service.update_measurement_group_nf_status')
+    def test_handle_response_locking_failed(self, mock_update_sub_nf):
+        with patch.dict(policy_response_handle_functions,
+                        {AdministrativeState.LOCKING.value: {'failed': mock_update_sub_nf}}):
+            self.policy_response_handler._handle_response(
+                'msr_grp_name',
+                AdministrativeState.LOCKING.value,
+                self.nf.nf_name, 'failed')
+            mock_update_sub_nf.assert_called_with(
+                measurement_group_name='msr_grp_name',
+                status=SubNfState.DELETE_FAILED.value, nf_name=self.nf.nf_name)
+
+    @patch('mod.api.services.measurement_group_service.update_measurement_group_nf_status')
     def test_handle_response_unlocked_success(self, mock_update_sub_nf):
         with patch.dict(policy_response_handle_functions,
                         {AdministrativeState.UNLOCKED.value: {'success': mock_update_sub_nf}}):
             self.policy_response_handler._handle_response(
-                self.app_conf.subscription.subscriptionName,
+                'msr_grp_name',
                 AdministrativeState.UNLOCKED.value,
                 self.nf.nf_name, 'success')
             mock_update_sub_nf.assert_called_with(
-                subscription_name=self.app_conf.subscription.subscriptionName,
+                measurement_group_name='msr_grp_name',
                 status=SubNfState.CREATED.value, nf_name=self.nf.nf_name)
 
-    @patch('mod.subscription.Subscription.update_sub_nf_status')
+    @patch('mod.api.services.measurement_group_service.update_measurement_group_nf_status')
     def test_handle_response_unlocked_failed(self, mock_update_sub_nf):
         with patch.dict(policy_response_handle_functions,
                         {AdministrativeState.UNLOCKED.value: {'failed': mock_update_sub_nf}}):
             self.policy_response_handler._handle_response(
-                self.app_conf.subscription.subscriptionName,
+                'msr_grp_name',
                 AdministrativeState.UNLOCKED.value,
                 self.nf.nf_name, 'failed')
             mock_update_sub_nf.assert_called_with(
-                subscription_name=self.app_conf.subscription.subscriptionName,
+                measurement_group_name='msr_grp_name',
                 status=SubNfState.CREATE_FAILED.value, nf_name=self.nf.nf_name)
 
     def test_handle_response_exception(self):
@@ -99,45 +116,34 @@
                           'wrong_state', 'nf1', 'wrong_message')
 
     @patch('mod.policy_response_handler.PolicyResponseHandler._handle_response')
-    @patch('mod.subscription.Subscription.get')
-    def test_poll_policy_topic_calls_methods_correct_sub(self, mock_get_sub, mock_handle_response):
+    @patch('mod.pmsh_config.AppConfig.get_from_topic')
+    def test_poll_policy_topic_calls_methods_correct_mg(self, mock_policy_mr_sub,
+                                                        mock_handle_response):
         response_data = ['{"name": "ResponseEvent","status": { "subscriptionName": '
-                         '"ExtraPM-All-gNB-R2B", "nfName": "pnf300", "message": "success" } }']
-        self.mock_policy_mr_sub.get_from_topic.return_value = response_data
-        mock_get_sub.return_value = SubscriptionModel(subscription_name='ExtraPM-All-gNB-R2B',
-                                                      operational_policy_name='policy-name',
-                                                      control_loop_name='control-loop-name',
-                                                      status=AdministrativeState.UNLOCKED.value)
+                         '"ExtraPM-All-gNB-R2B2", "nfName": "pnf300", "message": "success", '
+                         '"measurementGroupName":"MG1"} }']
+        mock_policy_mr_sub.return_value = response_data
+        sub_model = create_subscription_data('ExtraPM-All-gNB-R2B2')
+        db.session.add(sub_model)
+        db.session.commit()
         self.policy_response_handler.poll_policy_topic()
-        self.mock_policy_mr_sub.get_from_topic.assert_called()
-        mock_handle_response.assert_called_with(self.app_conf.subscription.subscriptionName,
+        mock_handle_response.assert_called_with("MG1",
                                                 AdministrativeState.UNLOCKED.value, 'pnf300',
                                                 'success')
 
     @patch('mod.policy_response_handler.PolicyResponseHandler._handle_response')
-    @patch('mod.subscription.Subscription.get')
-    def test_poll_policy_topic_no_method_calls_incorrect_sub(self, mock_get_sub,
-                                                             mock_handle_response):
+    @patch('mod.pmsh_config.AppConfig.get_from_topic')
+    def test_poll_policy_topic_no_method_calls_unavailable_mg(self, mock_policy_mr_sub,
+                                                              mock_handle_response):
         response_data = ['{"name": "ResponseEvent","status": { "subscriptionName": '
-                         '"Different_Subscription", "nfName": "pnf300", "message": "success" } }']
-        self.mock_policy_mr_sub.get_from_topic.return_value = response_data
-        mock_get_sub.return_value = SubscriptionModel(subscription_name='ExtraPM-All-gNB-R2B',
-                                                      operational_policy_name='policy-name',
-                                                      control_loop_name='control-loop-name',
-                                                      status=AdministrativeState.UNLOCKED.value)
+                         '"Different_Subscription", "nfName": "pnf300", "message": "success",'
+                         '"measurementGroupName":"msr_grp_name" } }']
+        mock_policy_mr_sub.return_value = response_data
         self.policy_response_handler.poll_policy_topic()
-
-        self.mock_policy_mr_sub.get_from_topic.assert_called()
-
         mock_handle_response.assert_not_called()
 
+    @patch('mod.pmsh_config.AppConfig.get_from_topic', MagicMock(return_value='wrong_return'))
     @patch('mod.logger.error')
-    @patch('mod.subscription.Subscription.get')
-    def test_poll_policy_topic_exception(self, mock_get_sub, mock_logger):
-        self.mock_policy_mr_sub.get_from_topic.return_value = 'wrong_return'
-        mock_get_sub.return_value = SubscriptionModel(subscription_name='ExtraPM-All-gNB-R2B',
-                                                      operational_policy_name='policy-name',
-                                                      control_loop_name='control-loop-name',
-                                                      status=AdministrativeState.UNLOCKED.value)
+    def test_poll_policy_topic_exception(self, mock_logger):
         self.policy_response_handler.poll_policy_topic()
         mock_logger.assert_called()