# 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 # # https://aws.amazon.com/apache2.0/ # # 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 Action, Collection, ResourceModel, Waiter from tests import BaseTestCase class TestModels(BaseTestCase): def test_resource_name(self): model = ResourceModel('test', {}, {}) assert model.name == 'test' def test_resource_shape(self): model = ResourceModel('test', {'shape': 'Frob'}, {}) assert model.shape == 'Frob' def test_resource_identifiers(self): model = ResourceModel( 'test', { 'identifiers': [ {'name': 'one'}, {'name': 'two', 'memberName': 'three'}, ] }, {}, ) assert model.identifiers[0].name == 'one' assert model.identifiers[1].name == 'two' assert model.identifiers[1].member_name == 'three' def test_resource_action_raw(self): model = ResourceModel( 'test', { 'actions': { 'GetFrobs': { 'request': { 'operation': 'GetFrobsOperation', 'params': [ { 'target': 'FrobId', 'source': 'identifier', 'name': 'Id', } ], }, 'path': 'Container.Frobs[]', } } }, {}, ) assert isinstance(model.actions, list) assert len(model.actions) == 1 action = model.actions[0] 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[]' def test_resource_action_response_resource(self): model = ResourceModel( 'test', { 'actions': { 'GetFrobs': { 'resource': { 'type': 'Frob', 'path': 'Container.Frobs[]', } } } }, {'Frob': {}}, ) action = model.actions[0] assert action.resource.type == 'Frob' assert action.resource.path == 'Container.Frobs[]' assert isinstance(action.resource.model, ResourceModel) assert action.resource.model.name == 'Frob' def test_resource_load_action(self): model = ResourceModel( 'test', {'load': {'request': {'operation': 'GetFrobInfo'}, 'path': '$'}}, {}, ) assert isinstance(model.load, Action) assert model.load.request.operation == 'GetFrobInfo' assert model.load.path == '$' def test_resource_batch_action(self): model = ResourceModel( 'test', { 'batchActions': { 'Delete': { 'request': { 'operation': 'DeleteObjects', 'params': [ { 'target': 'Bucket', 'sourceType': 'identifier', 'source': 'BucketName', } ], } } } }, {}, ) assert isinstance(model.batch_actions, list) action = model.batch_actions[0] assert isinstance(action, Action) assert action.request.operation == 'DeleteObjects' assert action.request.params[0].target == 'Bucket' 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': {}}, ) assert isinstance(model.subresources, list) assert len(model.subresources) == 2 action = model.subresources[0] resource = action.resource assert action.name in ['RedFrob', 'GreenFrob'] assert resource.identifiers[0].target == 'Id' assert resource.identifiers[0].source == 'input' assert resource.type == 'Frob' def test_resource_references(self): model_def = { 'has': { 'Frob': { 'resource': { 'type': 'Frob', 'identifiers': [ { 'target': 'Id', 'source': 'data', 'path': 'FrobId', } ], } } } } resource_defs = {'Frob': {}} model = ResourceModel('test', model_def, resource_defs) assert isinstance(model.references, list) assert len(model.references) == 1 ref = model.references[0] 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' def test_resource_collections(self): model = ResourceModel( 'test', { 'hasMany': { 'Frobs': { 'request': {'operation': 'GetFrobList'}, 'resource': {'type': 'Frob', 'path': 'FrobList[]'}, } } }, {'Frob': {}}, ) 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[]' def test_waiter(self): model = ResourceModel( 'test', { 'waiters': { 'Exists': { 'waiterName': 'ObjectExists', 'params': [ { 'target': 'Bucket', 'sourceType': 'identifier', 'source': 'BucketName', } ], } } }, {}, ) assert isinstance(model.waiters, list) waiter = model.waiters[0] assert isinstance(waiter, Waiter) assert waiter.name == 'wait_until_exists' assert waiter.waiter_name == 'ObjectExists' assert waiter.params[0].target == 'Bucket' 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': [ { 'target': 'Id', 'source': 'data', 'path': 'FrobId', } ], } } }, 'hasMany': {'Foo': {}}, 'waiters': {'Foo': {}}, }, {'Frob': {}}, ) shape = ( DenormalizedStructureBuilder() .with_members( { 'Foo': { 'type': 'string', }, 'Bar': {'type': 'string'}, } ) .build_model() ) model.load_rename_map(shape) 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' # If an identifier and an attribute share the same name, then # the attribute is essentially hidden. assert 'foo_attribute' not in model.get_attributes(shape) # Other attributes need to be there, though assert 'bar' in model.get_attributes(shape) # 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() assert model.identifiers[0].name == 'meta_identifier' def test_load_beats_identifier(self): model = ResourceModel( 'test', { 'identifiers': [{'name': 'Load'}], 'load': {'request': {'operation': 'GetFrobs'}}, }, {}, ) model.load_rename_map() assert model.load assert model.identifiers[0].name == 'load_identifier' def test_identifier_beats_action(self): model = ResourceModel( 'test', { 'identifiers': [{'name': 'foo'}], 'actions': {'Foo': {'request': {'operation': 'GetFoo'}}}, }, {}, ) model.load_rename_map() assert model.identifiers[0].name == 'foo' assert model.actions[0].name == 'foo_action' def test_action_beats_reference(self): model = ResourceModel( 'test', { 'actions': {'Foo': {'request': {'operation': 'GetFoo'}}}, 'has': { 'Foo': { 'resource': { 'type': 'Frob', 'identifiers': [ { 'target': 'Id', 'source': 'data', 'path': 'FrobId', } ], } } }, }, {'Frob': {}}, ) model.load_rename_map() assert model.actions[0].name == 'foo' assert model.references[0].name == 'foo_reference' def test_reference_beats_collection(self): model = ResourceModel( 'test', { 'has': { 'Foo': { 'resource': { 'type': 'Frob', 'identifiers': [ { 'target': 'Id', 'source': 'data', 'path': 'FrobId', } ], } } }, 'hasMany': {'Foo': {'resource': {'type': 'Frob'}}}, }, {'Frob': {}}, ) model.load_rename_map() assert model.references[0].name == 'foo' assert model.collections[0].name == 'foo_collection' def test_collection_beats_waiter(self): model = ResourceModel( 'test', { 'hasMany': {'WaitUntilFoo': {'resource': {'type': 'Frob'}}}, 'waiters': {'Foo': {}}, }, {'Frob': {}}, ) model.load_rename_map() assert model.collections[0].name == 'wait_until_foo' assert model.waiters[0].name == 'wait_until_foo_waiter' 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) assert model.waiters[0].name == 'wait_until_foo' assert 'wait_until_foo_attribute' in model.get_attributes(shape)