[PMSH] Adding 'subscriptions' api endpoint

Signed-off-by: efiacor <fiachra.corcoran@est.tech>
Change-Id: I837045b3b618a98d4aabe190359d0ad47f27ca9f
Issue-ID: DCAEGEN2-2154
diff --git a/components/pm-subscription-handler/Changelog.md b/components/pm-subscription-handler/Changelog.md
index 3d2af6c..2ec36fb 100755
--- a/components/pm-subscription-handler/Changelog.md
+++ b/components/pm-subscription-handler/Changelog.md
@@ -5,6 +5,11 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
+## [1.1.0]
+### Changed
+* Added new API endpoint to fetch all Subscription data (DCAEGEN2-2154)
+* Added support for config-binding-docker module in PMSH config fetch (DCAEGEN2-2156)
+
 ## [1.0.3]
 ### Fixed
 * Fixed bug where PMSH pushes subscription to xnf regardless of it's orchestration status (DCAEGEN2-2173)
diff --git a/components/pm-subscription-handler/pmsh_service/mod/__init__.py b/components/pm-subscription-handler/pmsh_service/mod/__init__.py
index e09ec28..5c0a514 100644
--- a/components/pm-subscription-handler/pmsh_service/mod/__init__.py
+++ b/components/pm-subscription-handler/pmsh_service/mod/__init__.py
@@ -37,7 +37,7 @@
 
 def launch_api_server(app_config):
     connex_app = _get_app()
-    connex_app.add_api('pmsh_swagger.yml')
+    connex_app.add_api('api/pmsh_swagger.yml')
     connex_app.run(port=os.environ.get('PMSH_API_PORT', '8443'),
                    ssl_context=(app_config.cert_path, app_config.key_path))
 
diff --git a/components/pm-subscription-handler/pmsh_service/mod/api/__init__.py b/components/pm-subscription-handler/pmsh_service/mod/api/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/components/pm-subscription-handler/pmsh_service/mod/api/__init__.py
diff --git a/components/pm-subscription-handler/pmsh_service/mod/healthcheck.py b/components/pm-subscription-handler/pmsh_service/mod/api/controller.py
similarity index 77%
rename from components/pm-subscription-handler/pmsh_service/mod/healthcheck.py
rename to components/pm-subscription-handler/pmsh_service/mod/api/controller.py
index af82fc4..21d29ca 100755
--- a/components/pm-subscription-handler/pmsh_service/mod/healthcheck.py
+++ b/components/pm-subscription-handler/pmsh_service/mod/api/controller.py
@@ -16,6 +16,8 @@
 # SPDX-License-Identifier: Apache-2.0
 # ============LICENSE_END=====================================================
 
+from mod.subscription import Subscription
+
 
 def status():
     """
@@ -28,3 +30,13 @@
         NA
     """
     return {'status': 'healthy'}
+
+
+def get_all_sub_to_nf_relations():
+    """ Retrieves all subscription to nf relations
+
+    Returns:
+        list: of Subscriptions and it's related Network Functions, else empty
+    """
+    subs_dict = [s.serialize() for s in Subscription.get_all()]
+    return subs_dict
diff --git a/components/pm-subscription-handler/pmsh_service/mod/db_models.py b/components/pm-subscription-handler/pmsh_service/mod/api/db_models.py
similarity index 72%
rename from components/pm-subscription-handler/pmsh_service/mod/db_models.py
rename to components/pm-subscription-handler/pmsh_service/mod/api/db_models.py
index d183676..1d6f72b 100755
--- a/components/pm-subscription-handler/pmsh_service/mod/db_models.py
+++ b/components/pm-subscription-handler/pmsh_service/mod/api/db_models.py
@@ -38,13 +38,19 @@
         self.status = status
 
     def __repr__(self):
-        return f'Subscription: {self.subscription_name}  {self.status}'
+        return f'subscription_name: {self.subscription_name}, status: {self.status}'
 
     def __eq__(self, other):
         if isinstance(self, other.__class__):
             return self.subscription_name == other.subscription_name
         return False
 
+    def serialize(self):
+        sub_nfs = NfSubRelationalModel.query.filter(
+            NfSubRelationalModel.subscription_name == self.subscription_name).all()
+        return {'subscription_name': self.subscription_name, 'subscription_status': self.status,
+                'network_functions': [sub_nf.serialize_nf() for sub_nf in sub_nfs]}
+
 
 class NetworkFunctionModel(db.Model):
     __tablename__ = 'network_functions'
@@ -62,7 +68,7 @@
         self.orchestration_status = orchestration_status
 
     def __repr__(self):
-        return f'NetworkFunctionModel: {self.nf_name}, {self.orchestration_status}'
+        return f'nf_name: {self.nf_name}, orchestration_status: {self.orchestration_status}'
 
 
 class NfSubRelationalModel(db.Model):
@@ -87,5 +93,15 @@
         self.nf_sub_status = nf_sub_status
 
     def __repr__(self):
-        return f'NetworkFunctionSubscriptions: {self.subscription_name}, ' \
-            f'{self.nf_name}, {self.nf_sub_status}'
+        return f'subscription_name: {self.subscription_name}, ' \
+            f'nf_name: {self.nf_name}, nf_sub_status: {self.nf_sub_status}'
+
+    def serialize(self):
+        return {'subscription_name': self.subscription_name, 'nf_name': self.nf_name,
+                'nf_sub_status': self.nf_sub_status}
+
+    def serialize_nf(self):
+        nf_orch_status = NetworkFunctionModel.query.filter(
+            NetworkFunctionModel.nf_name == self.nf_name).one_or_none().orchestration_status
+        return {'nf_name': self.nf_name, 'orchestration_status': nf_orch_status,
+                'nf_sub_status': self.nf_sub_status}
diff --git a/components/pm-subscription-handler/pmsh_service/mod/api/pmsh_swagger.yml b/components/pm-subscription-handler/pmsh_service/mod/api/pmsh_swagger.yml
new file mode 100644
index 0000000..58e6a78
--- /dev/null
+++ b/components/pm-subscription-handler/pmsh_service/mod/api/pmsh_swagger.yml
@@ -0,0 +1,89 @@
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2020 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+
+swagger: "2.0"
+info:
+  title: PM Subscription Handler Service
+  version: "1.1.0"
+  description: PM subscription handler enables control of performance management jobs on network functions in ONAP
+produces:
+  - "application/json"
+basePath: "/"
+schemes:
+  - https
+# Paths supported by the server application
+paths:
+  /subscriptions:
+    get:
+      description: >-
+        Get all defined Subscriptions and their related Network Functions from ONAP.
+      operationId: mod.api.controller.get_all_sub_to_nf_relations
+      responses:
+        200:
+          description: OK; Array of subscriptions are returned as an object
+          schema:
+            type: array
+            items:
+              type: object
+              properties:
+                subscription_name:
+                  type: string
+                  description: Name of the Subscription
+                subscription_status:
+                  type: string
+                  description: Status of the Subscription
+                network_functions:
+                  type: array
+                  items:
+                    type: object
+                    properties:
+                      nf_name:
+                        type: string
+                        description: Name of the Network Function
+                      nf_sub_status:
+                        type: string
+                        description: Status of the Subscription on the Network Function
+                      orchestration_status:
+                        type: string
+                        description: Orchestration status of the Network Function
+        401:
+          description: Unauthorized
+        403:
+          description: Forbidden
+        404:
+          description: there are no subscriptions defined
+
+  /healthcheck:
+    get:
+      operationId: mod.api.controller.status
+      tags:
+        - "HealthCheck"
+      description: >-
+        This is the health check endpoint. If this returns a 200, the server is alive.
+      responses:
+        200:
+          description: Successful response
+          schema:
+            type: object
+            properties:
+              status:
+                type: string
+                description: Overall health of PMSH
+                enum: [healthy, unhealthy]
+        503:
+          description: the pmsh service is unavailable
diff --git a/components/pm-subscription-handler/pmsh_service/mod/network_function.py b/components/pm-subscription-handler/pmsh_service/mod/network_function.py
index bf22318..0663be0 100755
--- a/components/pm-subscription-handler/pmsh_service/mod/network_function.py
+++ b/components/pm-subscription-handler/pmsh_service/mod/network_function.py
@@ -20,7 +20,7 @@
 from enum import Enum
 
 from mod import pmsh_logging as logger, db
-from mod.db_models import NetworkFunctionModel
+from mod.api.db_models import NetworkFunctionModel
 
 
 class NetworkFunction:
@@ -53,10 +53,9 @@
                                           orchestration_status=self.orchestration_status)
             db.session.add(new_nf)
             db.session.commit()
-
             return new_nf
         else:
-            logger.debug(f'Network function {existing_nf} already exists,'
+            logger.debug(f'Network function {existing_nf.nf_name} already exists,'
                          f' returning this network function..')
             return existing_nf
 
diff --git a/components/pm-subscription-handler/pmsh_service/mod/pmsh_swagger.yml b/components/pm-subscription-handler/pmsh_service/mod/pmsh_swagger.yml
deleted file mode 100644
index 7bfecd8..0000000
--- a/components/pm-subscription-handler/pmsh_service/mod/pmsh_swagger.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-swagger: "2.0"
-info:
-  title: PM Subscription Handler Service
-  version: "1.0.0"
-  description: This is the swagger file that outlines the PM subscription handler api
-consumes:
-  - "application/json"
-produces:
-  - "application/json"
-
-schemes:
-  - https
-
-# Paths supported by the server application
-paths:
-  /healthcheck:
-    get:
-      operationId: "mod.healthcheck.status"
-      tags:
-        - "HealthCheck"
-      description: >-
-        This is the health check endpoint. If this returns a 200, the server is alive.
-      responses:
-        200:
-          description: Successful response
-          schema:
-            type: object
-            properties:
-              status:
-                type: string
-                description: Overall health of PMSH
-                enum: [healthy, unhealthy]
-        503:
-          description: the pmsh service is unavailable
diff --git a/components/pm-subscription-handler/pmsh_service/mod/subscription.py b/components/pm-subscription-handler/pmsh_service/mod/subscription.py
index 3add720..7517ba9 100755
--- a/components/pm-subscription-handler/pmsh_service/mod/subscription.py
+++ b/components/pm-subscription-handler/pmsh_service/mod/subscription.py
@@ -15,14 +15,13 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 # ============LICENSE_END=====================================================
-
 from enum import Enum
 
 from tenacity import retry, retry_if_exception_type, wait_exponential, stop_after_attempt
 
 import mod.pmsh_logging as logger
 from mod import db
-from mod.db_models import SubscriptionModel, NfSubRelationalModel, NetworkFunctionModel
+from mod.api.db_models import SubscriptionModel, NfSubRelationalModel, NetworkFunctionModel
 from mod.network_function import NetworkFunction
 
 
@@ -84,35 +83,33 @@
         Returns:
             Subscription object
         """
-        existing_subscription = (SubscriptionModel.query.filter(
-            SubscriptionModel.subscription_name == self.subscriptionName).one_or_none())
+        try:
+            existing_subscription = (SubscriptionModel.query.filter(
+                SubscriptionModel.subscription_name == self.subscriptionName).one_or_none())
+            if existing_subscription is None:
+                new_subscription = SubscriptionModel(subscription_name=self.subscriptionName,
+                                                     status=self.administrativeState)
+                db.session.add(new_subscription)
+                db.session.commit()
+                return new_subscription
+            else:
+                logger.debug(f'Subscription {self.subscriptionName} already exists,'
+                             f' returning this subscription..')
+                return existing_subscription
+        except Exception as e:
+            logger.debug(f'Failed to create subscription {self.subscriptionName} in the DB: {e}')
 
-        if existing_subscription is None:
-            new_subscription = SubscriptionModel(subscription_name=self.subscriptionName,
-                                                 status=self.administrativeState)
-
-            db.session.add(new_subscription)
-            db.session.commit()
-
-            return new_subscription
-
-        else:
-            logger.debug(f'Subscription {self.subscriptionName} already exists,'
-                         f' returning this subscription..')
-            return existing_subscription
-
-    def add_network_functions_to_subscription(self, nf_list):
-        """ Associates network functions to a Subscription
+    def add_network_function_to_subscription(self, nf):
+        """ Associates a network function to a Subscription
 
         Args:
-            nf_list : A list of NetworkFunction objects.
+            nf : A NetworkFunction object.
         """
         current_sub = self.create()
-        logger.debug(f'Adding network functions to subscription {current_sub.subscription_name}')
-
-        for nf in nf_list:
+        try:
             current_nf = nf.create()
-
+            logger.debug(f'Adding network function {nf.nf_name} to Subscription '
+                         f'{current_sub.subscription_name}')
             existing_entry = NfSubRelationalModel.query.filter(
                 NfSubRelationalModel.subscription_name == current_sub.subscription_name,
                 NfSubRelationalModel.nf_name == current_nf.nf_name).one_or_none()
@@ -120,11 +117,14 @@
                 new_nf_sub = NfSubRelationalModel(current_sub.subscription_name,
                                                   nf.nf_name, SubNfState.PENDING_CREATE.value)
                 new_nf_sub.nf = current_nf
-                logger.debug(current_nf)
                 current_sub.nfs.append(new_nf_sub)
-
-        db.session.add(current_sub)
-        db.session.commit()
+                logger.debug(f'Network function {current_nf.nf_name} added to Subscription '
+                             f'{current_sub.subscription_name}')
+                db.session.add(current_sub)
+                db.session.commit()
+        except Exception as e:
+            logger.debug(f'Failed to add nf {nf.nf_name} to subscription '
+                         f'{current_sub.subscription_name}: {e}')
 
     @staticmethod
     def get(subscription_name):
@@ -150,27 +150,34 @@
 
     def update_subscription_status(self):
         """ Updates the status of subscription in subscription table """
-        SubscriptionModel.query.filter(
-            SubscriptionModel.subscription_name == self.subscriptionName). \
-            update({SubscriptionModel.status: self.administrativeState},
-                   synchronize_session='evaluate')
+        try:
+            SubscriptionModel.query.filter(
+                SubscriptionModel.subscription_name == self.subscriptionName)\
+                .update({SubscriptionModel.status: self.administrativeState},
+                        synchronize_session='evaluate')
 
-        db.session.commit()
+            db.session.commit()
+        except Exception as e:
+            logger.debug(f'Failed to update status of subscription: {self.subscriptionName}: {e}')
 
     def delete_subscription(self):
         """ Deletes a subscription and all its association from the database. A network function
         that is only associated with the subscription being removed will also be deleted."""
-        subscription = SubscriptionModel.query.filter(
-            SubscriptionModel.subscription_name == self.subscriptionName).one_or_none()
-        if subscription:
-            for nf_relationship in subscription.nfs:
-                other_nf_relationship = NfSubRelationalModel.query.filter(
-                    NfSubRelationalModel.subscription_name != self.subscriptionName,
-                    NfSubRelationalModel.nf_name == nf_relationship.nf_name).one_or_none()
-                if not other_nf_relationship:
-                    db.session.delete(nf_relationship.nf)
-            db.session.delete(subscription)
-            db.session.commit()
+        try:
+            subscription = SubscriptionModel.query.filter(
+                SubscriptionModel.subscription_name == self.subscriptionName).one_or_none()
+            if subscription:
+                for nf_relationship in subscription.nfs:
+                    other_nf_relationship = NfSubRelationalModel.query.filter(
+                        NfSubRelationalModel.subscription_name != self.subscriptionName,
+                        NfSubRelationalModel.nf_name == nf_relationship.nf_name).one_or_none()
+                    if not other_nf_relationship:
+                        db.session.delete(nf_relationship.nf)
+                db.session.delete(subscription)
+                db.session.commit()
+        except Exception as e:
+            logger.debug(f'Failed to delete subscription: {self.subscriptionName} '
+                         f'and it\'s relations from the DB: {e}')
 
     @retry(wait=wait_exponential(multiplier=1, min=30, max=120), stop=stop_after_attempt(3),
            retry=retry_if_exception_type(Exception))
@@ -188,7 +195,7 @@
                 mr_pub.publish_subscription_event_data(self, nf.nf_name, app_conf)
                 logger.debug(f'Publishing Event to {action} '
                              f'Sub: {self.subscriptionName} for the nf: {nf.nf_name}')
-                self.add_network_functions_to_subscription(nfs)
+                self.add_network_function_to_subscription(nf)
                 self.update_sub_nf_status(self.subscriptionName, sub_nf_state, nf.nf_name)
         except Exception as err:
             raise Exception(f'Error publishing activation event to MR: {err}')
@@ -213,12 +220,15 @@
             nf_name (str): The network function name
             status (str): Status of the subscription
         """
-        NfSubRelationalModel.query.filter(
-            NfSubRelationalModel.subscription_name == subscription_name,
-            NfSubRelationalModel.nf_name == nf_name). \
-            update({NfSubRelationalModel.nf_sub_status: status}, synchronize_session='evaluate')
-
-        db.session.commit()
+        try:
+            NfSubRelationalModel.query.filter(
+                NfSubRelationalModel.subscription_name == subscription_name,
+                NfSubRelationalModel.nf_name == nf_name). \
+                update({NfSubRelationalModel.nf_sub_status: status}, synchronize_session='evaluate')
+            db.session.commit()
+        except Exception as e:
+            logger.debug(f'Failed to update status of nf: {nf_name} for subscription: '
+                         f'{subscription_name}: {e}')
 
     def _get_nf_models(self):
         nf_sub_relationships = NfSubRelationalModel.query.filter(
diff --git a/components/pm-subscription-handler/setup.py b/components/pm-subscription-handler/setup.py
index 0437f5d..cc09dc8 100644
--- a/components/pm-subscription-handler/setup.py
+++ b/components/pm-subscription-handler/setup.py
@@ -20,7 +20,7 @@
 
 setup(
     name="pm_subscription_handler",
-    version="1.0.0",
+    version="1.1.0",
     packages=find_packages(),
     author="lego@est.tech",
     author_email="lego@est.tech",
@@ -34,6 +34,7 @@
         "connexion==2.5.0",
         "flask_sqlalchemy==2.4.1",
         "Flask==1.1.1",
+        "swagger-ui-bundle==0.0.6",
         "psycopg2-binary==2.8.4",
         "onap_dcae_cbs_docker_client==2.1.0"]
 )
diff --git a/components/pm-subscription-handler/tests/test_controller.py b/components/pm-subscription-handler/tests/test_controller.py
new file mode 100755
index 0000000..8ef3946
--- /dev/null
+++ b/components/pm-subscription-handler/tests/test_controller.py
@@ -0,0 +1,69 @@
+# ============LICENSE_START===================================================
+#  Copyright (C) 2019-2020 Nordix Foundation.
+# ============================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=====================================================
+import json
+import os
+import unittest
+from test.support import EnvironmentVarGuard
+from unittest.mock import patch
+
+from requests import Session
+
+from mod import aai_client, create_app, db
+from mod.api.controller import status, get_all_sub_to_nf_relations
+from mod.network_function import NetworkFunction
+
+
+class ControllerTestCase(unittest.TestCase):
+    @patch('mod.get_db_connection_url')
+    @patch.object(Session, 'put')
+    def setUp(self, mock_session, mock_get_db_url):
+        mock_get_db_url.return_value = 'sqlite://'
+        with open(os.path.join(os.path.dirname(__file__), 'data/aai_xnfs.json'), 'r') as data:
+            self.aai_response_data = data.read()
+        mock_session.return_value.status_code = 200
+        mock_session.return_value.text = self.aai_response_data
+        self.env = EnvironmentVarGuard()
+        self.env.set('AAI_SERVICE_HOST', '1.2.3.4')
+        self.env.set('AAI_SERVICE_PORT', '8443')
+        self.env.set('TESTING', 'True')
+        self.env.set('LOGS_PATH', './unit_test_logs')
+        with open(os.path.join(os.path.dirname(__file__), 'data/cbs_data_1.json'), 'r') as data:
+            self.cbs_data_1 = json.load(data)
+        self.sub_1, self.xnfs = aai_client.get_pmsh_subscription_data(self.cbs_data_1)
+        self.nf_1 = NetworkFunction(nf_name='pnf_1', orchestration_status='Inventoried')
+        self.nf_2 = NetworkFunction(nf_name='pnf_2', orchestration_status='Active')
+        self.app = create_app()
+        self.app_context = self.app.app_context()
+        self.app_context.push()
+        db.create_all()
+
+    def tearDown(self):
+        db.session.remove()
+        db.drop_all()
+        self.app_context.pop()
+
+    def test_status_response_healthy(self):
+        self.assertEqual(status()['status'], 'healthy')
+
+    def test_get_all_sub_to_nf_relations(self):
+        self.sub_1.create()
+        for nf in [self.nf_1, self.nf_2]:
+            self.sub_1.add_network_function_to_subscription(nf)
+        all_subs = get_all_sub_to_nf_relations()
+        self.assertEqual(len(all_subs[0]['network_functions']), 2)
+        self.assertEqual(all_subs[0]['subscription_name'], 'ExtraPM-All-gNB-R2B')
diff --git a/components/pm-subscription-handler/tests/test_healthcheck.py b/components/pm-subscription-handler/tests/test_healthcheck.py
deleted file mode 100755
index 1c40c3f..0000000
--- a/components/pm-subscription-handler/tests/test_healthcheck.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# ============LICENSE_START===================================================
-#  Copyright (C) 2019-2020 Nordix Foundation.
-# ============================================================================
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# SPDX-License-Identifier: Apache-2.0
-# ============LICENSE_END=====================================================
-
-import unittest
-
-from mod.healthcheck import status
-
-
-class HealthcheckTestCase(unittest.TestCase):
-
-    def test_status_response_healthy(self):
-        self.assertEqual(status()['status'], 'healthy')
diff --git a/components/pm-subscription-handler/tests/test_network_function.py b/components/pm-subscription-handler/tests/test_network_function.py
index 4fca077..138d99a 100755
--- a/components/pm-subscription-handler/tests/test_network_function.py
+++ b/components/pm-subscription-handler/tests/test_network_function.py
@@ -71,7 +71,8 @@
         self.nf_1.create()
         self.nf_2.create()
         sub = Subscription(**{"subscriptionName": "sub"})
-        sub.add_network_functions_to_subscription([self.nf_1, self.nf_2])
+        for nf in [self.nf_1, self.nf_2]:
+            sub.add_network_function_to_subscription(nf)
 
         NetworkFunction.delete(nf_name=self.nf_1.nf_name)
 
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 1cf947f..6de3363 100644
--- a/components/pm-subscription-handler/tests/test_policy_response_handler.py
+++ b/components/pm-subscription-handler/tests/test_policy_response_handler.py
@@ -22,7 +22,7 @@
 
 from tenacity import stop_after_attempt
 
-from mod.db_models import SubscriptionModel
+from mod.api.db_models import SubscriptionModel
 from mod.network_function import NetworkFunction
 from mod.subscription import AdministrativeState, SubNfState
 from mod.policy_response_handler import PolicyResponseHandler, policy_response_handle_functions
diff --git a/components/pm-subscription-handler/tests/test_subscription.py b/components/pm-subscription-handler/tests/test_subscription.py
index e6ee2b5..dc549c9 100755
--- a/components/pm-subscription-handler/tests/test_subscription.py
+++ b/components/pm-subscription-handler/tests/test_subscription.py
@@ -26,7 +26,7 @@
 
 import mod.aai_client as aai_client
 from mod import db, create_app
-from mod.db_models import NetworkFunctionModel
+from mod.api.db_models import NetworkFunctionModel
 from mod.network_function import NetworkFunction, NetworkFunctionFilter, OrchestrationStatus
 from mod.pmsh_utils import AppConfig
 from mod.subscription import Subscription
@@ -46,7 +46,7 @@
         mock_session.return_value.text = self.aai_response_data
         self.env = EnvironmentVarGuard()
         self.env.set('AAI_SERVICE_HOST', '1.2.3.4')
-        self.env.set('AAI_SERVICE_PORT_AAI_SSL', '8443')
+        self.env.set('AAI_SERVICE_PORT', '8443')
         self.env.set('TESTING', 'True')
         self.env.set('LOGS_PATH', './unit_test_logs')
         with open(os.path.join(os.path.dirname(__file__), 'data/cbs_data_1.json'), 'r') as data:
@@ -110,22 +110,21 @@
         self.assertEqual(1, len(self.sub_1.get_all()))
 
     def test_add_network_functions_per_subscription(self):
-        nf_array = [self.nf_1, self.nf_2]
-        self.sub_1.add_network_functions_to_subscription(nf_array)
+        for nf in [self.nf_1, self.nf_2]:
+            self.sub_1.add_network_function_to_subscription(nf)
         nfs_for_sub_1 = Subscription.get_all_nfs_subscription_relations()
         self.assertEqual(2, len(nfs_for_sub_1))
-        new_nf_array = [NetworkFunction(nf_name='vnf_3', orchestration_status='Inventoried')]
-        self.sub_1.add_network_functions_to_subscription(new_nf_array)
+        new_nf = NetworkFunction(nf_name='vnf_3', orchestration_status='Inventoried')
+        self.sub_1.add_network_function_to_subscription(new_nf)
         nf_subs = Subscription.get_all_nfs_subscription_relations()
         print(nf_subs)
         self.assertEqual(3, len(nf_subs))
 
     def test_add_duplicate_network_functions_per_subscription(self):
-        nf_array = [self.nf_1]
-        self.sub_1.add_network_functions_to_subscription(nf_array)
+        self.sub_1.add_network_function_to_subscription(self.nf_1)
         nf_subs = Subscription.get_all_nfs_subscription_relations()
         self.assertEqual(1, len(nf_subs))
-        self.sub_1.add_network_functions_to_subscription(nf_array)
+        self.sub_1.add_network_function_to_subscription(self.nf_1)
         nf_subs = Subscription.get_all_nfs_subscription_relations()
         self.assertEqual(1, len(nf_subs))
 
@@ -139,8 +138,10 @@
         self.assertEqual('new_status', sub.status)
 
     def test_delete_subscription(self):
-        self.sub_1.add_network_functions_to_subscription([self.nf_1, self.nf_2])
-        self.sub_2.add_network_functions_to_subscription([self.nf_2])
+        for nf in [self.nf_1, self.nf_2]:
+            self.sub_1.add_network_function_to_subscription(nf)
+        for nf in [self.nf_2]:
+            self.sub_2.add_network_function_to_subscription(nf)
 
         self.sub_1.delete_subscription()
 
@@ -152,8 +153,8 @@
 
     def test_update_sub_nf_status(self):
         sub_name = 'ExtraPM-All-gNB-R2B'
-        nf_array = [self.nf_1, self.nf_2]
-        self.sub_1.add_network_functions_to_subscription(nf_array)
+        for nf in [self.nf_1, self.nf_2]:
+            self.sub_1.add_network_function_to_subscription(nf)
         sub_nfs = Subscription.get_all_nfs_subscription_relations()
         self.assertEqual('PENDING_CREATE', sub_nfs[0].nf_sub_status)
 
@@ -162,7 +163,7 @@
         self.assertEqual('Active', sub_nfs[0].nf_sub_status)
         self.assertEqual('PENDING_CREATE', sub_nfs[1].nf_sub_status)
 
-    @patch('mod.subscription.Subscription.add_network_functions_to_subscription')
+    @patch('mod.subscription.Subscription.add_network_function_to_subscription')
     @patch('mod.subscription.Subscription.update_sub_nf_status')
     @patch('mod.subscription.Subscription.update_subscription_status')
     def test_process_activate_subscription(self, mock_update_sub_status,
@@ -204,16 +205,16 @@
         self.assertEqual(expected_sub_event, actual_sub_event)
 
     def test_get_nf_models(self):
-        nf_array = [self.nf_1, self.nf_2]
-        self.sub_1.add_network_functions_to_subscription(nf_array)
+        for nf in [self.nf_1, self.nf_2]:
+            self.sub_1.add_network_function_to_subscription(nf)
         nf_models = self.sub_1._get_nf_models()
 
         self.assertEqual(2, len(nf_models))
         self.assertIsInstance(nf_models[0], NetworkFunctionModel)
 
     def test_get_network_functions(self):
-        nf_array = [self.nf_1, self.nf_2]
-        self.sub_1.add_network_functions_to_subscription(nf_array)
+        for nf in [self.nf_1, self.nf_2]:
+            self.sub_1.add_network_function_to_subscription(nf)
         nfs = self.sub_1.get_network_functions()
 
         self.assertEqual(2, len(nfs))