[CORD-2391] Supporting one_of keys
Change-Id: I9d62ca3069f7218839c532270cf789a6fd33b120
diff --git a/src/grpc_client/models_accessor.py b/src/grpc_client/models_accessor.py
index 918c04d..5d54644 100644
--- a/src/grpc_client/models_accessor.py
+++ b/src/grpc_client/models_accessor.py
@@ -41,10 +41,22 @@
filter = {}
for k in filter_keys:
- try:
- filter[k] = data[k]
- except KeyError, e:
- raise Exception("[XOS-TOSCA] Model %s doesn't have a property for the specified tosca_key (%s)" % (class_name, e))
+ if isinstance(k, str):
+ try:
+ filter[k] = data[k]
+ except KeyError, e:
+ raise Exception("[XOS-TOSCA] Model %s doesn't have a property for the specified tosca_key (%s)" % (class_name, e))
+ elif isinstance(k, list):
+ # one of they keys in this list has to be set
+ one_of_key = None
+ for i in k:
+ if i in data:
+ one_of_key = i
+ one_of_key_val = data[i]
+ if not one_of_key:
+ raise Exception("[XOS-TOSCA] Model %s doesn't have a property for the specified tosca_key_one_of (%s)" % (class_name, k))
+ else:
+ filter[one_of_key] = one_of_key_val
key = "%s~%s" % (username, password)
if not key in RESOURCES:
diff --git a/test/test_grpc_models_accessor.py b/test/test_grpc_models_accessor.py
index 729fac3..60e86e0 100644
--- a/test/test_grpc_models_accessor.py
+++ b/test/test_grpc_models_accessor.py
@@ -37,7 +37,8 @@
'username~pass': {
'test-model': FakeResource,
'single-key': FakeResource,
- 'double-key': FakeResource
+ 'double-key': FakeResource,
+ 'one-of-key': FakeResource
}
}
@@ -47,6 +48,7 @@
'empty-key': [],
'single-key': ['fake_key'],
'double-key': ['key_1', 'key_2'],
+ 'one-of-key': ['key_1', ['key_2', 'key_3']],
}
USERNAME = 'username'
@@ -134,6 +136,46 @@
@patch.object(FakeResource.objects, "filter")
@patch.object(FakeResource.objects, "new", MagicMock(return_value=FakeModel))
@patch.dict(TOSCA_KEYS, mock_keys, clear=True)
+ def test_one_of_key(self, mock_filter):
+ """
+ [GRPCModelsAccessor] get_model_from_classname: should use a composite with one_of key to lookup a model
+ """
+ # NOTE it should be valid for items with either one of the keys
+ data2 = {
+ "name": "test",
+ "key_1": "key1",
+ "key_2": "key2"
+ }
+ with patch.dict(RESOURCES, mock_resources, clear=True):
+ model = GRPCModelsAccessor.get_model_from_classname('one-of-key', data2, USERNAME, PASSWORD)
+ mock_filter.assert_called_with(key_1="key1", key_2="key2")
+ self.assertEqual(model, FakeModel)
+
+ data3 = {
+ "name": "test",
+ "key_1": "key1",
+ "key_3": "key3"
+ }
+ with patch.dict(RESOURCES, mock_resources, clear=True):
+ model = GRPCModelsAccessor.get_model_from_classname('one-of-key', data3, USERNAME, PASSWORD)
+ mock_filter.assert_called_with(key_1="key1", key_3="key3")
+ self.assertEqual(model, FakeModel)
+
+ @patch.object(FakeResource.objects, "filter")
+ @patch.object(FakeResource.objects, "new", MagicMock(return_value=FakeModel))
+ @patch.dict(TOSCA_KEYS, mock_keys, clear=True)
+ def test_one_of_key_error(self, mock_filter):
+ data = {
+ "name": "test",
+ "key_1": "key1"
+ }
+ with self.assertRaises(Exception) as e:
+ GRPCModelsAccessor.get_model_from_classname('one-of-key', data, USERNAME, PASSWORD)
+ self.assertEqual(e.exception.message, "[XOS-TOSCA] Model one-of-key doesn't have a property for the specified tosca_key_one_of (['key_2', 'key_3'])")
+
+ @patch.object(FakeResource.objects, "filter")
+ @patch.object(FakeResource.objects, "new", MagicMock(return_value=FakeModel))
+ @patch.dict(TOSCA_KEYS, mock_keys, clear=True)
def test_new_model(self, mock_filter):
"""
[GRPCModelsAccessor] get_model_from_classname: should create a new model
diff --git a/test/test_tosca_parser_e2e.py b/test/test_tosca_parser_e2e.py
index 154638f..6a44b6f 100644
--- a/test/test_tosca_parser_e2e.py
+++ b/test/test_tosca_parser_e2e.py
@@ -57,7 +57,7 @@
@patch.dict(RESOURCES, mock_resources, clear=True)
@patch.object(FakeGuiExt.objects, 'filter', MagicMock(return_value=[FakeModel]))
@patch.object(FakeModel, 'save')
- def _test_basic_creation(self, mock_save):
+ def test_basic_creation(self, mock_save):
"""
[TOSCA_Parser] Should save models defined in a TOSCA recipe
"""
@@ -98,7 +98,7 @@
@patch.dict(RESOURCES, mock_resources, clear=True)
@patch.object(FakeGuiExt.objects, 'filter', MagicMock(return_value=[FakeModel]))
@patch.object(FakeModel, 'delete')
- def _test_basic_deletion(self, mock_delete):
+ def test_basic_deletion(self, mock_delete):
"""
[TOSCA_Parser] Should delete models defined in a TOSCA recipe
"""
@@ -135,7 +135,7 @@
@patch.object(FakeSite.objects, 'filter', MagicMock(return_value=[FakeModel]))
@patch.object(FakeUser.objects, 'filter', MagicMock(return_value=[FakeModel]))
@patch.object(FakeModel, 'save')
- def _test_related_models_creation(self, mock_save):
+ def test_related_models_creation(self, mock_save):
"""
[TOSCA_Parser] Should save related models defined in a TOSCA recipe
"""
@@ -161,7 +161,7 @@
hosts_nodes: True
# User
- user_test:
+ usertest:
type: tosca.nodes.User
properties:
username: test@opencord.org
@@ -183,20 +183,20 @@
self.assertEqual(mock_save.call_count, 2)
self.assertIsNotNone(parser.templates_by_model_name['site_onlab'])
- self.assertIsNotNone(parser.templates_by_model_name['user_test'])
- self.assertEqual(parser.ordered_models_name, ['site_onlab', 'user_test'])
+ self.assertIsNotNone(parser.templates_by_model_name['usertest'])
+ self.assertEqual(parser.ordered_models_name, ['site_onlab', 'usertest'])
# check that the model was saved with the expected values
saved_site = parser.saved_model_by_name['site_onlab']
self.assertEqual(saved_site.name, 'Open Networking Lab')
- saved_user = parser.saved_model_by_name['user_test']
+ saved_user = parser.saved_model_by_name['usertest']
self.assertEqual(saved_user.firstname, 'User')
self.assertEqual(saved_user.site_id, 1)
@patch.dict(RESOURCES, mock_resources, clear=True)
@patch.object(FakeSite.objects, 'filter', MagicMock(return_value=[]))
- def _test_must_exist_fail(self):
+ def test_must_exist_fail(self):
"""
[TOSCA_Parser] Should throw an error if an object with 'must_exist' does not exist
"""