summaryrefslogtreecommitdiffstats
path: root/onap-dcae-dcaepolicy-lib
diff options
context:
space:
mode:
authorAlex Shatov <alexs@att.com>2017-09-26 17:03:11 -0400
committerAlex Shatov <alexs@att.com>2017-09-26 17:03:11 -0400
commit8cdeeeb9a2e8b51f9897173dc26d672e55b00304 (patch)
tree087b09e5a71dbd85030f2dd53cc7727749ce5166 /onap-dcae-dcaepolicy-lib
parent7b31008280fa8b5d45af59f6fd86d49293f14abc (diff)
72% unit test and coverage with tox
* usage on local run: tox -c tox-local.ini * usage on ONAP run: tox Change-Id: I8075b035f9f05fa45a3e7eba52dc40fbcef8feec Issue-Id: DCAEGEN2-62 Signed-off-by: Alex Shatov <alexs@att.com>
Diffstat (limited to 'onap-dcae-dcaepolicy-lib')
-rw-r--r--onap-dcae-dcaepolicy-lib/.coveragerc29
-rw-r--r--onap-dcae-dcaepolicy-lib/tests/log_ctx.py134
-rw-r--r--onap-dcae-dcaepolicy-lib/tests/mock_cloudify_ctx.py146
-rw-r--r--onap-dcae-dcaepolicy-lib/tests/test_dcae_policy.py262
-rw-r--r--onap-dcae-dcaepolicy-lib/tox-local.ini16
-rw-r--r--onap-dcae-dcaepolicy-lib/tox.ini7
6 files changed, 592 insertions, 2 deletions
diff --git a/onap-dcae-dcaepolicy-lib/.coveragerc b/onap-dcae-dcaepolicy-lib/.coveragerc
new file mode 100644
index 0000000..26ed8ac
--- /dev/null
+++ b/onap-dcae-dcaepolicy-lib/.coveragerc
@@ -0,0 +1,29 @@
+# .coveragerc to control coverage.py
+[run]
+branch = True
+cover_pylib = False
+# include = */onap_dcae_dcaepolicy_lib/*.py
+
+[report]
+# Regexes for lines to exclude from consideration
+exclude_lines =
+ # Have to re-enable the standard pragma
+ pragma: no cover
+
+ # Don't complain about missing debug-only code:
+ def __repr__
+ if self\.debug
+
+ # Don't complain if tests don't hit defensive assertion code:
+ raise AssertionError
+ raise NotImplementedError
+
+ # Don't complain if non-runnable code isn't run:
+ if 0:
+ if __name__ == .__main__.:
+
+ignore_errors = True
+
+[xml]
+output = coverage-reports/coverage-onap_dcae_dcaepolicy_lib.xml
+
diff --git a/onap-dcae-dcaepolicy-lib/tests/log_ctx.py b/onap-dcae-dcaepolicy-lib/tests/log_ctx.py
new file mode 100644
index 0000000..9f5464d
--- /dev/null
+++ b/onap-dcae-dcaepolicy-lib/tests/log_ctx.py
@@ -0,0 +1,134 @@
+""":@CtxLogger.log_ctx: decorator for logging the cloudify ctx before and after operation"""
+
+# org.onap.dcae
+# ================================================================================
+# Copyright (c) 2017 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.
+# 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.
+# ============LICENSE_END=========================================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+import json
+from functools import wraps
+
+from cloudify import ctx
+from cloudify.context import NODE_INSTANCE, RELATIONSHIP_INSTANCE
+
+class CtxLogger(object):
+ """static class for logging cloudify context ctx"""
+ @staticmethod
+ def _get_ctx_node_info(ctx_node):
+ if not ctx_node:
+ return {}
+ return {'id': ctx_node.id, 'name': ctx_node.name, 'type': ctx_node.type,
+ 'type_hierarchy': ctx_node.type_hierarchy, 'properties': ctx_node.properties}
+
+ @staticmethod
+ def _get_ctx_instance_info(ctx_instance):
+ if not ctx_instance:
+ return {}
+ return {'id' : ctx_instance.id, 'runtime_properties' : ctx_instance.runtime_properties,
+ 'relationships' : CtxLogger._get_ctx_instance_relationships_info(ctx_instance)}
+
+ @staticmethod
+ def _get_ctx_instance_relationships_info(ctx_instance):
+ if not ctx_instance or not ctx_instance.relationships:
+ return []
+ return [{'target': CtxLogger._get_ctx_source_target_info(r.target), \
+ 'type':r.type, 'type_hierarchy':r.type_hierarchy} \
+ for r in ctx_instance.relationships]
+
+ @staticmethod
+ def _get_ctx_source_target_info(ctx_source_target):
+ if not ctx_source_target:
+ return {}
+ return {'node': CtxLogger._get_ctx_node_info(ctx_source_target.node),
+ 'instance' : CtxLogger._get_ctx_instance_info(ctx_source_target.instance)}
+
+ @staticmethod
+ def get_ctx_info():
+ """collect the context data from ctx"""
+ context = {
+ 'type': ctx.type,
+ 'blueprint.id': ctx.blueprint.id,
+ 'deployment.id': ctx.deployment.id,
+ 'execution_id': ctx.execution_id,
+ 'workflow_id': ctx.workflow_id,
+ 'task_id': ctx.task_id,
+ 'task_name': ctx.task_name,
+ 'task_queue': ctx.task_queue,
+ 'task_target': ctx.task_target,
+ 'operation': {
+ 'name': ctx.operation.name,
+ 'retry_number': ctx.operation.retry_number,
+ 'max_retries': ctx.operation.max_retries
+ },
+ 'plugin': {
+ 'name': ctx.plugin.name,
+ 'package_name': ctx.plugin.package_name,
+ 'package_version': ctx.plugin.package_version,
+ 'prefix': ctx.plugin.prefix,
+ 'workdir': ctx.plugin.workdir
+ }
+ }
+ if ctx.type == NODE_INSTANCE:
+ context['node'] = CtxLogger._get_ctx_node_info(ctx.node)
+ context['instance'] = CtxLogger._get_ctx_instance_info(ctx.instance)
+ elif ctx.type == RELATIONSHIP_INSTANCE:
+ context['source'] = CtxLogger._get_ctx_source_target_info(ctx.source)
+ context['target'] = CtxLogger._get_ctx_source_target_info(ctx.target)
+
+ return context
+
+ @staticmethod
+ def log_ctx_info(func_name):
+ """shortcut for logging of the ctx of the function"""
+ try:
+ if ctx.type == NODE_INSTANCE:
+ ctx.logger.info("{0} {1} context: {2}".format(\
+ func_name, ctx.instance.id, json.dumps(CtxLogger.get_ctx_info())))
+ elif ctx.type == RELATIONSHIP_INSTANCE:
+ ctx.logger.info("{0} context: {1}".format(\
+ func_name, json.dumps(CtxLogger.get_ctx_info())))
+ except Exception as ex:
+ ctx.logger.error("Failed to log the node context: {0}".format(str(ex)))
+
+ @staticmethod
+ def log_ctx(pre_log=True, after_log=False, exe_task=None):
+ """Decorate each operation on the node to log the context - before and after.
+ Optionally save the current function name into runtime_properties[exe_task]
+ """
+ def log_ctx_info_decorator(func, **arguments):
+ """Decorate each operation on the node to log the context"""
+ if func is not None:
+ @wraps(func)
+ def wrapper(*args, **kwargs):
+ """the actual logger before and after"""
+ try:
+ if ctx.type == NODE_INSTANCE and exe_task:
+ ctx.instance.runtime_properties[exe_task] = func.__name__
+ except Exception as ex:
+ ctx.logger.error("Failed to set exe_task {0}: {1}".format(\
+ exe_task, str(ex)))
+ if pre_log:
+ CtxLogger.log_ctx_info('before ' + func.__name__)
+
+ result = func(*args, **kwargs)
+
+ if after_log:
+ CtxLogger.log_ctx_info('after ' + func.__name__)
+
+ return result
+ return wrapper
+ return log_ctx_info_decorator
diff --git a/onap-dcae-dcaepolicy-lib/tests/mock_cloudify_ctx.py b/onap-dcae-dcaepolicy-lib/tests/mock_cloudify_ctx.py
new file mode 100644
index 0000000..0c130c0
--- /dev/null
+++ b/onap-dcae-dcaepolicy-lib/tests/mock_cloudify_ctx.py
@@ -0,0 +1,146 @@
+
+# ============LICENSE_START=======================================================
+# org.onap.dcae
+# ================================================================================
+# Copyright (c) 2017 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.
+# 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.
+# ============LICENSE_END=========================================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+from cloudify.mocks import MockCloudifyContext, MockNodeInstanceContext, MockNodeContext
+
+TARGET_NODE_ID = "target_node_id"
+TARGET_NODE_NAME = "target_node_name"
+
+class MockContextNode(MockNodeContext):
+ """ctx.node with type and type_hierarchy"""
+
+ def __init__(self, id=None, properties=None, node_type=None, type_hierarchy=None):
+ super(MockContextNode, self).__init__(id, properties or {})
+ self._type = node_type
+ self._type_hierarchy = type_hierarchy or [self._type]
+ MockCloudifyContextFull.nodes[id] = self
+
+ @property
+ def type(self):
+ """node type"""
+ return self._type
+
+ @property
+ def type_hierarchy(self):
+ """node type hierarchy is a list of types"""
+ return self._type_hierarchy
+
+class MockContextNodeInstance(MockNodeInstanceContext):
+ """ctx.instance with relationships"""
+
+ def __init__(self, id=None, runtime_properties=None, relationships=None):
+ super(MockContextNodeInstance, self).__init__(id, runtime_properties or {})
+ self._relationships = []
+ self.add_relationships(relationships)
+ MockCloudifyContextFull.instances[id] = self
+
+ def add_relationships(self, relationships):
+ """add more relationships to the node instance"""
+ if not relationships:
+ return
+ if not self._relationships:
+ self._relationships = []
+ self._relationships.extend([
+ MockContextRelationship(relationship)
+ for relationship in (relationships or []) if TARGET_NODE_ID in relationship
+ ])
+
+ @property
+ def relationships(self):
+ """list of relationships to other node instances"""
+ return self._relationships
+
+class MockContextRelationshipTarget(object):
+ """target of relationship"""
+ def __init__(self, relationship):
+ target_node_name = relationship[TARGET_NODE_NAME]
+ target_node_id = relationship[TARGET_NODE_ID]
+
+ self.node = MockCloudifyContextFull.nodes.get(target_node_name)
+ self.instance = MockCloudifyContextFull.instances.get(target_node_id)
+
+ if not self.node:
+ self.node = MockContextNode(target_node_name)
+ if not self.instance:
+ self.instance = MockContextNodeInstance(target_node_id)
+
+class MockContextRelationship(object):
+ """item of ctx.instance.relationships"""
+
+ def __init__(self, relationship):
+ self.target = MockContextRelationshipTarget(relationship)
+ self.type = relationship.get("type", "cloudify.relationships.depends_on")
+ self.type_hierarchy = relationship.get("type_hierarchy") or [self.type]
+
+class MockCloudifyContextFull(MockCloudifyContext):
+ """
+ ctx1 = MockCloudifyContextFull(node_id='node_1',
+ node_name='my_1', properties={'foo': 'bar'})
+ ctx2 = MockCloudifyContextFull(node_id='node_2',
+ node_name='my_2',
+ relationships=[{'target_node_id': 'node_1',
+ 'target_node_name': 'my_1'}])
+ """
+ nodes = {}
+ instances = {}
+
+ def __init__(self,
+ node_id=None,
+ node_name=None,
+ blueprint_id=None,
+ deployment_id=None,
+ execution_id=None,
+ properties=None, node_type=None, type_hierarchy=None,
+ runtime_properties=None,
+ capabilities=None,
+ related=None,
+ source=None,
+ target=None,
+ operation=None,
+ resources=None,
+ provider_context=None,
+ bootstrap_context=None,
+ relationships=None):
+ super(MockCloudifyContextFull, self).__init__(
+ node_id=node_id,
+ node_name=node_name,
+ blueprint_id=blueprint_id,
+ deployment_id=deployment_id,
+ execution_id=execution_id,
+ properties=properties,
+ capabilities=capabilities,
+ related=related,
+ source=source,
+ target=target,
+ operation=operation,
+ resources=resources,
+ provider_context=provider_context,
+ bootstrap_context=bootstrap_context,
+ runtime_properties=runtime_properties
+ )
+ self._node = MockContextNode(node_name, properties, node_type, type_hierarchy)
+ self._instance = MockContextNodeInstance(node_id, runtime_properties, relationships)
+
+ @staticmethod
+ def clear():
+ """clean up the context links"""
+ MockCloudifyContextFull.instances.clear()
+ MockCloudifyContextFull.nodes.clear()
diff --git a/onap-dcae-dcaepolicy-lib/tests/test_dcae_policy.py b/onap-dcae-dcaepolicy-lib/tests/test_dcae_policy.py
new file mode 100644
index 0000000..29b192c
--- /dev/null
+++ b/onap-dcae-dcaepolicy-lib/tests/test_dcae_policy.py
@@ -0,0 +1,262 @@
+# ============LICENSE_START=======================================================
+# org.onap.dcae
+# ================================================================================
+# Copyright (c) 2017 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.
+# 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.
+# ============LICENSE_END=========================================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+
+import json
+import logging
+from datetime import datetime, timedelta
+
+import pytest
+
+from cloudify import ctx
+from cloudify.state import current_ctx
+from cloudify.exceptions import NonRecoverableError
+
+from mock_cloudify_ctx import MockCloudifyContextFull, TARGET_NODE_ID, TARGET_NODE_NAME
+from log_ctx import CtxLogger
+
+from onap_dcae_dcaepolicy_lib import Policies, POLICIES
+
+DCAE_POLICY_TYPE = 'dcae.nodes.policy'
+POLICY_ID = 'policy_id'
+POLICY_VERSION = "policyVersion"
+POLICY_NAME = "policyName"
+POLICY_BODY = 'policy_body'
+POLICY_CONFIG = 'config'
+MONKEYED_POLICY_ID = 'monkeyed.Config_peach'
+MONKEYED_POLICY_ID_2 = 'monkeyed.Config_peach_2'
+APPLICATION_CONFIG = "application_config"
+LOG_FILE = 'test_onap_dcae_dcaepolicy_lib.log'
+
+RUN_TS = datetime.utcnow()
+
+class MonkeyedLogHandler(object):
+ """keep the shared logger handler here"""
+ _log_handler = None
+
+ @staticmethod
+ def add_handler_to(logger):
+ """adds the local handler to the logger"""
+ if not MonkeyedLogHandler._log_handler:
+ MonkeyedLogHandler._log_handler = logging.FileHandler(LOG_FILE)
+ MonkeyedLogHandler._log_handler.setLevel(logging.DEBUG)
+ formatter = logging.Formatter(
+ fmt='%(asctime)s.%(msecs)03d %(levelname)+8s ' + \
+ '%(threadName)s %(name)s.%(funcName)s: %(message)s', \
+ datefmt='%Y%m%d_%H%M%S')
+ MonkeyedLogHandler._log_handler.setFormatter(formatter)
+ logger.addHandler(MonkeyedLogHandler._log_handler)
+
+class MonkeyedPolicyBody(object):
+ """policy body that policy-engine returns"""
+ @staticmethod
+ def create_policy_body(policy_id, policy_version=1):
+ """returns a fake policy-body"""
+ prev_ver = policy_version - 1
+ timestamp = RUN_TS + timedelta(hours=prev_ver)
+
+ prev_ver = str(prev_ver)
+ this_ver = str(policy_version)
+ config = {
+ "policy_updated_from_ver": prev_ver,
+ "policy_updated_to_ver": this_ver,
+ "policy_hello": "world!",
+ "policy_updated_ts": timestamp.isoformat()[:-3] + 'Z',
+ "updated_policy_id": policy_id
+ }
+ return {
+ "policyConfigMessage": "Config Retrieved! ",
+ "policyConfigStatus": "CONFIG_RETRIEVED",
+ "type": "JSON",
+ POLICY_NAME: "{0}.{1}.xml".format(policy_id, this_ver),
+ POLICY_VERSION: this_ver,
+ POLICY_CONFIG: config,
+ "matchingConditions": {
+ "ECOMPName": "DCAE",
+ "ConfigName": "alex_config_name"
+ },
+ "responseAttributes": {},
+ "property": None
+ }
+
+ @staticmethod
+ def create_policy(policy_id, policy_version=1):
+ """returns the whole policy object for policy_id and policy_version"""
+ return {
+ POLICY_ID : policy_id,
+ POLICY_BODY : MonkeyedPolicyBody.create_policy_body(policy_id, policy_version)
+ }
+
+ @staticmethod
+ def is_the_same_dict(policy_body_1, policy_body_2):
+ """check whether both policy_body objects are the same"""
+ if not isinstance(policy_body_1, dict) or not isinstance(policy_body_2, dict):
+ return False
+ for key in policy_body_1.keys():
+ if key not in policy_body_2:
+ return False
+ if isinstance(policy_body_1[key], dict):
+ return MonkeyedPolicyBody.is_the_same_dict(
+ policy_body_1[key], policy_body_2[key])
+ if (policy_body_1[key] is None and policy_body_2[key] is not None) \
+ or (policy_body_1[key] is not None and policy_body_2[key] is None) \
+ or (policy_body_1[key] != policy_body_2[key]):
+ return False
+ return True
+
+
+class MonkeyedNode(object):
+ """node in cloudify"""
+ BLUEPRINT_ID = 'test_dcae_policy_bp_id'
+ DEPLOYMENT_ID = 'test_dcae_policy_dpl_id'
+ EXECUTION_ID = 'test_dcae_policy_exe_id'
+
+ def __init__(self, node_id, node_name, node_type, properties,
+ relationships=None, runtime_properties=None):
+ self.node_id = node_id
+ self.node_name = node_name
+ self.ctx = MockCloudifyContextFull(
+ node_id=self.node_id,
+ node_name=self.node_name,
+ node_type=node_type,
+ blueprint_id=MonkeyedNode.BLUEPRINT_ID,
+ deployment_id=MonkeyedNode.DEPLOYMENT_ID,
+ execution_id=MonkeyedNode.EXECUTION_ID,
+ properties=properties,
+ relationships=relationships,
+ runtime_properties=runtime_properties
+ )
+ MonkeyedLogHandler.add_handler_to(self.ctx.logger)
+
+@CtxLogger.log_ctx(pre_log=True, after_log=True, exe_task='exe_task')
+@Policies.gather_policies_to_node
+def node_configure(**kwargs):
+ """decorate with @Policies.gather_policies_to_node on policy consumer node to
+ bring all policies to runtime_properties["policies"]
+ """
+ ctx.logger.info("node_configure kwargs: {0}".format(kwargs))
+
+ app_config = None
+ if APPLICATION_CONFIG in ctx.node.properties:
+ # dockerized blueprint puts the app config into property application_config
+ app_config = ctx.node.properties.get(APPLICATION_CONFIG)
+
+ app_config = Policies.shallow_merge_policies_into(app_config)
+ ctx.instance.runtime_properties[APPLICATION_CONFIG] = app_config
+ ctx.logger.info("example: applied policy_configs to property app_config: {0}" \
+ .format(json.dumps(app_config)))
+
+ policy_configs = Policies.get_policy_configs()
+ if policy_configs:
+ ctx.logger.warn("TBD: apply policy_configs: {0}".format(json.dumps(policy_configs)))
+
+@CtxLogger.log_ctx(pre_log=True, after_log=True, exe_task='execute_operation')
+@Policies.update_policies_on_node(configs_only=True)
+def policy_update(updated_policies, **kwargs):
+ """decorate with @Policies.update_policies_on_node() to update runtime_properties["policies"]
+
+ :updated_policies: contains the list of changed policy-configs when configs_only=True (default).
+ Use configs_only=False to bring the full policy objects in :updated_policies:.
+
+ Use :Policies.shallow_merge_policies_into(): to merge the updated_policies into app_config
+ """
+ app_config = ctx.instance.runtime_properties[APPLICATION_CONFIG]
+
+ # This is how to merge the policies into app_config object
+ app_config = Policies.shallow_merge_policies_into(app_config)
+
+ ctx.logger.info("merged updated_policies {0} into app_config {1}"
+ .format(json.dumps(updated_policies), json.dumps(app_config)))
+
+ ctx.instance.runtime_properties[APPLICATION_CONFIG] = app_config
+
+
+def test_policies_to_node():
+ """test gather_policies_to_node and policy_update"""
+
+ node_policy = MonkeyedNode(
+ 'test_dcae_policy_node_id',
+ 'test_dcae_policy_node_name',
+ DCAE_POLICY_TYPE,
+ {POLICY_ID: MONKEYED_POLICY_ID},
+ None,
+ {POLICY_BODY : MonkeyedPolicyBody.create_policy_body(MONKEYED_POLICY_ID)}
+ )
+ node_policy_2 = MonkeyedNode(
+ 'test_dcae_policy_node_id_2',
+ 'test_dcae_policy_node_name_2',
+ DCAE_POLICY_TYPE,
+ {POLICY_ID: MONKEYED_POLICY_ID_2},
+ None,
+ {POLICY_BODY : MonkeyedPolicyBody.create_policy_body(MONKEYED_POLICY_ID_2)}
+ )
+ node_ms = MonkeyedNode('test_ms_id', 'test_ms_name', "ms.nodes.type", None, \
+ [{TARGET_NODE_ID: node_policy.node_id, TARGET_NODE_NAME: node_policy.node_name},
+ {TARGET_NODE_ID: node_policy_2.node_id, TARGET_NODE_NAME: node_policy_2.node_name}
+ ])
+
+ try:
+ current_ctx.set(node_ms.ctx)
+
+ node_configure()
+
+ runtime_properties = ctx.instance.runtime_properties
+ ctx.logger.info("runtime_properties: {0}".format(json.dumps(runtime_properties)))
+
+ assert POLICIES in runtime_properties
+ policies = runtime_properties[POLICIES]
+ ctx.logger.info("policies: {0}".format(json.dumps(policies)))
+
+ assert MONKEYED_POLICY_ID in policies
+ expected_1 = MonkeyedPolicyBody.create_policy(MONKEYED_POLICY_ID)
+ policy = policies[MONKEYED_POLICY_ID]
+ ctx.logger.info("expected[{0}]: {1}".format(MONKEYED_POLICY_ID, json.dumps(expected_1)))
+ ctx.logger.info("policy[{0}]: {1}".format(MONKEYED_POLICY_ID, json.dumps(policy)))
+ assert MonkeyedPolicyBody.is_the_same_dict(policy, expected_1)
+ assert MonkeyedPolicyBody.is_the_same_dict(expected_1, policy)
+
+ assert MONKEYED_POLICY_ID_2 in policies
+ expected_2 = MonkeyedPolicyBody.create_policy(MONKEYED_POLICY_ID_2)
+ policy = policies[MONKEYED_POLICY_ID_2]
+ ctx.logger.info("expected[{0}]: {1}".format(MONKEYED_POLICY_ID_2, json.dumps(expected_2)))
+ ctx.logger.info("policy[{0}]: {1}".format(MONKEYED_POLICY_ID_2, json.dumps(policy)))
+ assert MonkeyedPolicyBody.is_the_same_dict(policy, expected_2)
+ assert MonkeyedPolicyBody.is_the_same_dict(expected_2, policy)
+
+ updated_policy = MonkeyedPolicyBody.create_policy(MONKEYED_POLICY_ID_2, 2)
+ ctx.logger.info("policy_update: [{0}]".format(json.dumps(updated_policy)))
+
+ policy_update([updated_policy])
+
+ assert MONKEYED_POLICY_ID_2 in policies
+ policy = policies[MONKEYED_POLICY_ID_2]
+ ctx.logger.info("policy[{0}]: {1}".format(MONKEYED_POLICY_ID_2, json.dumps(policy)))
+ assert MonkeyedPolicyBody.is_the_same_dict(policy, updated_policy)
+ assert MonkeyedPolicyBody.is_the_same_dict(updated_policy, policy)
+
+ assert MONKEYED_POLICY_ID in policies
+ policy = policies[MONKEYED_POLICY_ID]
+ ctx.logger.info("expected[{0}]: {1}".format(MONKEYED_POLICY_ID, json.dumps(expected_1)))
+ ctx.logger.info("policy[{0}]: {1}".format(MONKEYED_POLICY_ID, json.dumps(policy)))
+ assert MonkeyedPolicyBody.is_the_same_dict(policy, expected_1)
+ assert MonkeyedPolicyBody.is_the_same_dict(expected_1, policy)
+
+ finally:
+ MockCloudifyContextFull.clear()
+ current_ctx.clear()
diff --git a/onap-dcae-dcaepolicy-lib/tox-local.ini b/onap-dcae-dcaepolicy-lib/tox-local.ini
new file mode 100644
index 0000000..ed9879a
--- /dev/null
+++ b/onap-dcae-dcaepolicy-lib/tox-local.ini
@@ -0,0 +1,16 @@
+[tox]
+envlist = py27
+
+[testenv]
+deps=
+ -rrequirements.txt
+ cloudify-plugins-common==3.4
+ pytest
+ coverage
+ pytest-cov
+setenv =
+ PYTHONPATH={toxinidir}
+# recreate = True
+commands=pytest -v --cov onap_dcae_dcaepolicy_lib --cov-report html
+
+
diff --git a/onap-dcae-dcaepolicy-lib/tox.ini b/onap-dcae-dcaepolicy-lib/tox.ini
index 987b009..78af290 100644
--- a/onap-dcae-dcaepolicy-lib/tox.ini
+++ b/onap-dcae-dcaepolicy-lib/tox.ini
@@ -1,11 +1,14 @@
# content of: tox.ini , put in same dir as setup.py
[tox]
-envlist = py27,py35
+envlist = py27
[testenv]
deps=
-rrequirements.txt
+ cloudify-plugins-common==3.4
pytest
coverage
pytest-cov
-commands=pytest --junitxml xunit-results.xml --cov {envsitepackagesdir} --cov-report=xml
+setenv =
+ PYTHONPATH={toxinidir}
+commands=pytest --junitxml xunit-reports/xunit-result-onap_dcae_dcaepolicy_lib.xml --cov onap_dcae_dcaepolicy_lib --cov-report=xml