예제 #1
0
    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)
예제 #2
0
    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()
예제 #3
0
    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()
예제 #4
0
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 = {}
예제 #5
0
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 '
        )
예제 #6
0
 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')
예제 #7
0
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')
예제 #8
0
 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()
예제 #9
0
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')
예제 #10
0
 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()
예제 #11
0
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()
예제 #12
0
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 ')
예제 #13
0
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')