From 7b81da666387932a265b3bf38dd449449d8dcdb9 Mon Sep 17 00:00:00 2001 From: Fiete Ostkamp Date: Sat, 7 Feb 2026 10:22:26 +0100 Subject: [PATCH] Enhance tracing context for pythonsdk-tests - define spans in central places to connect the disconnected traces that are now mostly being produced by the http requests the tests are making - fix tox issue in the pipeline by replacing coala-bears linter package which was last updated in 2017 - fix linter warnings Issue-ID: INT-2345 Change-Id: I53fd7db0c453cb2e3ce58cf69fbac7a30b2a8631 Signed-off-by: Fiete Ostkamp --- run_test.py | 35 +++++- src/onaptests/__init__.py | 4 + src/onaptests/scenario/scenario_base.py | 89 ++++++++------ src/onaptests/steps/base.py | 198 +++++++++++++++++++------------- src/onaptests/steps/onboard/service.py | 93 +++++++++++---- tox.ini | 44 +++---- 6 files changed, 300 insertions(+), 163 deletions(-) diff --git a/run_test.py b/run_test.py index 0cd28c0..a00580e 100644 --- a/run_test.py +++ b/run_test.py @@ -1,3 +1,4 @@ +"""Test runner module for ONAP Python SDK tests.""" import configparser import importlib import importlib.util @@ -6,9 +7,12 @@ import os import sys import glob +from opentelemetry import trace from onapsdk.exceptions import ModuleError import onaptests.utils.exceptions as onap_test_exceptions +tracer = trace.get_tracer(__name__) + SETTING_FILE_EXCEPTIONS = { "clearwater_ims": "clearwater_ims_nomulticloud_settings", "basic_cnf": "basic_cnf_yaml_settings", @@ -23,7 +27,9 @@ MODULES_TO_RELOAD = [ "onaptests" ] + def get_entrypoints(): + """Get entry points from setup.cfg.""" config = configparser.ConfigParser() config.read('setup.cfg') entry_points = config['options.entry_points']['xtesting.testcase'] @@ -39,10 +45,12 @@ def get_entrypoints(): } return entry_points_result + def check_scenarios(scenarios, entry_points): + """Check that all scenarios are registered in entry points.""" path = importlib.util.find_spec(scenarios.__name__).submodule_search_locations modules = glob.glob(f"{path._path[0]}/*.py") - all_mods = [ os.path.basename(f)[:-3] for f in modules if os.path.isfile(f) and not f.endswith('__init__.py')] + all_mods = [os.path.basename(f)[:-3] for f in modules if os.path.isfile(f) and not f.endswith('__init__.py')] for mod_name in all_mods: full_mod_name = f"{scenarios.__name__}.{mod_name}" if mod_name != "scenario_base": @@ -55,12 +63,22 @@ def check_scenarios(scenarios, entry_points): raise onap_test_exceptions.TestConfigurationException( f"Scenario defined in {full_mod_name}.py is not added to setup.cfg file") + def run_test(test_name, validation, force_cleanup, entry_point): - print(f"Configuring {test_name} test") - settings_env = "ONAP_PYTHON_SDK_SETTINGS" - if force_cleanup: - validation_env = "PYTHON_SDK_TESTS_FORCE_CLEANUP" - os.environ[validation_env] = "True" + """Run a single test scenario.""" + with tracer.start_as_current_span( + f"test.{test_name}", + attributes={ + "test.name": test_name, + "test.validation": validation, + "test.force_cleanup": force_cleanup + } + ) as root_span: + print(f"Configuring {test_name} test") + settings_env = "ONAP_PYTHON_SDK_SETTINGS" + if force_cleanup: + validation_env = "PYTHON_SDK_TESTS_FORCE_CLEANUP" + os.environ[validation_env] = "True" setting_file_name = f"{test_name}_settings" if test_name in SETTING_FILE_EXCEPTIONS: @@ -98,9 +116,12 @@ def run_test(test_name, validation, force_cleanup, entry_point): if validation: logger.info(f"Validating {test_name} test") test_instance.validate() + root_span.set_attribute("test.result", "success") return scenarios + def validate_scenario_base_class(test_name, scenario, scenarios): + """Validate that scenario class properly inherits from ScenarioBase.""" has_scenario_base = False if test_name != scenario.case_name: raise onap_test_exceptions.TestConfigurationException( @@ -119,6 +140,7 @@ def validate_scenario_base_class(test_name, scenario, scenarios): raise onap_test_exceptions.TestConfigurationException( f"[{test_name}] {scenario.__class__.__name__} class does not inherit from ScenarioBase") + def main(argv): """Script is used to run one or all the tests. @@ -166,5 +188,6 @@ def main(argv): entry_point = entry_points[test_name] run_test(test_name, validation, force_cleanup, entry_point) + if __name__ == "__main__": main(sys.argv[1:]) diff --git a/src/onaptests/__init__.py b/src/onaptests/__init__.py index 9b917f6..fb3f6d3 100644 --- a/src/onaptests/__init__.py +++ b/src/onaptests/__init__.py @@ -1 +1,5 @@ """onaptests package.""" + +from opentelemetry import trace + +tracer = trace.get_tracer(__name__) diff --git a/src/onaptests/scenario/scenario_base.py b/src/onaptests/scenario/scenario_base.py index f1b4455..7158906 100644 --- a/src/onaptests/scenario/scenario_base.py +++ b/src/onaptests/scenario/scenario_base.py @@ -1,6 +1,8 @@ +"""Base scenario classes for ONAP test scenarios.""" import logging import time +from opentelemetry import trace from onapsdk.configuration import settings from onapsdk.exceptions import SDKException, SettingsError from xtesting.core import testcase @@ -9,6 +11,8 @@ from onaptests.steps.base import BaseStep, YamlTemplateBaseStep from onaptests.utils.exceptions import (OnapTestException, TestConfigurationException) +tracer = trace.get_tracer(__name__) + class ScenarioBase(testcase.TestCase): """Scenario base class.""" @@ -33,37 +37,57 @@ class ScenarioBase(testcase.TestCase): self.test: BaseStep = None def run(self, **kwargs): - """Run scenario and cleanup resources afterwards""" - self.start_time = time.time() - try: - for test_phase in (self.test.execute, self.test.cleanup): - phase_name = test_phase.__name__ - try: - if (phase_name == "cleanup" and settings.CLEANUP_FLAG and - settings.CLEANUP_ACTIVITY_TIMER > 0): - time.sleep(settings.CLEANUP_ACTIVITY_TIMER) - self.__logger.info("%s %s Phase Started", - self.scenario_name, phase_name.title()) - test_phase() - self.result += 50 - except OnapTestException as exc: - self.__logger.exception("Test Exception %s on %s", str(exc), phase_name) - self.__logger.info("ROOT CAUSE") - self.__logger.info(exc.root_cause) - except SDKException as exc: - self.__logger.exception("SDK Exception %s on %s", str(exc), phase_name) - self.__logger.info("ROOT CAUSE") - self.__logger.info(str(exc)) - except Exception as exc: - self.__logger.exception("General Exception %s on %s", str(exc), phase_name) - if self.general_exception: - exc = ExceptionGroup("General Exceptions", [self.general_exception, exc]) # noqa - self.general_exception = exc - finally: - self.stop_time = time.time() - self.__logger.info(f"{self.scenario_name} Execution {self.result}% Completed") - if self.general_exception: - raise self.general_exception + """Run scenario and cleanup resources afterwards.""" + with tracer.start_as_current_span( + f"scenario.{self.case_name}", + attributes={ + "scenario.name": self.scenario_name, + "scenario.case_name": self.case_name + } + ) as scenario_span: + self.start_time = time.time() + try: + for test_phase in (self.test.execute, self.test.cleanup): + phase_name = test_phase.__name__ + with tracer.start_as_current_span( + f"phase.{phase_name}", + attributes={"phase.name": phase_name} + ) as phase_span: + try: + if (phase_name == "cleanup" and settings.CLEANUP_FLAG and + settings.CLEANUP_ACTIVITY_TIMER > 0): + time.sleep(settings.CLEANUP_ACTIVITY_TIMER) + self.__logger.info("%s %s Phase Started", + self.scenario_name, phase_name.title()) + test_phase() + self.result += 50 + phase_span.set_attribute("phase.result", "success") + except OnapTestException as exc: + phase_span.record_exception(exc) + phase_span.set_attribute("phase.result", "failed") + self.__logger.exception("Test Exception %s on %s", str(exc), phase_name) + self.__logger.info("ROOT CAUSE") + self.__logger.info(exc.root_cause) + except SDKException as exc: + phase_span.record_exception(exc) + phase_span.set_attribute("phase.result", "failed") + self.__logger.exception("SDK Exception %s on %s", str(exc), phase_name) + self.__logger.info("ROOT CAUSE") + self.__logger.info(str(exc)) + except Exception as exc: + phase_span.record_exception(exc) + phase_span.set_attribute("phase.result", "failed") + self.__logger.exception("General Exception %s on %s", str(exc), phase_name) + if self.general_exception: + exc = ExceptionGroup("General Exceptions", [self.general_exception, exc]) # noqa + self.general_exception = exc + finally: + self.stop_time = time.time() + scenario_span.set_attribute("scenario.result_percentage", self.result) + scenario_span.set_attribute("scenario.duration", self.stop_time - self.start_time) + self.__logger.info(f"{self.scenario_name} Execution {self.result}% Completed") + if self.general_exception: + raise self.general_exception def clean(self): """Clean Additional resources if needed.""" @@ -72,13 +96,13 @@ class ScenarioBase(testcase.TestCase): def validate(self): """Validate implementation of the scenario.""" - self._validate_service_details() self.test.validate_step_implementation() self.test.validate_execution() self.test.validate_cleanup() def _validate_service_details(self): + """Validate that service details are properly configured.""" self._check_setting("SERVICE_NAME") self._check_setting("SERVICE_DETAILS") @@ -101,6 +125,7 @@ class BaseScenarioStep(BaseStep): @BaseStep.store_state def execute(self) -> None: + """Execute base scenario step.""" super().execute() diff --git a/src/onaptests/steps/base.py b/src/onaptests/steps/base.py index 9356f4d..3d8c1f4 100644 --- a/src/onaptests/steps/base.py +++ b/src/onaptests/steps/base.py @@ -1,3 +1,4 @@ +"""Base step classes for ONAP test scenarios.""" import functools import itertools import logging @@ -7,6 +8,7 @@ import time from abc import ABC, abstractmethod from typing import Iterator, List, Optional +from opentelemetry import trace from onapsdk.aai.business import Customer, ServiceInstance, ServiceSubscription from onapsdk.configuration import settings from onapsdk.exceptions import SDKException, SettingsError @@ -19,6 +21,8 @@ from onaptests.utils.exceptions import (OnapTestException, SubstepExecutionExceptionGroup, TestConfigurationException) +tracer = trace.get_tracer(__name__) + # pylint: disable=protected-access IF_FORCE_CLEANUP = "PYTHON_SDK_TESTS_FORCE_CLEANUP" @@ -41,85 +45,111 @@ class StoreStateHandler(ABC): self._state_execute = True initial_exception = None error_reason = [] - try: - execution_status: Optional[ReportStepStatus] = ReportStepStatus.FAIL - if cleanup: - self._start_cleanup_time = time.time() - try: - if (self._cleanup and self._state_execute and - (not self.has_substeps or self._substeps_executed) and - (self._is_validation_only or - self.check_preconditions(cleanup=True))): + + operation = "cleanup" if cleanup else "execute" + with tracer.start_as_current_span( + f"step.{operation}.{self.name}", + attributes={ + "step.name": self.name, + "step.component": self.component, + "step.description": self.description, + "step.operation": operation, + "step.nesting_level": self._nesting_level, + "step.is_root": self.is_root + } + ) as step_span: + try: + execution_status: Optional[ReportStepStatus] = ReportStepStatus.FAIL + if cleanup: + self._start_cleanup_time = time.time() + try: + if (self._cleanup and self._state_execute and + (not self.has_substeps or self._substeps_executed) and + (self._is_validation_only or + self.check_preconditions(cleanup=True))): + self._log_execution_state("START", cleanup) + if not self._is_validation_only or self._is_force_cleanup: + fun(self, *args, **kwargs) + self._cleaned_up = True + execution_status = ReportStepStatus.PASS + else: + execution_status = ReportStepStatus.NOT_EXECUTED + except (OnapTestException, SDKException) as test_exc: + initial_exception = test_exc + finally: + self._log_execution_state(execution_status.name, cleanup) + self._cleanup_substeps() + if initial_exception: + new_exception = initial_exception + initial_exception = None + raise new_exception + else: + if self._is_validation_only or self.check_preconditions(): self._log_execution_state("START", cleanup) - if not self._is_validation_only or self._is_force_cleanup: + self._execute_substeps() + if not self._is_validation_only: fun(self, *args, **kwargs) - self._cleaned_up = True execution_status = ReportStepStatus.PASS + self._executed = True else: execution_status = ReportStepStatus.NOT_EXECUTED - except (OnapTestException, SDKException) as test_exc: - initial_exception = test_exc - finally: - self._log_execution_state(execution_status.name, cleanup) - self._cleanup_substeps() + except SubstepExecutionException as substep_exc: + step_span.record_exception(substep_exc) + if not cleanup: + execution_status = ReportStepStatus.NOT_EXECUTED if initial_exception: - new_exception = initial_exception - initial_exception = None - raise new_exception - else: - if self._is_validation_only or self.check_preconditions(): - self._log_execution_state("START", cleanup) - self._execute_substeps() - if not self._is_validation_only: - fun(self, *args, **kwargs) - execution_status = ReportStepStatus.PASS - self._executed = True + substep_exc = OnapTestExceptionGroup("Cleanup Exceptions", + [initial_exception, substep_exc]) + error_reason = substep_exc.root_cause + raise substep_exc + except (OnapTestException, SDKException) as test_exc: + step_span.record_exception(test_exc) + if initial_exception: + test_exc = OnapTestExceptionGroup("Cleanup Exceptions", + [initial_exception, test_exc]) + if isinstance(test_exc, OnapTestException): + error_reason = test_exc.root_cause else: - execution_status = ReportStepStatus.NOT_EXECUTED - except SubstepExecutionException as substep_exc: - if not cleanup: - execution_status = ReportStepStatus.NOT_EXECUTED - if initial_exception: - substep_exc = OnapTestExceptionGroup("Cleanup Exceptions", - [initial_exception, substep_exc]) - error_reason = substep_exc.root_cause - raise substep_exc - except (OnapTestException, SDKException) as test_exc: - if initial_exception: - test_exc = OnapTestExceptionGroup("Cleanup Exceptions", - [initial_exception, test_exc]) - if isinstance(test_exc, OnapTestException): - error_reason = test_exc.root_cause - else: - error_reason = [str(test_exc)] - raise test_exc - finally: - if not cleanup: - self._log_execution_state(execution_status.name, cleanup) - if cleanup: - self._cleanup_report = Report( - step_description=self._step_title(cleanup), - step_execution_status=execution_status, - step_execution_duration=time.time() - self._start_cleanup_time, - step_component=self.component, - step_error_reason=error_reason - ) - else: - if not self._start_execution_time: - if execution_status != ReportStepStatus.NOT_EXECUTED: - self._logger.error("No execution start time saved for %s step. " - "Fix it by call `super.execute()` " - "in step class `execute()` method definition", - self.name) - self._start_execution_time = time.time() - self._execution_report = Report( - step_description=self._step_title(cleanup), - step_execution_status=(execution_status if execution_status else - ReportStepStatus.FAIL), - step_execution_duration=time.time() - self._start_execution_time, - step_component=self.component, - step_error_reason=error_reason - ) + error_reason = [str(test_exc)] + raise test_exc + finally: + if not cleanup: + self._log_execution_state(execution_status.name, cleanup) + + # Set span attributes for final status + if execution_status: + step_span.set_attribute("step.status", execution_status.name) + if error_reason: + step_span.set_attribute("step.error_reasons", str(error_reason)) + + if cleanup: + duration = time.time() - self._start_cleanup_time + step_span.set_attribute("step.duration", duration) + self._cleanup_report = Report( + step_description=self._step_title(cleanup), + step_execution_status=execution_status, + step_execution_duration=duration, + step_component=self.component, + step_error_reason=error_reason + ) + else: + if not self._start_execution_time: + if execution_status != ReportStepStatus.NOT_EXECUTED: + self._logger.error("No execution start time saved for %s step. " + "Fix it by call `super.execute()` " + "in step class `execute()` method definition", + self.name) + self._start_execution_time = time.time() + duration = time.time() - self._start_execution_time + step_span.set_attribute("step.duration", duration) + self._execution_report = Report( + step_description=self._step_title(cleanup), + step_execution_status=(execution_status if execution_status else + ReportStepStatus.FAIL), + step_execution_duration=duration, + step_component=self.component, + step_error_reason=error_reason + ) wrapper._is_wrapped = True return wrapper @@ -374,7 +404,7 @@ class BaseStep(StoreStateHandler, ABC): return True def _execute_substeps(self) -> None: - """Step's action execution. + """Execute step's action. Run all substeps action before it's own action. Override this method and remember to call `super().execute()` before. @@ -388,7 +418,7 @@ class BaseStep(StoreStateHandler, ABC): if step._is_optional: self._logger.info("Step is optional, error ignored, continue test execution") elif step._break_on_error: - raise SubstepExecutionException("", substep_err) # noqa: W0707 + raise SubstepExecutionException("", substep_err) # noqa: W0707 else: substep_exceptions.append(substep_err) if self._steps: @@ -416,7 +446,7 @@ class BaseStep(StoreStateHandler, ABC): step._default_cleanup_handler() except (OnapTestException, SDKException) as substep_err: try: - raise SubstepExecutionException("", substep_err) # noqa: W0707 + raise SubstepExecutionException("", substep_err) # noqa: W0707 except Exception as e: exceptions_to_raise.append(e) if len(exceptions_to_raise) > 0: @@ -425,14 +455,14 @@ class BaseStep(StoreStateHandler, ABC): raise SubstepExecutionExceptionGroup("", exceptions_to_raise) def execute(self) -> None: - """Step's execute. + """Execute step. Must be implemented in the steps with store_state decorator """ def cleanup(self) -> None: - """Step's cleanup. + """Clean up step. Not all steps has to have cleanup method @@ -456,7 +486,6 @@ class BaseStep(StoreStateHandler, ABC): def validate_step_implementation(self): """Validate is step addes store_state decorators.""" - if not getattr(self.execute, "_is_wrapped", False): raise TestConfigurationException( f"{self._step_title()} - store_state decorator not present in execute() method") @@ -468,7 +497,6 @@ class BaseStep(StoreStateHandler, ABC): def validate_execution(self): """Validate if each step was executed by decorator.""" - if self._is_validation_only: self._log_execution_state(f"VALIDATE EXECUTION [{self._state_execute}]") if not self._state_execute: @@ -479,7 +507,6 @@ class BaseStep(StoreStateHandler, ABC): def validate_cleanup(self): """Validate if each step was cleaned by decorator.""" - if self._is_validation_only: for step in reversed(self._steps): step.validate_cleanup() @@ -496,7 +523,6 @@ class YamlTemplateBaseStep(BaseStep, ABC): def __init__(self, cleanup: bool): """Initialize step.""" - super().__init__(cleanup=cleanup) self._service_instance: ServiceInstance = None self._service_subscription: ServiceSubscription = None @@ -588,18 +614,28 @@ class DelayStep(BaseStep): """Delay step -- useful if some delay between two steps is needed.""" def __init__(self, delay: int, break_on_error=True): + """Initialize delay step. + + Args: + delay (int): Delay duration in seconds + break_on_error (bool): Whether to break on error + + """ super().__init__(BaseStep.HAS_NO_CLEANUP, break_on_error) self.delay: int = delay @property def description(self) -> str: + """Step description.""" return f"Wait for {self.delay} seconds." @property def component(self) -> str: + """Component name.""" return "Python ONAP SDK" @BaseStep.store_state def execute(self): + """Execute delay step.""" super().execute() time.sleep(self.delay) diff --git a/src/onaptests/steps/onboard/service.py b/src/onaptests/steps/onboard/service.py index a35b4da..c28ff8b 100644 --- a/src/onaptests/steps/onboard/service.py +++ b/src/onaptests/steps/onboard/service.py @@ -1,8 +1,10 @@ +"""Service onboarding step module.""" import time from typing import Any, Dict, Iterator from urllib.parse import urlencode import mysql.connector as mysql +from opentelemetry import trace from onapsdk.aai.service_design_and_creation import Model from onapsdk.configuration import settings from onapsdk.exceptions import InvalidResponse, ResourceNotFound @@ -24,6 +26,8 @@ from ..base import BaseStep, YamlTemplateBaseStep from .pnf import YamlTemplatePnfOnboardStep from .vf import YamlTemplateVfOnboardStep +tracer = trace.get_tracer(__name__) + class YamlTemplateServiceOnboardStep(YamlTemplateBaseStep): """Service onboard using YAML template step.""" @@ -54,6 +58,15 @@ class YamlTemplateServiceOnboardStep(YamlTemplateBaseStep): return "SDC" def check_preconditions(self, cleanup=False) -> bool: + """Check preconditions before step execution. + + Args: + cleanup (bool): Whether this is cleanup phase + + Returns: + bool: True if preconditions are met, False otherwise + + """ if not super().check_preconditions(cleanup): return False if cleanup: @@ -112,20 +125,37 @@ class YamlTemplateServiceOnboardStep(YamlTemplateBaseStep): self.yaml_template[self.service_name]["instantiation_type"]) else: instantiation_type: ServiceInstantiationType = ServiceInstantiationType.A_LA_CARTE - try: - service: Service = Service.get_by_name(name=self.service_name) - if service.distributed: - return - except ResourceNotFound: + + with tracer.start_as_current_span( + "sdc.service.get_or_create", + attributes={"service.name": self.service_name} + ) as sdc_span: + try: + service: Service = Service.get_by_name(name=self.service_name) + sdc_span.set_attribute("service.existed", True) + sdc_span.set_attribute("service.distributed", service.distributed) + if service.distributed: + return + except ResourceNotFound: + sdc_span.set_attribute("service.existed", False) self._logger.info("before service create") service = Service.create(name=self.service_name, instantiation_type=instantiation_type, category=category) self._logger.info("after service create") + sdc_span.set_attribute("service.instantiation_type", instantiation_type.value) self.declare_resources(service) self.assign_properties(service) + if service.lifecycle_state != LifecycleState.CERTIFIED: - service.lifecycle_operation(LifecycleOperation.CERTIFY) + with tracer.start_as_current_span( + "sdc.service.certify", + attributes={ + "service.name": self.service_name, + "service.lifecycle_state": service.lifecycle_state.value + } + ): + service.lifecycle_operation(LifecycleOperation.CERTIFY) def declare_resources(self, service: Service) -> None: """Declare resources. @@ -193,13 +223,21 @@ class YamlTemplateServiceOnboardStep(YamlTemplateBaseStep): @YamlTemplateBaseStep.store_state(cleanup=True) def cleanup(self) -> None: """Cleanup service onboard step.""" - try: - service: Service = Service.get_by_name(name=self.service_name) - if service.lifecycle_state == LifecycleState.CERTIFIED: - service.archive() - service.delete() - except ResourceNotFound: - self._logger.info(f"Service {self.service_name} not found") + with tracer.start_as_current_span( + "sdc.service.delete", + attributes={"service.name": self.service_name} + ) as cleanup_span: + try: + service: Service = Service.get_by_name(name=self.service_name) + cleanup_span.set_attribute("service.found", True) + cleanup_span.set_attribute("service.lifecycle_state", service.lifecycle_state.value) + if service.lifecycle_state == LifecycleState.CERTIFIED: + service.archive() + service.delete() + cleanup_span.set_attribute("service.deleted", True) + except ResourceNotFound: + cleanup_span.set_attribute("service.found", False) + self._logger.info(f"Service {self.service_name} not found") super().cleanup() @@ -264,16 +302,24 @@ class YamlTemplateServiceDistributionStep(YamlTemplateBaseStep): def execute(self): """Distribute service.""" super().execute() - service: Service = Service.get_by_name(name=self.service_name) - if service: - if not service.distributed: - service.distribute() - self._logger.info(f"Service {self.service_name} distributed successfully.") + with tracer.start_as_current_span( + "sdc.service.distribute", + attributes={"service.name": self.service_name} + ) as dist_span: + service: Service = Service.get_by_name(name=self.service_name) + if service: + dist_span.set_attribute("service.found", True) + if not service.distributed: + dist_span.set_attribute("service.already_distributed", False) + service.distribute() + self._logger.info(f"Service {self.service_name} distributed successfully.") + else: + dist_span.set_attribute("service.already_distributed", True) + self._logger.info(f"Service {self.service_name} is already distributed.") else: - self._logger.info(f"Service {self.service_name} is already distributed.") - else: - raise onap_test_exceptions.OnapTestException(f"Service {self.service_name} " - f"not found for distribution.") + dist_span.set_attribute("service.found", False) + raise onap_test_exceptions.OnapTestException(f"Service {self.service_name} " + f"not found for distribution.") class BaseServiceDistributionComponentCheckStep(BaseStep): @@ -361,7 +407,7 @@ class VerifyServiceDistributionInAaiStep(BaseServiceDistributionComponentCheckSt """Check service distribution in AAI step.""" class ModelWithGet(Model): - """"Workaround to fix """ + """Workaround to fix.""" @classmethod def get_all(cls, @@ -561,7 +607,6 @@ class VerifyServiceDistributionStatusStep(BaseServiceDistributionComponentCheckS notified_module (str): Name of notified module component_name (str): Name of the module's component """ - super().__init__( component_name=component_name, break_on_error=False, load_model=False) self.component_id = notified_module diff --git a/tox.ini b/tox.ini index 2292c42..08075a5 100644 --- a/tox.ini +++ b/tox.ini @@ -5,51 +5,55 @@ skipsdist = true requires = pip >= 8 [testenv] -basepython = python3.9 +basepython = python3.10 allowlist_externals = git /bin/sh sh /bin/bash bash -deps = - pyyaml == 3.13 - bandit == 1.3 - coala-bears - nodeenv + xargs [testenv:json] +deps = +skip_install = True commands_pre = /bin/sh -c "git --no-pager diff HEAD HEAD^ --name-only '*.json' > /tmp/.coalist_json" commands = -# '\ ' at the end of command is needed for a case where above command returns empty list (it adds empty file -# parameter to '--files' opt - /bin/bash -c "coala --non-interactive --disable-caching --no-autoapply-warn json --files $( /dev/null" [testenv:yaml] +deps = + yamllint +skip_install = True commands_pre = /bin/sh -c "git --no-pager diff HEAD HEAD^ --name-only '*.yaml' '*.yml' > /tmp/.coalist_yaml" commands = -# '\ ' at the end of command is needed for a case where above command returns empty list (it adds empty file -# parameter to '--files' opt - /bin/bash -c "coala --non-interactive --disable-caching --no-autoapply-warn yaml --files $( /tmp/.coalist_py" commands = - /bin/bash -c "coala --non-interactive --disable-caching --no-autoapply-warn py --files $( /tmp/.coalist_md" commands = - /bin/bash -c "coala --non-interactive --disable-caching --no-autoapply-warn md --files $(