def __init__(self, session=None, factory=None): super(Session, self).__init__() self.core_session = session self.factory = factory if not self.core_session: self.core_session = botocore.session.get_session() if not self.factory: self.factory = ServiceFactory(session=self)
def setUp(self): super(BaseMethodTestCase, self).setUp() self.fake_resource = FakeResource() self.create_method = BaseMethod('create_queue') self.create_method.resource = self.fake_resource self.session = Session(FakeSession(TestCoreService())) self.sf = ServiceFactory(session=self.session) self.conn_class = self.sf.construct_for('test') self.conn = self.conn_class()
class Session(object): """ Stores all the state for a given ``boto3`` session. Can dynamically create all the various ``Connection`` classes. Usage:: >>> from boto3.core.session import Session >>> session = Session() >>> sqs_conn = session.connect_to_region('sqs', region_name='us-west-2') """ conn_classes = {} def __init__(self, session=None, factory=None): super(Session, self).__init__() self.core_session = session self.factory = factory if not self.core_session: self.core_session = botocore.session.get_session() if not self.factory: self.factory = ServiceFactory(session=self) def get_service(self, service_name): classes = self.__class__.conn_classes # FIXME: We may need a way to track multiple versions of a service # within the same running codebase. For now, just the services # themselves are fine. if service_name in classes: return classes[service_name] # We didn't find it. Construct it. new_class = self.factory.construct_for(service_name) classes[service_name] = new_class return new_class def connect_to(self, service_name, **kwargs): """ Shortcut method to make instantiating the ``Connection`` classes easier. Forwards ``kwargs`` like region, keys, etc. on to the constructor. """ service_class = self.get_service(service_name) return service_class.connect_to(**kwargs) def get_core_service(self, service_name): """ Returns a ``botocore.service.Service``. Mostly an abstraction for the ``*Connection`` objects to get what they need for introspection. """ return self.core_session.get_service(service_name) @classmethod def _reset(cls): cls.conn_classes = {}
class BaseMethodTestCase(unittest.TestCase): def setUp(self): super(BaseMethodTestCase, self).setUp() self.fake_resource = FakeResource() self.create_method = BaseMethod('create_queue') self.create_method.resource = self.fake_resource self.session = Session(FakeSession(TestCoreService())) self.sf = ServiceFactory(session=self.session) self.conn_class = self.sf.construct_for('test') self.conn = self.conn_class() def remove_added_method(self, method_name): delattr(FakeResource, method_name) def test_incorrect_setup(self): bare = BaseMethod() with self.assertRaises(NoNameProvidedError): bare.check_name() with self.assertRaises(NoResourceAttachedError): bare.check_resource_class() def test_setup_on_resource(self): bare = BaseMethod() with self.assertRaises(NotImplementedError): bare.setup_on_resource(FakeResource) def test_teardown_on_resource(self): self.create_method.name = 'create_thing' setattr(FakeResource, 'create_thing', True) self.assertTrue(FakeResource.create_thing) self.create_method.teardown_on_resource(FakeResource) with self.assertRaises(AttributeError): FakeResource.create_thing def test_get_expected_parameters(self): base = BaseMethod('create_queue') self.assertEqual(base.get_expected_parameters(self.conn), [ { 'type': 'string', 'required': True, 'api_name': 'QueueName', 'var_name': 'queue_name' }, { 'type': 'map', 'required': False, 'api_name': 'Attributes', 'var_name': 'attributes' } ]) # We should get different parameters for a different operation. base = BaseMethod('delete_queue') self.assertEqual(base.get_expected_parameters(self.conn), [ { 'type': 'string', 'required': True, 'api_name': 'QueueName', 'var_name': 'queue_name' }, ]) def test_get_bound_params(self): expected = [ { 'type': 'string', 'required': True, 'api_name': 'QueueName', 'var_name': 'queue_name' }, { 'type': 'map', 'required': False, 'api_name': 'Attributes', 'var_name': 'attributes' } ] # First, with no data on the resource. self.assertEqual(self.create_method.get_bound_params(expected), { 'queue_name': NOTHING_PROVIDED, }) # Set data. self.fake_resource.name = 'whatever' self.assertEqual(self.create_method.get_bound_params(expected), { 'queue_name': 'whatever', }) def test_check_required_params(self): # FIXME: For now, this does nothing in the implementation. If we remove # it there, we should remove it here. self.assertEqual(self.create_method.check_required_params({}, {}), None) def test_update_bound_params_from_api(self): def del_new_attr(name): try: delattr(self.fake_resource, name) except AttributeError: pass # They shouldn't be there. self.assertEqual(getattr(self.fake_resource, 'name', None), None) self.assertEqual(getattr(self.fake_resource, 'url', None), None) self.addCleanup(del_new_attr, 'name') self.addCleanup(del_new_attr, 'url') # Get data back from an API call & update. self.create_method.update_bound_params_from_api({ 'QueueName': 'whatever', }) self.assertEqual(getattr(self.fake_resource, 'name', None), 'whatever') self.assertEqual(getattr(self.fake_resource, 'url', None), None) # New data. self.create_method.update_bound_params_from_api({ 'QueueUrl': '/197246/whatever', }) self.assertEqual(getattr(self.fake_resource, 'name', None), 'whatever') self.assertEqual( getattr(self.fake_resource, 'url', None), '/197246/whatever' ) def test_post_process_results(self): # If we don't recognize anything, just pass it through. self.assertEqual( self.create_method.post_process_results({ 'this': 'is a test', }), { 'this': 'is a test', } ) # We find a single structure. result = self.create_method.post_process_results({ 'this': 'is a test', 'Queue': { 'Message': { 'body': 'o hai', } } }) self.assertEqual(result['Queue']['Message'].body, 'o hai') # We find a list at a different key. result = self.create_method.post_process_results({ 'this': 'is a test', 'Messages': [ { 'body': 'o hai', }, { 'body': 'another', } ] }) self.assertEqual(len(result['Messages']), 2) self.assertEqual(result['Messages'][0].body, 'o hai') self.assertEqual(result['Messages'][1].body, 'another') def test_call(self): base = BaseMethod('create_queue') base.name = 'create_method' base.resource = self.fake_resource mpo = mock.patch.object # Just the passed args. ret = {'QueueUrl': '/test-queue'} with mpo(self.conn, 'create_queue', return_value=ret) as mock_conn: results = base.call(self.conn, queue_name='test-queue') self.assertEqual( getattr(self.fake_resource, 'name', None), None ) self.assertEqual( getattr(self.fake_resource, 'url', None), '/test-queue' ) self.assertEqual(results, { 'QueueUrl': '/test-queue', }) mock_conn.assert_called_once_with(queue_name='test-queue') # With the kwargs to be partially applied. base = BaseMethod('create_queue', limit=2, queue_name='unseen') base.name = 'create_method' base.resource = self.fake_resource ret = {'QueueUrl': '/test-queue', 'CreateCount': 1} with mpo(self.conn, 'create_queue', return_value=ret) as mock_conn: results = base.call(self.conn, queue_name='test-queue') self.assertEqual( getattr(self.fake_resource, 'name', None), None ) self.assertEqual( getattr(self.fake_resource, 'url', None), '/test-queue' ) self.assertEqual(results, { 'CreateCount': 1, 'QueueUrl': '/test-queue', }) mock_conn.assert_called_once_with(limit=2, queue_name='test-queue') # With bound params. base = BaseMethod('create_queue', limit=2) base.name = 'create_method' base.resource = self.fake_resource self.fake_resource.name = 'whatever' ret = { 'QueueUrl': '/whatever-queue', # This should update the instance's ``name``. 'QueueName': 'Whatever', } with mpo(self.conn, 'create_queue', return_value=ret) as mock_conn: results = base.call(self.conn) self.assertEqual( getattr(self.fake_resource, 'name', None), 'Whatever' ) self.assertEqual( getattr(self.fake_resource, 'url', None), '/whatever-queue' ) self.assertEqual(results, { 'QueueName': 'Whatever', 'QueueUrl': '/whatever-queue', }) mock_conn.assert_called_once_with(limit=2, queue_name='whatever') def test_update_docstring(self): # Setup to fake a method we can actually test. def create_thing(self, *args, **kwargs): return True fake_resource = FakeResource() fake_resource._connection = self.conn create_method = BaseMethod('create_queue') create_method.name = 'create_thing' setattr(FakeResource, 'create_thing', create_thing) self.addCleanup(self.remove_added_method, 'create_thing') # Shouldn't have a docstring. self.assertEqual(fake_resource.create_thing.__doc__, None) create_method.update_docstring(fake_resource) # Shouldn't have a docstring. self.assertEqual( fake_resource.create_thing.__doc__, ' <p>Creates a queue.</p>\n ' )
def setUp(self): super(ServiceFactoryTestCase, self).setUp() self.session = Session(FakeSession(TestCoreService())) self.sf = ServiceFactory(session=self.session) self.test_service_class = self.sf.construct_for('test')
class ServiceFactoryTestCase(unittest.TestCase): def setUp(self): super(ServiceFactoryTestCase, self).setUp() self.session = Session(FakeSession(TestCoreService())) self.sf = ServiceFactory(session=self.session) self.test_service_class = self.sf.construct_for('test') def test__check_method_params(self): _cmp = self.test_service_class()._check_method_params op_params = [ { 'var_name': 'queue_name', 'api_name': 'QueueName', 'required': True, 'type': 'string', }, { 'var_name': 'attributes', 'api_name': 'Attributes', 'required': False, 'type': 'map', }, ] # Missing the required ``queue_name`` parameter. self.assertRaises(TypeError, _cmp, op_params) self.assertRaises(TypeError, _cmp, op_params, attributes=1) # All required params present. self.assertEqual(_cmp(op_params, queue_name='boo'), None) self.assertEqual(_cmp(op_params, queue_name='boo', attributes=1), None) def test__build_service_params(self): _bsp = self.test_service_class()._build_service_params op_params = [ { 'var_name': 'queue_name', 'api_name': 'QueueName', 'required': True, 'type': 'string', }, { 'var_name': 'attributes', 'api_name': 'Attributes', 'required': False, 'type': 'map', }, ] self.assertEqual(_bsp(op_params, queue_name='boo'), { 'queue_name': 'boo', }) self.assertEqual(_bsp(op_params, queue_name='boo', attributes=1), { 'queue_name': 'boo', 'attributes': 1, }) def test__create_operation_method(self): func = self.sf._create_operation_method('test', { 'method_name': 'test', 'api_name': 'Test', 'docs': 'This is a test.', 'params': [], 'output': True, }) self.assertEqual(func.__name__, 'test') self.assertEqual(func.__doc__, 'This is a test.') def test__post_process_results(self): ppr = self.test_service_class()._post_process_results self.assertEqual(ppr('whatever', {}, (None, True)), True) self.assertEqual(ppr('whatever', {}, (None, False)), False) self.assertEqual(ppr('whatever', {}, (None, 'abc')), 'abc') self.assertEqual(ppr('whatever', {}, (None, ['abc', 1])), [ 'abc', 1 ]) self.assertEqual(ppr('whatever', {}, (None, {'abc': 1})), { 'abc': 1, }) def test_integration(self): # Essentially testing ``_build_methods``. # This is a painful integration test. If the other methods don't work, # this will certainly fail. self.assertTrue(hasattr(self.test_service_class, 'create_queue')) self.assertTrue(hasattr(self.test_service_class, 'delete_queue')) ts = self.test_service_class() # Missing required parameters. self.assertRaises(TypeError, ts, 'create_queue') self.assertRaises(TypeError, ts, 'delete_queue') # Successful calls. self.assertEqual(ts.create_queue(queue_name='boo'), { 'QueueUrl': 'http://example.com' }) self.assertEqual(ts.delete_queue(queue_name='boo'), True) # Test the params. create_queue_params = ts._get_operation_params('create_queue') self.assertEqual( [param['var_name'] for param in create_queue_params], ['queue_name', 'attributes'] ) def test_late_binding(self): # If the ``ServiceDetails`` data changes, it should be reflected in # the dynamic methods. ts = self.test_service_class() # Successful calls. self.assertEqual(ts.create_queue(queue_name='boo'), { 'QueueUrl': 'http://example.com' }) # Now the required params change underneath us. # This is ugly/fragile, but also unlikely. sd = ts._details._loaded_service_data sd['create_queue']['params'][1]['required'] = True # Now this call should fail, since there's a new required parameter. self.assertRaises(TypeError, ts, 'create_queue')
def setUp(self): super(ResourceTestCase, self).setUp() self.session = Session(FakeSession(TestCoreService())) self.sf = ServiceFactory(session=self.session) self.conn_class = self.sf.construct_for('test') self.conn = self.conn_class()
class ResourceTestCase(unittest.TestCase): def setUp(self): super(ResourceTestCase, self).setUp() self.session = Session(FakeSession(TestCoreService())) self.sf = ServiceFactory(session=self.session) self.conn_class = self.sf.construct_for('test') self.conn = self.conn_class() def test_meta(self): # By this point, the ``TestResource`` class has already been altered. # Let's verify the important bits. self.assertEqual(TestResource.valid_api_versions[0], '2013-08-23') self.assertEqual(TestResource.service_name, 'test') # Ensure we've got all the fields. self.assertEqual(sorted(TestResource.fields.keys()), [ 'name', 'url', ]) # Make sure the metaclass sets the name. self.assertEqual(TestResource.fields['url'].name, 'url') # Make sure we picked up all the methods. self.assertEqual(sorted(TestResource._methods.keys()), [ 'delete', 'receive', 'send', ]) # Make sure the method objects are safely ferreted away. self.assertTrue(isinstance( TestResource._methods['delete'], methods.InstanceMethod )) # Make sure the metaclass sets the name. self.assertEqual(TestResource._methods['delete'].name, 'delete') # Check that the new methods have been created. self.assertTrue(hasattr(TestResource, 'delete')) self.assertTrue(callable(TestResource.delete)) self.assertTrue(hasattr(TestResource, 'delete')) self.assertTrue(callable(TestResource.send)) def test_init_defaults(self): # Without an explicit session or connection, should get defaults. # We need to mock part of this here, because we're dealing with a # non-real service. mpo = mock.patch.object sess = boto3.session with mpo(sess, 'connect_to', return_value=self.conn) as mock_conn: test = TestResource() self.assertEqual(test._session, sess) self.assertEqual(test._data, {}) mock_conn.assert_called_once_with('test') def test_init_with_session(self): # With an explicit session. mpo = mock.patch.object session = Session() with mpo(session, 'connect_to', return_value=self.conn) as mock_conn: test = TestResource(session=session) self.assertEqual(test._session, session) self.assertEqual(test._data, {}) mock_conn.assert_called_once_with('test') def test_init_with_connection(self): # With an explicit connection. mpo = mock.patch.object sess = boto3.session with mpo(sess, 'connect_to', return_value=self.conn) as mock_conn: test = TestResource(connection=self.conn) self.assertEqual(test._session, sess) self.assertEqual(test._data, {}) # Make sure ``connect_to`` *isn't* called. self.assertEqual(mock_conn.call_count, 0) def test_update_docstrings(self): # In the definition above, there are no docstrings. # Just make sure they got populated. test = TestResource(connection=self.conn) self.assertEqual( TestResource.delete.__doc__, ' <p>Deletes a queue.</p>\n ' ) self.assertEqual( TestResource.send.__doc__, ' <p>Sends a message to a queue.</p>\n ' ) def test_check_api_version(self): # With an acceptable API version. test = TestResource(connection=self.conn) test._check_api_version() # With a bad API version test.valid_api_versions = [ 'nopenopenope', ] with self.assertRaises(APIVersionMismatchError): test._check_api_version() def test_getattr(self): test = TestResource(connection=self.conn) # A plain old attribute. test.not_a_field = True self.assertEqual(test.not_a_field, True) # A field. test._data['name'] = 'a-test' self.assertEqual(test.name, 'a-test') # Not found. with self.assertRaises(AttributeError): test.not_anything_known def test_setattr(self): test = TestResource(connection=self.conn) # A field. self.assertEqual(test._data, {}) test.name = 'a-test' self.assertEqual(test._data, { 'name': 'a-test', }) # A plain old attribute. test.now_known_but_poorly_understood = True self.assertEqual(test._data, { 'name': 'a-test', }) self.assertEqual(test.now_known_but_poorly_understood, True) def test_delattr(self): test = TestResource(connection=self.conn) # A field. test._data['name'] = 'a-test' self.assertTrue('name' in test._data) del test.name self.assertFalse('name' in test._data) # A plain old attribute. test.now_known_but_poorly_understood = True self.assertTrue(hasattr(test, 'now_known_but_poorly_understood')) del test.now_known_but_poorly_understood self.assertFalse(hasattr(test, 'now_known_but_poorly_understood')) def test_response_parsing(self): test = TestResource(connection=self.conn) test.url = '/a-test/url' result = test.receive() self.assertEqual(len(result['Messages']), 2) msg_0 = result['Messages'][0] msg_1 = result['Messages'][1] self.assertTrue(isinstance(msg_0, TestMessage)) self.assertTrue(isinstance(msg_1, TestMessage)) self.assertEqual(msg_0.message_id, 'msg-12345') self.assertEqual(msg_0.body, 'Hello, world!') self.assertEqual(msg_0.md5, '6cd3556deb0da54bca060b4c39479839') self.assertEqual(msg_1.message_id, 'msg-12346') self.assertEqual(msg_1.body, 'Another message!') self.assertEqual(msg_1.md5, '6cd355')
def setUp(self): super(ResourceCollectionTestCase, self).setUp() self.session = Session(FakeSession(TestCoreService())) self.sf = ServiceFactory(session=self.session) self.conn_class = self.sf.construct_for('test') self.conn = self.conn_class()
class ResourceCollectionTestCase(unittest.TestCase): def setUp(self): super(ResourceCollectionTestCase, self).setUp() self.session = Session(FakeSession(TestCoreService())) self.sf = ServiceFactory(session=self.session) self.conn_class = self.sf.construct_for('test') self.conn = self.conn_class() def tearDown(self): TestResourceCollection.resource_class = \ 'tests.unit.core.resources.test_collections.FakeQueue' super(ResourceCollectionTestCase, self).tearDown() def test_meta(self): # By this point, the ``TestResourceCollection`` class has already been # altered. Let's verify the important bits. self.assertEqual( TestResourceCollection.valid_api_versions[0], '2013-08-23' ) self.assertEqual( TestResourceCollection.service_name, 'test' ) self.assertEqual( TestResourceCollection.resource_class, 'tests.unit.core.resources.test_collections.FakeQueue' ) # Make sure we picked up all the methods. self.assertEqual(sorted(TestResourceCollection._methods.keys()), [ 'create', ]) # Make sure the method objects are safely ferreted away. self.assertTrue(isinstance( TestResourceCollection._methods['create'], methods.CollectionMethod )) # Make sure the metaclass sets the name. self.assertEqual( TestResourceCollection._methods['create'].name, 'create' ) # Check that the new methods have been created. self.assertTrue(hasattr(TestResourceCollection, 'create')) self.assertTrue(callable(TestResourceCollection.create)) def test_init_defaults(self): # Without an explicit session or connection, should get defaults. # We need to mock part of this here, because we're dealing with a # non-real service. mpo = mock.patch.object sess = boto3.session with mpo(sess, 'connect_to', return_value=self.conn) as mock_conn: test = TestResourceCollection() self.assertEqual(test._session, sess) self.assertEqual( test._resource_class, 'tests.unit.core.resources.test_collections.FakeQueue' ) mock_conn.assert_called_once_with('test') def test_init_with_session(self): # With an explicit session. mpo = mock.patch.object session = Session() with mpo(session, 'connect_to', return_value=self.conn) as mock_conn: test = TestResourceCollection(session=session) self.assertEqual(test._session, session) self.assertEqual( test._resource_class, 'tests.unit.core.resources.test_collections.FakeQueue' ) mock_conn.assert_called_once_with('test') def test_init_with_connection(self): # With an explicit connection. mpo = mock.patch.object sess = boto3.session with mpo(sess, 'connect_to', return_value=self.conn) as mock_conn: test = TestResourceCollection(connection=self.conn) self.assertEqual(test._session, sess) self.assertEqual( test._resource_class, 'tests.unit.core.resources.test_collections.FakeQueue' ) # Make sure ``connect_to`` *isn't* called. self.assertEqual(mock_conn.call_count, 0) def test_init_with_resource_class(self): # With an overridden resource class. mpo = mock.patch.object sess = boto3.session with mpo(sess, 'connect_to', return_value=self.conn) as mock_conn: test = TestResourceCollection( connection=self.conn, resource_class=AnotherFakeQueue ) self.assertEqual(test._session, sess) self.assertEqual(test._resource_class, AnotherFakeQueue) # Make sure ``connect_to`` *isn't* called. self.assertEqual(mock_conn.call_count, 0) def test_get_resource_class(self): test = TestResourceCollection(connection=self.conn) # With the string-type import path. cls = test.get_resource_class() self.assertTrue(cls.is_fake) # With an actual class. test = TestResourceCollection( connection=self.conn, resource_class=AnotherFakeQueue ) cls = test.get_resource_class() self.assertTrue(cls.is_another) # Not found. with self.assertRaises(IncorrectImportPath): test = TestResourceCollection( connection=self.conn, resource_class='a.nonexistant.path.to.a.Resource' ) cls = test.get_resource_class() # No class configured. with self.assertRaises(ResourceError): class NopeCollection(ResourceCollection): valid_api_versions = [ '2013-08-23' ] service_name = 'nope' test = NopeCollection( connection=self.conn ) cls = test.get_resource_class()
class BaseMethodTestCase(unittest.TestCase): def setUp(self): super(BaseMethodTestCase, self).setUp() self.fake_resource = FakeResource() self.create_method = BaseMethod('create_queue') self.create_method.resource = self.fake_resource self.session = Session(FakeSession(TestCoreService())) self.sf = ServiceFactory(session=self.session) self.conn_class = self.sf.construct_for('test') self.conn = self.conn_class() def remove_added_method(self, method_name): delattr(FakeResource, method_name) def test_incorrect_setup(self): bare = BaseMethod() with self.assertRaises(NoNameProvidedError): bare.check_name() with self.assertRaises(NoResourceAttachedError): bare.check_resource_class() def test_setup_on_resource(self): bare = BaseMethod() with self.assertRaises(NotImplementedError): bare.setup_on_resource(FakeResource) def test_teardown_on_resource(self): self.create_method.name = 'create_thing' setattr(FakeResource, 'create_thing', True) self.assertTrue(FakeResource.create_thing) self.create_method.teardown_on_resource(FakeResource) with self.assertRaises(AttributeError): FakeResource.create_thing def test_get_expected_parameters(self): base = BaseMethod('create_queue') self.assertEqual(base.get_expected_parameters(self.conn), [{ 'type': 'string', 'required': True, 'api_name': 'QueueName', 'var_name': 'queue_name' }, { 'type': 'map', 'required': False, 'api_name': 'Attributes', 'var_name': 'attributes' }]) # We should get different parameters for a different operation. base = BaseMethod('delete_queue') self.assertEqual(base.get_expected_parameters(self.conn), [ { 'type': 'string', 'required': True, 'api_name': 'QueueName', 'var_name': 'queue_name' }, ]) def test_get_bound_params(self): expected = [{ 'type': 'string', 'required': True, 'api_name': 'QueueName', 'var_name': 'queue_name' }, { 'type': 'map', 'required': False, 'api_name': 'Attributes', 'var_name': 'attributes' }] # First, with no data on the resource. self.assertEqual(self.create_method.get_bound_params(expected), { 'queue_name': NOTHING_PROVIDED, }) # Set data. self.fake_resource.name = 'whatever' self.assertEqual(self.create_method.get_bound_params(expected), { 'queue_name': 'whatever', }) def test_check_required_params(self): # FIXME: For now, this does nothing in the implementation. If we remove # it there, we should remove it here. self.assertEqual(self.create_method.check_required_params({}, {}), None) def test_update_bound_params_from_api(self): def del_new_attr(name): try: delattr(self.fake_resource, name) except AttributeError: pass # They shouldn't be there. self.assertEqual(getattr(self.fake_resource, 'name', None), None) self.assertEqual(getattr(self.fake_resource, 'url', None), None) self.addCleanup(del_new_attr, 'name') self.addCleanup(del_new_attr, 'url') # Get data back from an API call & update. self.create_method.update_bound_params_from_api({ 'QueueName': 'whatever', }) self.assertEqual(getattr(self.fake_resource, 'name', None), 'whatever') self.assertEqual(getattr(self.fake_resource, 'url', None), None) # New data. self.create_method.update_bound_params_from_api({ 'QueueUrl': '/197246/whatever', }) self.assertEqual(getattr(self.fake_resource, 'name', None), 'whatever') self.assertEqual(getattr(self.fake_resource, 'url', None), '/197246/whatever') def test_post_process_results(self): # If we don't recognize anything, just pass it through. self.assertEqual( self.create_method.post_process_results({ 'this': 'is a test', }), { 'this': 'is a test', }) # We find a single structure. result = self.create_method.post_process_results({ 'this': 'is a test', 'Queue': { 'Message': { 'body': 'o hai', } } }) self.assertEqual(result['Queue']['Message'].body, 'o hai') # We find a list at a different key. result = self.create_method.post_process_results({ 'this': 'is a test', 'Messages': [{ 'body': 'o hai', }, { 'body': 'another', }] }) self.assertEqual(len(result['Messages']), 2) self.assertEqual(result['Messages'][0].body, 'o hai') self.assertEqual(result['Messages'][1].body, 'another') def test_call(self): base = BaseMethod('create_queue') base.name = 'create_method' base.resource = self.fake_resource mpo = mock.patch.object # Just the passed args. ret = {'QueueUrl': '/test-queue'} with mpo(self.conn, 'create_queue', return_value=ret) as mock_conn: results = base.call(self.conn, queue_name='test-queue') self.assertEqual(getattr(self.fake_resource, 'name', None), None) self.assertEqual(getattr(self.fake_resource, 'url', None), '/test-queue') self.assertEqual(results, { 'QueueUrl': '/test-queue', }) mock_conn.assert_called_once_with(queue_name='test-queue') # With the kwargs to be partially applied. base = BaseMethod('create_queue', limit=2, queue_name='unseen') base.name = 'create_method' base.resource = self.fake_resource ret = {'QueueUrl': '/test-queue', 'CreateCount': 1} with mpo(self.conn, 'create_queue', return_value=ret) as mock_conn: results = base.call(self.conn, queue_name='test-queue') self.assertEqual(getattr(self.fake_resource, 'name', None), None) self.assertEqual(getattr(self.fake_resource, 'url', None), '/test-queue') self.assertEqual(results, { 'CreateCount': 1, 'QueueUrl': '/test-queue', }) mock_conn.assert_called_once_with(limit=2, queue_name='test-queue') # With bound params. base = BaseMethod('create_queue', limit=2) base.name = 'create_method' base.resource = self.fake_resource self.fake_resource.name = 'whatever' ret = { 'QueueUrl': '/whatever-queue', # This should update the instance's ``name``. 'QueueName': 'Whatever', } with mpo(self.conn, 'create_queue', return_value=ret) as mock_conn: results = base.call(self.conn) self.assertEqual(getattr(self.fake_resource, 'name', None), 'Whatever') self.assertEqual(getattr(self.fake_resource, 'url', None), '/whatever-queue') self.assertEqual(results, { 'QueueName': 'Whatever', 'QueueUrl': '/whatever-queue', }) mock_conn.assert_called_once_with(limit=2, queue_name='whatever') def test_update_docstring(self): # Setup to fake a method we can actually test. def create_thing(self, *args, **kwargs): return True fake_resource = FakeResource() fake_resource._connection = self.conn create_method = BaseMethod('create_queue') create_method.name = 'create_thing' setattr(FakeResource, 'create_thing', create_thing) self.addCleanup(self.remove_added_method, 'create_thing') # Shouldn't have a docstring. self.assertEqual(fake_resource.create_thing.__doc__, None) create_method.update_docstring(fake_resource) # Shouldn't have a docstring. self.assertEqual(fake_resource.create_thing.__doc__, ' <p>Creates a queue.</p>\n ')
class ResourceTestCase(unittest.TestCase): def setUp(self): super(ResourceTestCase, self).setUp() self.session = Session(FakeSession(TestCoreService())) self.sf = ServiceFactory(session=self.session) self.conn_class = self.sf.construct_for('test') self.conn = self.conn_class() def test_meta(self): # By this point, the ``TestResource`` class has already been altered. # Let's verify the important bits. self.assertEqual(TestResource.valid_api_versions[0], '2013-08-23') self.assertEqual(TestResource.service_name, 'test') # Ensure we've got all the fields. self.assertEqual(sorted(TestResource.fields.keys()), [ 'name', 'url', ]) # Make sure the metaclass sets the name. self.assertEqual(TestResource.fields['url'].name, 'url') # Make sure we picked up all the methods. self.assertEqual(sorted(TestResource._methods.keys()), [ 'delete', 'receive', 'send', ]) # Make sure the method objects are safely ferreted away. self.assertTrue( isinstance(TestResource._methods['delete'], methods.InstanceMethod)) # Make sure the metaclass sets the name. self.assertEqual(TestResource._methods['delete'].name, 'delete') # Check that the new methods have been created. self.assertTrue(hasattr(TestResource, 'delete')) self.assertTrue(callable(TestResource.delete)) self.assertTrue(hasattr(TestResource, 'delete')) self.assertTrue(callable(TestResource.send)) def test_init_defaults(self): # Without an explicit session or connection, should get defaults. # We need to mock part of this here, because we're dealing with a # non-real service. mpo = mock.patch.object sess = boto3.session with mpo(sess, 'connect_to', return_value=self.conn) as mock_conn: test = TestResource() self.assertEqual(test._session, sess) self.assertEqual(test._data, {}) mock_conn.assert_called_once_with('test') def test_init_with_session(self): # With an explicit session. mpo = mock.patch.object session = Session() with mpo(session, 'connect_to', return_value=self.conn) as mock_conn: test = TestResource(session=session) self.assertEqual(test._session, session) self.assertEqual(test._data, {}) mock_conn.assert_called_once_with('test') def test_init_with_connection(self): # With an explicit connection. mpo = mock.patch.object sess = boto3.session with mpo(sess, 'connect_to', return_value=self.conn) as mock_conn: test = TestResource(connection=self.conn) self.assertEqual(test._session, sess) self.assertEqual(test._data, {}) # Make sure ``connect_to`` *isn't* called. self.assertEqual(mock_conn.call_count, 0) def test_update_docstrings(self): # In the definition above, there are no docstrings. # Just make sure they got populated. test = TestResource(connection=self.conn) self.assertEqual(TestResource.delete.__doc__, ' <p>Deletes a queue.</p>\n ') self.assertEqual(TestResource.send.__doc__, ' <p>Sends a message to a queue.</p>\n ') def test_check_api_version(self): # With an acceptable API version. test = TestResource(connection=self.conn) test._check_api_version() # With a bad API version test.valid_api_versions = [ 'nopenopenope', ] with self.assertRaises(APIVersionMismatchError): test._check_api_version() def test_getattr(self): test = TestResource(connection=self.conn) # A plain old attribute. test.not_a_field = True self.assertEqual(test.not_a_field, True) # A field. test._data['name'] = 'a-test' self.assertEqual(test.name, 'a-test') # Not found. with self.assertRaises(AttributeError): test.not_anything_known def test_setattr(self): test = TestResource(connection=self.conn) # A field. self.assertEqual(test._data, {}) test.name = 'a-test' self.assertEqual(test._data, { 'name': 'a-test', }) # A plain old attribute. test.now_known_but_poorly_understood = True self.assertEqual(test._data, { 'name': 'a-test', }) self.assertEqual(test.now_known_but_poorly_understood, True) def test_delattr(self): test = TestResource(connection=self.conn) # A field. test._data['name'] = 'a-test' self.assertTrue('name' in test._data) del test.name self.assertFalse('name' in test._data) # A plain old attribute. test.now_known_but_poorly_understood = True self.assertTrue(hasattr(test, 'now_known_but_poorly_understood')) del test.now_known_but_poorly_understood self.assertFalse(hasattr(test, 'now_known_but_poorly_understood')) def test_response_parsing(self): test = TestResource(connection=self.conn) test.url = '/a-test/url' result = test.receive() self.assertEqual(len(result['Messages']), 2) msg_0 = result['Messages'][0] msg_1 = result['Messages'][1] self.assertTrue(isinstance(msg_0, TestMessage)) self.assertTrue(isinstance(msg_1, TestMessage)) self.assertEqual(msg_0.message_id, 'msg-12345') self.assertEqual(msg_0.body, 'Hello, world!') self.assertEqual(msg_0.md5, '6cd3556deb0da54bca060b4c39479839') self.assertEqual(msg_1.message_id, 'msg-12346') self.assertEqual(msg_1.body, 'Another message!') self.assertEqual(msg_1.md5, '6cd355')