From 0080fa4309a40599b7d239b53bab9a74182ae500 Mon Sep 17 00:00:00 2001 From: efiacor Date: Tue, 8 Sep 2020 16:26:50 +0100 Subject: [PMSSH] Add sdnc model info to event publish Signed-off-by: efiacor Change-Id: I89e25e99a2d541a29cf4a8dde986fab5b1812c9e Issue-ID: DCAEGEN2-2405 --- components/pm-subscription-handler/Changelog.md | 1 + .../pmsh_service/mod/aai_client.py | 114 ++++++++++++++------- .../pmsh_service/mod/aai_event_handler.py | 36 +++---- .../pmsh_service/mod/api/db_models.py | 35 +++++-- .../pmsh_service/mod/network_function.py | 68 ++++++++---- .../pmsh_service/mod/pmsh_utils.py | 10 +- .../pmsh_service/mod/subscription.py | 77 +++----------- .../pmsh_service/mod/subscription_handler.py | 4 +- .../pm-subscription-handler/tests/base_setup.py | 57 +++++++++++ .../tests/data/aai_model_info.json | 36 +++++++ .../tests/data/aai_model_info_no_sdnc.json | 34 ++++++ .../tests/data/cbs_data_1.json | 2 +- .../tests/data/filter_test_data.json | 50 +++------ .../tests/data/pm_subscription_event.json | 2 + .../pm-subscription-handler/tests/log_config.yaml | 9 +- .../tests/test_aai_event_handler.py | 57 ++++------- .../tests/test_aai_service.py | 88 ++++++++++------ .../tests/test_controller.py | 65 ++++++------ .../tests/test_exit_handler.py | 38 ++++--- .../tests/test_network_function.py | 77 +++++++------- .../tests/test_network_function_filter.py | 39 +++---- .../tests/test_pmsh_utils.py | 105 +++++++------------ .../tests/test_policy_response_handler.py | 31 +++--- .../tests/test_subscription.py | 86 ++++++---------- .../tests/test_subscription_handler.py | 49 ++++----- 25 files changed, 636 insertions(+), 534 deletions(-) create mode 100755 components/pm-subscription-handler/tests/base_setup.py create mode 100644 components/pm-subscription-handler/tests/data/aai_model_info.json create mode 100644 components/pm-subscription-handler/tests/data/aai_model_info_no_sdnc.json (limited to 'components/pm-subscription-handler') diff --git a/components/pm-subscription-handler/Changelog.md b/components/pm-subscription-handler/Changelog.md index 8f4ce1b5..1d97b586 100755 --- a/components/pm-subscription-handler/Changelog.md +++ b/components/pm-subscription-handler/Changelog.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed * Moved to alpine base image (DCAEGEN2-2292) * Added model-invariant-id and model-version-id to filter (DCAEGEN2-2151) +* Added support for multiple CDS blueprints (DCAEGEN2-2405) ## [1.1.0] ### Changed diff --git a/components/pm-subscription-handler/pmsh_service/mod/aai_client.py b/components/pm-subscription-handler/pmsh_service/mod/aai_client.py index c8dea9f7..73bf8d4c 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/aai_client.py +++ b/components/pm-subscription-handler/pmsh_service/mod/aai_client.py @@ -21,9 +21,9 @@ from os import environ import requests from requests.auth import HTTPBasicAuth +import mod.network_function +import mod.pmsh_utils from mod import logger -from mod.network_function import NetworkFunction -from mod.pmsh_utils import mdc_handler def get_pmsh_nfs_from_aai(app_conf): @@ -34,21 +34,20 @@ def get_pmsh_nfs_from_aai(app_conf): app_conf (AppConfig): the AppConfig object. Returns: - set(NetworkFunctions): set of NetworkFunctions. + NetworkFunctions (list): list of NetworkFunctions. Raises: RuntimeError: if AAI Network Function data cannot be retrieved. """ aai_nf_data = _get_all_aai_nf_data(app_conf) if aai_nf_data: - nfs = _filter_nf_data(aai_nf_data, app_conf.nf_filter) + nfs = _filter_nf_data(aai_nf_data, app_conf) else: raise RuntimeError('Failed to get data from AAI') return nfs -@mdc_handler -def _get_all_aai_nf_data(app_conf, **kwargs): +def _get_all_aai_nf_data(app_conf): """ Return queried nf data from the AAI service. @@ -61,24 +60,19 @@ def _get_all_aai_nf_data(app_conf, **kwargs): nf_data = None try: session = requests.Session() - aai_endpoint = f'{_get_aai_service_url()}{"/aai/v19/query"}' + aai_named_query_endpoint = f'{_get_aai_service_url()}{"/query"}' logger.info('Fetching XNFs from AAI.') - headers = {'accept': 'application/json', - 'content-type': 'application/json', - 'x-fromappid': 'dcae-pmsh', - 'x-transactionid': kwargs['request_id'], - 'InvocationID': kwargs['invocation_id'], - 'RequestID': kwargs['request_id']} - json_data = """ - {'start': - ['network/pnfs', - 'network/generic-vnfs'] - }""" + headers = _get_aai_request_headers() + data = """ + {'start': + ['network/pnfs', + 'network/generic-vnfs'] + }""" params = {'format': 'simple', 'nodesOnly': 'true'} - response = session.put(aai_endpoint, headers=headers, + response = session.put(aai_named_query_endpoint, headers=headers, auth=HTTPBasicAuth(app_conf.aaf_creds.get('aaf_id'), app_conf.aaf_creds.get('aaf_pass')), - data=json_data, params=params, + data=data, params=params, verify=(app_conf.ca_cert_path if app_conf.enable_tls else False), cert=(app_conf.cert_params if app_conf.enable_tls else None)) response.raise_for_status() @@ -103,39 +97,89 @@ def _get_aai_service_url(): """ try: aai_ssl_port = environ['AAI_SERVICE_PORT'] - return f'https://aai:{aai_ssl_port}' + return f'https://aai:{aai_ssl_port}/aai/v20' except KeyError as e: logger.error(f'Failed to get AAI env var: {e}', exc_info=True) raise -def _filter_nf_data(nf_data, nf_filter): +@mod.pmsh_utils.mdc_handler +def _get_aai_request_headers(**kwargs): + return {'accept': 'application/json', + 'content-type': 'application/json', + 'x-fromappid': 'dcae-pmsh', + 'x-transactionid': kwargs['request_id'], + 'InvocationID': kwargs['invocation_id'], + 'RequestID': kwargs['request_id']} + + +def _filter_nf_data(nf_data, app_conf): """ Returns a list of filtered NetworkFunctions using the nf_filter. Args: - nf_data(dict): the nf json data from AAI. - nf_filter(NetworkFunctionFilter): the NetworkFunctionFilter to be applied. + nf_data (dict): the nf json data from AAI. + app_conf (AppConfig): the AppConfig object. Returns: - set(NetworkFunctions): a set of filtered NetworkFunctions. + NetworkFunction (list): a list of filtered NetworkFunction Objects. Raises: KeyError: if AAI data cannot be parsed. """ - nf_set = set() + nf_list = [] try: for nf in nf_data['results']: + if nf['properties'].get('orchestration-status') != 'Active': + continue name_identifier = 'pnf-name' if nf['node-type'] == 'pnf' else 'vnf-name' - orchestration_status = nf['properties'].get('orchestration-status') - model_invariant_id = nf['properties'].get('model-invariant-id') - model_version_id = nf['properties'].get('model-version-id') - if nf_filter.is_nf_in_filter(nf['properties'].get(name_identifier), - model_invariant_id, model_version_id, orchestration_status): - nf_set.add(NetworkFunction( - nf_name=nf['properties'].get(name_identifier), - orchestration_status=orchestration_status)) + new_nf = mod.network_function.NetworkFunction( + nf_name=nf['properties'].get(name_identifier), + model_invariant_id=nf['properties'].get('model-invariant-id'), + model_version_id=nf['properties'].get('model-version-id')) + if not new_nf.set_sdnc_params(app_conf): + continue + if app_conf.nf_filter.is_nf_in_filter(new_nf): + nf_list.append(new_nf) except KeyError as e: logger.error(f'Failed to parse AAI data: {e}', exc_info=True) raise - return nf_set + return nf_list + + +def get_aai_model_data(app_conf, model_invariant_id, model_version_id, nf_name): + """ + Get the sdnc_model info for the xNF from AAI. + + Args: + model_invariant_id (str): the AAI model-invariant-id + model_version_id (str): the AAI model-version-id + app_conf (AppConfig): the AppConfig object. + nf_name (str): The xNF name. + + Returns: + json (dict): the sdnc_model json object. + + Raises: + Exception: if AAI model data cannot be retrieved. + """ + try: + session = requests.Session() + aai_model_ver_endpoint = \ + f'{_get_aai_service_url()}/service-design-and-creation/models/model/' \ + f'{model_invariant_id}/model-vers/model-ver/{model_version_id}' + + logger.info(f'Fetching sdnc-model info for xNF: {nf_name} from AAI.') + headers = _get_aai_request_headers() + response = session.get(aai_model_ver_endpoint, headers=headers, + auth=HTTPBasicAuth(app_conf.aaf_creds.get('aaf_id'), + app_conf.aaf_creds.get('aaf_pass')), + verify=(app_conf.ca_cert_path if app_conf.enable_tls else False), + cert=(app_conf.cert_params if app_conf.enable_tls else None)) + response.raise_for_status() + if response.ok: + data = json.loads(response.text) + logger.debug(f'Successfully fetched sdnc-model info from AAI: {data}') + return data + except Exception: + raise diff --git a/components/pm-subscription-handler/pmsh_service/mod/aai_event_handler.py b/components/pm-subscription-handler/pmsh_service/mod/aai_event_handler.py index 92369322..61b42b52 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/aai_event_handler.py +++ b/components/pm-subscription-handler/pmsh_service/mod/aai_event_handler.py @@ -58,28 +58,26 @@ def process_aai_events(mr_sub, mr_pub, app, app_conf): entity_type = entry['event-header']['entity-type'] xnf_name = aai_entity['pnf-name'] if entity_type == XNFType.PNF.value \ else aai_entity['vnf-name'] - new_status = aai_entity['orchestration-status'] - model_invariant_id = aai_entity['model-invariant-id'] - model_version_id = aai_entity['model-version-id'] - - if app_conf.nf_filter.is_nf_in_filter(xnf_name, model_invariant_id, model_version_id, new_status): - _process_event(action, new_status, xnf_name, mr_pub, app_conf) + if aai_entity['orchestration-status'] != 'Active': + logger.info(f'Skipping XNF {xnf_name} as its orchestration-status ' + f'is not "Active"') + continue + nf = NetworkFunction(nf_name=xnf_name, + model_invariant_id=aai_entity['model-invariant-id'], + model_version_id=aai_entity['model-version-id']) + if not nf.set_sdnc_params(app_conf): + continue + if app_conf.nf_filter.is_nf_in_filter(nf): + _process_event(action, nf, mr_pub, app_conf) except Exception as e: logger.error(f'Failed to process AAI event: {e}', exc_info=True) -def _process_event(action, new_status, xnf_name, mr_pub, app_conf): +def _process_event(action, nf, mr_pub, app_conf): if action == AAIEvent.UPDATE.value: - logger.info(f'Update event found for network function {xnf_name}') - local_xnf = NetworkFunction.get(xnf_name) - - if local_xnf is None: - app_conf.subscription.activate_subscription([NetworkFunction( - nf_name=xnf_name, orchestration_status=new_status)], mr_pub, app_conf) - else: - logger.debug(f"Update Event for network function {xnf_name} will not be processed " - f" as it's state is set to {local_xnf.orchestration_status}.") + logger.info(f'Update event found for network function {nf.nf_name}') + app_conf.subscription.activate_subscription([nf], mr_pub, app_conf) elif action == AAIEvent.DELETE.value: - logger.info(f'Delete event found for network function {xnf_name}') - NetworkFunction.delete(nf_name=xnf_name) - logger.info(f'{xnf_name} successfully deleted.') + logger.info(f'Delete event found for network function {nf.nf_name}') + NetworkFunction.delete(nf_name=nf.nf_name) + logger.info(f'{nf.nf_name} successfully deleted.') diff --git a/components/pm-subscription-handler/pmsh_service/mod/api/db_models.py b/components/pm-subscription-handler/pmsh_service/mod/api/db_models.py index 1d6f72b3..ff172d1c 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/api/db_models.py +++ b/components/pm-subscription-handler/pmsh_service/mod/api/db_models.py @@ -56,19 +56,34 @@ class NetworkFunctionModel(db.Model): __tablename__ = 'network_functions' id = Column(Integer, primary_key=True, autoincrement=True) nf_name = Column(String(100), unique=True) - orchestration_status = Column(String(100)) + model_invariant_id = Column(String(100)) + model_version_id = Column(String(100)) + sdnc_model_name = Column(String(100)) + sdnc_model_version = Column(String(100)) subscriptions = relationship( 'NfSubRelationalModel', cascade='all, delete-orphan', backref='nf') - def __init__(self, nf_name, orchestration_status): + def __init__(self, nf_name, model_invariant_id, model_version_id, sdnc_model_name=None, + sdnc_model_version=None): self.nf_name = nf_name - self.orchestration_status = orchestration_status + self.model_invariant_id = model_invariant_id + self.model_version_id = model_version_id + self.sdnc_model_name = sdnc_model_name + self.sdnc_model_version = sdnc_model_version def __repr__(self): - return f'nf_name: {self.nf_name}, orchestration_status: {self.orchestration_status}' + return str(self.to_nf()) + + def to_nf(self): + from mod.network_function import NetworkFunction + return NetworkFunction(**{'nf_name': self.nf_name, + 'model_invariant_id': self.model_invariant_id, + 'model_version_id': self.model_version_id, + 'sdnc_model_name': self.sdnc_model_name, + 'sdnc_model_version': self.sdnc_model_version}) class NfSubRelationalModel(db.Model): @@ -101,7 +116,11 @@ class NfSubRelationalModel(db.Model): '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} + nf = NetworkFunctionModel.query.filter( + NetworkFunctionModel.nf_name == self.nf_name).one_or_none() + return {'nf_name': self.nf_name, + 'nf_sub_status': self.nf_sub_status, + 'model_invariant_id': nf.model_invariant_id, + 'model_version_id': nf.model_version_id, + 'sdnc_model_name': nf.sdnc_model_name, + 'sdnc_model_version': nf.sdnc_model_version} 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 62cd546f..fd940385 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/network_function.py +++ b/components/pm-subscription-handler/pmsh_service/mod/network_function.py @@ -18,6 +18,7 @@ import re +import mod.aai_client from mod import logger, db from mod.api.db_models import NetworkFunctionModel @@ -26,21 +27,34 @@ class NetworkFunction: def __init__(self, **kwargs): """ Object representation of the NetworkFunction. """ self.nf_name = kwargs.get('nf_name') - self.orchestration_status = kwargs.get('orchestration_status') + self.model_invariant_id = kwargs.get('model_invariant_id') + self.model_version_id = kwargs.get('model_version_id') + self.sdnc_model_name = None + self.sdnc_model_version = None @classmethod def nf_def(cls): - return cls(nf_name=None, orchestration_status=None) + return cls(nf_name=None, model_invariant_id=None, model_version_id=None, + sdnc_model_name=None, sdnc_model_version=None) def __str__(self): - return f'nf-name: {self.nf_name}, orchestration-status: {self.orchestration_status}' + return f'nf-name: {self.nf_name}, ' \ + f'model-invariant-id: {self.model_invariant_id}, ' \ + f'model-version-id: {self.model_version_id}, ' \ + f'sdnc-model-name: {self.sdnc_model_name}, ' \ + f'sdnc-model-version: {self.sdnc_model_version}' def __eq__(self, other): - return self.nf_name == other.nf_name and \ - self.orchestration_status == other.orchestration_status + return \ + self.nf_name == other.nf_name and \ + self.model_invariant_id == other.model_invariant_id and \ + self.model_version_id == other.model_version_id and \ + self.sdnc_model_name == other.sdnc_model_name and \ + self.sdnc_model_version == other.sdnc_model_version def __hash__(self): - return hash((self.nf_name, self.orchestration_status)) + return hash((self.nf_name, self.model_invariant_id, + self.model_version_id, self.sdnc_model_name, self.sdnc_model_version)) def create(self): """ Creates a NetworkFunction database entry """ @@ -49,7 +63,10 @@ class NetworkFunction: if existing_nf is None: new_nf = NetworkFunctionModel(nf_name=self.nf_name, - orchestration_status=self.orchestration_status) + model_invariant_id=self.model_invariant_id, + model_version_id=self.model_version_id, + sdnc_model_name=self.sdnc_model_name, + sdnc_model_version=self.sdnc_model_version) db.session.add(new_nf) db.session.commit() logger.info(f'Network Function {new_nf.nf_name} successfully created.') @@ -59,6 +76,23 @@ class NetworkFunction: f' returning this network function..') return existing_nf + def set_sdnc_params(self, app_conf): + params_set = True + try: + sdnc_model_data = mod.aai_client.get_aai_model_data(app_conf, self.model_invariant_id, + self.model_version_id, self.nf_name) + try: + self.sdnc_model_name = sdnc_model_data['sdnc-model-name'] + self.sdnc_model_version = sdnc_model_data['sdnc-model-version'] + return params_set + except KeyError as e: + logger.info(f'Skipping NF {self.nf_name} as there is no ' + f'sdnc-model data associated in AAI: {e}', exc_info=True) + return not params_set + except Exception as e: + logger.error(f'Failed to get sdnc-model info for XNFs from AAI: {e}', exc_info=True) + return not params_set + @staticmethod def get(nf_name): """ Retrieves a network function @@ -90,33 +124,27 @@ class NetworkFunction: db.session.commit() - class NetworkFunctionFilter: def __init__(self, **kwargs): self.nf_names = kwargs.get('nfNames') - self.model_invariant_ids = kwargs.get('modelInvariantUUIDs') + self.model_invariant_ids = kwargs.get('modelInvariantIDs') self.model_version_ids = kwargs.get('modelVersionIDs') self.regex_matcher = re.compile('|'.join(raw_regex for raw_regex in self.nf_names)) - def is_nf_in_filter(self, nf_name, model_invariant_id, model_version_id, orchestration_status): - """Match the nf name against regex values in Subscription.nfFilter.nfNames + def is_nf_in_filter(self, nf): + """Match the nf fields against values in Subscription.nfFilter Args: - nf_name (str): the AAI nf name. - invariant_uuid (str): the AAI model-invariant-id - uuid (str): the AAI model-version-id - orchestration_status (str): orchestration status of the nf + nf (NetworkFunction): The NF to be filtered. Returns: bool: True if matched, else False. """ match = True - if orchestration_status != 'Active': - match = False - if self.nf_names and self.regex_matcher.search(nf_name) is None: + if self.nf_names and self.regex_matcher.search(nf.nf_name) is None: match = False - if self.model_invariant_ids and not model_invariant_id in self.model_invariant_ids: + if self.model_invariant_ids and nf.model_invariant_id not in self.model_invariant_ids: match = False - if self.model_version_ids and not model_version_id in self.model_version_ids: + if self.model_version_ids and nf.model_version_id not in self.model_version_ids: match = False return match diff --git a/components/pm-subscription-handler/pmsh_service/mod/pmsh_utils.py b/components/pm-subscription-handler/pmsh_service/mod/pmsh_utils.py index fd24fca9..24eade98 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/pmsh_utils.py +++ b/components/pm-subscription-handler/pmsh_service/mod/pmsh_utils.py @@ -25,8 +25,8 @@ from onaplogging.mdcContext import MDC from requests.auth import HTTPBasicAuth from tenacity import wait_fixed, stop_after_attempt, retry, retry_if_exception_type +import mod.network_function from mod import logger -from mod.network_function import NetworkFunctionFilter from mod.subscription import Subscription @@ -77,7 +77,7 @@ class AppConfig: self.operational_policy_name = conf['config'].get('operational_policy_name') self.control_loop_name = conf['config'].get('control_loop_name') self.subscription = Subscription(**conf['policy']['subscription']) - self.nf_filter = NetworkFunctionFilter(**self.subscription.nfFilter) + self.nf_filter = mod.network_function.NetworkFunctionFilter(**self.subscription.nfFilter) def __new__(cls, *args, **kwargs): if AppConfig.INSTANCE is None: @@ -223,17 +223,17 @@ class _MrPub(_DmaapMrClient): except Exception as e: raise e - def publish_subscription_event_data(self, subscription, xnf_name, app_conf): + def publish_subscription_event_data(self, subscription, nf, app_conf): """ Update the Subscription dict with xnf and policy name then publish to DMaaP MR topic. Args: subscription (Subscription): the `Subscription` object. - xnf_name (str): the xnf to include in the event. + nf (NetworkFunction): the NetworkFunction to include in the event. app_conf (AppConfig): the application configuration. """ try: - subscription_event = subscription.prepare_subscription_event(xnf_name, app_conf) + subscription_event = subscription.prepare_subscription_event(nf, app_conf) self.publish_to_topic(subscription_event) except Exception as e: logger.error(f'Failed to publish to topic {self.topic_url}: {e}', exc_info=True) diff --git a/components/pm-subscription-handler/pmsh_service/mod/subscription.py b/components/pm-subscription-handler/pmsh_service/mod/subscription.py index 97bfc401..21e2399d 100755 --- a/components/pm-subscription-handler/pmsh_service/mod/subscription.py +++ b/components/pm-subscription-handler/pmsh_service/mod/subscription.py @@ -19,7 +19,6 @@ from enum import Enum from mod import db, logger from mod.api.db_models import SubscriptionModel, NfSubRelationalModel, NetworkFunctionModel -from mod.network_function import NetworkFunction class SubNfState(Enum): @@ -94,30 +93,11 @@ class Subscription: logger.error(f'Failed to update status of subscription: {self.subscriptionName}: {e}', exc_info=True) - 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.""" - 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.error(f'Failed to delete subscription: {self.subscriptionName} ' - f'and it\'s relations from the DB: {e}', exc_info=True) - - def prepare_subscription_event(self, xnf_name, app_conf): + def prepare_subscription_event(self, nf, app_conf): """Prepare the sub event for publishing Args: - xnf_name: the AAI xnf name. + nf (NetworkFunction): the AAI nf. app_conf (AppConfig): the application configuration. Returns: @@ -125,14 +105,16 @@ class Subscription: """ try: clean_sub = {k: v for k, v in self.__dict__.items() if k != 'nfFilter'} - sub_event = {'nfName': xnf_name, 'policyName': app_conf.operational_policy_name, + sub_event = {'nfName': nf.nf_name, 'blueprintName': nf.sdnc_model_name, + 'blueprintVersion': nf.sdnc_model_version, + 'policyName': app_conf.operational_policy_name, 'changeType': 'DELETE' if self.administrativeState == AdministrativeState.LOCKED.value else 'CREATE', 'closedLoopControlName': app_conf.control_loop_name, 'subscription': clean_sub} return sub_event except Exception as e: - logger.error(f'Failed to prep Sub event for xNF {xnf_name}: {e}', exc_info=True) + logger.error(f'Failed to prep Sub event for xNF {nf.nf_name}: {e}', exc_info=True) raise def add_network_function_to_subscription(self, nf, sub_model): @@ -159,7 +141,7 @@ class Subscription: logger.error(f'Failed to add nf {nf.nf_name} to subscription ' f'{self.subscriptionName}: {e}', exc_info=True) logger.debug(f'Subscription {self.subscriptionName} now contains these XNFs:' - f'{Subscription.get_nf_names_per_sub(self.subscriptionName)}') + f'{[nf.nf_name for nf.nf_name in self.get_network_functions()]}') def get(self): """ Retrieves a SubscriptionModel object @@ -189,32 +171,15 @@ class Subscription: """ return SubscriptionModel.query.all() - @staticmethod - def get_nf_names_per_sub(subscription_name): - """ Retrieves a list of network function names related to the subscription - - Args: - subscription_name (str): The subscription name - - Returns: - list(str): List of network function names - """ - nf_sub_rel = NfSubRelationalModel.query.filter( - NfSubRelationalModel.subscription_name == subscription_name).all() - list_of_nfs = [] - for nf in nf_sub_rel: - list_of_nfs.append(nf.nf_name) - - return list_of_nfs - def activate_subscription(self, nfs, mr_pub, app_conf): logger.info(f'Activate subscription initiated for {self.subscriptionName}.') try: + existing_nfs = self.get_network_functions() sub_model = self.get() - for nf in nfs: - mr_pub.publish_subscription_event_data(self, nf.nf_name, app_conf) + for nf in set(nfs + existing_nfs): logger.info(f'Publishing event to activate ' f'Sub: {self.subscriptionName} for the nf: {nf.nf_name}') + mr_pub.publish_subscription_event_data(self, nf, app_conf) self.add_network_function_to_subscription(nf, sub_model) self.update_sub_nf_status(self.subscriptionName, SubNfState.PENDING_CREATE.value, nf.nf_name) @@ -222,12 +187,12 @@ class Subscription: raise Exception(f'Error publishing activation event to MR: {err}') def deactivate_subscription(self, mr_pub, app_conf): - nfs = self.get_network_functions() try: + nfs = self.get_network_functions() if nfs: logger.info(f'Deactivate subscription initiated for {self.subscriptionName}.') for nf in nfs: - mr_pub.publish_subscription_event_data(self, nf.nf_name, app_conf) + mr_pub.publish_subscription_event_data(self, nf, app_conf) logger.debug(f'Publishing Event to deactivate ' f'Sub: {self.subscriptionName} for the nf: {nf.nf_name}') self.update_sub_nf_status(self.subscriptionName, @@ -265,25 +230,13 @@ class Subscription: logger.error(f'Failed to update status of nf: {nf_name} for subscription: ' f'{subscription_name}: {e}', exc_info=True) - def _get_nf_models(self): + def get_network_functions(self): nf_sub_relationships = NfSubRelationalModel.query.filter( NfSubRelationalModel.subscription_name == self.subscriptionName) - nf_models = [] + nfs = [] for nf_sub_entry in nf_sub_relationships: nf_model_object = NetworkFunctionModel.query.filter( NetworkFunctionModel.nf_name == nf_sub_entry.nf_name).one_or_none() - nf_models.append(nf_model_object) - - return nf_models - - def get_network_functions(self): - nfs = [] - nf_models = self._get_nf_models() - for nf_model in nf_models: - nf = NetworkFunction( - nf_name=nf_model.nf_name, - orchestration_status=nf_model.orchestration_status - ) - nfs.append(nf) + nfs.append(nf_model_object.to_nf()) return nfs diff --git a/components/pm-subscription-handler/pmsh_service/mod/subscription_handler.py b/components/pm-subscription-handler/pmsh_service/mod/subscription_handler.py index e74a1732..6de702f2 100644 --- a/components/pm-subscription-handler/pmsh_service/mod/subscription_handler.py +++ b/components/pm-subscription-handler/pmsh_service/mod/subscription_handler.py @@ -54,8 +54,8 @@ class SubscriptionHandler: def _activate(self, local_admin_state, new_administrative_state): logger.info(f'Administrative State has changed from {local_admin_state} ' f'to {new_administrative_state}.') - existing_nfs_in_aai = aai.get_pmsh_nfs_from_aai(self.app_conf) - self.app_conf.subscription.activate_subscription(existing_nfs_in_aai, self.mr_pub, + nfs_in_aai = aai.get_pmsh_nfs_from_aai(self.app_conf) + self.app_conf.subscription.activate_subscription(nfs_in_aai, self.mr_pub, self.app_conf) self.app_conf.subscription.update_subscription_status() logger.info('Start listening for new NFs on AAI-EVENT topic in MR.') diff --git a/components/pm-subscription-handler/tests/base_setup.py b/components/pm-subscription-handler/tests/base_setup.py new file mode 100755 index 00000000..2e50dde9 --- /dev/null +++ b/components/pm-subscription-handler/tests/base_setup.py @@ -0,0 +1,57 @@ +# ============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===================================================== +import json +import os +from unittest import TestCase +from unittest.mock import patch, MagicMock + +from mod import create_app, db +from mod.pmsh_utils import AppConfig + + +def get_pmsh_config(): + with open(os.path.join(os.path.dirname(__file__), 'data/cbs_data_1.json'), 'r') as data: + return json.load(data) + + +class BaseClassSetup(TestCase): + app = None + app_context = None + + @classmethod + @patch('mod.get_db_connection_url', MagicMock(return_value='sqlite://')) + @patch('mod.update_logging_config', MagicMock()) + def setUpClass(cls): + os.environ['LOGGER_CONFIG'] = os.path.join(os.path.dirname(__file__), 'log_config.yaml') + os.environ['LOGS_PATH'] = '.' + cls.app = create_app() + cls.app_context = cls.app.app_context() + cls.app_context.push() + + @patch('mod.pmsh_utils.AppConfig._get_pmsh_config', MagicMock(return_value=get_pmsh_config())) + def setUp(self): + os.environ['AAI_SERVICE_PORT'] = '8443' + db.create_all() + self.app_conf = AppConfig() + + def tearDown(self): + db.drop_all() + + @classmethod + def tearDownClass(cls): + db.session.remove() diff --git a/components/pm-subscription-handler/tests/data/aai_model_info.json b/components/pm-subscription-handler/tests/data/aai_model_info.json new file mode 100644 index 00000000..625de52a --- /dev/null +++ b/components/pm-subscription-handler/tests/data/aai_model_info.json @@ -0,0 +1,36 @@ +{ + "model-version-id": "6d25b637-8bca-47e2-af1a-61258424183d", + "model-name": "PNF102", + "model-version": "1.0", + "model-description": "sartgserg", + "sdnc-model-name": "pm_control", + "sdnc-model-version": "1.0.0", + "resource-version": "1598626661947", + "relationship-list": { + "relationship": [ + { + "related-to": "model-element", + "relationship-label": "org.onap.relationships.inventory.IsA", + "related-link": "/aai/v20/service-design-and-creation/models/model/c1a44771-3aa8-4888-a4f4-be89d1caa0cb/model-vers/model-ver/7256a992-10a7-4ac8-8c2c-63c67e5c48c8/model-elements/model-element/fddc70fe-8343-48c1-af2e-b54f551a32ee/model-elements/model-element/7bff45b7-8254-44e5-b7ad-6e10dee6dfc3", + "relationship-data": [ + { + "relationship-key": "model.model-invariant-id", + "relationship-value": "c1a44771-3aa8-4888-a4f4-be89d1caa0cb" + }, + { + "relationship-key": "model-ver.model-version-id", + "relationship-value": "7256a992-10a7-4ac8-8c2c-63c67e5c48c8" + }, + { + "relationship-key": "model-element.model-element-uuid", + "relationship-value": "fddc70fe-8343-48c1-af2e-b54f551a32ee" + }, + { + "relationship-key": "model-element.model-element-uuid", + "relationship-value": "7bff45b7-8254-44e5-b7ad-6e10dee6dfc3" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/components/pm-subscription-handler/tests/data/aai_model_info_no_sdnc.json b/components/pm-subscription-handler/tests/data/aai_model_info_no_sdnc.json new file mode 100644 index 00000000..fffdfa92 --- /dev/null +++ b/components/pm-subscription-handler/tests/data/aai_model_info_no_sdnc.json @@ -0,0 +1,34 @@ +{ + "model-version-id": "b7469cc5-be51-41cc-b37f-361537656771", + "model-name": "PNF104", + "model-version": "1.0", + "model-description": "aervaer", + "resource-version": "1599053901976", + "relationship-list": { + "relationship": [ + { + "related-to": "model-element", + "relationship-label": "org.onap.relationships.inventory.IsA", + "related-link": "/aai/v20/service-design-and-creation/models/model/9f751399-59f7-46e4-aaf4-f78b7bf8af84/model-vers/model-ver/135b8bab-b24c-4c6d-b042-dcd7fcd937ba/model-elements/model-element/3c323039-c6ab-47bb-b8e0-d1e57a78fbea/model-elements/model-element/8a424916-020f-4c83-b785-7c04ac06567a", + "relationship-data": [ + { + "relationship-key": "model.model-invariant-id", + "relationship-value": "9f751399-59f7-46e4-aaf4-f78b7bf8af84" + }, + { + "relationship-key": "model-ver.model-version-id", + "relationship-value": "135b8bab-b24c-4c6d-b042-dcd7fcd937ba" + }, + { + "relationship-key": "model-element.model-element-uuid", + "relationship-value": "3c323039-c6ab-47bb-b8e0-d1e57a78fbea" + }, + { + "relationship-key": "model-element.model-element-uuid", + "relationship-value": "8a424916-020f-4c83-b785-7c04ac06567a" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/components/pm-subscription-handler/tests/data/cbs_data_1.json b/components/pm-subscription-handler/tests/data/cbs_data_1.json index 5c2e0296..86515343 100644 --- a/components/pm-subscription-handler/tests/data/cbs_data_1.json +++ b/components/pm-subscription-handler/tests/data/cbs_data_1.json @@ -10,7 +10,7 @@ "^pnf.*", "^vnf.*" ], - "modelInvariantUUIDs": [ + "modelInvariantIDs": [ ], "modelVersionIDs": [ diff --git a/components/pm-subscription-handler/tests/data/filter_test_data.json b/components/pm-subscription-handler/tests/data/filter_test_data.json index 28dc61d1..0d8fc7c8 100644 --- a/components/pm-subscription-handler/tests/data/filter_test_data.json +++ b/components/pm-subscription-handler/tests/data/filter_test_data.json @@ -6,7 +6,7 @@ "^pnf.*", "^vnf.*" ], - "modelInvariantUUIDs": [ + "modelInvariantIDs": [ ], "modelVersionIDs": [ @@ -16,7 +16,6 @@ "nfName": "pnf1", "modelInvariantUUID": "7129e420-d396-4efb-af02-6b83499b12f8", "modelVersionID": "e80a6ae3-cafd-4d24-850d-e14c084a5ca9", - "orchestration_status": "Active", "expectedResult": true }, { @@ -26,7 +25,7 @@ "^pnf.*", "^vnf.*" ], - "modelInvariantUUIDs": [ + "modelInvariantIDs": [ ], "modelVersionIDs": [ @@ -36,15 +35,14 @@ "nfName": "PNF-33", "modelInvariantUUID": "7129e420-d396-4efb-af02-6b83499b12f8", "modelVersionID": "e80a6ae3-cafd-4d24-850d-e14c084a5ca9", - "orchestration_status": "Active", "expectedResult": false }, { - "testName": "test_filter_true_on_modelInvariantUUIDs", + "testName": "test_filter_true_on_modelInvariantIDs", "nfFilter":{ "nfNames":[ ], - "modelInvariantUUIDs": [ + "modelInvariantIDs": [ "5845y423-g654-6fju-po78-8n53154532k6", "7129e420-d396-4efb-af02-6b83499b12f8" ], @@ -55,15 +53,14 @@ "nfName": "pnf1", "modelInvariantUUID": "7129e420-d396-4efb-af02-6b83499b12f8", "modelVersionID": "e80a6ae3-cafd-4d24-850d-e14c084a5ca9", - "orchestration_status": "Active", "expectedResult": true }, { - "testName": "test_filter_false_on_modelInvariantUUIDs", + "testName": "test_filter_false_on_modelInvariantIDs", "nfFilter":{ "nfNames":[ ], - "modelInvariantUUIDs": [ + "modelInvariantIDs": [ "5845y423-g654-6fju-po78-8n53154532k6", "7129e420-d396-4efb-af02-6b83499b12f8" ], @@ -74,17 +71,16 @@ "nfName": "pnf1", "modelInvariantUUID": "WrongModelInvariantUUID", "modelVersionID": "e80a6ae3-cafd-4d24-850d-e14c084a5ca9", - "orchestration_status": "Active", "expectedResult": false }, { - "testName": "test_filter_false_on_modelInvariantUUIDs_being_false_and_pnfname_being_true", + "testName": "test_filter_false_on_modelInvariantIDs_being_false_and_pnfname_being_true", "nfFilter":{ "nfNames":[ "^pnf.*", "^vnf.*" ], - "modelInvariantUUIDs": [ + "modelInvariantIDs": [ "7129e420-d396-4efb-af02-6b83499b12f8" ], "modelVersionIDs": [ @@ -94,7 +90,6 @@ "nfName": "pnf1", "modelInvariantUUID": "WrongModelInvariantUUID", "modelVersionID": "e80a6ae3-cafd-4d24-850d-e14c084a5ca9", - "orchestration_status": "Active", "expectedResult": false }, { @@ -102,7 +97,7 @@ "nfFilter":{ "nfNames":[ ], - "modelInvariantUUIDs": [ + "modelInvariantIDs": [ ], "modelVersionIDs": [ "e80a6ae3-cafd-4d24-850d-e14c084a5ca9" @@ -111,7 +106,6 @@ "nfName": "pnf1", "modelInvariantUUID": "7129e420-d396-4efb-af02-6b83499b12f8", "modelVersionID": "e80a6ae3-cafd-4d24-850d-e14c084a5ca9", - "orchestration_status": "Active", "expectedResult": true }, { @@ -119,7 +113,7 @@ "nfFilter":{ "nfNames":[ ], - "modelInvariantUUIDs": [ + "modelInvariantIDs": [ ], "modelVersionIDs": [ "e80a6ae3-cafd-4d24-850d-e14c084a5ca9" @@ -128,7 +122,6 @@ "nfName": "pnf1", "modelInvariantUUID": "7129e420-d396-4efb-af02-6b83499b12f8", "modelVersionID": "WrongModelVersionID", - "orchestration_status": "Active", "expectedResult": false }, { @@ -138,7 +131,7 @@ "^pnf.*", "^vnf.*" ], - "modelInvariantUUIDs": [ + "modelInvariantIDs": [ ], "modelVersionIDs": [ "e80a6ae3-cafd-4d24-850d-e14c084a5ca9" @@ -147,25 +140,6 @@ "nfName": "pnf1", "modelInvariantUUID": "7129e420-d396-4efb-af02-6b83499b12f8", "modelVersionID": "WrongModelVersionID", - "orchestration_status": "Active", - "expectedResult": false - }, - { - "testName": "test_filter_false_on_OrchestrationStatus", - "nfFilter":{ - "nfNames":[ - "^pnf.*", - "^vnf.*" - ], - "modelInvariantUUIDs": [ - ], - "modelVersionIDs": [ - ] - }, - "nfName": "pnf1", - "modelInvariantUUID": "7129e420-d396-4efb-af02-6b83499b12f8", - "modelVersionID": "e80a6ae3-cafd-4d24-850d-e14c084a5ca9", - "orchestration_status": "Inventoried", "expectedResult": false } - ] \ No newline at end of file +] diff --git a/components/pm-subscription-handler/tests/data/pm_subscription_event.json b/components/pm-subscription-handler/tests/data/pm_subscription_event.json index e190aa26..9416ec28 100755 --- a/components/pm-subscription-handler/tests/data/pm_subscription_event.json +++ b/components/pm-subscription-handler/tests/data/pm_subscription_event.json @@ -1,5 +1,7 @@ { "nfName":"pnf_1", + "blueprintName": "some-name", + "blueprintVersion": "some-version", "policyName":"pmsh-operational-policy", "changeType":"CREATE", "closedLoopControlName":"pmsh-control-loop", diff --git a/components/pm-subscription-handler/tests/log_config.yaml b/components/pm-subscription-handler/tests/log_config.yaml index 1c3abd8b..f3f39772 100755 --- a/components/pm-subscription-handler/tests/log_config.yaml +++ b/components/pm-subscription-handler/tests/log_config.yaml @@ -5,9 +5,16 @@ disable_existing_loggers: true loggers: onap_logger: level: DEBUG - handlers: [stdout_handler] + handlers: [onap_log_handler, stdout_handler] propagate: false handlers: + onap_log_handler: + class: logging.handlers.RotatingFileHandler + filename: ./application.log + mode: a + maxBytes: 10000000 + backupCount: 10 + formatter: mdcFormatter stdout_handler: class: logging.StreamHandler formatter: mdcFormatter diff --git a/components/pm-subscription-handler/tests/test_aai_event_handler.py b/components/pm-subscription-handler/tests/test_aai_event_handler.py index 9ac76477..dc5243d7 100755 --- a/components/pm-subscription-handler/tests/test_aai_event_handler.py +++ b/components/pm-subscription-handler/tests/test_aai_event_handler.py @@ -16,59 +16,40 @@ # SPDX-License-Identifier: Apache-2.0 # ============LICENSE_END===================================================== import json -import os from os import path -from test.support import EnvironmentVarGuard -from unittest import TestCase from unittest.mock import patch, Mock -from mod import create_app, db from mod.aai_event_handler import process_aai_events -from mod.network_function import NetworkFunction -from mod.pmsh_utils import AppConfig +from tests.base_setup import BaseClassSetup -class AAIEventHandlerTest(TestCase): +class AAIEventHandlerTest(BaseClassSetup): - @patch('mod.get_db_connection_url') - @patch('mod.update_logging_config') - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') - def setUp(self, mock_get_pmsh_config, mock_update_config, mock_get_db_url): - mock_get_db_url.return_value = 'sqlite://' - with open(path.join(path.dirname(__file__), 'data/cbs_data_1.json'), 'r') as data: - self.cbs_data = json.load(data) - mock_get_pmsh_config.return_value = self.cbs_data - self.app_conf = AppConfig() + @classmethod + def setUpClass(cls): + super().setUpClass() + + def setUp(self): + super().setUp() with open(path.join(path.dirname(__file__), 'data/mr_aai_events.json'), 'r') as data: self.mr_aai_events = json.load(data)["mr_response"] - self.env = EnvironmentVarGuard() - self.env.set('LOGGER_CONFIG', os.path.join(os.path.dirname(__file__), 'log_config.yaml')) self.mock_mr_sub = Mock(get_from_topic=Mock(return_value=self.mr_aai_events)) self.mock_mr_pub = Mock() self.mock_app = Mock() - 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() + super().tearDown() + + @classmethod + def tearDownClass(cls): + super().tearDownClass() + @patch('mod.network_function.NetworkFunction.set_sdnc_params') @patch('mod.subscription.Subscription.activate_subscription') @patch('mod.aai_event_handler.NetworkFunction.delete') - @patch('mod.aai_event_handler.NetworkFunction.get') - def test_process_aai_update_and_delete_events(self, mock_nf_get, mock_nf_delete, - mock_activate_sub): - pnf_already_active = NetworkFunction(nf_name='pnf_already_active', - orchestration_status='Active') - mock_nf_get.side_effect = [None, pnf_already_active] - expected_nf_for_processing = NetworkFunction( - nf_name='pnf_newly_discovered', orchestration_status='Active') - + def test_process_aai_update_and_delete_events(self, mock_nf_delete, mock_activate_sub, + mock_set_sdnc_params): + mock_set_sdnc_params.return_value = True process_aai_events(self.mock_mr_sub, self.mock_mr_pub, self.mock_app, self.app_conf) - - mock_activate_sub.assert_called_once_with([expected_nf_for_processing], - self.mock_mr_pub, self.app_conf) - mock_nf_delete.assert_called_once_with(nf_name='pnf_to_be_deleted') + self.assertEqual(mock_activate_sub.call_count, 2) + mock_nf_delete.assert_called_once() diff --git a/components/pm-subscription-handler/tests/test_aai_service.py b/components/pm-subscription-handler/tests/test_aai_service.py index 4b7be153..7a3b846d 100644 --- a/components/pm-subscription-handler/tests/test_aai_service.py +++ b/components/pm-subscription-handler/tests/test_aai_service.py @@ -17,40 +17,46 @@ # ============LICENSE_END===================================================== import json import os -from test.support import EnvironmentVarGuard -from unittest import mock, TestCase +from unittest import mock from unittest.mock import patch import responses -from requests import Session +from requests import Session, HTTPError import mod.aai_client as aai_client -from mod import create_app -from mod.pmsh_utils import AppConfig - - -class AaiClientTestCase(TestCase): - - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') - @patch('mod.update_logging_config') - @patch('mod.get_db_connection_url') - def setUp(self, mock_get_db_url, mock_update_config, mock_get_pmsh_config): - mock_get_db_url.return_value = 'sqlite://' - self.env = EnvironmentVarGuard() - self.env.set('AAI_SERVICE_PORT', '8443') - self.env.set('LOGGER_CONFIG', os.path.join(os.path.dirname(__file__), 'log_config.yaml')) - with open(os.path.join(os.path.dirname(__file__), 'data/cbs_data_1.json'), 'r') as data: - self.cbs_data = json.load(data) - mock_get_pmsh_config.return_value = self.cbs_data - self.app_conf = AppConfig() +from tests.base_setup import BaseClassSetup + + +class AaiClientTestCase(BaseClassSetup): + + @classmethod + def setUpClass(cls): + super().setUpClass() + + def setUp(self): + super().setUp() with open(os.path.join(os.path.dirname(__file__), 'data/aai_xnfs.json'), 'r') as data: self.aai_response_data = data.read() - self.app = create_app() + with open(os.path.join(os.path.dirname(__file__), 'data/aai_model_info.json'), 'r') as data: + self.good_model_info = data.read() + + def tearDown(self): + super().tearDown() + @classmethod + def tearDownClass(cls): + super().tearDownClass() + + @patch('mod.network_function.NetworkFunction.set_sdnc_params') + @patch.object(Session, 'get') @patch.object(Session, 'put') - def test_aai_client_get_pm_sub_data_success(self, mock_session): - mock_session.return_value.status_code = 200 - mock_session.return_value.text = self.aai_response_data + def test_aai_client_get_pm_sub_data_success(self, mock_put_session, mock_get_session, + mock_get_sdnc_params): + mock_put_session.return_value.status_code = 200 + mock_put_session.return_value.text = self.aai_response_data + mock_get_session.return_value.status_code = 200 + mock_get_session.return_value.text = self.good_model_info + mock_get_sdnc_params.return_value = True xnfs = aai_client.get_pmsh_nfs_from_aai(self.app_conf) self.assertEqual(self.app_conf.subscription.subscriptionName, 'ExtraPM-All-gNB-R2B') self.assertEqual(self.app_conf.subscription.administrativeState, 'UNLOCKED') @@ -61,26 +67,48 @@ class AaiClientTestCase(TestCase): mock_session.return_value.status_code = 404 with mock.patch('mod.aai_client._get_all_aai_nf_data', return_value=None): with self.assertRaises(RuntimeError): - aai_client.get_pmsh_nfs_from_aai(self.cbs_data) + aai_client.get_pmsh_nfs_from_aai(self.app_conf) @responses.activate def test_aai_client_get_all_aai_xnf_data_not_found(self): responses.add(responses.PUT, - 'https://1.2.3.4:8443/aai/v19/query?format=simple&nodesOnly=true', + 'https://1.2.3.4:8443/aai/v20/query?format=simple&nodesOnly=true', json={'error': 'not found'}, status=404) self.assertIsNone(aai_client._get_all_aai_nf_data(self.app_conf)) @responses.activate def test_aai_client_get_all_aai_xnf_data_success(self): responses.add(responses.PUT, - 'https://aai:8443/aai/v19/query?format=simple&nodesOnly=true', + 'https://aai:8443/aai/v20/query?format=simple&nodesOnly=true', json={'dummy_data': 'blah_blah'}, status=200) self.assertIsNotNone(aai_client._get_all_aai_nf_data(self.app_conf)) + @responses.activate + def test_aai_client_get_sdnc_params_success(self): + responses.add(responses.GET, + 'https://aai:8443/aai/v20/service-design-and-creation/models/model/' + '6fb9f466-7a79-4109-a2a3-72b340aca53d/model-vers/model-ver/' + '6d25b637-8bca-47e2-af1a-61258424183d', + json=json.loads(self.good_model_info), status=200) + self.assertIsNotNone(aai_client.get_aai_model_data(self.app_conf, + '6fb9f466-7a79-4109-a2a3-72b340aca53d', + '6d25b637-8bca-47e2-af1a-61258424183d', + 'pnf_1')) + + @responses.activate + def test_aai_client_get_sdnc_params_fail(self): + responses.add(responses.GET, + 'https://aai:8443/aai/v20/service-design-and-creation/models/model/' + '9fb9f466-7a79-4109-a2a3-72b340aca53d/model-vers/model-ver/' + 'b7469cc5-be51-41cc-b37f-361537656771', status=404) + with self.assertRaises(HTTPError): + aai_client.get_aai_model_data(self.app_conf, '9fb9f466-7a79-4109-a2a3-72b340aca53d', + 'b7469cc5-be51-41cc-b37f-361537656771', 'pnf_2') + def test_aai_client_get_aai_service_url_fail(self): - self.env.clear() + os.environ.clear() with self.assertRaises(KeyError): aai_client._get_aai_service_url() def test_aai_client_get_aai_service_url_success(self): - self.assertEqual('https://aai:8443', aai_client._get_aai_service_url()) + self.assertEqual('https://aai:8443/aai/v20', aai_client._get_aai_service_url()) diff --git a/components/pm-subscription-handler/tests/test_controller.py b/components/pm-subscription-handler/tests/test_controller.py index 4fcecc37..c38cd976 100755 --- a/components/pm-subscription-handler/tests/test_controller.py +++ b/components/pm-subscription-handler/tests/test_controller.py @@ -17,56 +17,55 @@ # ============LICENSE_END===================================================== import json import os -import unittest -from test.support import EnvironmentVarGuard from unittest.mock import patch +import responses from requests import Session -from mod import aai_client, create_app, db +from mod import aai_client from mod.api.controller import status, get_all_sub_to_nf_relations -from mod.network_function import NetworkFunction -from mod.pmsh_utils import AppConfig +from tests.base_setup import BaseClassSetup -class ControllerTestCase(unittest.TestCase): +class ControllerTestCase(BaseClassSetup): - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') - @patch('mod.update_logging_config') - @patch('mod.get_db_connection_url') - @patch.object(Session, 'put') - def setUp(self, mock_session, mock_get_db_url, mock_update_config, mock_get_pmsh_config): - mock_get_db_url.return_value = 'sqlite://' + @classmethod + def setUpClass(cls): + super().setUpClass() + + def setUp(self): + super().setUp() 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_PORT', '8443') - self.env.set('LOGGER_CONFIG', os.path.join(os.path.dirname(__file__), 'log_config.yaml')) - with open(os.path.join(os.path.dirname(__file__), 'data/cbs_data_1.json'), 'r') as data: - self.cbs_data = json.load(data) - mock_get_pmsh_config.return_value = self.cbs_data - 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() - self.app_conf = AppConfig() - self.xnfs = aai_client.get_pmsh_nfs_from_aai(self.app_conf) + with open(os.path.join(os.path.dirname(__file__), 'data/aai_model_info.json'), 'r') as data: + self.good_model_info = data.read() def tearDown(self): - db.session.remove() - db.drop_all() + super().tearDown() + + @classmethod + def tearDownClass(cls): + super().tearDownClass() def test_status_response_healthy(self): self.assertEqual(status()['status'], 'healthy') - def test_get_all_sub_to_nf_relations(self): + @patch.object(Session, 'get') + @patch.object(Session, 'put') + def test_get_all_sub_to_nf_relations(self, mock_put_session, mock_get_session): + mock_put_session.return_value.status_code = 200 + mock_put_session.return_value.text = self.aai_response_data + mock_get_session.return_value.status_code = 200 + mock_get_session.return_value.text = self.good_model_info + responses.add(responses.GET, + 'https://aai:8443/aai/v20/service-design-and-creation/models/model/' + '7129e420-d396-4efb-af02-6b83499b12f8/model-vers/model-ver/' + 'e80a6ae3-cafd-4d24-850d-e14c084a5ca9', + json=json.loads(self.good_model_info), status=200) + self.xnfs = aai_client.get_pmsh_nfs_from_aai(self.app_conf) sub_model = self.app_conf.subscription.get() - for nf in [self.nf_1, self.nf_2]: + for nf in self.xnfs: self.app_conf.subscription.add_network_function_to_subscription(nf, sub_model) all_subs = get_all_sub_to_nf_relations() - self.assertEqual(len(all_subs[0]['network_functions']), 2) + self.assertEqual(len(all_subs[0]['network_functions']), 3) self.assertEqual(all_subs[0]['subscription_name'], 'ExtraPM-All-gNB-R2B') diff --git a/components/pm-subscription-handler/tests/test_exit_handler.py b/components/pm-subscription-handler/tests/test_exit_handler.py index d41bd03b..c3cc0241 100755 --- a/components/pm-subscription-handler/tests/test_exit_handler.py +++ b/components/pm-subscription-handler/tests/test_exit_handler.py @@ -15,40 +15,38 @@ # # SPDX-License-Identifier: Apache-2.0 # ============LICENSE_END===================================================== -import json import os from signal import SIGTERM, signal -from test.support import EnvironmentVarGuard -from unittest import TestCase from unittest.mock import patch, Mock -from mod.api.db_models import NetworkFunctionModel from mod.exit_handler import ExitHandler -from mod.pmsh_utils import AppConfig from mod.subscription import Subscription +from tests.base_setup import BaseClassSetup -class ExitHandlerTests(TestCase): - @patch('mod.subscription.Subscription.create') - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') +class ExitHandlerTests(BaseClassSetup): + + @classmethod + def setUpClass(cls): + super().setUpClass() + @patch('mod.pmsh_utils.PeriodicTask') - def setUp(self, mock_periodic_task, mock_get_pmsh_config, mock_sub_create): - self.env = EnvironmentVarGuard() - self.env.set('LOGGER_CONFIG', os.path.join(os.path.dirname(__file__), 'log_config.yaml')) - with open(os.path.join(os.path.dirname(__file__), 'data/cbs_data_1.json'), 'r') as data: - self.cbs_data = json.load(data) - mock_get_pmsh_config.return_value = self.cbs_data + def setUp(self, mock_periodic_task): + super().setUp() self.mock_aai_event_thread = mock_periodic_task - self.app_conf = AppConfig() self.sub = self.app_conf.subscription - @patch('mod.logger.debug') + def tearDown(self): + super().tearDown() + + @classmethod + def tearDownClass(cls): + super().tearDownClass() + @patch.object(Subscription, 'update_sub_nf_status') @patch.object(Subscription, 'update_subscription_status') - @patch.object(Subscription, '_get_nf_models', - return_value=[NetworkFunctionModel('pnf1', 'ACTIVE')]) - def test_terminate_signal_successful(self, mock_sub_get_nf_models, mock_upd_sub_status, - mock_upd_subnf_status, mock_logger): + def test_terminate_signal_successful(self, mock_upd_sub_status, + mock_upd_subnf_status): handler = ExitHandler(periodic_tasks=[self.mock_aai_event_thread], app_conf=self.app_conf, subscription_handler=Mock()) diff --git a/components/pm-subscription-handler/tests/test_network_function.py b/components/pm-subscription-handler/tests/test_network_function.py index cdfb1eb5..f79ec93d 100755 --- a/components/pm-subscription-handler/tests/test_network_function.py +++ b/components/pm-subscription-handler/tests/test_network_function.py @@ -17,40 +17,38 @@ # ============LICENSE_END===================================================== import json import os -from test.support import EnvironmentVarGuard -from unittest import TestCase from unittest.mock import patch -from mod import db, create_app from mod.network_function import NetworkFunction -from mod.pmsh_utils import AppConfig -from mod.subscription import Subscription - - -class NetworkFunctionTests(TestCase): - - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') - @patch('mod.update_logging_config') - @patch('mod.get_db_connection_url') - def setUp(self, mock_get_db_url, mock_update_config, mock_get_pmsh_config): - mock_get_db_url.return_value = 'sqlite://' - self.nf_1 = NetworkFunction(nf_name='pnf_1', orchestration_status='Inventoried') - self.nf_2 = NetworkFunction(nf_name='pnf_2', orchestration_status='Active') - with open(os.path.join(os.path.dirname(__file__), 'data/cbs_data_1.json'), 'r') as data: - self.cbs_data = json.load(data) - mock_get_pmsh_config.return_value = self.cbs_data - self.env = EnvironmentVarGuard() - self.env.set('LOGGER_CONFIG', os.path.join(os.path.dirname(__file__), 'log_config.yaml')) - self.app = create_app() - self.app_context = self.app.app_context() - self.app_context.push() - db.create_all() - self.app_conf = AppConfig() +from tests.base_setup import BaseClassSetup + + +class NetworkFunctionTests(BaseClassSetup): + + @classmethod + def setUpClass(cls): + super().setUpClass() + + def setUp(self): + super().setUp() + self.nf_1 = NetworkFunction(nf_name='pnf_1', + model_invariant_id='some-id', + model_version_id='some-id') + self.nf_2 = NetworkFunction(nf_name='pnf_2', + model_invariant_id='some-id', + model_version_id='some-id') + with open(os.path.join(os.path.dirname(__file__), 'data/aai_model_info.json'), 'r') as data: + self.good_model_info = json.loads(data.read()) + with open(os.path.join(os.path.dirname(__file__), + 'data/aai_model_info_no_sdnc.json'), 'r') as data: + self.bad_model_info = json.loads(data.read()) def tearDown(self): - db.session.remove() - db.drop_all() - self.app_context.pop() + super().tearDown() + + @classmethod + def tearDownClass(cls): + super().tearDownClass() def test_get_network_function(self): self.nf_1.create() @@ -77,16 +75,21 @@ class NetworkFunctionTests(TestCase): self.assertEqual(nf, same_nf) def test_delete_network_function(self): - self.nf_1.create() - self.nf_2.create() - sub = Subscription(**{"subscriptionName": "sub"}) + sub = self.app_conf.subscription for nf in [self.nf_1, self.nf_2]: sub.add_network_function_to_subscription(nf, self.app_conf.subscription.get()) - + nfs = NetworkFunction.get_all() + self.assertEqual(2, len(nfs)) NetworkFunction.delete(nf_name=self.nf_1.nf_name) - nfs = NetworkFunction.get_all() self.assertEqual(1, len(nfs)) - self.assertEqual(1, len(Subscription.get_all_nfs_subscription_relations())) - pnf_1_deleted = [nf for nf in nfs if nf.nf_name != self.nf_1.nf_name] - self.assertTrue(pnf_1_deleted) + + @patch('mod.aai_client.get_aai_model_data') + def test_set_sdnc_params_true(self, mock_get_aai_model): + mock_get_aai_model.return_value = self.good_model_info + self.assertTrue(self.nf_1.set_sdnc_params(self.app_conf)) + + @patch('mod.aai_client.get_aai_model_data') + def test_set_sdnc_params_false(self, mock_get_aai_model): + mock_get_aai_model.return_value = self.bad_model_info + self.assertFalse(self.nf_1.set_sdnc_params(self.app_conf)) diff --git a/components/pm-subscription-handler/tests/test_network_function_filter.py b/components/pm-subscription-handler/tests/test_network_function_filter.py index 95c9b7bc..2151925d 100644 --- a/components/pm-subscription-handler/tests/test_network_function_filter.py +++ b/components/pm-subscription-handler/tests/test_network_function_filter.py @@ -20,7 +20,7 @@ import json import os from unittest import TestCase from parameterized import parameterized -from mod.network_function import NetworkFunctionFilter +from mod.network_function import NetworkFunctionFilter, NetworkFunction def custom_name_func(testcase_func, param_num, param): @@ -32,7 +32,8 @@ def custom_name_func(testcase_func, param_num, param): def load_test_cases(): test_parameters = [] - with open(os.path.join(os.path.dirname(__file__), 'data/filter_test_data.json'), 'r') as test_data: + with open(os.path.join(os.path.dirname(__file__), + 'data/filter_test_data.json'), 'r') as test_data: loaded_test_data = json.load(test_data) for test in loaded_test_data: params = [value for key, value in test.items()] @@ -43,44 +44,44 @@ def load_test_cases(): class NetworkFunctionFilterTest(TestCase): @parameterized.expand(load_test_cases, name_func=custom_name_func) - def test(self, test_name, nf_filter, nf_name, model_invariant_uuid, model_version_id, orchestration_status, + def test(self, test_name, nf_filter, nf_name, model_invariant_uuid, model_version_id, expected_result): nf_filter = NetworkFunctionFilter(**nf_filter) - self.assertEqual(nf_filter.is_nf_in_filter(nf_name, - model_invariant_uuid, - model_version_id, - orchestration_status), expected_result) + self.assertEqual(nf_filter.is_nf_in_filter(NetworkFunction(nf_name=nf_name, + model_invariant_id=model_invariant_uuid, + model_version_id=model_version_id)), + expected_result) - def test_filter_true_on_multiple_modelInvariantUUIDs(self): + def test_filter_true_on_multiple_modelInvariantIDs(self): nf_filter = NetworkFunctionFilter(**{ "nfNames": [ ], - "modelInvariantUUIDs": [ + "modelInvariantIDs": [ '5845y423-g654-6fju-po78-8n53154532k6', '7129e420-d396-4efb-af02-6b83499b12f8' ], "modelVersionIDs": [ ] }) - self.assertTrue(nf_filter.is_nf_in_filter('pnf1', - '7129e420-d396-4efb-af02-6b83499b12f8', - 'e80a6ae3-cafd-4d24-850d-e14c084a5ca9', - 'Active')) + self.assertTrue(nf_filter.is_nf_in_filter( + NetworkFunction(nf_name='pnf1', + model_invariant_id='7129e420-d396-4efb-af02-6b83499b12f8', + model_version_id='e80a6ae3-cafd-4d24-850d-e14c084a5ca9'))) - def test_filter_false_on_modelInvariantUUIDs_being_false_and_pnfname_being_true(self): + def test_filter_false_on_modelInvariantIDs_being_false_and_pnfname_being_true(self): nf_filter = NetworkFunctionFilter(**{ "nfNames": [ "^pnf.*", "^vnf.*" ], - "modelInvariantUUIDs": [ + "modelInvariantIDs": [ '5845y423-g654-6fju-po78-8n53154532k6', '7129e420-d396-4efb-af02-6b83499b12f8' ], "modelVersionIDs": [ ] }) - self.assertFalse(nf_filter.is_nf_in_filter('pnf1', - 'WrongModelInvariantUUID', - 'e80a6ae3-cafd-4d24-850d-e14c084a5ca9', - 'Active')) \ No newline at end of file + self.assertFalse(nf_filter.is_nf_in_filter( + NetworkFunction(nf_name='pnf1', + model_invariant_id='WrongModelInvariantUUID', + model_version_id='e80a6ae3-cafd-4d24-850d-e14c084a5ca9'))) diff --git a/components/pm-subscription-handler/tests/test_pmsh_utils.py b/components/pm-subscription-handler/tests/test_pmsh_utils.py index 6e5585f5..1bc039d2 100644 --- a/components/pm-subscription-handler/tests/test_pmsh_utils.py +++ b/components/pm-subscription-handler/tests/test_pmsh_utils.py @@ -15,88 +15,67 @@ # # SPDX-License-Identifier: Apache-2.0 # ============LICENSE_END===================================================== -import json -import os from test.support import EnvironmentVarGuard -from unittest import TestCase -from unittest.mock import patch +from unittest.mock import patch, Mock import responses from requests import Session from tenacity import RetryError -from mod import db, get_db_connection_url, create_app +from mod import get_db_connection_url +from mod.network_function import NetworkFunction from mod.pmsh_utils import AppConfig +from tests.base_setup import BaseClassSetup +from tests.base_setup import get_pmsh_config -class PmshUtilsTestCase(TestCase): +class PmshUtilsTestCase(BaseClassSetup): - @patch('mod.update_logging_config') - @patch('mod.create_app') - @patch('mod.get_db_connection_url') - def setUp(self, mock_get_db_url, mock_app, mock_update_config): - mock_get_db_url.return_value = 'sqlite://' - with open(os.path.join(os.path.dirname(__file__), 'data/cbs_data_1.json'), 'r') as data: - self.cbs_data = json.load(data) - self.env = EnvironmentVarGuard() - self.env.set('LOGGER_CONFIG', os.path.join(os.path.dirname(__file__), 'log_config.yaml')) - self.mock_app = mock_app - self.app = create_app() - self.app_context = self.app.app_context() - self.app_context.push() - db.create_all() - - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') - def test_utils_get_mr_sub(self, mock_get_pmsh_config): - mock_get_pmsh_config.return_value = self.cbs_data - self.app_conf = AppConfig() + @classmethod + def setUpClass(cls): + super().setUpClass() + + def setUp(self): + super().setUp() + self.mock_app = Mock() + + def tearDown(self): + super().tearDown() + + @classmethod + def tearDownClass(cls): + super().tearDownClass() + + def test_utils_get_mr_sub(self): mr_policy_sub = self.app_conf.get_mr_sub('policy_pm_subscriber') self.assertTrue(mr_policy_sub.aaf_id, 'dcae@dcae.onap.org') - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') - def test_utils_get_mr_sub_fails_with_invalid_name(self, mock_get_pmsh_config): - mock_get_pmsh_config.return_value = self.cbs_data - self.app_conf = AppConfig() + def test_utils_get_mr_sub_fails_with_invalid_name(self): with self.assertRaises(KeyError): self.app_conf.get_mr_sub('invalid_sub') - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') - def test_utils_get_mr_pub(self, mock_get_pmsh_config): - mock_get_pmsh_config.return_value = self.cbs_data - self.app_conf = AppConfig() + def test_utils_get_mr_pub(self): mr_policy_pub = self.app_conf.get_mr_pub('policy_pm_publisher') self.assertTrue(mr_policy_pub.aaf_pass, 'demo123456!') - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') - def test_utils_get_mr_pub_fails_with_invalid_name(self, mock_get_pmsh_config): - mock_get_pmsh_config.return_value = self.cbs_data - self.app_conf = AppConfig() + def test_utils_get_mr_pub_fails_with_invalid_name(self): with self.assertRaises(KeyError): self.app_conf.get_mr_pub('invalid_pub') - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') - def test_utils_get_cert_data(self, mock_get_pmsh_config): - mock_get_pmsh_config.return_value = self.cbs_data - self.app_conf = AppConfig() + def test_utils_get_cert_data(self): self.assertEqual(self.app_conf.cert_params, ('/opt/app/pmsh/etc/certs/cert.pem', '/opt/app/pmsh/etc/certs/key.pem')) - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') @patch.object(Session, 'post') - def test_mr_pub_publish_to_topic_success(self, mock_session, mock_get_pmsh_config): - mock_get_pmsh_config.return_value = self.cbs_data - self.app_conf = AppConfig() + def test_mr_pub_publish_to_topic_success(self, mock_session): mock_session.return_value.status_code = 200 mr_policy_pub = self.app_conf.get_mr_pub('policy_pm_publisher') with patch('requests.Session.post') as session_post_call: mr_policy_pub.publish_to_topic({"dummy_val": "43c4ee19-6b8d-4279-a80f-c507850aae47"}) session_post_call.assert_called_once() - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') @responses.activate - def test_mr_pub_publish_to_topic_fail(self, mock_get_pmsh_config): - mock_get_pmsh_config.return_value = self.cbs_data - self.app_conf = AppConfig() + def test_mr_pub_publish_to_topic_fail(self): responses.add(responses.POST, 'https://message-router:3905/events/org.onap.dmaap.mr.PM_SUBSCRIPTIONS', json={'error': 'Client Error'}, status=400) @@ -104,21 +83,19 @@ class PmshUtilsTestCase(TestCase): with self.assertRaises(Exception): mr_policy_pub.publish_to_topic({"dummy_val": "43c4ee19-6b8d-4279-a80f-c507850aae47"}) - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') - def test_mr_pub_publish_sub_event_data_success(self, mock_get_pmsh_config): - mock_get_pmsh_config.return_value = self.cbs_data - self.app_conf = AppConfig() + def test_mr_pub_publish_sub_event_data_success(self): mr_policy_pub = self.app_conf.get_mr_pub('policy_pm_publisher') with patch('mod.pmsh_utils._MrPub.publish_to_topic') as pub_to_topic_call: - mr_policy_pub.publish_subscription_event_data(self.app_conf.subscription, 'pnf201', - self.app_conf) + mr_policy_pub.publish_subscription_event_data( + self.app_conf.subscription, + NetworkFunction(nf_name='pnf_1', + model_invariant_id='some-id', + model_version_id='some-id'), + self.app_conf) pub_to_topic_call.assert_called_once() - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') @responses.activate - def test_mr_sub_get_from_topic_success(self, mock_get_pmsh_config): - mock_get_pmsh_config.return_value = self.cbs_data - self.app_conf = AppConfig() + def test_mr_sub_get_from_topic_success(self): policy_mr_sub = self.app_conf.get_mr_sub('policy_pm_subscriber') responses.add(responses.GET, 'https://message-router:3905/events/org.onap.dmaap.mr.PM_SUBSCRIPTIONS/' @@ -127,11 +104,8 @@ class PmshUtilsTestCase(TestCase): mr_topic_data = policy_mr_sub.get_from_topic(1) self.assertIsNotNone(mr_topic_data) - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') @responses.activate - def test_mr_sub_get_from_topic_fail(self, mock_get_pmsh_config): - mock_get_pmsh_config.return_value = self.cbs_data - self.app_conf = AppConfig() + def test_mr_sub_get_from_topic_fail(self): policy_mr_sub = self.app_conf.get_mr_sub('policy_pm_subscriber') responses.add(responses.GET, 'https://message-router:3905/events/org.onap.dmaap.mr.PM_SUBSCRIPTIONS/' @@ -158,15 +132,14 @@ class PmshUtilsTestCase(TestCase): @patch('mod.logger.info') @patch('mod.pmsh_utils.get_all') def test_refresh_config_success(self, mock_cbs_client_get_all, mock_logger): - mock_cbs_client_get_all.return_value = self.cbs_data - self.app_conf = AppConfig() + mock_cbs_client_get_all.return_value = get_pmsh_config() self.app_conf.refresh_config() mock_logger.assert_called_with('AppConfig data has been refreshed') @patch('mod.logger.error') @patch('mod.pmsh_utils.get_all') def test_refresh_config_fail(self, mock_cbs_client_get_all, mock_logger): - mock_cbs_client_get_all.return_value = self.cbs_data + mock_cbs_client_get_all.return_value = get_pmsh_config() self.app_conf = AppConfig() mock_cbs_client_get_all.side_effect = Exception with self.assertRaises(RetryError): 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 9dd73ee0..26a06fce 100644 --- a/components/pm-subscription-handler/tests/test_policy_response_handler.py +++ b/components/pm-subscription-handler/tests/test_policy_response_handler.py @@ -15,36 +15,37 @@ # # SPDX-License-Identifier: Apache-2.0 # ============LICENSE_END===================================================== -import json -import os -from unittest import TestCase from unittest.mock import patch from mod.api.db_models import SubscriptionModel from mod.network_function import NetworkFunction -from mod.pmsh_utils import AppConfig from mod.policy_response_handler import PolicyResponseHandler, policy_response_handle_functions from mod.subscription import AdministrativeState, SubNfState +from tests.base_setup import BaseClassSetup -class PolicyResponseHandlerTest(TestCase): +class PolicyResponseHandlerTest(BaseClassSetup): + + @classmethod + def setUpClass(cls): + super().setUpClass() - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') @patch('mod.create_app') - @patch('mod.subscription.Subscription') @patch('mod.pmsh_utils._MrSub') - def setUp(self, mock_mr_sub, mock_sub, mock_app, mock_get_app_conf): - with open(os.path.join(os.path.dirname(__file__), 'data/cbs_data_1.json'), 'r') as data: - self.cbs_data = json.load(data) + def setUp(self, mock_mr_sub, mock_app): + super().setUp() self.mock_policy_mr_sub = mock_mr_sub - mock_get_app_conf.return_value = self.cbs_data - self.app_conf = AppConfig() - self.sub = self.app_conf.subscription - self.mock_app = mock_app self.nf = NetworkFunction(nf_name='nf1') self.policy_response_handler = PolicyResponseHandler(self.mock_policy_mr_sub, self.app_conf, - self.mock_app) + mock_app) + + def tearDown(self): + super().tearDown() + + @classmethod + def tearDownClass(cls): + super().tearDownClass() @patch('mod.network_function.NetworkFunction.delete') def test_handle_response_locked_success(self, mock_delete): diff --git a/components/pm-subscription-handler/tests/test_subscription.py b/components/pm-subscription-handler/tests/test_subscription.py index c7845e74..9bfe825f 100755 --- a/components/pm-subscription-handler/tests/test_subscription.py +++ b/components/pm-subscription-handler/tests/test_subscription.py @@ -17,54 +17,45 @@ # ============LICENSE_END===================================================== import json import os -from test.support import EnvironmentVarGuard -from unittest import TestCase -from unittest.mock import patch +from unittest.mock import patch, Mock from requests import Session import mod.aai_client as aai_client -from mod import db, create_app -from mod.api.db_models import NetworkFunctionModel from mod.network_function import NetworkFunction -from mod.pmsh_utils import AppConfig from mod.subscription import Subscription +from tests.base_setup import BaseClassSetup -class SubscriptionTest(TestCase): - @patch('mod.update_logging_config') - @patch('mod.pmsh_utils._MrPub') - @patch('mod.pmsh_utils._MrSub') - @patch('mod.get_db_connection_url') +class SubscriptionTest(BaseClassSetup): + + @classmethod + def setUpClass(cls): + super().setUpClass() + + @patch.object(Session, 'get') @patch.object(Session, 'put') - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') - def setUp(self, mock_get_pmsh_config, mock_session, mock_get_db_url, - mock_mr_sub, mock_mr_pub, mock_update_config): - mock_get_db_url.return_value = 'sqlite://' + def setUp(self, mock_session_put, mock_session_get): + super().setUp() 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_PORT', '8443') - self.env.set('LOGGER_CONFIG', os.path.join(os.path.dirname(__file__), 'log_config.yaml')) - with open(os.path.join(os.path.dirname(__file__), 'data/cbs_data_1.json'), 'r') as data: - self.cbs_data = json.load(data) - mock_get_pmsh_config.return_value = self.cbs_data - self.mock_mr_sub = mock_mr_sub - self.mock_mr_pub = mock_mr_pub - self.app = create_app() - self.app_context = self.app.app_context() - self.app_context.push() - db.create_all() - self.app_conf = AppConfig() + mock_session_put.return_value.status_code = 200 + mock_session_put.return_value.text = self.aai_response_data + with open(os.path.join(os.path.dirname(__file__), 'data/aai_model_info.json'), 'r') as data: + self.aai_model_data = data.read() + mock_session_get.return_value.status_code = 200 + mock_session_get.return_value.text = self.aai_model_data + self.mock_mr_sub = Mock() + self.mock_mr_pub = Mock() self.xnfs = aai_client.get_pmsh_nfs_from_aai(self.app_conf) self.sub_model = self.app_conf.subscription.get() def tearDown(self): - db.drop_all() - db.session.remove() - self.app_context.pop() + super().tearDown() + + @classmethod + def tearDownClass(cls): + super().tearDownClass() def test_sub_measurement_group(self): self.assertEqual(len(self.app_conf.subscription.measurementGroups), 2) @@ -84,8 +75,6 @@ class SubscriptionTest(TestCase): self.sub_model) self.app_conf.subscription.add_network_function_to_subscription(list(self.xnfs)[1], self.sub_model) - nfs = Subscription.get_nf_names_per_sub(self.app_conf.subscription.subscriptionName) - self.assertEqual(2, len(nfs)) def test_create_existing_subscription(self): sub1 = self.app_conf.subscription.create() @@ -121,16 +110,6 @@ class SubscriptionTest(TestCase): self.assertEqual('new_status', sub.status) - def test_delete_subscription(self): - for nf in self.xnfs: - self.app_conf.subscription.add_network_function_to_subscription(nf, self.sub_model) - self.app_conf.subscription.delete_subscription() - self.assertEqual(0, len(Subscription.get_all())) - self.assertEqual(None, self.app_conf.subscription.get()) - self.assertEqual(0, len(Subscription.get_all_nfs_subscription_relations())) - self.assertEqual(0, len(NetworkFunction.get_all())) - self.assertEqual(None, NetworkFunction.get(nf_name=list(self.xnfs)[0].nf_name)) - def test_update_sub_nf_status(self): sub_name = 'ExtraPM-All-gNB-R2B' for nf in self.xnfs: @@ -172,18 +151,15 @@ class SubscriptionTest(TestCase): with open(os.path.join(os.path.dirname(__file__), 'data/pm_subscription_event.json'), 'r') as data: expected_sub_event = json.load(data) - actual_sub_event = self.app_conf.subscription.prepare_subscription_event('pnf_1', - self.app_conf) + nf = NetworkFunction(nf_name='pnf_1', + model_invariant_id='some-id', + model_version_id='some-id') + nf.sdnc_model_name = 'some-name' + nf.sdnc_model_version = 'some-version' + actual_sub_event = self.app_conf.subscription.prepare_subscription_event(nf, self.app_conf) + print(actual_sub_event) self.assertEqual(expected_sub_event, actual_sub_event) - def test_get_nf_models(self): - for nf in self.xnfs: - self.app_conf.subscription.add_network_function_to_subscription(nf, self.sub_model) - nf_models = self.app_conf.subscription._get_nf_models() - - self.assertEqual(3, len(nf_models)) - self.assertIsInstance(nf_models[0], NetworkFunctionModel) - def test_get_network_functions(self): for nf in self.xnfs: self.app_conf.subscription.add_network_function_to_subscription(nf, self.sub_model) diff --git a/components/pm-subscription-handler/tests/test_subscription_handler.py b/components/pm-subscription-handler/tests/test_subscription_handler.py index a6611666..bf72382a 100644 --- a/components/pm-subscription-handler/tests/test_subscription_handler.py +++ b/components/pm-subscription-handler/tests/test_subscription_handler.py @@ -15,50 +15,39 @@ # # SPDX-License-Identifier: Apache-2.0 # ============LICENSE_END===================================================== -import json -import os -from test.support import EnvironmentVarGuard -from unittest import TestCase -from unittest.mock import patch +from unittest.mock import patch, Mock -from mod import create_app, db from mod.network_function import NetworkFunction -from mod.pmsh_utils import AppConfig from mod.subscription import AdministrativeState from mod.subscription_handler import SubscriptionHandler +from tests.base_setup import BaseClassSetup -class SubscriptionHandlerTest(TestCase): +class SubscriptionHandlerTest(BaseClassSetup): @classmethod def setUpClass(cls): - cls.env = EnvironmentVarGuard() - cls.env.set('AAI_SERVICE_PORT', '8443') - cls.env.set('LOGGER_CONFIG', os.path.join(os.path.dirname(__file__), 'log_config.yaml')) - cls.nfs = [NetworkFunction(nf_name='pnf_1'), NetworkFunction(nf_name='pnf_2')] + super().setUpClass() - @patch('mod.get_db_connection_url') - @patch('mod.update_logging_config') - @patch('mod.pmsh_utils.AppConfig._get_pmsh_config') @patch('mod.pmsh_utils._MrPub') - @patch('mod.pmsh_utils.PeriodicTask') - def setUp(self, mock_periodic_task, mock_mr_pub, mock_get_pmsh_config, mock_update_config, - mock_get_db_url): - mock_get_db_url.return_value = 'sqlite://' - with open(os.path.join(os.path.dirname(__file__), 'data/cbs_data_1.json'), 'r') as data: - self.cbs_data = json.load(data) - mock_get_pmsh_config.return_value = self.cbs_data + def setUp(self, mock_mr_pub): + super().setUp() + self.nfs = [NetworkFunction(nf_name='pnf_1', + model_invariant_id='some-id', + model_version_id='some-id'), + NetworkFunction(nf_name='pnf_2', + model_invariant_id='some-id', + model_version_id='some-id')] self.mock_mr_pub = mock_mr_pub - self.mock_aai_event_thread = mock_periodic_task - self.mock_policy_event_thread = mock_periodic_task - self.app = create_app() - self.app.app_context().push() - db.create_all() - self.app_conf = AppConfig() + self.mock_aai_event_thread = Mock() + self.mock_policy_event_thread = Mock() def tearDown(self): - db.drop_all() - db.session.remove() + super().tearDown() + + @classmethod + def tearDownClass(cls): + super().tearDownClass() @patch('mod.subscription.Subscription.get_local_sub_admin_state') @patch('mod.logger.info') -- cgit 1.2.3-korg