You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ariatosca.apache.org by mx...@apache.org on 2017/06/08 06:56:29 UTC
incubator-ariatosca git commit: ARIA-276 Support model
instrumentation for workflows [Forced Update!]
Repository: incubator-ariatosca
Updated Branches:
refs/heads/ARIA-276-Support-model-instrumentation-for-workflows ada473f6a -> 2b29c80ff (forced update)
ARIA-276 Support model instrumentation for workflows
Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/2b29c80f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/2b29c80f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/2b29c80f
Branch: refs/heads/ARIA-276-Support-model-instrumentation-for-workflows
Commit: 2b29c80ffc09da4541254db7b4b3cd00f87c4aa9
Parents: 5afa2f7
Author: max-orlov <ma...@gigaspaces.com>
Authored: Thu Jun 8 09:52:31 2017 +0300
Committer: max-orlov <ma...@gigaspaces.com>
Committed: Thu Jun 8 09:56:15 2017 +0300
----------------------------------------------------------------------
aria/orchestrator/context/common.py | 7 +
aria/orchestrator/context/operation.py | 7 -
aria/orchestrator/decorators.py | 5 +-
.../context/test_collection_instrumentation.py | 325 -------------------
.../context/test_context_instrumentation.py | 108 ++++++
.../storage/test_collection_instrumentation.py | 257 +++++++++++++++
6 files changed, 375 insertions(+), 334 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2b29c80f/aria/orchestrator/context/common.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/context/common.py b/aria/orchestrator/context/common.py
index c98e026..f4df317 100644
--- a/aria/orchestrator/context/common.py
+++ b/aria/orchestrator/context/common.py
@@ -36,6 +36,13 @@ class BaseContext(object):
Base context object for workflow and operation
"""
+ INSTRUMENTATION_FIELDS = (
+ modeling.models.Node.attributes,
+ modeling.models.Node.properties,
+ modeling.models.NodeTemplate.attributes,
+ modeling.models.NodeTemplate.properties
+ )
+
class PrefixedLogger(object):
def __init__(self, base_logger, task_id=None):
self._logger = base_logger
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2b29c80f/aria/orchestrator/context/operation.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/context/operation.py b/aria/orchestrator/context/operation.py
index af7220d..efdc04d 100644
--- a/aria/orchestrator/context/operation.py
+++ b/aria/orchestrator/context/operation.py
@@ -29,13 +29,6 @@ class BaseOperationContext(common.BaseContext):
Context object used during operation creation and execution
"""
- INSTRUMENTATION_FIELDS = (
- aria.modeling.models.Node.attributes,
- aria.modeling.models.Node.properties,
- aria.modeling.models.NodeTemplate.attributes,
- aria.modeling.models.NodeTemplate.properties
- )
-
def __init__(self, task_id, actor_id, **kwargs):
self._task_id = task_id
self._actor_id = actor_id
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2b29c80f/aria/orchestrator/decorators.py
----------------------------------------------------------------------
diff --git a/aria/orchestrator/decorators.py b/aria/orchestrator/decorators.py
index 80f6962..389bfb8 100644
--- a/aria/orchestrator/decorators.py
+++ b/aria/orchestrator/decorators.py
@@ -49,8 +49,9 @@ def workflow(func=None, suffix_template=''):
workflow_parameters.setdefault('ctx', ctx)
workflow_parameters.setdefault('graph', task_graph.TaskGraph(workflow_name))
validate_function_arguments(func, workflow_parameters)
- with context.workflow.current.push(ctx):
- func(**workflow_parameters)
+ with ctx.model.instrument(*ctx.INSTRUMENTATION_FIELDS):
+ with context.workflow.current.push(ctx):
+ func(**workflow_parameters)
return workflow_parameters['graph']
return _wrapper
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2b29c80f/tests/orchestrator/context/test_collection_instrumentation.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/context/test_collection_instrumentation.py b/tests/orchestrator/context/test_collection_instrumentation.py
deleted file mode 100644
index ae3e8ac..0000000
--- a/tests/orchestrator/context/test_collection_instrumentation.py
+++ /dev/null
@@ -1,325 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You 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.
-
-import pytest
-
-from aria.modeling import models
-from aria.storage import collection_instrumentation
-from aria.orchestrator.context import operation
-
-from tests import (
- mock,
- storage
-)
-
-
-class MockActor(object):
- def __init__(self):
- self.dict_ = {}
- self.list_ = []
-
-
-class MockMAPI(object):
-
- def __init__(self):
- pass
-
- def put(self, *args, **kwargs):
- pass
-
- def update(self, *args, **kwargs):
- pass
-
-
-class CollectionInstrumentation(object):
-
- @pytest.fixture
- def actor(self):
- return MockActor()
-
- @pytest.fixture
- def model(self):
- return MockMAPI()
-
- @pytest.fixture
- def dict_(self, actor, model):
- return collection_instrumentation._InstrumentedDict(model, actor, 'dict_', models.Attribute)
-
- @pytest.fixture
- def list_(self, actor, model):
- return collection_instrumentation._InstrumentedList(model, actor, 'list_', models.Attribute)
-
-
-class TestDict(CollectionInstrumentation):
-
- def test_keys(self, actor, dict_):
- dict_.update(
- {
- 'key1': models.Attribute.wrap('key1', 'value1'),
- 'key2': models.Attribute.wrap('key2', 'value2')
- }
- )
- assert sorted(dict_.keys()) == sorted(['key1', 'key2']) == sorted(actor.dict_.keys())
-
- def test_values(self, actor, dict_):
- dict_.update({
- 'key1': models.Attribute.wrap('key1', 'value1'),
- 'key2': models.Attribute.wrap('key1', 'value2')
- })
- assert (sorted(dict_.values()) ==
- sorted(['value1', 'value2']) ==
- sorted(v.value for v in actor.dict_.values()))
-
- def test_items(self, dict_):
- dict_.update({
- 'key1': models.Attribute.wrap('key1', 'value1'),
- 'key2': models.Attribute.wrap('key1', 'value2')
- })
- assert sorted(dict_.items()) == sorted([('key1', 'value1'), ('key2', 'value2')])
-
- def test_iter(self, actor, dict_):
- dict_.update({
- 'key1': models.Attribute.wrap('key1', 'value1'),
- 'key2': models.Attribute.wrap('key1', 'value2')
- })
- assert sorted(list(dict_)) == sorted(['key1', 'key2']) == sorted(actor.dict_.keys())
-
- def test_bool(self, dict_):
- assert not dict_
- dict_.update({
- 'key1': models.Attribute.wrap('key1', 'value1'),
- 'key2': models.Attribute.wrap('key1', 'value2')
- })
- assert dict_
-
- def test_set_item(self, actor, dict_):
- dict_['key1'] = models.Attribute.wrap('key1', 'value1')
- assert dict_['key1'] == 'value1' == actor.dict_['key1'].value
- assert isinstance(actor.dict_['key1'], models.Attribute)
-
- def test_nested(self, actor, dict_):
- dict_['key'] = {}
- assert isinstance(actor.dict_['key'], models.Attribute)
- assert dict_['key'] == actor.dict_['key'].value == {}
-
- dict_['key']['inner_key'] = 'value'
-
- assert len(dict_) == 1
- assert 'inner_key' in dict_['key']
- assert dict_['key']['inner_key'] == 'value'
- assert dict_['key'].keys() == ['inner_key']
- assert dict_['key'].values() == ['value']
- assert dict_['key'].items() == [('inner_key', 'value')]
- assert isinstance(actor.dict_['key'], models.Attribute)
- assert isinstance(dict_['key'], collection_instrumentation._InstrumentedDict)
-
- dict_['key'].update({'updated_key': 'updated_value'})
- assert len(dict_) == 1
- assert 'updated_key' in dict_['key']
- assert dict_['key']['updated_key'] == 'updated_value'
- assert sorted(dict_['key'].keys()) == sorted(['inner_key', 'updated_key'])
- assert sorted(dict_['key'].values()) == sorted(['value', 'updated_value'])
- assert sorted(dict_['key'].items()) == sorted([('inner_key', 'value'),
- ('updated_key', 'updated_value')])
- assert isinstance(actor.dict_['key'], models.Attribute)
- assert isinstance(dict_['key'], collection_instrumentation._InstrumentedDict)
-
- dict_.update({'key': 'override_value'})
- assert len(dict_) == 1
- assert 'key' in dict_
- assert dict_['key'] == 'override_value'
- assert len(actor.dict_) == 1
- assert isinstance(actor.dict_['key'], models.Attribute)
- assert actor.dict_['key'].value == 'override_value'
-
- def test_get_item(self, actor, dict_):
- dict_['key1'] = models.Attribute.wrap('key1', 'value1')
- assert isinstance(actor.dict_['key1'], models.Attribute)
-
- def test_update(self, actor, dict_):
- dict_['key1'] = 'value1'
-
- new_dict = {'key2': 'value2'}
- dict_.update(new_dict)
- assert len(dict_) == 2
- assert dict_['key2'] == 'value2'
- assert isinstance(actor.dict_['key2'], models.Attribute)
-
- new_dict = {}
- new_dict.update(dict_)
- assert new_dict['key1'] == dict_['key1']
-
- def test_copy(self, dict_):
- dict_['key1'] = 'value1'
-
- new_dict = dict_.copy()
- assert new_dict is not dict_
- assert new_dict == dict_
-
- dict_['key1'] = 'value2'
- assert new_dict['key1'] == 'value1'
- assert dict_['key1'] == 'value2'
-
- def test_clear(self, dict_):
- dict_['key1'] = 'value1'
- dict_.clear()
-
- assert len(dict_) == 0
-
-
-class TestList(CollectionInstrumentation):
-
- def test_append(self, actor, list_):
- list_.append(models.Attribute.wrap('name', 'value1'))
- list_.append('value2')
- assert len(actor.list_) == 2
- assert len(list_) == 2
- assert isinstance(actor.list_[0], models.Attribute)
- assert list_[0] == 'value1'
-
- assert isinstance(actor.list_[1], models.Attribute)
- assert list_[1] == 'value2'
-
- list_[0] = 'new_value1'
- list_[1] = 'new_value2'
- assert isinstance(actor.list_[1], models.Attribute)
- assert isinstance(actor.list_[1], models.Attribute)
- assert list_[0] == 'new_value1'
- assert list_[1] == 'new_value2'
-
- def test_iter(self, list_):
- list_.append('value1')
- list_.append('value2')
- assert sorted(list_) == sorted(['value1', 'value2'])
-
- def test_insert(self, actor, list_):
- list_.append('value1')
- list_.insert(0, 'value2')
- list_.insert(2, 'value3')
- list_.insert(10, 'value4')
- assert sorted(list_) == sorted(['value1', 'value2', 'value3', 'value4'])
- assert len(actor.list_) == 4
-
- def test_set(self, list_):
- list_.append('value1')
- list_.append('value2')
-
- list_[1] = 'value3'
- assert len(list_) == 2
- assert sorted(list_) == sorted(['value1', 'value3'])
-
- def test_insert_into_nested(self, actor, list_):
- list_.append([])
-
- list_[0].append('inner_item')
- assert isinstance(actor.list_[0], models.Attribute)
- assert len(list_) == 1
- assert list_[0][0] == 'inner_item'
-
- list_[0].append('new_item')
- assert isinstance(actor.list_[0], models.Attribute)
- assert len(list_) == 1
- assert list_[0][1] == 'new_item'
-
- assert list_[0] == ['inner_item', 'new_item']
- assert ['inner_item', 'new_item'] == list_[0]
-
-
-class TestDictList(CollectionInstrumentation):
- def test_dict_in_list(self, actor, list_):
- list_.append({})
- assert len(list_) == 1
- assert isinstance(actor.list_[0], models.Attribute)
- assert actor.list_[0].value == {}
-
- list_[0]['key'] = 'value'
- assert list_[0]['key'] == 'value'
- assert len(actor.list_) == 1
- assert isinstance(actor.list_[0], models.Attribute)
- assert actor.list_[0].value['key'] == 'value'
-
- def test_list_in_dict(self, actor, dict_):
- dict_['key'] = []
- assert len(dict_) == 1
- assert isinstance(actor.dict_['key'], models.Attribute)
- assert actor.dict_['key'].value == []
-
- dict_['key'].append('value')
- assert dict_['key'][0] == 'value'
- assert len(actor.dict_) == 1
- assert isinstance(actor.dict_['key'], models.Attribute)
- assert actor.dict_['key'].value[0] == 'value'
-
-
-class TestModelInstrumentation(object):
-
- @pytest.fixture
- def workflow_ctx(self, tmpdir):
- context = mock.context.simple(str(tmpdir), inmemory=True)
- yield context
- storage.release_sqlite_storage(context.model)
-
- def test_attributes_access(self, workflow_ctx):
- node = workflow_ctx.model.node.list()[0]
- task = models.Task(node=node)
- workflow_ctx.model.task.put(task)
-
- ctx = operation.NodeOperationContext(
- task.id, node.id, name='', service_id=workflow_ctx.model.service.list()[0].id,
- model_storage=workflow_ctx.model, resource_storage=workflow_ctx.resource,
- execution_id=1)
-
- def _run_assertions(is_under_ctx):
- def ctx_assert(expr):
- if is_under_ctx:
- assert expr
- else:
- assert not expr
-
- ctx_assert(isinstance(ctx.node.attributes,
- collection_instrumentation._InstrumentedDict))
- assert not isinstance(ctx.node.properties,
- collection_instrumentation._InstrumentedCollection)
-
- for rel in ctx.node.inbound_relationships:
- ctx_assert(isinstance(rel, collection_instrumentation._WrappedModel))
- ctx_assert(isinstance(rel.source_node.attributes,
- collection_instrumentation._InstrumentedDict))
- ctx_assert(isinstance(rel.target_node.attributes,
- collection_instrumentation._InstrumentedDict))
-
- for node in ctx.model.node:
- ctx_assert(isinstance(node.attributes,
- collection_instrumentation._InstrumentedDict))
- assert not isinstance(node.properties,
- collection_instrumentation._InstrumentedCollection)
-
- for rel in ctx.model.relationship:
- ctx_assert(isinstance(rel, collection_instrumentation._WrappedModel))
-
- ctx_assert(isinstance(rel.source_node.attributes,
- collection_instrumentation._InstrumentedDict))
- ctx_assert(isinstance(rel.target_node.attributes,
- collection_instrumentation._InstrumentedDict))
-
- assert not isinstance(rel.source_node.properties,
- collection_instrumentation._InstrumentedCollection)
- assert not isinstance(rel.target_node.properties,
- collection_instrumentation._InstrumentedCollection)
-
- with ctx.model.instrument(models.Node.attributes):
- _run_assertions(True)
-
- _run_assertions(False)
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2b29c80f/tests/orchestrator/context/test_context_instrumentation.py
----------------------------------------------------------------------
diff --git a/tests/orchestrator/context/test_context_instrumentation.py b/tests/orchestrator/context/test_context_instrumentation.py
new file mode 100644
index 0000000..69819a9
--- /dev/null
+++ b/tests/orchestrator/context/test_context_instrumentation.py
@@ -0,0 +1,108 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+import pytest
+
+from aria.modeling import models
+from aria.storage import collection_instrumentation
+from aria.orchestrator.context import operation
+
+from tests import (
+ mock,
+ storage
+)
+
+
+class TestContextInstrumentation(object):
+
+ @pytest.fixture
+ def workflow_ctx(self, tmpdir):
+ context = mock.context.simple(str(tmpdir), inmemory=True)
+ yield context
+ storage.release_sqlite_storage(context.model)
+
+ def test_workflow_context_instrumentation(self, workflow_ctx):
+ with workflow_ctx.model.instrument(models.Node.attributes):
+ self._run_common_assertions(workflow_ctx, True)
+ self._run_common_assertions(workflow_ctx, False)
+
+ def test_operation_context_instrumentation(self, workflow_ctx):
+ node = workflow_ctx.model.node.list()[0]
+ task = models.Task(node=node)
+ workflow_ctx.model.task.put(task)
+
+ ctx = operation.NodeOperationContext(
+ task.id, node.id, name='', service_id=workflow_ctx.model.service.list()[0].id,
+ model_storage=workflow_ctx.model, resource_storage=workflow_ctx.resource,
+ execution_id=1)
+
+
+ with ctx.model.instrument(models.Node.attributes):
+ self._run_op_assertions(ctx, True)
+ self._run_common_assertions(ctx, True)
+
+ self._run_op_assertions(ctx, False)
+ self._run_common_assertions(ctx, False)
+ @staticmethod
+ def ctx_assert(expr, is_under_ctx):
+ if is_under_ctx:
+ assert expr
+ else:
+ assert not expr
+
+ def _run_op_assertions(self, ctx, is_under_ctx):
+ self.ctx_assert(isinstance(ctx.node.attributes,
+ collection_instrumentation._InstrumentedDict), is_under_ctx)
+ assert not isinstance(ctx.node.properties,
+ collection_instrumentation._InstrumentedCollection)
+
+ for rel in ctx.node.inbound_relationships:
+ self.ctx_assert(
+ isinstance(rel, collection_instrumentation._WrappedModel), is_under_ctx)
+ self.ctx_assert(
+ isinstance(rel.source_node.attributes,
+ collection_instrumentation._InstrumentedDict),
+ is_under_ctx)
+ self.ctx_assert(
+ isinstance(rel.target_node.attributes,
+ collection_instrumentation._InstrumentedDict),
+ is_under_ctx)
+
+ def _run_common_assertions(self, ctx, is_under_ctx):
+
+ for node in ctx.model.node:
+ self.ctx_assert(
+ isinstance(node.attributes, collection_instrumentation._InstrumentedDict),
+ is_under_ctx)
+ assert not isinstance(node.properties,
+ collection_instrumentation._InstrumentedCollection)
+
+ for rel in ctx.model.relationship:
+ self.ctx_assert(
+ isinstance(rel, collection_instrumentation._WrappedModel), is_under_ctx)
+
+ self.ctx_assert(
+ isinstance(rel.source_node.attributes,
+ collection_instrumentation._InstrumentedDict),
+ is_under_ctx)
+ self.ctx_assert(
+ isinstance(rel.target_node.attributes,
+ collection_instrumentation._InstrumentedDict),
+ is_under_ctx)
+
+ assert not isinstance(rel.source_node.properties,
+ collection_instrumentation._InstrumentedCollection)
+ assert not isinstance(rel.target_node.properties,
+ collection_instrumentation._InstrumentedCollection)
http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/2b29c80f/tests/storage/test_collection_instrumentation.py
----------------------------------------------------------------------
diff --git a/tests/storage/test_collection_instrumentation.py b/tests/storage/test_collection_instrumentation.py
new file mode 100644
index 0000000..e915421
--- /dev/null
+++ b/tests/storage/test_collection_instrumentation.py
@@ -0,0 +1,257 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+import pytest
+
+from aria.modeling import models
+from aria.storage import collection_instrumentation
+
+
+class MockActor(object):
+ def __init__(self):
+ self.dict_ = {}
+ self.list_ = []
+
+
+class MockMAPI(object):
+
+ def __init__(self):
+ pass
+
+ def put(self, *args, **kwargs):
+ pass
+
+ def update(self, *args, **kwargs):
+ pass
+
+
+class CollectionInstrumentation(object):
+
+ @pytest.fixture
+ def actor(self):
+ return MockActor()
+
+ @pytest.fixture
+ def model(self):
+ return MockMAPI()
+
+ @pytest.fixture
+ def dict_(self, actor, model):
+ return collection_instrumentation._InstrumentedDict(model, actor, 'dict_', models.Attribute)
+
+ @pytest.fixture
+ def list_(self, actor, model):
+ return collection_instrumentation._InstrumentedList(model, actor, 'list_', models.Attribute)
+
+
+class TestDict(CollectionInstrumentation):
+
+ def test_keys(self, actor, dict_):
+ dict_.update(
+ {
+ 'key1': models.Attribute.wrap('key1', 'value1'),
+ 'key2': models.Attribute.wrap('key2', 'value2')
+ }
+ )
+ assert sorted(dict_.keys()) == sorted(['key1', 'key2']) == sorted(actor.dict_.keys())
+
+ def test_values(self, actor, dict_):
+ dict_.update({
+ 'key1': models.Attribute.wrap('key1', 'value1'),
+ 'key2': models.Attribute.wrap('key1', 'value2')
+ })
+ assert (sorted(dict_.values()) ==
+ sorted(['value1', 'value2']) ==
+ sorted(v.value for v in actor.dict_.values()))
+
+ def test_items(self, dict_):
+ dict_.update({
+ 'key1': models.Attribute.wrap('key1', 'value1'),
+ 'key2': models.Attribute.wrap('key1', 'value2')
+ })
+ assert sorted(dict_.items()) == sorted([('key1', 'value1'), ('key2', 'value2')])
+
+ def test_iter(self, actor, dict_):
+ dict_.update({
+ 'key1': models.Attribute.wrap('key1', 'value1'),
+ 'key2': models.Attribute.wrap('key1', 'value2')
+ })
+ assert sorted(list(dict_)) == sorted(['key1', 'key2']) == sorted(actor.dict_.keys())
+
+ def test_bool(self, dict_):
+ assert not dict_
+ dict_.update({
+ 'key1': models.Attribute.wrap('key1', 'value1'),
+ 'key2': models.Attribute.wrap('key1', 'value2')
+ })
+ assert dict_
+
+ def test_set_item(self, actor, dict_):
+ dict_['key1'] = models.Attribute.wrap('key1', 'value1')
+ assert dict_['key1'] == 'value1' == actor.dict_['key1'].value
+ assert isinstance(actor.dict_['key1'], models.Attribute)
+
+ def test_nested(self, actor, dict_):
+ dict_['key'] = {}
+ assert isinstance(actor.dict_['key'], models.Attribute)
+ assert dict_['key'] == actor.dict_['key'].value == {}
+
+ dict_['key']['inner_key'] = 'value'
+
+ assert len(dict_) == 1
+ assert 'inner_key' in dict_['key']
+ assert dict_['key']['inner_key'] == 'value'
+ assert dict_['key'].keys() == ['inner_key']
+ assert dict_['key'].values() == ['value']
+ assert dict_['key'].items() == [('inner_key', 'value')]
+ assert isinstance(actor.dict_['key'], models.Attribute)
+ assert isinstance(dict_['key'], collection_instrumentation._InstrumentedDict)
+
+ dict_['key'].update({'updated_key': 'updated_value'})
+ assert len(dict_) == 1
+ assert 'updated_key' in dict_['key']
+ assert dict_['key']['updated_key'] == 'updated_value'
+ assert sorted(dict_['key'].keys()) == sorted(['inner_key', 'updated_key'])
+ assert sorted(dict_['key'].values()) == sorted(['value', 'updated_value'])
+ assert sorted(dict_['key'].items()) == sorted([('inner_key', 'value'),
+ ('updated_key', 'updated_value')])
+ assert isinstance(actor.dict_['key'], models.Attribute)
+ assert isinstance(dict_['key'], collection_instrumentation._InstrumentedDict)
+
+ dict_.update({'key': 'override_value'})
+ assert len(dict_) == 1
+ assert 'key' in dict_
+ assert dict_['key'] == 'override_value'
+ assert len(actor.dict_) == 1
+ assert isinstance(actor.dict_['key'], models.Attribute)
+ assert actor.dict_['key'].value == 'override_value'
+
+ def test_get_item(self, actor, dict_):
+ dict_['key1'] = models.Attribute.wrap('key1', 'value1')
+ assert isinstance(actor.dict_['key1'], models.Attribute)
+
+ def test_update(self, actor, dict_):
+ dict_['key1'] = 'value1'
+
+ new_dict = {'key2': 'value2'}
+ dict_.update(new_dict)
+ assert len(dict_) == 2
+ assert dict_['key2'] == 'value2'
+ assert isinstance(actor.dict_['key2'], models.Attribute)
+
+ new_dict = {}
+ new_dict.update(dict_)
+ assert new_dict['key1'] == dict_['key1']
+
+ def test_copy(self, dict_):
+ dict_['key1'] = 'value1'
+
+ new_dict = dict_.copy()
+ assert new_dict is not dict_
+ assert new_dict == dict_
+
+ dict_['key1'] = 'value2'
+ assert new_dict['key1'] == 'value1'
+ assert dict_['key1'] == 'value2'
+
+ def test_clear(self, dict_):
+ dict_['key1'] = 'value1'
+ dict_.clear()
+
+ assert len(dict_) == 0
+
+
+class TestList(CollectionInstrumentation):
+
+ def test_append(self, actor, list_):
+ list_.append(models.Attribute.wrap('name', 'value1'))
+ list_.append('value2')
+ assert len(actor.list_) == 2
+ assert len(list_) == 2
+ assert isinstance(actor.list_[0], models.Attribute)
+ assert list_[0] == 'value1'
+
+ assert isinstance(actor.list_[1], models.Attribute)
+ assert list_[1] == 'value2'
+
+ list_[0] = 'new_value1'
+ list_[1] = 'new_value2'
+ assert isinstance(actor.list_[1], models.Attribute)
+ assert isinstance(actor.list_[1], models.Attribute)
+ assert list_[0] == 'new_value1'
+ assert list_[1] == 'new_value2'
+
+ def test_iter(self, list_):
+ list_.append('value1')
+ list_.append('value2')
+ assert sorted(list_) == sorted(['value1', 'value2'])
+
+ def test_insert(self, actor, list_):
+ list_.append('value1')
+ list_.insert(0, 'value2')
+ list_.insert(2, 'value3')
+ list_.insert(10, 'value4')
+ assert sorted(list_) == sorted(['value1', 'value2', 'value3', 'value4'])
+ assert len(actor.list_) == 4
+
+ def test_set(self, list_):
+ list_.append('value1')
+ list_.append('value2')
+
+ list_[1] = 'value3'
+ assert len(list_) == 2
+ assert sorted(list_) == sorted(['value1', 'value3'])
+
+ def test_insert_into_nested(self, actor, list_):
+ list_.append([])
+
+ list_[0].append('inner_item')
+ assert isinstance(actor.list_[0], models.Attribute)
+ assert len(list_) == 1
+ assert list_[0][0] == 'inner_item'
+
+ list_[0].append('new_item')
+ assert isinstance(actor.list_[0], models.Attribute)
+ assert len(list_) == 1
+ assert list_[0][1] == 'new_item'
+
+ assert list_[0] == ['inner_item', 'new_item']
+ assert ['inner_item', 'new_item'] == list_[0]
+
+
+class TestDictList(CollectionInstrumentation):
+ def test_dict_in_list(self, actor, list_):
+ list_.append({})
+ assert len(list_) == 1
+ assert isinstance(actor.list_[0], models.Attribute)
+ assert actor.list_[0].value == {}
+
+ list_[0]['key'] = 'value'
+ assert list_[0]['key'] == 'value'
+ assert len(actor.list_) == 1
+ assert isinstance(actor.list_[0], models.Attribute)
+ assert actor.list_[0].value['key'] == 'value'
+
+ def test_list_in_dict(self, actor, dict_):
+ dict_['key'] = []
+ assert len(dict_) == 1
+ assert isinstance(actor.dict_['key'], models.Attribute)
+ assert actor.dict_['key'].value == []
+
+ dict_['key'].append('value')
+ assert dict_['key'][0] == 'value'
+ assert len(actor.dict_) == 1
+ assert isinstance(actor.dict_['key'], models.Attribute)
+ assert actor.dict_['key'].value[0] == 'value'