2015-11-27 23:25:33 +01:00
|
|
|
# Copyright 2014 Amazon.com, Inc. or its affiliates. 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. A copy of
|
|
|
|
# the License is located at
|
|
|
|
#
|
2021-09-22 18:34:33 +02:00
|
|
|
# https://aws.amazon.com/apache2.0/
|
2015-11-27 23:25:33 +01:00
|
|
|
#
|
|
|
|
# or in the 'license' file accompanying this file. This file 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.
|
|
|
|
|
|
|
|
from botocore.model import DenormalizedStructureBuilder
|
|
|
|
|
|
|
|
from boto3.resources.model import ResourceModel, Action, Collection, Waiter
|
|
|
|
from tests import BaseTestCase
|
|
|
|
|
|
|
|
|
|
|
|
class TestModels(BaseTestCase):
|
|
|
|
def test_resource_name(self):
|
|
|
|
model = ResourceModel('test', {}, {})
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert model.name == 'test'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_resource_shape(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'shape': 'Frob'
|
|
|
|
}, {})
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert model.shape == 'Frob'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_resource_identifiers(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'identifiers': [
|
|
|
|
{'name': 'one'},
|
2016-05-22 04:03:29 +02:00
|
|
|
{'name': 'two', 'memberName': 'three'}
|
2015-11-27 23:25:33 +01:00
|
|
|
]
|
|
|
|
}, {})
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert model.identifiers[0].name == 'one'
|
|
|
|
assert model.identifiers[1].name == 'two'
|
|
|
|
assert model.identifiers[1].member_name == 'three'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_resource_action_raw(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'actions': {
|
|
|
|
'GetFrobs': {
|
|
|
|
'request': {
|
|
|
|
'operation': 'GetFrobsOperation',
|
|
|
|
'params': [
|
|
|
|
{'target': 'FrobId', 'source': 'identifier',
|
|
|
|
'name': 'Id'}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
'path': 'Container.Frobs[]'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, {})
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert isinstance(model.actions, list)
|
|
|
|
assert len(model.actions) == 1
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
action = model.actions[0]
|
2021-10-04 19:51:32 +02:00
|
|
|
assert isinstance(action, Action)
|
|
|
|
assert action.request.operation == 'GetFrobsOperation'
|
|
|
|
assert isinstance(action.request.params, list)
|
|
|
|
assert len(action.request.params) == 1
|
|
|
|
assert action.request.params[0].target == 'FrobId'
|
|
|
|
assert action.request.params[0].source == 'identifier'
|
|
|
|
assert action.request.params[0].name == 'Id'
|
|
|
|
assert action.path == 'Container.Frobs[]'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_resource_action_response_resource(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'actions': {
|
|
|
|
'GetFrobs': {
|
|
|
|
'resource': {
|
|
|
|
'type': 'Frob',
|
|
|
|
'path': 'Container.Frobs[]'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, {
|
|
|
|
'Frob': {}
|
|
|
|
})
|
|
|
|
|
|
|
|
action = model.actions[0]
|
2021-10-04 19:51:32 +02:00
|
|
|
assert action.resource.type == 'Frob'
|
|
|
|
assert action.resource.path == 'Container.Frobs[]'
|
|
|
|
assert isinstance(action.resource.model, ResourceModel)
|
|
|
|
assert action.resource.model.name == 'Frob'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_resource_load_action(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'load': {
|
|
|
|
'request': {
|
|
|
|
'operation': 'GetFrobInfo'
|
|
|
|
},
|
|
|
|
'path': '$'
|
|
|
|
}
|
|
|
|
}, {})
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert isinstance(model.load, Action)
|
|
|
|
assert model.load.request.operation == 'GetFrobInfo'
|
|
|
|
assert model.load.path == '$'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_resource_batch_action(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'batchActions': {
|
|
|
|
'Delete': {
|
|
|
|
'request': {
|
|
|
|
'operation': 'DeleteObjects',
|
|
|
|
'params': [
|
|
|
|
{'target': 'Bucket', 'sourceType': 'identifier',
|
|
|
|
'source': 'BucketName'}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, {})
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert isinstance(model.batch_actions, list)
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
action = model.batch_actions[0]
|
2021-10-04 19:51:32 +02:00
|
|
|
assert isinstance(action, Action)
|
|
|
|
assert action.request.operation == 'DeleteObjects'
|
|
|
|
assert action.request.params[0].target == 'Bucket'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_sub_resources(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'has': {
|
|
|
|
'RedFrob': {
|
|
|
|
'resource': {
|
|
|
|
'type': 'Frob',
|
|
|
|
'identifiers': [
|
|
|
|
{'target': 'Id', 'source': 'input'}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'GreenFrob': {
|
|
|
|
'resource': {
|
|
|
|
'type': 'Frob',
|
|
|
|
'identifiers': [
|
|
|
|
{'target': 'Id', 'source': 'input'}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, {
|
|
|
|
'Frob': {}
|
|
|
|
})
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert isinstance(model.subresources, list)
|
|
|
|
assert len(model.subresources) == 2
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
action = model.subresources[0]
|
|
|
|
resource = action.resource
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert action.name in ['RedFrob', 'GreenFrob']
|
|
|
|
assert resource.identifiers[0].target == 'Id'
|
|
|
|
assert resource.identifiers[0].source == 'input'
|
|
|
|
assert resource.type == 'Frob'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_resource_references(self):
|
|
|
|
model_def = {
|
|
|
|
'has': {
|
|
|
|
'Frob': {
|
|
|
|
'resource': {
|
|
|
|
'type': 'Frob',
|
|
|
|
'identifiers': [
|
2021-11-03 18:27:47 +01:00
|
|
|
{
|
|
|
|
'target': 'Id',
|
|
|
|
'source': 'data',
|
|
|
|
'path': 'FrobId'
|
|
|
|
}
|
2015-11-27 23:25:33 +01:00
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
resource_defs = {
|
|
|
|
'Frob': {}
|
|
|
|
}
|
|
|
|
model = ResourceModel('test', model_def, resource_defs)
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert isinstance(model.references, list)
|
|
|
|
assert len(model.references) == 1
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
ref = model.references[0]
|
2021-10-04 19:51:32 +02:00
|
|
|
assert ref.name == 'frob'
|
|
|
|
assert ref.resource.type == 'Frob'
|
|
|
|
assert ref.resource.identifiers[0].target == 'Id'
|
|
|
|
assert ref.resource.identifiers[0].source == 'data'
|
|
|
|
assert ref.resource.identifiers[0].path == 'FrobId'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_resource_collections(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'hasMany': {
|
|
|
|
'Frobs': {
|
|
|
|
'request': {
|
|
|
|
'operation': 'GetFrobList'
|
|
|
|
},
|
|
|
|
'resource': {
|
|
|
|
'type': 'Frob',
|
|
|
|
'path': 'FrobList[]'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, {
|
|
|
|
'Frob': {}
|
|
|
|
})
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert isinstance(model.collections, list)
|
|
|
|
assert len(model.collections) == 1
|
|
|
|
assert isinstance(model.collections[0], Collection)
|
|
|
|
assert model.collections[0].request.operation == 'GetFrobList'
|
|
|
|
assert model.collections[0].resource.type == 'Frob'
|
|
|
|
assert model.collections[0].resource.model.name == 'Frob'
|
|
|
|
assert model.collections[0].resource.path == 'FrobList[]'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_waiter(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'waiters': {
|
|
|
|
'Exists': {
|
|
|
|
'waiterName': 'ObjectExists',
|
|
|
|
'params': [
|
|
|
|
{'target': 'Bucket', 'sourceType': 'identifier',
|
|
|
|
'source': 'BucketName'}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, {})
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert isinstance(model.waiters, list)
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
waiter = model.waiters[0]
|
2021-10-04 19:51:32 +02:00
|
|
|
assert isinstance(waiter, Waiter)
|
|
|
|
assert waiter.name == 'wait_until_exists'
|
|
|
|
assert waiter.waiter_name == 'ObjectExists'
|
|
|
|
assert waiter.params[0].target == 'Bucket'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
2021-11-03 18:27:47 +01:00
|
|
|
|
2015-11-27 23:25:33 +01:00
|
|
|
class TestRenaming(BaseTestCase):
|
|
|
|
def test_multiple(self):
|
|
|
|
# This tests a bunch of different renames working together
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'identifiers': [{'name': 'Foo'}],
|
|
|
|
'actions': {
|
|
|
|
'Foo': {}
|
|
|
|
},
|
|
|
|
'has': {
|
|
|
|
'Foo': {
|
|
|
|
'resource': {
|
|
|
|
'type': 'Frob',
|
|
|
|
'identifiers': [
|
2021-11-03 18:27:47 +01:00
|
|
|
{
|
|
|
|
'target': 'Id',
|
|
|
|
'source': 'data',
|
|
|
|
'path': 'FrobId'
|
|
|
|
}
|
2015-11-27 23:25:33 +01:00
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'hasMany': {
|
|
|
|
'Foo': {}
|
|
|
|
},
|
|
|
|
'waiters': {
|
|
|
|
'Foo': {}
|
|
|
|
}
|
|
|
|
}, {
|
|
|
|
'Frob': {}
|
|
|
|
})
|
|
|
|
|
|
|
|
shape = DenormalizedStructureBuilder().with_members({
|
|
|
|
'Foo': {
|
|
|
|
'type': 'string',
|
|
|
|
},
|
|
|
|
'Bar': {
|
|
|
|
'type': 'string'
|
|
|
|
}
|
|
|
|
}).build_model()
|
|
|
|
|
|
|
|
model.load_rename_map(shape)
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert model.identifiers[0].name == 'foo'
|
|
|
|
assert model.actions[0].name == 'foo_action'
|
|
|
|
assert model.references[0].name == 'foo_reference'
|
|
|
|
assert model.collections[0].name == 'foo_collection'
|
|
|
|
assert model.waiters[0].name == 'wait_until_foo'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
# If an identifier and an attribute share the same name, then
|
|
|
|
# the attribute is essentially hidden.
|
2021-10-04 19:51:32 +02:00
|
|
|
assert 'foo_attribute' not in model.get_attributes(shape)
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
# Other attributes need to be there, though
|
2021-10-04 19:51:32 +02:00
|
|
|
assert 'bar' in model.get_attributes(shape)
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
# The rest of the tests below ensure the correct order of precedence
|
|
|
|
# for the various categories of attributes/properties/methods on the
|
|
|
|
# resource model.
|
|
|
|
def test_meta_beats_identifier(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'identifiers': [{'name': 'Meta'}]
|
|
|
|
}, {})
|
|
|
|
|
|
|
|
model.load_rename_map()
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert model.identifiers[0].name == 'meta_identifier'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_load_beats_identifier(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'identifiers': [{'name': 'Load'}],
|
|
|
|
'load': {
|
|
|
|
'request': {
|
|
|
|
'operation': 'GetFrobs'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, {})
|
|
|
|
|
|
|
|
model.load_rename_map()
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert model.load
|
|
|
|
assert model.identifiers[0].name == 'load_identifier'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_identifier_beats_action(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'identifiers': [{'name': 'foo'}],
|
|
|
|
'actions': {
|
|
|
|
'Foo': {
|
|
|
|
'request': {
|
|
|
|
'operation': 'GetFoo'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, {})
|
|
|
|
|
|
|
|
model.load_rename_map()
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert model.identifiers[0].name == 'foo'
|
|
|
|
assert model.actions[0].name == 'foo_action'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_action_beats_reference(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'actions': {
|
|
|
|
'Foo': {
|
|
|
|
'request': {
|
|
|
|
'operation': 'GetFoo'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'has': {
|
|
|
|
'Foo': {
|
|
|
|
'resource': {
|
|
|
|
'type': 'Frob',
|
|
|
|
'identifiers': [
|
2021-11-03 18:27:47 +01:00
|
|
|
{
|
|
|
|
'target': 'Id',
|
|
|
|
'source': 'data',
|
|
|
|
'path': 'FrobId'
|
|
|
|
}
|
2015-11-27 23:25:33 +01:00
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, {'Frob': {}})
|
|
|
|
|
|
|
|
model.load_rename_map()
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert model.actions[0].name == 'foo'
|
|
|
|
assert model.references[0].name == 'foo_reference'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_reference_beats_collection(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'has': {
|
|
|
|
'Foo': {
|
|
|
|
'resource': {
|
|
|
|
'type': 'Frob',
|
|
|
|
'identifiers': [
|
2021-11-03 18:27:47 +01:00
|
|
|
{
|
|
|
|
'target': 'Id',
|
|
|
|
'source': 'data',
|
|
|
|
'path': 'FrobId'
|
|
|
|
}
|
2015-11-27 23:25:33 +01:00
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'hasMany': {
|
|
|
|
'Foo': {
|
|
|
|
'resource': {
|
|
|
|
'type': 'Frob'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, {'Frob': {}})
|
|
|
|
|
|
|
|
model.load_rename_map()
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert model.references[0].name == 'foo'
|
|
|
|
assert model.collections[0].name == 'foo_collection'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_collection_beats_waiter(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'hasMany': {
|
|
|
|
'WaitUntilFoo': {
|
|
|
|
'resource': {
|
|
|
|
'type': 'Frob'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
'waiters': {
|
|
|
|
'Foo': {}
|
|
|
|
}
|
|
|
|
}, {'Frob': {}})
|
|
|
|
|
|
|
|
model.load_rename_map()
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert model.collections[0].name == 'wait_until_foo'
|
|
|
|
assert model.waiters[0].name == 'wait_until_foo_waiter'
|
2015-11-27 23:25:33 +01:00
|
|
|
|
|
|
|
def test_waiter_beats_attribute(self):
|
|
|
|
model = ResourceModel('test', {
|
|
|
|
'waiters': {
|
|
|
|
'Foo': {}
|
|
|
|
}
|
|
|
|
}, {'Frob': {}})
|
|
|
|
|
|
|
|
shape = DenormalizedStructureBuilder().with_members({
|
|
|
|
'WaitUntilFoo': {
|
|
|
|
'type': 'string',
|
|
|
|
}
|
|
|
|
}).build_model()
|
|
|
|
|
|
|
|
model.load_rename_map(shape)
|
|
|
|
|
2021-10-04 19:51:32 +02:00
|
|
|
assert model.waiters[0].name == 'wait_until_foo'
|
|
|
|
assert 'wait_until_foo_attribute' in model.get_attributes(shape)
|