From 1bfe4e2392fe3ba155d71ad4f99fbc7fd21e68be Mon Sep 17 00:00:00 2001 From: tierno Date: Mon, 2 Sep 2019 16:03:25 +0000 Subject: [PATCH] initial unittest for osm_nbi.instance_topics Change-Id: Ib38b3e6625014c8641e7cadce69624f46b41d1ac Signed-off-by: tierno --- .gitignore-common | 4 +- Dockerfile.local | 10 +- Makefile | 2 +- devops-stages/stage-test.sh | 2 + osm_nbi/instance_topics.py | 18 +- osm_nbi/tests/test_db_descriptors.py | 591 ++++++++++++++++++++++++++ osm_nbi/tests/test_instance_topics.py | 235 ++++++++++ requirements.txt | 1 + test-requirements.txt | 9 +- tox.ini | 12 +- 10 files changed, 861 insertions(+), 23 deletions(-) create mode 100644 osm_nbi/tests/test_db_descriptors.py create mode 100644 osm_nbi/tests/test_instance_topics.py diff --git a/.gitignore-common b/.gitignore-common index 157e9ef..30f83df 100644 --- a/.gitignore-common +++ b/.gitignore-common @@ -46,6 +46,8 @@ build dist *.egg-info .eggs +.temp-tox #vscode -.vscode \ No newline at end of file +.vscode + diff --git a/Dockerfile.local b/Dockerfile.local index e72aefa..8635e4b 100644 --- a/Dockerfile.local +++ b/Dockerfile.local @@ -36,11 +36,13 @@ RUN pip3 install pyang && mkdir -p /app && cd /app \ && git -C /app clone https://github.com/robshakir/pyangbind \ && pip3 install -e /app/pyangbind \ && git -C /app clone https://osm.etsi.org/gerrit/osm/IM \ - && cd /app/IM/models/yang \ && mkdir /app/IM/osm_im \ - && pyang --plugindir /app/pyangbind/pyangbind/plugin -f pybind -o /app/IM/osm_im/vnfd.py vnfd.yang \ - && pyang --plugindir /app/pyangbind/pyangbind/plugin -f pybind -o /app/IM/osm_im/nsd.py nsd.yang \ - && pyang --plugindir /app/pyangbind/pyangbind/plugin -f pybind -o /app/IM/osm_im/nst.py nst.yang \ + && pyang --plugindir /app/pyangbind/pyangbind/plugin -f pybind -p /app/IM/models/yang \ + -o /app/IM/osm_im/vnfd.py /app/IM/models/yang/vnfd.yang \ + && pyang --plugindir /app/pyangbind/pyangbind/plugin -f pybind -p /app/IM/models/yang \ + -o /app/IM/osm_im/nsd.py /app/IM/models/yang/nsd.yang \ + && pyang --plugindir /app/pyangbind/pyangbind/plugin -f pybind -p /app/IM/models/yang \ + -o /app/IM/osm_im/nst.py /app/IM/models/yang/nst.yang \ && pip3 install -e /app/IM EXPOSE 9999 diff --git a/Makefile b/Makefile index fba5941..528cca1 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ all: clean package clean: - rm -rf dist deb_dist osm_nbi-*.tar.gz osm_nbi.egg-info .eggs + rm -rf dist deb_dist osm_nbi-*.tar.gz osm_nbi.egg-info .eggs .temp-tox package: python3 setup.py --command-packages=stdeb.command sdist_dsc diff --git a/devops-stages/stage-test.sh b/devops-stages/stage-test.sh index b47e138..5f94ba3 100755 --- a/devops-stages/stage-test.sh +++ b/devops-stages/stage-test.sh @@ -14,3 +14,5 @@ # limitations under the License. tox -e flake8 +tox -e unittest + diff --git a/osm_nbi/instance_topics.py b/osm_nbi/instance_topics.py index 8024996..4cb1e9c 100644 --- a/osm_nbi/instance_topics.py +++ b/osm_nbi/instance_topics.py @@ -23,6 +23,8 @@ from osm_nbi.base_topic import BaseTopic, EngineException, get_iterable # from descriptor_topics import DescriptorTopic from yaml import safe_dump from osm_common.dbbase import DbException +from osm_common.msgbase import MsgException +from osm_common.fsbase import FsException from re import match # For checking that additional parameter names are valid Jinja2 identifiers __author__ = "Alfonso Tierno " @@ -178,7 +180,9 @@ class NsrTopic(BaseTopic): :param indata: params to be used for the nsr :param kwargs: used to override the indata descriptor :param headers: http request headers - :return: the _id of nsr descriptor created at database + :return: the _id of nsr descriptor created at database. Or an exception of type + EngineException, ValidationError, DbException, FsException, MsgException. + Note: Exceptions are not captured on purpose. They should be captured at called """ try: @@ -380,11 +384,8 @@ class NsrTopic(BaseTopic): self.fs.mkdir(nsr_id) return nsr_id, None - except ValidationError as e: # TODO remove try Except, it is captured at nbi.py - raise EngineException(e, HTTPStatus.UNPROCESSABLE_ENTITY) - except Exception as e: - self.logger.exception("Exception {} at NsrTopic.new()".format(e), exc_info=True) - raise EngineException("Error {}: {}".format(step, e)) + except (ValidationError, EngineException, DbException, MsgException, FsException) as e: + raise type(e)("{} while '{}".format(e, step), http_code=e.http_code) def edit(self, session, _id, indata=None, kwargs=None, content=None): raise EngineException("Method edit called directly", HTTPStatus.INTERNAL_SERVER_ERROR) @@ -489,7 +490,7 @@ class NsLcmOpTopic(BaseTopic): for in_ivld in get_iterable(in_vnfd.get("internal-vld")): for ivld in get_iterable(vnfd.get("internal-vld")): if in_ivld["name"] == ivld["name"] or in_ivld["name"] == ivld["id"]: - for in_icp in get_iterable(in_ivld["internal-connection-point"]): + for in_icp in get_iterable(in_ivld.get("internal-connection-point")): for icp in ivld["internal-connection-point"]: if in_icp["id-ref"] == icp["id-ref"]: break @@ -826,8 +827,9 @@ class NsLcmOpTopic(BaseTopic): self._update_vnfrs(session, rollback, nsr, indata) nslcmop_desc = self._create_nslcmop(nsInstanceId, operation, indata) + _id = nslcmop_desc["_id"] self.format_on_new(nslcmop_desc, session["project_id"], make_public=session["public"]) - _id = self.db.create("nslcmops", nslcmop_desc) + self.db.create("nslcmops", nslcmop_desc) rollback.append({"topic": "nslcmops", "_id": _id}) if not slice_object: self.msg.write("ns", operation, nslcmop_desc) diff --git a/osm_nbi/tests/test_db_descriptors.py b/osm_nbi/tests/test_db_descriptors.py new file mode 100644 index 0000000..d445d09 --- /dev/null +++ b/osm_nbi/tests/test_db_descriptors.py @@ -0,0 +1,591 @@ +# +# 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: esousa@whitestack.com or alfonso.tiernosepulveda@telefonica.com +## + +"""Contains database content needed for tests""" + + +db_vim_accounts_text = """ +--- +- _admin: + created: 1566818150.3024442 + current_operation: 0 + deployed: + RO: dc51ce6c-c7f2-11e9-b9c0-02420aff0004 + RO-account: dc5c67fa-c7f2-11e9-b9c0-02420aff0004 + detailed-status: Done + modified: 1566818150.3024442 + operationalState: ENABLED + operations: + - detailed-status: Done + lcmOperationType: create + operationParams: null + operationState: COMPLETED + startTime: 1566818150.3025382 + statusEnteredTime: 1566818150.3025382 + worker: 86434c2948e2 + projects_read: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + projects_write: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + _id: ea958ba5-4e58-4405-bf42-6e3be15d4c3a + description: Openstack site 2, based on Mirantis, also called DSS9000-1, with + tenant tid + name: ost2-mrt-tid + schema_version: '1.1' + vim_password: 5g0yGX86qIhprX86YTMcpg== + vim_tenant_name: osm + vim_type: openstack + vim_url: http://10.95.87.162:5000/v2.0 + vim_user: osm +""" + +db_vnfds_text = """ +--- +- _admin: + created: 1566823352.7154346 + modified: 1566823353.9295402 + onboardingState: ONBOARDED + operationalState: ENABLED + projects_read: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + projects_write: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + storage: + descriptor: hackfest_3charmed_vnfd/hackfest_3charmed_vnfd.yaml + folder: 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77 + fs: local + path: /app/storage/ + pkg-dir: hackfest_3charmed_vnfd + zipfile: package.tar.gz + type: vnfd + usageState: NOT_IN_USE + userDefinedData: {} + _id: 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77 + connection-point: + - id: vnf-mgmt + name: vnf-mgmt + short-name: vnf-mgmt + type: VPORT + - id: vnf-data + name: vnf-data + short-name: vnf-data + type: VPORT + description: A VNF consisting of 2 VDUs connected to an internal VL, and one VDU + with cloud-init + id: hackfest3charmed-vnf + internal-vld: + - id: internal + internal-connection-point: + - id-ref: mgmtVM-internal + - id-ref: dataVM-internal + name: internal + short-name: internal + type: ELAN + logo: osm.png + mgmt-interface: + cp: vnf-mgmt + monitoring-param: + - aggregation-type: AVERAGE + id: monitor1 + name: monitor1 + vdu-monitoring-param: + vdu-monitoring-param-ref: dataVM_cpu_util + vdu-ref: dataVM + name: hackfest3charmed-vnf + scaling-group-descriptor: + - max-instance-count: 10 + name: scale_dataVM + scaling-config-action: + - trigger: post-scale-out + vnf-config-primitive-name-ref: touch + - trigger: pre-scale-in + vnf-config-primitive-name-ref: touch + scaling-policy: + - cooldown-time: 60 + name: auto_cpu_util_above_threshold + scaling-criteria: + - name: cpu_util_above_threshold + scale-in-relational-operation: LE + scale-in-threshold: '15.0000000000' + scale-out-relational-operation: GE + scale-out-threshold: '60.0000000000' + vnf-monitoring-param-ref: monitor1 + scaling-type: automatic + threshold-time: 0 + vdu: + - count: 1 + vdu-id-ref: dataVM + short-name: hackfest3charmed-vnf + vdu: + - count: '1' + cloud-init-file: cloud-config.txt + id: mgmtVM + image: hackfest3-mgmt + interface: + - external-connection-point-ref: vnf-mgmt + name: mgmtVM-eth0 + position: 1 + type: EXTERNAL + virtual-interface: + type: VIRTIO + - internal-connection-point-ref: mgmtVM-internal + name: mgmtVM-eth1 + position: 2 + type: INTERNAL + virtual-interface: + type: VIRTIO + internal-connection-point: + - id: mgmtVM-internal + name: mgmtVM-internal + short-name: mgmtVM-internal + type: VPORT + name: mgmtVM + vm-flavor: + memory-mb: '1024' + storage-gb: '10' + vcpu-count: 1 + - count: '1' + id: dataVM + image: hackfest3-mgmt + interface: + - internal-connection-point-ref: dataVM-internal + name: dataVM-eth0 + position: 1 + type: INTERNAL + virtual-interface: + type: VIRTIO + - external-connection-point-ref: vnf-data + name: dataVM-xe0 + position: 2 + type: EXTERNAL + virtual-interface: + type: VIRTIO + internal-connection-point: + - id: dataVM-internal + name: dataVM-internal + short-name: dataVM-internal + type: VPORT + monitoring-param: + - id: dataVM_cpu_util + nfvi-metric: cpu_utilization + name: dataVM + vm-flavor: + memory-mb: '1024' + storage-gb: '10' + vcpu-count: 1 + version: '1.0' + vnf-configuration: + config-primitive: + - name: touch + parameter: + - data-type: STRING + default-value: + name: filename + initial-config-primitive: + - name: config + parameter: + - name: ssh-hostname + value: + - name: ssh-username + value: ubuntu + - name: ssh-password + value: osm4u + seq: '1' + - name: touch + parameter: + - name: filename + value: + seq: '2' + juju: + charm: simple +""" + +db_nsds_text = """ +--- +- _admin: + created: 1566823353.971486 + modified: 1566823353.971486 + onboardingState: ONBOARDED + operationalState: ENABLED + projects_read: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + projects_write: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + storage: + descriptor: hackfest_3charmed_nsd/hackfest_3charmed_nsd.yaml + folder: 8c2f8b95-bb1b-47ee-8001-36dc090678da + fs: local + path: /app/storage/ + pkg-dir: hackfest_3charmed_nsd + zipfile: package.tar.gz + usageState: NOT_IN_USE + userDefinedData: {} + _id: 8c2f8b95-bb1b-47ee-8001-36dc090678da + constituent-vnfd: + - member-vnf-index: '1' + vnfd-id-ref: hackfest3charmed-vnf + - member-vnf-index: '2' + vnfd-id-ref: hackfest3charmed-vnf + description: NS with 2 VNFs hackfest3charmed-vnf connected by datanet and mgmtnet + VLs + id: hackfest3charmed-ns + logo: osm.png + name: hackfest3charmed-ns + short-name: hackfest3charmed-ns + version: '1.0' + vld: + - id: mgmt + mgmt-network: true + name: mgmt + short-name: mgmt + type: ELAN + vim-network-name: mgmt + vnfd-connection-point-ref: + - member-vnf-index-ref: '1' + vnfd-connection-point-ref: vnf-mgmt + vnfd-id-ref: hackfest3charmed-vnf + - member-vnf-index-ref: '2' + vnfd-connection-point-ref: vnf-mgmt + vnfd-id-ref: hackfest3charmed-vnf + - id: datanet + name: datanet + short-name: datanet + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '1' + vnfd-connection-point-ref: vnf-data + vnfd-id-ref: hackfest3charmed-vnf + - member-vnf-index-ref: '2' + vnfd-connection-point-ref: vnf-data + vnfd-id-ref: hackfest3charmed-vnf +""" + +db_nsrs_text = """ +--- +- _admin: + created: 1566823354.3716335 + modified: 1566823354.3716335 + nsState: NOT_INSTANTIATED + nslcmop: null + projects_read: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + projects_write: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + _id: f48163a6-c807-47bc-9682-f72caef5af85 + additionalParamsForNs: null + admin-status: ENABLED + config-status: init + constituent-vnfr-ref: + - 88d90b0c-faff-4b9f-bccd-017f33985984 + - 1ca3bb1a-b29b-49fe-bed6-5f3076d77434 + create-time: 1566823354.36234 + datacenter: ea958ba5-4e58-4405-bf42-6e3be15d4c3a + description: default description + detailed-status: 'ERROR executing proxy charm initial primitives for member_vnf_index=1 + vdu_id=None: charm error executing primitive verify-ssh-credentials for member_vnf_index=1 + vdu_id=None: ''timeout after 600 seconds''' + id: f48163a6-c807-47bc-9682-f72caef5af85 + instantiate_params: + nsDescription: default description + nsName: ALF + nsdId: 8c2f8b95-bb1b-47ee-8001-36dc090678da + vimAccountId: ea958ba5-4e58-4405-bf42-6e3be15d4c3a + name: ALF + name-ref: ALF + ns-instance-config-ref: f48163a6-c807-47bc-9682-f72caef5af85 + nsd: + _admin: + created: 1566823353.971486 + modified: 1566823353.971486 + onboardingState: ONBOARDED + operationalState: ENABLED + projects_read: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + projects_write: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + storage: + descriptor: hackfest_3charmed_nsd/hackfest_3charmed_nsd.yaml + folder: 8c2f8b95-bb1b-47ee-8001-36dc090678da + fs: local + path: /app/storage/ + pkg-dir: hackfest_3charmed_nsd + zipfile: package.tar.gz + usageState: NOT_IN_USE + userDefinedData: {} + _id: 8c2f8b95-bb1b-47ee-8001-36dc090678da + constituent-vnfd: + - member-vnf-index: '1' + vnfd-id-ref: hackfest3charmed-vnf + - member-vnf-index: '2' + vnfd-id-ref: hackfest3charmed-vnf + description: NS with 2 VNFs hackfest3charmed-vnf connected by datanet and + mgmtnet VLs + id: hackfest3charmed-ns + logo: osm.png + name: hackfest3charmed-ns + short-name: hackfest3charmed-ns + version: '1.0' + vld: + - id: mgmt + mgmt-network: true + name: mgmt + short-name: mgmt + type: ELAN + vim-network-name: mgmt + vnfd-connection-point-ref: + - member-vnf-index-ref: '1' + vnfd-connection-point-ref: vnf-mgmt + vnfd-id-ref: hackfest3charmed-vnf + - member-vnf-index-ref: '2' + vnfd-connection-point-ref: vnf-mgmt + vnfd-id-ref: hackfest3charmed-vnf + - id: datanet + name: datanet + short-name: datanet + type: ELAN + vnfd-connection-point-ref: + - member-vnf-index-ref: '1' + vnfd-connection-point-ref: vnf-data + vnfd-id-ref: hackfest3charmed-vnf + - member-vnf-index-ref: '2' + vnfd-connection-point-ref: vnf-data + vnfd-id-ref: hackfest3charmed-vnf + nsd-id: 8c2f8b95-bb1b-47ee-8001-36dc090678da + nsd-name-ref: hackfest3charmed-ns + nsd-ref: hackfest3charmed-ns + operational-events: [] + operational-status: failed + orchestration-progress: {} + resource-orchestrator: osmopenmano + short-name: ALF + ssh-authorized-key: null + vld: + - id: mgmt + name: null + status: ACTIVE + status-detailed: null + vim-id: f99ae780-0e2f-4985-af41-574eae6919c0 + vim-network-name: mgmt + - id: datanet + name: ALF-datanet + status: ACTIVE + status-detailed: null + vim-id: c31364ba-f573-4ab6-bf1a-fed30ede39a8 + vnfd-id: + - 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77 +""" + +db_nslcmops_text = """ +--- +- _admin: + created: 1566823354.4148262 + modified: 1566823354.4148262 + projects_read: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + projects_write: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + worker: 86434c2948e2 + _id: a639fac7-e0bb-4225-8ecb-c1f8efcc125e + detailed-status: 'FAILED executing proxy charm initial primitives for member_vnf_index=1 + vdu_id=None: charm error executing primitive verify-ssh-credentials for member_vnf_index=1 + vdu_id=None: ''timeout after 600 seconds''' + id: a639fac7-e0bb-4225-8ecb-c1f8efcc125e + isAutomaticInvocation: false + isCancelPending: false + lcmOperationType: instantiate + links: + nsInstance: /osm/nslcm/v1/ns_instances/f48163a6-c807-47bc-9682-f72caef5af85 + self: /osm/nslcm/v1/ns_lcm_op_occs/a639fac7-e0bb-4225-8ecb-c1f8efcc125e + nsInstanceId: f48163a6-c807-47bc-9682-f72caef5af85 + operationParams: + additionalParamsForVnf: + - additionalParams: + touch_filename: /home/ubuntu/first-touch-1 + touch_filename2: /home/ubuntu/second-touch-1 + member-vnf-index: '1' + - additionalParams: + touch_filename: /home/ubuntu/first-touch-2 + touch_filename2: /home/ubuntu/second-touch-2 + member-vnf-index: '2' + lcmOperationType: instantiate + nsDescription: default description + nsInstanceId: f48163a6-c807-47bc-9682-f72caef5af85 + nsName: ALF + nsdId: 8c2f8b95-bb1b-47ee-8001-36dc090678da + vimAccountId: ea958ba5-4e58-4405-bf42-6e3be15d4c3a + operationState: FAILED + startTime: 1566823354.414689 + statusEnteredTime: 1566824534.5112448 +""" + +db_vnfrs_text = """ +--- +- _admin: + created: 1566823354.3668208 + modified: 1566823354.3668208 + nsState: NOT_INSTANTIATED + projects_read: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + projects_write: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + _id: 88d90b0c-faff-4b9f-bccd-017f33985984 + additionalParamsForVnf: + touch_filename: /home/ubuntu/first-touch-1 + touch_filename2: /home/ubuntu/second-touch-1 + connection-point: + - connection-point-id: vnf-mgmt + id: vnf-mgmt + name: vnf-mgmt + - connection-point-id: vnf-data + id: vnf-data + name: vnf-data + created-time: 1566823354.36234 + id: 88d90b0c-faff-4b9f-bccd-017f33985984 + ip-address: 10.205.1.46 + member-vnf-index-ref: '1' + nsr-id-ref: f48163a6-c807-47bc-9682-f72caef5af85 + vdur: + - _id: f0e7d7ce-2443-4dcb-ad0b-5ab9f3b13d37 + count-index: 0 + interfaces: + - ip-address: 10.205.1.46 + mac-address: fa:16:3e:b4:3e:b1 + mgmt-vnf: true + name: mgmtVM-eth0 + ns-vld-id: mgmt + - ip-address: 192.168.54.2 + mac-address: fa:16:3e:6e:7e:78 + name: mgmtVM-eth1 + vnf-vld-id: internal + internal-connection-point: + - connection-point-id: mgmtVM-internal + id: mgmtVM-internal + name: mgmtVM-internal + ip-address: 10.205.1.46 + name: ALF-1-mgmtVM-1 + status: ACTIVE + status-detailed: null + vdu-id-ref: mgmtVM + vim-id: c2538499-4c30-41c0-acd5-80cb92f48061 + - _id: ab453219-2d9a-45c2-864d-2c0788385028 + count-index: 0 + interfaces: + - ip-address: 192.168.54.3 + mac-address: fa:16:3e:d9:7a:5d + name: dataVM-eth0 + vnf-vld-id: internal + - ip-address: 192.168.24.3 + mac-address: fa:16:3e:d1:6c:0d + name: dataVM-xe0 + ns-vld-id: datanet + internal-connection-point: + - connection-point-id: dataVM-internal + id: dataVM-internal + name: dataVM-internal + ip-address: null + name: ALF-1-dataVM-1 + status: ACTIVE + status-detailed: null + vdu-id-ref: dataVM + vim-id: 87973c3f-365d-4227-95c2-7a8abc74349c + vim-account-id: ea958ba5-4e58-4405-bf42-6e3be15d4c3a + vld: + - id: internal + name: ALF-internal + status: ACTIVE + status-detailed: null + vim-id: ff181e6d-2597-4244-b40b-bb0174bdfeb6 + vnfd-id: 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77 + vnfd-ref: hackfest3charmed-vnf +- _admin: + created: 1566823354.3703845 + modified: 1566823354.3703845 + nsState: NOT_INSTANTIATED + projects_read: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + projects_write: + - 25b5aebf-3da1-49ed-99de-1d2b4a86d6e4 + _id: 1ca3bb1a-b29b-49fe-bed6-5f3076d77434 + additionalParamsForVnf: + touch_filename: /home/ubuntu/first-touch-2 + touch_filename2: /home/ubuntu/second-touch-2 + connection-point: + - connection-point-id: vnf-mgmt + id: vnf-mgmt + name: vnf-mgmt + - connection-point-id: vnf-data + id: vnf-data + name: vnf-data + created-time: 1566823354.36234 + id: 1ca3bb1a-b29b-49fe-bed6-5f3076d77434 + ip-address: 10.205.1.47 + member-vnf-index-ref: '2' + nsr-id-ref: f48163a6-c807-47bc-9682-f72caef5af85 + vdur: + - _id: 190b4a2c-4f85-4cfe-9406-4cef7ffb1e67 + count-index: 0 + interfaces: + - ip-address: 10.205.1.47 + mac-address: fa:16:3e:cb:9f:c7 + mgmt-vnf: true + name: mgmtVM-eth0 + ns-vld-id: mgmt + - ip-address: 192.168.231.1 + mac-address: fa:16:3e:1a:89:24 + name: mgmtVM-eth1 + vnf-vld-id: internal + internal-connection-point: + - connection-point-id: mgmtVM-internal + id: mgmtVM-internal + name: mgmtVM-internal + ip-address: 10.205.1.47 + name: ALF-2-mgmtVM-1 + status: ACTIVE + status-detailed: null + vdu-id-ref: mgmtVM + vim-id: 248077b2-e3b8-4a37-8b72-575abb8ed912 + - _id: 889b874d-e1c3-4e75-aa45-53a9b0ddabd9 + count-index: 0 + interfaces: + - ip-address: 192.168.231.3 + mac-address: fa:16:3e:7e:ba:8c + name: dataVM-eth0 + vnf-vld-id: internal + - ip-address: 192.168.24.4 + mac-address: fa:16:3e:d2:e1:f5 + name: dataVM-xe0 + ns-vld-id: datanet + internal-connection-point: + - connection-point-id: dataVM-internal + id: dataVM-internal + name: dataVM-internal + ip-address: null + name: ALF-2-dataVM-1 + status: ACTIVE + status-detailed: null + vdu-id-ref: dataVM + vim-id: a4ce4372-e0ad-4ae3-8f9f-1c969f32e77b + vim-account-id: ea958ba5-4e58-4405-bf42-6e3be15d4c3a + vld: + - id: internal + name: ALF-internal + status: ACTIVE + status-detailed: null + vim-id: ff181e6d-2597-4244-b40b-bb0174bdfeb6 + vnfd-id: 7637bcf8-cf14-42dc-ad70-c66fcf1e6e77 + vnfd-ref: hackfest3charmed-vnf +""" diff --git a/osm_nbi/tests/test_instance_topics.py b/osm_nbi/tests/test_instance_topics.py new file mode 100644 index 0000000..5c91114 --- /dev/null +++ b/osm_nbi/tests/test_instance_topics.py @@ -0,0 +1,235 @@ +# +# 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. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact: esousa@whitestack.com or alfonso.tiernosepulveda@telefonica.com +## + +import unittest +from unittest.mock import Mock, mock_open # patch, MagicMock +from osm_common.dbbase import DbException +from osm_nbi.engine import EngineException +from osm_common.dbmemory import DbMemory +from osm_common.fsbase import FsBase +from osm_common.msgbase import MsgBase +from http import HTTPStatus +from osm_nbi.instance_topics import NsLcmOpTopic, NsrTopic +from osm_nbi.tests.test_db_descriptors import db_vim_accounts_text, db_nsds_text, db_vnfds_text, db_nsrs_text,\ + db_vnfrs_text +from copy import deepcopy +import yaml + + +class TestNsLcmOpTopic(unittest.TestCase): + + def setUp(self): + self.db = DbMemory() + self.fs = Mock(FsBase()) + self.fs.get_params.return_value = {"./fake/folder"} + self.fs.file_open = mock_open() + self.msg = Mock(MsgBase()) + # create class + self.nslcmop_topic = NsLcmOpTopic(self.db, self.fs, self.msg, None) + self.nslcmop_topic.check_quota = Mock(return_value=None) # skip quota + + self.db.create_list("vim_accounts", yaml.load(db_vim_accounts_text, Loader=yaml.Loader)) + self.db.create_list("nsds", yaml.load(db_nsds_text, Loader=yaml.Loader)) + self.db.create_list("vnfds", yaml.load(db_vnfds_text, Loader=yaml.Loader)) + self.db.create_list("vnfrs", yaml.load(db_vnfrs_text, Loader=yaml.Loader)) + self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader)) + self.db.create = Mock(return_value="created_id") + self.db.set_one = Mock(return_value={"updated": 1}) + self.nsd = self.db.get_list("nsds")[0] + self.nsd_id = self.nsd["_id"] + self.nsr = self.db.get_list("nsrs")[0] + self.nsr_id = self.nsr["_id"] + self.nsr_project = self.nsr["_admin"]["projects_read"][0] + + self.vim = self.db.get_list("vim_accounts")[0] + self.vim_id = self.vim["_id"] + + def test_create_instantiate(self): + session = {"force": False, "admin": False, "public": False, "project_id": [self.nsr_project], "method": "write"} + indata = { + "nsdId": self.nsd_id, + "nsInstanceId": self.nsr_id, + "nsName": "name", + "vimAccountId": self.vim_id, + "additionalParamsForVnf": [{"member-vnf-index": "1", "additionalParams": {"touch_filename": "file"}}, + {"member-vnf-index": "2", "additionalParams": {"touch_filename": "file"}}], + "vnf": [{"member-vnf-index": "1", + "vdu": [{"id": "dataVM", "interface": [{"name": "dataVM-eth0", + "ip-address": "10.11.12.13", + "floating-ip-required": True}] + }], + "internal-vld": [{"name": "internal", "vim-network-id": "vim-net-id"}] + }], + "lcmOperationType": "instantiate", + + } + rollback = [] + headers = {} + + nslcmop_id, _ = self.nslcmop_topic.new(rollback, session, indata=indata, kwargs=None, headers=headers) + + # check nslcmop is created at database + self.assertEqual(self.db.create.call_count, 1, "database create not called, or called more than once") + _call = self.db.create.call_args_list[0] + self.assertEqual(_call[0][0], "nslcmops", "must be create a nslcmops entry at database") + + created_nslcmop = _call[0][1] + self.assertEqual(nslcmop_id, created_nslcmop["_id"], "mismatch between return id and database '_id'") + self.assertEqual(self.nsr_id, created_nslcmop["nsInstanceId"], "bad reference id from nslcmop to nsr") + self.assertTrue(created_nslcmop["_admin"].get("projects_read"), + "Database record must contain '_amdin.projects_read'") + self.assertIn("created", created_nslcmop["_admin"], "Database record must contain '_admin.created'") + self.assertTrue(created_nslcmop["lcmOperationType"] == "instantiate", + "Database record must contain 'lcmOperationType=instantiate'") + + self.assertEqual(len(rollback), len(self.db.set_one.call_args_list) + 1, + "rollback mismatch with created/set items at database") + + # test parameters with error + bad_id = "88d90b0c-faff-4b9f-bccd-aaaaaaaaaaaa" + test_set = ( + ("nsr not found", {"nsInstanceId": bad_id}, DbException, HTTPStatus.NOT_FOUND, ("not found", bad_id)), + # TODO add "nsd" + # ({"vimAccountId": bad_id}, DbException, HTTPStatus.NOT_FOUND, ("not found", bad_id)), # TODO add "vim" + ("bad member-vnf-index", {"vnf.0.member-vnf-index": "k"}, EngineException, HTTPStatus.BAD_REQUEST, + ("k",)), + ) + for message, kwargs_, expect_exc, expect_code, expect_text_list in test_set: + with self.assertRaises(expect_exc, msg=message) as e: + self.nslcmop_topic.new(rollback, session, indata=deepcopy(indata), kwargs=kwargs_, headers=headers) + if expect_code: + self.assertTrue(e.exception.http_code == expect_code) + if expect_text_list: + for expect_text in expect_text_list: + self.assertIn(expect_text, str(e.exception).lower(), + "Expected '{}' at exception text".format(expect_text)) + + def test_check_ns_operation_action(self): + nsrs = self.db.get_list("nsrs")[0] + session = {} + + indata = { + "member_vnf_index": "1", + "vdu_id": None, + "primitive": "touch", + "primitive_params": {"filename": "file"} + } + + self.nslcmop_topic._check_ns_operation(session, nsrs, "action", indata) + for k in indata: + indata_copy = indata.copy() + if k == "primitive_params": + continue + indata_copy[k] = "non_existing" + with self.assertRaises(EngineException) as exc_manager: + self.nslcmop_topic._check_ns_operation(session, nsrs, "action", indata_copy) + exc = exc_manager.exception + self.assertEqual(exc.http_code, HTTPStatus.BAD_REQUEST, "Engine exception bad http_code with {}". + format(indata_copy)) + + +class TestNsrTopic(unittest.TestCase): + + def setUp(self): + self.db = DbMemory() + self.fs = Mock(FsBase()) + self.fs.get_params.return_value = {"./fake/folder"} + self.fs.file_open = mock_open() + self.msg = Mock(MsgBase()) + # create class + self.nsr_topic = NsrTopic(self.db, self.fs, self.msg, None) + self.nsr_topic.check_quota = Mock(return_value=None) # skip quota + + self.db.create_list("vim_accounts", yaml.load(db_vim_accounts_text, Loader=yaml.Loader)) + self.db.create_list("nsds", yaml.load(db_nsds_text, Loader=yaml.Loader)) + self.db.create_list("vnfds", yaml.load(db_vnfds_text, Loader=yaml.Loader)) + self.db.create = Mock(return_value="created_id") + self.nsd = self.db.get_list("nsds")[0] + self.nsd_id = self.nsd["_id"] + self.nsd_project = self.nsd["_admin"]["projects_read"][0] + + self.vim = self.db.get_list("vim_accounts")[0] + self.vim_id = self.vim["_id"] + + def test_create(self): + session = {"force": False, "admin": False, "public": False, "project_id": [self.nsd_project], "method": "write"} + indata = { + "nsdId": self.nsd_id, + "nsName": "name", + "vimAccountId": self.vim_id, + "additionalParamsForVnf": [{"member-vnf-index": "1", "additionalParams": {"touch_filename": "file"}}, + {"member-vnf-index": "2", "additionalParams": {"touch_filename": "file"}}] + } + rollback = [] + headers = {} + + self.nsr_topic.new(rollback, session, indata=indata, kwargs=None, headers=headers) + + # check vnfrs and nsrs created in whatever order + created_vnfrs = [] + created_nsrs = [] + nsr_id = None + for _call in self.db.create.call_args_list: + assert len(_call[0]) >= 2, "called db.create with few parameters" + created_item = _call[0][1] + if _call[0][0] == "vnfrs": + created_vnfrs.append(created_item) + self.assertIn("member-vnf-index-ref", created_item, + "Created item must contain member-vnf-index-ref section") + if nsr_id: + self.assertEqual(nsr_id, created_item["nsr-id-ref"], "bad reference id from vnfr to nsr") + else: + nsr_id = created_item["nsr-id-ref"] + + elif _call[0][0] == "nsrs": + created_nsrs.append(created_item) + if nsr_id: + self.assertEqual(nsr_id, created_item["_id"], "bad reference id from vnfr to nsr") + else: + nsr_id = created_item["_id"] + else: + assert True, "created an unknown record {} at database".format(_call[0][0]) + + self.assertTrue(created_item["_admin"].get("projects_read"), + "Database record must contain '_amdin.projects_read'") + self.assertIn("created", created_item["_admin"], "Database record must contain '_admin.created'") + self.assertTrue(created_item["_admin"]["nsState"] == "NOT_INSTANTIATED", + "Database record must contain '_admin.nstate=NOT INSTANTIATE'") + + self.assertEqual(len(created_vnfrs), len(self.nsd["constituent-vnfd"]), + "created a mismatch number of vnfr at database") + self.assertEqual(len(created_nsrs), 1, "Only one nsrs must be created at database") + self.assertEqual(len(rollback), len(created_vnfrs) + 1, "rollback mismatch with created items at database") + + # test parameters with error + bad_id = "88d90b0c-faff-4b9f-bccd-aaaaaaaaaaaa" + test_set = ( + # TODO add "nsd" + ("nsd not found", {"nsdId": bad_id}, DbException, HTTPStatus.NOT_FOUND, ("not found", bad_id)), + # ({"vimAccountId": bad_id}, DbException, HTTPStatus.NOT_FOUND, ("not found", bad_id)), # TODO add "vim" + ("additional params not supply", {"additionalParamsForVnf.0.member-vnf-index": "k"}, EngineException, + HTTPStatus.BAD_REQUEST, None), + ) + for message, kwargs_, expect_exc, expect_code, expect_text_list in test_set: + with self.assertRaises(expect_exc, msg=message) as e: + self.nsr_topic.new(rollback, session, indata=deepcopy(indata), kwargs=kwargs_, headers=headers) + if expect_code: + self.assertTrue(e.exception.http_code == expect_code) + if expect_text_list: + for expect_text in expect_text_list: + self.assertIn(expect_text, str(e.exception).lower(), + "Expected '{}' at exception text".format(expect_text)) diff --git a/requirements.txt b/requirements.txt index 64c7079..426e430 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,4 +17,5 @@ python-keystoneclient requests git+https://osm.etsi.org/gerrit/osm/common.git#egg=osm-common git+https://osm.etsi.org/gerrit/osm/IM.git#egg=osm-im +aiohttp==0.20.2 diff --git a/test-requirements.txt b/test-requirements.txt index e52d6ac..8f9f3b4 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -11,9 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -flake8<3.0 -mock -requests -parallel-ssh -urllib3 +# flake8<3.0 +# mock +# pyangbind +pyang diff --git a/tox.ini b/tox.ini index 5654da5..ef4af53 100644 --- a/tox.ini +++ b/tox.ini @@ -14,20 +14,20 @@ # limitations under the License. [tox] -envlist = py3 +envlist = flake8, unittest toxworkdir={toxinidir}/.tox [testenv] +usedevelop = True basepython = python3 -install_command = python3 -m pip install -r requirements.txt -U {opts} {packages} +install_command = python3 -m pip install -r requirements.txt -U {opts} {packages} deps = -r{toxinidir}/test-requirements.txt -commands=python3 -m unittest discover -v [testenv:flake8] basepython = python3 deps = flake8 commands = flake8 osm_nbi/ setup.py --max-line-length 120 \ - --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp,osm_im --ignore W291,W293,E226,E402,W504 + --exclude .svn,CVS,.gz,.git,__pycache__,.tox,local,temp,osm_im,.temp-tox --ignore W291,W293,E226,E402,W504 [testenv:build] basepython = python3 @@ -35,3 +35,7 @@ deps = stdeb setuptools-version-command commands = python3 setup.py --command-packages=stdeb.command bdist_deb +[testenv:unittest] +basepython = python3 +commands = python3 -m unittest discover {toxinidir}/osm_nbi/tests -v + -- 2.17.1