From 698fb766ab97734f0e6b72405a333bec657a47a4 Mon Sep 17 00:00:00 2001 From: Michal Jagiello Date: Wed, 18 Jan 2023 13:24:23 +0000 Subject: [PATCH] [CPS] Create basic_cps test Create test to check if creating basic cps resources (dataspace, schema-set, anchor) works and it's possible to create a node on an anchor. Issue-ID: INT-2194 Signed-off-by: Michal Jagiello Change-Id: I86c5a80da65b90e2f1a228fcc7fc46a54bee92bc --- requirements.txt | 2 +- run_basic_cps.py | 21 +++ setup.cfg | 1 + src/onaptests/configuration/basic_cps_settings.py | 46 +++++++ src/onaptests/scenario/basic_cps.py | 57 ++++++++ src/onaptests/steps/onboard/cps.py | 144 +++++++++++++++++++++ .../templates/artifacts/cps/bookstore.yang | 57 ++++++++ 7 files changed, 327 insertions(+), 1 deletion(-) create mode 100644 run_basic_cps.py create mode 100644 src/onaptests/configuration/basic_cps_settings.py create mode 100644 src/onaptests/scenario/basic_cps.py create mode 100644 src/onaptests/steps/onboard/cps.py create mode 100644 src/onaptests/templates/artifacts/cps/bookstore.yang diff --git a/requirements.txt b/requirements.txt index f553825..77b1a6e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,6 @@ cryptography==38.0.4 xtesting==0.91.0 avionix>=0.4.5 openstacksdk>=0.61.0 -onapsdk==10.1.0 +onapsdk==10.3.2 jinja2>3 kubernetes>=22.6.0 diff --git a/run_basic_cps.py b/run_basic_cps.py new file mode 100644 index 0000000..53deda2 --- /dev/null +++ b/run_basic_cps.py @@ -0,0 +1,21 @@ +import logging.config +import onaptests.utils.exceptions as onap_test_exceptions +from onapsdk.configuration import settings +from onaptests.steps.onboard.cps import CreateCpsAnchorStep, CreateCpsSchemaSetStep, CreateCpsDataspaceStep, CreateCpsAnchorNodeStep + + + +if __name__ == "__main__": + # logging configuration for onapsdk, it is not requested for onaptests + # Correction requested in onapsdk to avoid having this duplicate code + logging.config.dictConfig(settings.LOG_CONFIG) + logger = logging.getLogger("Basic CPS") + + basic_cps = CreateCpsAnchorNodeStep( + cleanup=settings.CLEANUP_FLAG) + try: + basic_cps.execute() + basic_cps.cleanup() + except onap_test_exceptions.TestConfigurationException: + logger.error("Basic CPS configuration error") + basic_cps.reports_collection.generate_report() diff --git a/setup.cfg b/setup.cfg index 7362a35..a74f7ad 100644 --- a/setup.cfg +++ b/setup.cfg @@ -57,3 +57,4 @@ xtesting.testcase = cds_resource_resolution = onaptests.scenario.cds_resource_resolution:CDSResourceResolution multi_vnf_ubuntu_macro = onaptests.scenario.multi_vnf_macro:MultiVnfUbuntuMacro basic_cnf_macro = onaptests.scenario.basic_cnf_macro:BasicCnfMacro + basic_cps = onaptests.scenario.basic_cps:BasicCps diff --git a/src/onaptests/configuration/basic_cps_settings.py b/src/onaptests/configuration/basic_cps_settings.py new file mode 100644 index 0000000..bea9646 --- /dev/null +++ b/src/onaptests/configuration/basic_cps_settings.py @@ -0,0 +1,46 @@ +from .settings import * + +import json +from pathlib import Path + +from onaptests.utils.resources import get_resource_location + +CLEANUP_FLAG = True + +ANCHOR_DATA = json.dumps({ + "bookstore": { + "bookstore-name": "Chapters", + "categories": [ + { + "code": 1, + "name": "SciFi", + "books": [ + { + "title": "2001: A Space Odyssey", + "price": 5 + }, + { + "title": "Dune", + "price": 5 + } + ] + }, + { + "code": 2, + "name": "Kids", + "books": [ + { + "title": "Matilda" + } + ] + } + ] + } + }) +ANCHOR_NAME = "basic-cps-test-anchor" +DATASPACE_NAME = "basic-cps-test-dataspace" +SCHEMA_SET_NAME = "basic-cps-test-schema-set" +SCHEMA_SET_FILE = Path(get_resource_location("templates/artifacts/cps/bookstore.yang")) + +SERVICE_NAME = "Basic CPS test" +SERVICE_COMPONENTS = "CPS" diff --git a/src/onaptests/scenario/basic_cps.py b/src/onaptests/scenario/basic_cps.py new file mode 100644 index 0000000..670972b --- /dev/null +++ b/src/onaptests/scenario/basic_cps.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +"""Basic CPS test case.""" +import logging +import time +from xtesting.core import testcase +from onapsdk.configuration import settings +from onapsdk.exceptions import SDKException +from onaptests.steps.onboard.service import YamlTemplateServiceOnboardStep +from onaptests.utils.exceptions import OnapTestException + +class BasicCps(testcase.TestCase): + """Create CPS resources: + - dataspace + - schemaset + - anchor + And create a node. Use bookstore YANG model (available on CPS repository + https://github.com/onap/cps/blob/master/cps-service/src/test/resources/bookstore.yang). + At the end delete what's available to be deleted. + + """ + + __logger = logging.getLogger(__name__) + + def __init__(self, **kwargs): + """Init Basic CPS.""" + if "case_name" not in kwargs: + kwargs["case_name"] = 'basic_cps' + super().__init__(**kwargs) + self.__logger.debug("BasicCps init started") + # self.test = YamlTemplateServiceOnboardStep( # To be created + # cleanup=settings.CLEANUP_FLAG) + self.start_time = None + self.stop_time = None + self.result = 0 + + def run(self): + """Run basic_cps and create some CPS resources""" + self.start_time = time.time() + self.__logger.debug("start time") + try: + self.test.execute() + self.test.cleanup() + self.__logger.info("Basic CPS test passed") + self.result = 100 + except OnapTestException as exc: + self.result = 0 + self.__logger.exception(exc.error_message) + except SDKException: + self.result = 0 + self.__logger.exception("SDK Exception") + finally: + self.stop_time = time.time() + + def clean(self): + """Clean Additional resources if needed.""" + self.__logger.info("Generate Test report") + self.test.reports_collection.generate_report() diff --git a/src/onaptests/steps/onboard/cps.py b/src/onaptests/steps/onboard/cps.py new file mode 100644 index 0000000..1c59086 --- /dev/null +++ b/src/onaptests/steps/onboard/cps.py @@ -0,0 +1,144 @@ +# http://www.apache.org/licenses/LICENSE-2.0 +"""CPS onboard module.""" +from abc import ABC + +from onapsdk.configuration import settings +from onapsdk.cps import Anchor, Dataspace, SchemaSet + +from ..base import BaseStep + + +class CpsBaseStep(BaseStep, ABC): + """Abstract CPS base step.""" + + @property + def component(self) -> str: + """Component name.""" + return "CPS" + + +class CreateCpsDataspaceStep(CpsBaseStep): + """Step to create a dataspace.""" + + @property + def description(self) -> str: + """Step description.""" + return "Create CPS dataspace." + + @BaseStep.store_state + def execute(self) -> None: + """Create a dataspace.""" + super().execute() + Dataspace.create(settings.DATASPACE_NAME) + + @BaseStep.store_state(cleanup=True) + def cleanup(self) -> None: + """Delete created dataspace.""" + dataspace: Dataspace = Dataspace(settings.DATASPACE_NAME) + dataspace.delete() + super().cleanup() + + +class CreateCpsSchemaSetStep(CpsBaseStep): + """Step to check schema-set creation.""" + + def __init__(self, cleanup: bool = False) -> None: + """Initialize step. + + Substeps: + - CreateCpsDataspaceStep. + """ + super().__init__(cleanup) + self.add_step(CreateCpsDataspaceStep(cleanup)) + + @property + def description(self) -> str: + """Step description.""" + return "Create CPS bookstore schema set" + + @BaseStep.store_state + def execute(self) -> None: + """Get dataspace created on substep and create schema-set.""" + super().execute() + dataspace: Dataspace = Dataspace(settings.DATASPACE_NAME) + with settings.SCHEMA_SET_FILE.open("rb") as schema_set_file: + dataspace.create_schema_set(settings.SCHEMA_SET_NAME, schema_set_file) + + @BaseStep.store_state(cleanup=True) + def cleanup(self) -> None: + """Delete created schema-set.""" + dataspace: Dataspace = Dataspace(settings.DATASPACE_NAME) + schema_set = dataspace.get_schema_set(settings.SCHEMA_SET_NAME) + schema_set.delete() + super().cleanup() + + +class CreateCpsAnchorStep(CpsBaseStep): + """Step to create an anchor.""" + + def __init__(self, cleanup: bool = False) -> None: + """Initialize step. + + Substeps: + - CreateCpsSchemaSetStep. + """ + super().__init__(cleanup) + self.add_step(CreateCpsSchemaSetStep(cleanup)) + + @property + def description(self) -> str: + """Step description.""" + return "Create CPS anchor" + + @BaseStep.store_state + def execute(self) -> None: + """Create anchor. + + Get dataspace and schema-set created substeps and create anchor. + """ + super().execute() + dataspace: Dataspace = Dataspace(settings.DATASPACE_NAME) + schema_set: SchemaSet = dataspace.get_schema_set(settings.SCHEMA_SET_NAME) + dataspace.create_anchor(schema_set, settings.ANCHOR_NAME) + + @BaseStep.store_state(cleanup=True) + def cleanup(self) -> None: + """Delete an anchor.""" + dataspace: Dataspace = Dataspace(settings.DATASPACE_NAME) + anchor: Anchor = dataspace.get_anchor(settings.ANCHOR_NAME) + anchor.delete() + super().cleanup() + + +class CreateCpsAnchorNodeStep(CpsBaseStep): + """Step to check node on anchor creation.""" + + def __init__(self, cleanup: bool = False) -> None: + """Initialize step. + + Substeps: + - CreateCpsAnchorStep. + """ + super().__init__(cleanup) + self.add_step(CreateCpsAnchorStep(cleanup)) + + @property + def description(self) -> str: + """Step description.""" + return "Create CPS anchor node" + + @BaseStep.store_state + def execute(self) -> None: + """Create a node on an anchor created on substep.""" + super().execute() + dataspace: Dataspace = Dataspace(settings.DATASPACE_NAME) + anchor: Anchor = dataspace.get_anchor(settings.ANCHOR_NAME) + anchor.create_node(settings.ANCHOR_DATA) + + @BaseStep.store_state(cleanup=True) + def cleanup(self) -> None: + """Delete nodes.""" + dataspace: Dataspace = Dataspace(settings.DATASPACE_NAME) + anchor: Anchor = dataspace.get_anchor(settings.ANCHOR_NAME) + anchor.delete_nodes("/") + super().cleanup() diff --git a/src/onaptests/templates/artifacts/cps/bookstore.yang b/src/onaptests/templates/artifacts/cps/bookstore.yang new file mode 100644 index 0000000..af8ba77 --- /dev/null +++ b/src/onaptests/templates/artifacts/cps/bookstore.yang @@ -0,0 +1,57 @@ +module stores { + yang-version 1.1; + namespace "org:onap:ccsdk:sample"; + + prefix book-store; + + revision "2020-09-15" { + description + "Sample Model"; + } + + typedef year { + type uint16 { + range "1000..9999"; + } + } + + container bookstore { + + leaf bookstore-name { + type string; + } + + list categories { + + key "code"; + + leaf code { + type string; + } + + leaf name { + type string; + } + + list books { + key title; + + leaf title { + type string; + } + leaf lang { + type string; + } + leaf-list authors { + type string; + } + leaf pub_year { + type year; + } + leaf price { + type uint64; + } + } + } + } +} \ No newline at end of file -- 2.16.6