summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHansen, Tony (th1395) <th1395@att.com>2021-06-22 21:12:32 +0000
committerHansen, Tony (th1395) <th1395@att.com>2021-07-01 16:42:05 +0000
commit876d17be6b1916c08fb36edcdf924859cb04e3cc (patch)
tree0ca229505a333fa20392a3cec411fa34782ffecf
parent1002e423a67cc4c22846ffc333b8027230e55dcb (diff)
support local config and policy files
* DCAEGEN2-2733/DCAEGEN2-2753 - onap-dcae-cbs-docker-client support local config and policy files Support $CBS_CLIENT_CONFIG_PATH and $CBS_CLIENT_POLICY_PATH, Default paths are /app-config/application_config.yaml and /etc/policies/policies.json. If files are missing or malformed, drop back to the current behavior. Change-Id: Iba2484f6be7fc54e412f7de302bb79a4d7bfde17 Signed-off-by: Hansen, Tony (th1395) <th1395@att.com> Issue-ID: DCAEGEN2-2733 Issue-ID: DCAEGEN2-2753 Signed-off-by: Hansen, Tony (th1395) <th1395@att.com>
-rw-r--r--onap-dcae-cbs-docker-client/Changelog.md14
-rw-r--r--onap-dcae-cbs-docker-client/onap_dcae_cbs_docker_client/client.py137
-rw-r--r--onap-dcae-cbs-docker-client/onap_dcae_cbs_docker_client/exceptions.py6
-rw-r--r--onap-dcae-cbs-docker-client/pom.xml2
-rw-r--r--onap-dcae-cbs-docker-client/setup.py4
-rw-r--r--onap-dcae-cbs-docker-client/tests/conftest.py7
-rw-r--r--onap-dcae-cbs-docker-client/tests/test_client.py316
-rw-r--r--onap-dcae-cbs-docker-client/tox.ini7
-rw-r--r--scripts/mvn-phase-lib.sh20
9 files changed, 470 insertions, 43 deletions
diff --git a/onap-dcae-cbs-docker-client/Changelog.md b/onap-dcae-cbs-docker-client/Changelog.md
index c16950d..c70aff4 100644
--- a/onap-dcae-cbs-docker-client/Changelog.md
+++ b/onap-dcae-cbs-docker-client/Changelog.md
@@ -4,16 +4,22 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
-## [2.1.2] - 05/13/2021
+## [2.2.0] 2021/06/22
+* DCAEGEN2-2733/DCAEGEN2-2753 - onap-dcae-cbs-docker-client support local config and policy files
+ Support $CBS_CLIENT_CONFIG_PATH and $CBS_CLIENT_POLICY_PATH,
+ Default paths are /app-config/application_config.yaml and /etc/policies/policies.json.
+ If files are missing or malformed, drop back to the current behavior.
+
+## [2.1.2] - 2021/05/13
* Add service for envs present in configuration
-## [2.1.1] - 04/27/2020
+## [2.1.1] - 2020/04/27
* Bug fix DCAEGEN2-2213 ConnectionError exception is lost when CBSUnreachable is raised
-## [2.1.0] - 6/24/2019
+## [2.1.0] - 2019/6/24
* Add support for connecting to the CBS if it is running as HTTPS instead of HTTP
-## [2.0.0] - 6/19/2019
+## [2.0.0] - 2019/6/19
* The env variable CONFIG_BINDING_SERVICE now has a different meaning per DCAEGEN2-1537. Specifically this variable now holds a resolvable hostname for the CBS, rather than a consul lookup key
* Since the API was broken anyway, the decision not to throw an exception was revisted and overturned. This was causing problems for some users, who were getting `{}` back in their configuration, but without knowing why; either the config wasn't set up, the config was set but as `{}`, or the CBS being unreachable altogether. This client library now throws native python exceptions, rather than logging and returning `{}`. The application client code can handle the exceptions, and retry if they choose.
* Add more tests, move fixtures to conftest
diff --git a/onap-dcae-cbs-docker-client/onap_dcae_cbs_docker_client/client.py b/onap-dcae-cbs-docker-client/onap_dcae_cbs_docker_client/client.py
index 7f36169..c42b4ae 100644
--- a/onap-dcae-cbs-docker-client/onap_dcae_cbs_docker_client/client.py
+++ b/onap-dcae-cbs-docker-client/onap_dcae_cbs_docker_client/client.py
@@ -1,5 +1,5 @@
# ================================================================================
-# Copyright (c) 2017-2019 AT&T Intellectual Property. All rights reserved.
+# Copyright (c) 2017-2021 AT&T Intellectual Property. All rights reserved.
# Copyright (C) 2021 Nokia. All rights reserved.
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,18 +14,36 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ============LICENSE_END=========================================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+""" provide a means to return a configuration to CBS """
import json
import os
import requests
+import sys
+import yaml
+
from onap_dcae_cbs_docker_client import get_module_logger
from onap_dcae_cbs_docker_client.exceptions import ENVsMissing, CantGetConfig, CBSUnreachable
logger = get_module_logger(__name__)
+DEFAULT_CONFIG_PATH = "/app-config/application_config.yaml"
+DEFAULT_POLICY_PATH = "/etc/policies/policies.json"
+
+
+# provide a means to import the default paths into unit tests
+# For some reason, tox does not like
+# from onap_dcae_cbs_docker_client.client import DEFAULT_CONFIG_PATH, DEFAULT_POLICY_PATH
+
+def default_config_path():
+ return DEFAULT_CONFIG_PATH
+
+
+def default_policy_path():
+ return DEFAULT_POLICY_PATH
+
#########
# HELPERS
@@ -35,7 +53,7 @@ def _recurse(config):
Recurse through a configuration, or recursively a sub element of it.
If it's a dict: recurse over all the values
If it's a list: recurse over all the values
- If it's a string: return the replacement
+ If it's a string: expand the string and return its replacement
If none of the above, just return the item.
"""
if isinstance(config, list):
@@ -96,11 +114,13 @@ def change_envs(value):
"""
Replace env reference by actual value and return it
"""
- if value.startswith('$'):
- try:
- value = os.environ[value.replace('${', '').replace('}', '')]
- except KeyError as e:
- raise ENVsMissing("Required ENV Variable {0} missing".format(e))
+ if value.startswith('${'):
+ name = value[2:-1]
+ if name in os.environ:
+ return os.environ[name]
+
+ logger.error(f"Required ENV Variable '{name}' missing. Is '{value}' properly formatted?")
+ raise ENVsMissing(f"Required ENV Variable {name} missing. Is '{value}' properly formatted?")
return value
@@ -108,18 +128,113 @@ def change_envs(value):
# Public
def get_all():
"""
- Hit the CBS service_component_all endpoint
+ If not configured locally,
+ hit the CBS service_component_all endpoint
+
+ Local configuration comes from $CBS_CLIENT_CONFIG_PATH and $CBS_CLIENT_POLICY_PATH,
+ defaulted to /app-config/application_config.yaml and /etc/policies/policies.json.
"""
+ config_path = os.getenv("CBS_CLIENT_CONFIG_PATH", DEFAULT_CONFIG_PATH)
+ if config_path == "":
+ config_path = DEFAULT_CONFIG_PATH
+ policy_path = os.getenv("CBS_CLIENT_POLICY_PATH", DEFAULT_POLICY_PATH)
+ if policy_path == "":
+ policy_path = DEFAULT_POLICY_PATH
+
+ try:
+ logger.debug(f"opening config_path={config_path}")
+ with open(config_path) as fp:
+ config = yaml.safe_load(fp)
+
+ policies = None
+ try:
+ logger.debug(f"opening policy_path={policy_path}")
+ with open(policy_path) as fp:
+ policies = json.load(fp)
+
+ except FileNotFoundError:
+ logger.debug("Policy File Not Found exception received")
+ pass
+
+ except (json.decoder.JSONDecodeError, ValueError) as e:
+ logger.error(f"The policy file '{policy_path}' has invalid JSON: %s", e)
+ pass
+
+ except Exception as e:
+ logger.error(f"An error occurred processing the policy file '{policy_path}': %s", e)
+ import traceback
+ traceback.print_exc(file=sys.stderr)
+ pass
+
+ if policies is not None:
+ if "policies" in policies:
+ logger.debug(f"Returning config read from {config_path} an policy read from {policy_path}")
+ ret = {"config": _recurse(config), "policies": policies["policies"]}
+ else:
+ logger.error(f"The policy file '{policy_path}' does NOT have a 'policies' block in it.")
+ ret = {"config": _recurse(config)}
+ else:
+ logger.debug(f"Returning config read from {config_path}")
+ ret = {"config": _recurse(config)}
+
+ return ret
+
+ except yaml.scanner.ScannerError as e:
+ logger.error(f"The configuration file '{config_path}' has invalid YAML: {e}")
+ pass
+
+ except FileNotFoundError:
+ logger.debug("Config File Not Found exception received")
+ pass
+
+ except Exception as e:
+ logger.error(f"An error occurred processing the configuration file '{config_path}': {e}")
+ import traceback
+ traceback.print_exc(file=sys.stderr)
+ pass
+
+ logger.debug("Fallback to using REST call")
config = _get_path("service_component_all")
return _recurse(config)
def get_config():
"""
- Hit the CBS service_component endpoint
+ If not configured locally,
+ hit the CBS service_component endpoint for the configuration.
+
+ Local configuration comes from $CBS_CLIENT_CONFIG_PATH,
+ defaulted to /app-config/application_config.yaml.
TODO: should we take in a "retry" boolean, and retry on behalf of the caller?
Currently, we return an exception and let the application decide how it wants to proceed (Crash, try again, etc).
"""
+ config_path = os.getenv("CBS_CLIENT_CONFIG_PATH", DEFAULT_CONFIG_PATH)
+ if config_path == "":
+ config_path = DEFAULT_CONFIG_PATH
+
+ try:
+ logger.debug(f"opening config_path={config_path}")
+ with open(config_path) as fp:
+ config = yaml.safe_load(fp)
+
+ logger.debug(f"Returning config read from {config_path}")
+ return _recurse({"config": config})
+
+ except yaml.scanner.ScannerError as e:
+ logger.error(f"The configuration file '{config_path}' has invalid YAML: {e}")
+ pass
+
+ except FileNotFoundError:
+ logger.debug("Config File Not Found exception received")
+ pass
+
+ except Exception as e:
+ logger.error(f"An error occurred processing the configuration file '{config_path}': {e}")
+ import traceback
+ traceback.print_exc(file=sys.stderr)
+ pass
+
+ logger.debug("Fallback to using REST call")
config = _get_path("service_component")
return _recurse(config)
diff --git a/onap-dcae-cbs-docker-client/onap_dcae_cbs_docker_client/exceptions.py b/onap-dcae-cbs-docker-client/onap_dcae_cbs_docker_client/exceptions.py
index 6b73b91..0cd19fd 100644
--- a/onap-dcae-cbs-docker-client/onap_dcae_cbs_docker_client/exceptions.py
+++ b/onap-dcae-cbs-docker-client/onap_dcae_cbs_docker_client/exceptions.py
@@ -1,5 +1,5 @@
# ================================================================================
-# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+# Copyright (c) 2019-2021 AT&T Intellectual Property. All rights reserved.
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,8 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ============LICENSE_END=========================================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+""" exceptions used by the Config Binding Server """
class ENVsMissing(Exception):
diff --git a/onap-dcae-cbs-docker-client/pom.xml b/onap-dcae-cbs-docker-client/pom.xml
index b566d89..4783ada 100644
--- a/onap-dcae-cbs-docker-client/pom.xml
+++ b/onap-dcae-cbs-docker-client/pom.xml
@@ -28,7 +28,7 @@ ECOMP is a trademark and service mark of AT&T Intellectual Property.
<groupId>org.onap.dcaegen2.utils</groupId>
<artifactId>onap-dcae-cbs-docker-client</artifactId>
<name>dcaegen2-utils-python-cbs-docker-client</name>
- <version>2.1.2-SNAPSHOT</version>
+ <version>2.2.0-SNAPSHOT</version>
<url>http://maven.apache.org</url>
<properties>
diff --git a/onap-dcae-cbs-docker-client/setup.py b/onap-dcae-cbs-docker-client/setup.py
index 84b7436..585d628 100644
--- a/onap-dcae-cbs-docker-client/setup.py
+++ b/onap-dcae-cbs-docker-client/setup.py
@@ -1,5 +1,5 @@
# ================================================================================
-# Copyright (c) 2017-2019 AT&T Intellectual Property. All rights reserved.
+# Copyright (c) 2017-2021 AT&T Intellectual Property. All rights reserved.
# Copyright (C) 2021 Nokia. All rights reserved.
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@ from setuptools import setup, find_packages
setup(
name="onap_dcae_cbs_docker_client",
description="very lightweight client for a DCAE dockerized component to get it's config from the CBS",
- version="2.1.2",
+ version="2.2.0",
packages=find_packages(),
author="Tommy Carpenter",
author_email="tommy@research.att.com",
diff --git a/onap-dcae-cbs-docker-client/tests/conftest.py b/onap-dcae-cbs-docker-client/tests/conftest.py
index 0f34ff1..5dc877d 100644
--- a/onap-dcae-cbs-docker-client/tests/conftest.py
+++ b/onap-dcae-cbs-docker-client/tests/conftest.py
@@ -1,5 +1,5 @@
# ================================================================================
-# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+# Copyright (c) 2019-2021 AT&T Intellectual Property. All rights reserved.
# Copyright (C) 2021 Nokia. All rights reserved.
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,8 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ============LICENSE_END=========================================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+""" helper functions/classes for unit tests for Config Binding Server """
+
import pytest
from requests.exceptions import HTTPError, ConnectionError
diff --git a/onap-dcae-cbs-docker-client/tests/test_client.py b/onap-dcae-cbs-docker-client/tests/test_client.py
index 3b10923..76249d4 100644
--- a/onap-dcae-cbs-docker-client/tests/test_client.py
+++ b/onap-dcae-cbs-docker-client/tests/test_client.py
@@ -1,5 +1,5 @@
# ================================================================================
-# Copyright (c) 2017-2019 AT&T Intellectual Property. All rights reserved.
+# Copyright (c) 2017-2021 AT&T Intellectual Property. All rights reserved.
# Copyright (C) 2021 Nokia. All rights reserved.
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,22 +14,37 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ============LICENSE_END=========================================================
+
+""" unit tests for Config Binding Server """
+
import pytest
+import io
+import json
+import os
+import yaml
+
+from unittest.mock import patch
+
from onap_dcae_cbs_docker_client.client import get_config, get_all
+from onap_dcae_cbs_docker_client.client import default_config_path, default_policy_path
from onap_dcae_cbs_docker_client.exceptions import CantGetConfig, CBSUnreachable, ENVsMissing
+DEFAULT_REQUESTS_CONFIG = {"key_to_your_heart": 666}
+DEFAULT_REQUESTS_CONFIG_ALL = {
+ "config": {"key_to_your_heart": 666},
+ "dti": {"some amazing": "dti stuff"},
+ "policies": {"event": {"foo": "bar"}, "items": [{"foo2": "bar2"}]},
+ "otherkey": {"foo3": "bar3"},
+}
+
+
def test_http(monkeypatch, monkeyed_requests_get):
monkeypatch.setattr("requests.get", monkeyed_requests_get)
- assert get_config() == {"key_to_your_heart": 666}
+ assert get_config() == DEFAULT_REQUESTS_CONFIG
- assert get_all() == {
- "config": {"key_to_your_heart": 666},
- "dti": {"some amazing": "dti stuff"},
- "policies": {"event": {"foo": "bar"}, "items": [{"foo2": "bar2"}]},
- "otherkey": {"foo3": "bar3"},
- }
+ assert get_all() == DEFAULT_REQUESTS_CONFIG_ALL
def test_https_url(monkeypatch, monkeyed_requests_get_https):
@@ -113,3 +128,288 @@ def test_http_with_wrong_env(monkeypatch, monkeyed_requests_get_http_with_wrong_
get_config()
with pytest.raises(ENVsMissing):
get_all()
+
+
+################
+################
+# Tests for using local configuration and profile files.
+################
+################
+
+# Combinations to test:
+# $CBS_CLIENT_CONFIG_PATH set, set to "", not set
+# $CBS_CLIENT_POLICY_PATH set, set to "", not set
+# config_path file exists, not exists
+# policy_path file exists, not exists
+# good config, bad config
+# good policy, bad policy
+# call get_all(), get_config()
+# config has ${VAR} to be expanded
+# policy does NOT expand ${VAR}
+
+# JSON found in https://jira.onap.org/browse/DCAEGEN2-2753
+policy_default = ''.join(['{"policies": {"items": [{"type": "onap.policies.monitoring.tcagen2", ',
+ '"type_version": "1.0.0", "name": "onap.vfirewall.tca", "version": "1.0.0", ',
+ '"metadata": {"policy-id": "onap.vfirewall.tca", "policy-version": "1.0.0"}, ',
+ '"policyName": "onap.vfirewall.tca.1-0-0.xml", "policyVersion": "1.0.0", ',
+ '"config": {"tca.policy": {"domain": "measurementsForVfScaling", ',
+ '"metricsPerEventName": [{"eventName": "vFirewallBroadcastPackets", ',
+ '"controlLoopSchemaType": "VM", "policyScope": "DCAE", "policyName": ',
+ '"DCAE.Config_tca-hi-lo", "policyVersion": "v0.0.1", "thresholds": ',
+ '[{"closedLoopControlName": ',
+ '"ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a", ',
+ '"version": "1.0.2", "fieldPath": ',
+ '"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].',
+ 'receivedTotalPacketsDelta", "thresholdValue": 300, "direction": ',
+ '"LESS_OR_EQUAL", "severity": "MAJOR", "closedLoopEventStatus": ',
+ '"ONSET"}, {"closedLoopControlName": "ControlLoop-vFirewall-d0a1dfc6-',
+ '94f5-4fd4-a5b5-4630b438850a", "version": "1.0.2", "fieldPath": ',
+ '"$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].',
+ 'receivedTotalPacketsDelta", "thresholdValue": 700, "direction": ',
+ '"GREATER_OR_EQUAL", "severity": "CRITICAL", "closedLoopEventStatus": ',
+ '"ONSET"}]}]}}}]}, "event": {"action": "gathered", "timestamp": ',
+ '"2021-04-19T23:37:19.709Z", "update_id": "379fb01a-cfe2-4c06-8f6b-',
+ 'd51f3c8504af", "policies_count": 1}}'])
+found_policy_path = '{"policies": "found policy/path"}'
+found_policy_path_with_env = '{"policies": "${POLICYENV}"}'
+found_policy_path_with_env_expanded = '{"policies": "pOlIcYeNv"}'
+found_policy_path_missing_policy = '{"XXpoliciesXX": "found policy/path"}'
+found_config_default = '["found config/default"]'
+found_config_default_with_env = '["${CONFIGENV}"]'
+found_config_default_with_env_expanded = '["cOnFiGeNv"]'
+found_config_path = '["found config/path"]'
+
+
+class my_mock_open(io.StringIO):
+ """
+ This class acts like the mock_open function,
+ but is able to return different results dependent
+ on the path being opened, or even raise different
+ exceptions.
+ """
+
+ def __init__(self, fname, mode="r"):
+ """ Do the right thing for the filename
+ """
+ ce = os.getenv("CONFIG_EXISTS", "no")
+ pe = os.getenv("POLICY_EXISTS", "no")
+
+ # are we a file with data to be returned?
+ ret_data = {
+ "config/path": [ce, found_config_path],
+ "config/env": [ce, found_config_default_with_env],
+ default_config_path(): [ce, found_config_default],
+ "policy/path": [pe, found_policy_path],
+ "policy/env": [pe, found_policy_path_with_env],
+ default_policy_path(): [pe, policy_default],
+ "bad/policy3": ["yes", found_policy_path_missing_policy],
+ }
+
+ if fname in ret_data:
+ if ret_data[fname][0] == "yes":
+ super().__init__(ret_data[fname][1])
+ return
+
+ # These return specifc exceptions
+ if fname == "bad/config":
+ raise yaml.scanner.ScannerError()
+ if fname == "bad/policy":
+ raise ValueError()
+ if fname == "bad/policy2":
+ raise json.decoder.JSONDecodeError(msg="bad json", doc=fname, pos=1)
+ if fname == "other/error":
+ raise ZeroDivisionError()
+ # raise OSError(2, "ENOENT")
+
+ raise FileNotFoundError(fname)
+
+
+def test_config_file_both_exist(monkeypatch, monkeyed_requests_get):
+ """
+ These tests cover the cases where both the policy and configuration files exist.
+ We vary WHICH file is being pointed at using the environment variables.
+ """
+
+ monkeypatch.setattr("requests.get", monkeyed_requests_get)
+
+ monkeypatch.setenv("CONFIG_EXISTS", "yes")
+ monkeypatch.setenv("POLICY_EXISTS", "yes")
+ monkeypatch.setenv("CONFIGENV", "cOnFiGeNv")
+ monkeypatch.setenv("POLICYENV", "pOlIcYeNv")
+ for (config_path, expected_config, set_config) in [
+ ("config/path", json.loads(found_config_path), True),
+ ("config/env", json.loads(found_config_default_with_env_expanded), True),
+ ("", json.loads(found_config_default), True),
+ (None, json.loads(found_config_default), False)]:
+
+ if set_config:
+ monkeypatch.setenv("CBS_CLIENT_CONFIG_PATH", config_path)
+ else:
+ monkeypatch.delenv("CBS_CLIENT_CONFIG_PATH")
+
+ expected_get_config = {"config": expected_config}
+
+ for (policy_path, expected_policy, set_policy) in [
+ ("policy/path", json.loads(found_policy_path)['policies'], True),
+ ("policy/env", json.loads(found_policy_path_with_env)['policies'], True),
+ ("", json.loads(policy_default)['policies'], True),
+ (None, json.loads(policy_default)['policies'], False)]:
+
+ if set_policy:
+ monkeypatch.setenv("CBS_CLIENT_POLICY_PATH", policy_path)
+ else:
+ monkeypatch.delenv("CBS_CLIENT_POLICY_PATH")
+
+ expected_get_all = {"config": expected_config, "policies": expected_policy}
+
+ with patch('builtins.open', my_mock_open):
+ gc = get_config()
+ assert gc == expected_get_config
+
+ ga = get_all()
+ assert ga == expected_get_all
+
+
+def test_config_file_config_exists_policy_does_not(monkeypatch, monkeyed_requests_get):
+ """
+ In this test, the policy file is always missing. Its value is always defaulted to {}.
+ The test structure is identical to what we had in test_config_file_both_exist(), but
+ the expected configuration to be returned is different.
+ """
+
+ monkeypatch.setattr("requests.get", monkeyed_requests_get)
+
+ monkeypatch.setenv("CONFIG_EXISTS", "yes")
+ monkeypatch.setenv("POLICY_EXISTS", "no")
+
+ for (config_path, expected_config, set_config) in [
+ ("config/path", json.loads(found_config_path), True),
+ ("", json.loads(found_config_default), True),
+ (None, json.loads(found_config_default), False)]:
+
+ if set_config:
+ monkeypatch.setenv("CBS_CLIENT_CONFIG_PATH", config_path)
+ else:
+ monkeypatch.delenv("CBS_CLIENT_CONFIG_PATH")
+
+ expected_get_config = {"config": expected_config}
+ expected_get_all = {"config": expected_config}
+
+ for (policy_path, expected_policy, set_policy) in [
+ ("policy/path", json.loads(found_policy_path)['policies'], True),
+ ("", json.loads(policy_default)['policies'], True),
+ (None, json.loads(policy_default)['policies'], False)]:
+
+ if set_policy:
+ monkeypatch.setenv("CBS_CLIENT_POLICY_PATH", policy_path)
+ else:
+ monkeypatch.delenv("CBS_CLIENT_POLICY_PATH")
+
+ with patch('builtins.open', my_mock_open):
+ gc = get_config()
+ assert gc == expected_get_config
+
+ ga = get_all()
+ assert ga == expected_get_all
+
+
+def test_config_file_config_does_not_policy_exists(monkeypatch, monkeyed_requests_get):
+ """
+ In this test, the config file is always missing. Its value is always defaulted to
+ the CBS response.
+ The test structure is identical to what we had in test_config_file_both_exist(), but
+ the expected configuration to be returned is different.
+ """
+
+ monkeypatch.setattr("requests.get", monkeyed_requests_get)
+
+ monkeypatch.setenv("CONFIG_EXISTS", "no")
+ monkeypatch.setenv("POLICY_EXISTS", "yes")
+
+ expected_get_config = DEFAULT_REQUESTS_CONFIG
+ expected_get_all = DEFAULT_REQUESTS_CONFIG_ALL
+
+ for (config_path, expected_config, set_config) in [
+ ("config/path", json.loads(found_config_path), True),
+ ("", json.loads(found_config_default), True),
+ (None, json.loads(found_config_default), False)]:
+
+ if set_config:
+ monkeypatch.setenv("CBS_CLIENT_CONFIG_PATH", config_path)
+ else:
+ monkeypatch.delenv("CBS_CLIENT_CONFIG_PATH")
+
+ for (policy_path, expected_policy, set_policy) in [
+ ("policy/path", json.loads(found_policy_path)['policies'], True),
+ ("", json.loads(policy_default)['policies'], True),
+ (None, json.loads(policy_default)['policies'], False)]:
+
+ if set_policy:
+ monkeypatch.setenv("CBS_CLIENT_POLICY_PATH", policy_path)
+ else:
+ monkeypatch.delenv("CBS_CLIENT_POLICY_PATH")
+
+ with patch('builtins.open', my_mock_open):
+ gc = get_config()
+ assert gc == expected_get_config
+
+ ga = get_all()
+ assert ga == expected_get_all
+
+
+def test_config_file_various_exceptions(monkeypatch, monkeyed_requests_get):
+ """
+ In this test, various forms of exceptions are tested while accessing the
+ configuration and policy files.
+ Exceptions on the policy file act as if the policy file does not exist.
+ Exceptions on the configuration file act as if the configuration file does not exist.
+ """
+
+ monkeypatch.setattr("requests.get", monkeyed_requests_get)
+
+ monkeypatch.setenv("CONFIG_EXISTS", "yes")
+ monkeypatch.setenv("POLICY_EXISTS", "yes")
+
+ # first do exceptions for the policy file
+ for (config_path, expected_config, set_config) in [
+ ("config/path", json.loads(found_config_path), True),
+ ("", json.loads(found_config_default), True),
+ (None, json.loads(found_config_default), False)]:
+
+ if set_config:
+ monkeypatch.setenv("CBS_CLIENT_CONFIG_PATH", config_path)
+ else:
+ monkeypatch.delenv("CBS_CLIENT_CONFIG_PATH")
+
+ expected_get_config = {"config": expected_config}
+ expected_get_all = {"config": expected_config}
+
+ for policy_path in ["bad/policy", "bad/policy2",
+ "bad/policy3", "other/error"]:
+
+ monkeypatch.setenv("CBS_CLIENT_POLICY_PATH", policy_path)
+
+ with patch('builtins.open', my_mock_open):
+ gc = get_config()
+ assert gc == expected_get_config
+
+ ga = get_all()
+ assert ga == expected_get_all
+
+ # next do exceptions for the config file
+ expected_get_config = DEFAULT_REQUESTS_CONFIG
+ expected_get_all = DEFAULT_REQUESTS_CONFIG_ALL
+
+ policy_path = "policy/path"
+ monkeypatch.setenv("CBS_CLIENT_POLICY_PATH", policy_path)
+
+ for config_path in ["bad/config", "other/error"]:
+
+ monkeypatch.setenv("CBS_CLIENT_CONFIG_PATH", config_path)
+
+ with patch('builtins.open', my_mock_open):
+ gc = get_config()
+ assert gc == expected_get_config
+
+ ga = get_all()
+ assert ga == expected_get_all
diff --git a/onap-dcae-cbs-docker-client/tox.ini b/onap-dcae-cbs-docker-client/tox.ini
index 04b292e..5f6d8f8 100644
--- a/onap-dcae-cbs-docker-client/tox.ini
+++ b/onap-dcae-cbs-docker-client/tox.ini
@@ -1,12 +1,15 @@
# content of: tox.ini , put in same dir as setup.py
[tox]
-envlist = py36, flake8, py38, py39
+# envlist = py36, flake8, py38, py39
+envlist = flake8, py38, py39
[testenv]
deps=
pytest
coverage
pytest-cov
+ pyyaml
+
setenv =
HOSTNAME = testhostname
CONFIG_BINDING_SERVICE = config-binding-service
@@ -14,7 +17,7 @@ setenv =
TEST_ENV=test_env
commands=
- pytest --junitxml xunit-results.xml --cov onap_dcae_cbs_docker_client --cov-report xml
+ pytest --junitxml xunit-results.xml --cov onap_dcae_cbs_docker_client --cov-report xml --cov-report=term --cov-report=html
coverage xml
[testenv:flake8]
diff --git a/scripts/mvn-phase-lib.sh b/scripts/mvn-phase-lib.sh
index 47bcd06..c9e8db9 100644
--- a/scripts/mvn-phase-lib.sh
+++ b/scripts/mvn-phase-lib.sh
@@ -231,12 +231,13 @@ run_tox_test()
DIR=$(echo "$TOXINI" | rev | cut -f2- -d'/' | rev)
cd "${CURDIR}/${DIR}"
rm -rf ./venv-tox ./.tox
- virtualenv ./venv-tox
+ python3 -m venv ./venv-tox
source ./venv-tox/bin/activate
- pip install pip==9.0.3
- pip install --upgrade argparse
- pip install tox==2.9.1
- pip freeze
+
+ pip3 install pip==9.0.3
+ pip3 install --upgrade argparse
+ pip3 install tox==2.9.1
+ pip3 freeze
tox
deactivate
rm -rf ./venv-tox ./.tox
@@ -248,11 +249,12 @@ build_wagons()
rm -rf ./*.wgn venv-pkg
SETUPFILES=$(find . -name "setup.py")
- virtualenv ./venv-pkg
+ python3 -m venv ./venv-pkg
source ./venv-pkg/bin/activate
- pip install --upgrade pip
- pip install wagon
-
+
+ pip3 install --upgrade pip
+ pip3 install wagon
+
CURDIR=$(pwd)
for SETUPFILE in $SETUPFILES; do
PLUGIN_DIR=$(dirname "$SETUPFILE")