Exemple #1
0
class TransportHelper(object):
    """
    Test helper for transport workers.

    This helper construct and wraps several lower-level helpers and provides
    higher-level functionality for transport tests.

    :param transport_class:
        The worker class for the transport being tested.

    :param bool use_riak:
        Set to ``True`` if the test requires Riak. This is passed to the
        underlying :class:`~vumi.tests.helpers.PersistenceHelper`.

    :param \**msg_helper_args:
        All other keyword params are passed to the underlying
        :class:`~vumi.tests.helpers.MessageHelper`.
    """

    implements(IHelper)

    def __init__(self, transport_class, use_riak=False, **msg_helper_args):
        self.transport_class = transport_class
        self.persistence_helper = PersistenceHelper(use_riak=use_riak)
        self.msg_helper = MessageHelper(**msg_helper_args)
        self.transport_name = self.msg_helper.transport_name
        self.worker_helper = WorkerHelper(self.transport_name)
        self.dispatch_helper = MessageDispatchHelper(
            self.msg_helper, self.worker_helper)

        # Proxy methods from our helpers.
        generate_proxies(self, self.msg_helper)
        generate_proxies(self, self.worker_helper)
        generate_proxies(self, self.dispatch_helper)
        generate_proxies(self, self.persistence_helper)

    def setup(self):
        self.persistence_helper.setup()
        self.worker_helper.setup()

    @inlineCallbacks
    def cleanup(self):
        yield self.worker_helper.cleanup()
        yield self.persistence_helper.cleanup()

    def get_transport(self, config, cls=None, start=True):
        """
        Get an instance of a transport class.

        :param config: Config dict.
        :param cls: The transport class to instantiate.
                    Defaults to :attr:`transport_class`
        :param start: True to start the transport (default), False otherwise.

        Some default config values are helpfully provided in the
        interests of reducing boilerplate:

        * ``transport_name`` defaults to :attr:`self.transport_name`
        """

        if cls is None:
            cls = self.transport_class
        config = self.mk_config(config)
        config.setdefault('transport_name', self.transport_name)
        return self.get_worker(cls, config, start)

    def get_dispatched_failures(self, connector_name=None):
        """
        Get failures dispatched by a transport.

        :param str connector_name:
            Connector name. If ``None``, the default connector name for the
            helper instance will be used.

        :returns:
            A list of :class:`~vumi.transports.failures.FailureMessage`
            instances.
        """
        return self.get_dispatched(connector_name, 'failures', FailureMessage)
Exemple #2
0
class VumiApiHelper(object):
    # TODO: Clear bucket properties.
    #       We need two things for this:
    #        * The ability to clear bucket properties in our Riak layer.
    #        * Tracking accounts created so we know which buckets to clear.
    #
    #       The first needs to happen in vumi and requires an updated Riak
    #       client. The second isn't really worth doing unitl the first is
    #       done.

    implements(IHelper)

    def __init__(self, is_sync=False, use_riak=True):
        self.is_sync = is_sync
        self._patch_helper = PatchHelper()
        generate_proxies(self, self._patch_helper)

        self._persistence_helper = PersistenceHelper(
            use_riak=use_riak, is_sync=is_sync)
        self.broker = None  # Will be replaced by the first worker_helper.
        self._worker_helpers = {}
        self._users_created = 0
        self._user_helpers = {}
        self._vumi_api = None

        generate_proxies(self, self._persistence_helper)

    def setup(self, setup_vumi_api=True):
        self._persistence_helper.setup()
        if self.is_sync:
            self._django_amqp_setup()
        if setup_vumi_api:
            return self.setup_vumi_api()

    @maybe_async
    def cleanup(self):
        for worker_helper in self._worker_helpers.values():
            # All of these will wait for the same broker, but that's fine.
            yield worker_helper.cleanup()
        yield self._persistence_helper.cleanup()
        self._patch_helper.cleanup()

    def _django_amqp_setup(self):
        import go.base.amqp
        import go.base.utils
        # We might need an AMQP connection at some point.
        broker = self.get_worker_helper().broker
        broker.exchange_declare('vumi', 'direct')
        self.django_amqp_connection = FakeAmqpConnection(broker)
        self.monkey_patch(
            go.base.utils, 'connection', self.django_amqp_connection)
        self.monkey_patch(
            go.base.amqp, 'connection', self.django_amqp_connection)

    def get_worker_helper(self, connector_name=None):
        if connector_name not in self._worker_helpers:
            worker_helper = WorkerHelper(connector_name, self.broker)
            # If this is our first worker helper, we need to grab the broker it
            # created. If it isn't, its broker will be self.broker anyway.
            self.broker = worker_helper.broker
            self._worker_helpers[connector_name] = worker_helper
        return self._worker_helpers[connector_name]

    @proxyable
    def get_vumi_api(self):
        assert self._vumi_api is not None, "No vumi_api provided."
        return self._vumi_api

    @proxyable
    def set_vumi_api(self, vumi_api):
        assert self._vumi_api is None, "Can't override existing vumi_api."
        self._vumi_api = vumi_api
        # TODO: Find a nicer way to give everything the same fake redis.
        pcfg = self._persistence_helper._config_overrides
        pcfg['redis_manager']['FAKE_REDIS'] = vumi_api.redis

    @proxyable
    def setup_vumi_api(self):
        if self.is_sync:
            return self.setup_sync_vumi_api()
        else:
            return self.setup_async_vumi_api()

    def setup_sync_vumi_api(self):
        from django.conf import settings
        import go.base.amqp
        self._vumi_api = VumiApi.from_config_sync(
            settings.VUMI_API_CONFIG, go.base.amqp.connection)

    def setup_async_vumi_api(self):
        worker_helper = self.get_worker_helper()
        amqp_client = worker_helper.get_fake_amqp_client(worker_helper.broker)
        d = amqp_client.start_publisher(ApiCommandPublisher)
        d.addCallback(lambda cmd_publisher: VumiApi.from_config_async(
            self.mk_config({}), cmd_publisher))
        return d.addCallback(self.set_vumi_api)

    @proxyable
    @maybe_async
    def make_user(self, username, enable_search=True, django_user_pk=None):
        # NOTE: We use bytes instead of unicode here because that's what the
        #       real new_user gives us.
        key = "test-%s-user" % (len(self._user_helpers),)
        user = self.get_vumi_api().account_store.users(key, username=username)
        yield user.save()
        user_helper = UserApiHelper(self, key, django_user_pk=django_user_pk)
        self._user_helpers[key] = user_helper
        if enable_search:
            contact_store = user_helper.user_api.contact_store
            yield contact_store.contacts.enable_search()
            yield contact_store.groups.enable_search()
        returnValue(self.get_user_helper(user.key))

    @proxyable
    def get_user_helper(self, account_key):
        return self._user_helpers[account_key]

    @proxyable
    @maybe_async
    def get_or_create_user(self):
        assert len(self._user_helpers) <= 1, "Too many users."
        if not self._user_helpers:
            yield self.make_user(u"testuser")
        returnValue(self._user_helpers.values()[0])

    @proxyable
    @maybe_async
    def setup_tagpool(self, pool, tags, metadata=None):
        tags = [(pool, tag) for tag in tags]
        yield self.get_vumi_api().tpm.declare_tags(tags)
        if metadata:
            yield self.get_vumi_api().tpm.set_metadata(pool, metadata)
        returnValue(tags)

    def get_dispatched_commands(self):
        return self.get_worker_helper().get_dispatched(
            'vumi', 'api', VumiApiCommand)
Exemple #3
0
class TransportHelper(object):
    """
    Test helper for transport workers.

    This helper construct and wraps several lower-level helpers and provides
    higher-level functionality for transport tests.

    :param transport_class:
        The worker class for the transport being tested.

    :param bool use_riak:
        Set to ``True`` if the test requires Riak. This is passed to the
        underlying :class:`~vumi.tests.helpers.PersistenceHelper`.

    :param \**msg_helper_args:
        All other keyword params are passed to the underlying
        :class:`~vumi.tests.helpers.MessageHelper`.
    """

    implements(IHelper)

    def __init__(self, transport_class, use_riak=False, **msg_helper_args):
        self.transport_class = transport_class
        self.persistence_helper = PersistenceHelper(use_riak=use_riak)
        self.msg_helper = MessageHelper(**msg_helper_args)
        self.transport_name = self.msg_helper.transport_name
        self.worker_helper = WorkerHelper(self.transport_name)
        self.dispatch_helper = MessageDispatchHelper(self.msg_helper,
                                                     self.worker_helper)

        # Proxy methods from our helpers.
        generate_proxies(self, self.msg_helper)
        generate_proxies(self, self.worker_helper)
        generate_proxies(self, self.dispatch_helper)
        generate_proxies(self, self.persistence_helper)

    def setup(self):
        self.persistence_helper.setup()
        self.worker_helper.setup()

    @inlineCallbacks
    def cleanup(self):
        yield self.worker_helper.cleanup()
        yield self.persistence_helper.cleanup()

    def get_transport(self, config, cls=None, start=True):
        """
        Get an instance of a transport class.

        :param config: Config dict.
        :param cls: The transport class to instantiate.
                    Defaults to :attr:`transport_class`
        :param start: True to start the transport (default), False otherwise.

        Some default config values are helpfully provided in the
        interests of reducing boilerplate:

        * ``transport_name`` defaults to :attr:`self.transport_name`
        """

        if cls is None:
            cls = self.transport_class
        config = self.mk_config(config)
        config.setdefault('transport_name', self.transport_name)
        return self.get_worker(cls, config, start)

    def get_dispatched_failures(self, connector_name=None):
        """
        Get failures dispatched by a transport.

        :param str connector_name:
            Connector name. If ``None``, the default connector name for the
            helper instance will be used.

        :returns:
            A list of :class:`~vumi.transports.failures.FailureMessage`
            instances.
        """
        return self.get_dispatched(connector_name, 'failures', FailureMessage)
Exemple #4
0
class DispatcherHelper(object):
    """
    Test helper for dispatcher workers.

    This helper construct and wraps several lower-level helpers and provides
    higher-level functionality for dispatcher tests.

    :param dispatcher_class:
        The worker class for the dispatcher being tested.

    :param bool use_riak:
        Set to ``True`` if the test requires Riak. This is passed to the
        underlying :class:`~vumi.tests.helpers.PersistenceHelper`.

    :param \**msg_helper_args:
        All other keyword params are passed to the underlying
        :class:`~vumi.tests.helpers.MessageHelper`.
    """

    implements(IHelper)

    def __init__(self, dispatcher_class, use_riak=False, **msg_helper_args):
        self.dispatcher_class = dispatcher_class
        self.worker_helper = WorkerHelper()
        self.persistence_helper = PersistenceHelper(use_riak=use_riak)
        self.msg_helper = MessageHelper(**msg_helper_args)
        self.dispatch_helper = MessageDispatchHelper(self.msg_helper,
                                                     self.worker_helper)

        # Proxy methods from our helpers.
        generate_proxies(self, self.msg_helper)
        generate_proxies(self, self.worker_helper)
        generate_proxies(self, self.dispatch_helper)

    def setup(self):
        self.persistence_helper.setup()
        self.worker_helper.setup()

    @inlineCallbacks
    def cleanup(self):
        yield self.worker_helper.cleanup()
        yield self.persistence_helper.cleanup()

    def get_dispatcher(self, config, cls=None, start=True):
        """
        Get an instance of a dispatcher class.

        :param dict config: Config dict.
        :param cls:
            The transport class to instantiate. Defaults to
            :attr:`dispatcher_class`
        :param bool start:
            ``True`` to start the dispatcher (default), ``False`` otherwise.
        """
        if cls is None:
            cls = self.dispatcher_class
        config = self.persistence_helper.mk_config(config)
        return self.get_worker(cls, config, start)

    def get_connector_helper(self, connector_name):
        """
        Construct a :class:`~DispatcherConnectorHelper` for the provided
        ``connector_name``.
        """
        return DispatcherConnectorHelper(self, connector_name)
Exemple #5
0
class VumiApiHelper(object):
    # TODO: Clear bucket properties.
    #       We need two things for this:
    #        * The ability to clear bucket properties in our Riak layer.
    #        * Tracking accounts created so we know which buckets to clear.
    #
    #       The first needs to happen in vumi and requires an updated Riak
    #       client. The second isn't really worth doing unitl the first is
    #       done.

    implements(IHelper)

    def __init__(self, is_sync=False, use_riak=True):
        self.is_sync = is_sync
        self._patch_helper = PatchHelper()
        generate_proxies(self, self._patch_helper)

        self._persistence_helper = PersistenceHelper(use_riak=use_riak,
                                                     is_sync=is_sync)
        self.broker = None  # Will be replaced by the first worker_helper.
        self._worker_helpers = {}
        self._users_created = 0
        self._user_helpers = {}
        self._vumi_api = None

        generate_proxies(self, self._persistence_helper)

    def setup(self, setup_vumi_api=True):
        self._persistence_helper.setup()
        if self.is_sync:
            self._django_amqp_setup()
        if setup_vumi_api:
            return self.setup_vumi_api()

    @maybe_async
    def cleanup(self):
        for worker_helper in self._worker_helpers.values():
            # All of these will wait for the same broker, but that's fine.
            yield worker_helper.cleanup()
        yield self._persistence_helper.cleanup()
        self._patch_helper.cleanup()

    def _django_amqp_setup(self):
        import go.base.amqp
        import go.base.utils
        # We might need an AMQP connection at some point.
        broker = self.get_worker_helper().broker
        broker.exchange_declare('vumi', 'direct')
        self.django_amqp_connection = FakeAmqpConnection(broker)
        self.monkey_patch(go.base.utils, 'connection',
                          self.django_amqp_connection)
        self.monkey_patch(go.base.amqp, 'connection',
                          self.django_amqp_connection)

    def get_worker_helper(self, connector_name=None):
        if connector_name not in self._worker_helpers:
            worker_helper = WorkerHelper(connector_name, self.broker)
            # If this is our first worker helper, we need to grab the broker it
            # created. If it isn't, its broker will be self.broker anyway.
            self.broker = worker_helper.broker
            self._worker_helpers[connector_name] = worker_helper
        return self._worker_helpers[connector_name]

    @proxyable
    def get_vumi_api(self):
        assert self._vumi_api is not None, "No vumi_api provided."
        return self._vumi_api

    @proxyable
    def set_vumi_api(self, vumi_api):
        assert self._vumi_api is None, "Can't override existing vumi_api."
        self._vumi_api = vumi_api
        # TODO: Find a nicer way to give everything the same fake redis.
        pcfg = self._persistence_helper._config_overrides
        pcfg['redis_manager']['FAKE_REDIS'] = vumi_api.redis

    @proxyable
    def setup_vumi_api(self):
        if self.is_sync:
            return self.setup_sync_vumi_api()
        else:
            return self.setup_async_vumi_api()

    def setup_sync_vumi_api(self):
        from django.conf import settings
        import go.base.amqp
        self._vumi_api = VumiApi.from_config_sync(settings.VUMI_API_CONFIG,
                                                  go.base.amqp.connection)

    def setup_async_vumi_api(self):
        worker_helper = self.get_worker_helper()
        amqp_client = worker_helper.get_fake_amqp_client(worker_helper.broker)
        d = amqp_client.start_publisher(ApiCommandPublisher)
        d.addCallback(lambda cmd_publisher: VumiApi.from_config_async(
            self.mk_config({}), cmd_publisher))
        return d.addCallback(self.set_vumi_api)

    @proxyable
    @maybe_async
    def make_user(self, username, enable_search=True, django_user_pk=None):
        # NOTE: We use bytes instead of unicode here because that's what the
        #       real new_user gives us.
        key = "test-%s-user" % (len(self._user_helpers), )
        user = self.get_vumi_api().account_store.users(key, username=username)
        yield user.save()
        user_helper = UserApiHelper(self, key, django_user_pk=django_user_pk)
        self._user_helpers[key] = user_helper
        if enable_search:
            contact_store = user_helper.user_api.contact_store
            yield contact_store.contacts.enable_search()
            yield contact_store.groups.enable_search()
        returnValue(self.get_user_helper(user.key))

    @proxyable
    def get_user_helper(self, account_key):
        return self._user_helpers[account_key]

    @proxyable
    @maybe_async
    def get_or_create_user(self):
        assert len(self._user_helpers) <= 1, "Too many users."
        if not self._user_helpers:
            yield self.make_user(u"testuser")
        returnValue(self._user_helpers.values()[0])

    @proxyable
    @maybe_async
    def setup_tagpool(self, pool, tags, metadata=None):
        tags = [(pool, tag) for tag in tags]
        yield self.get_vumi_api().tpm.declare_tags(tags)
        if metadata:
            yield self.get_vumi_api().tpm.set_metadata(pool, metadata)
        returnValue(tags)

    def get_dispatched_commands(self):
        return self.get_worker_helper().get_dispatched('vumi', 'api',
                                                       VumiApiCommand)
Exemple #6
0
class DispatcherHelper(object):
    """
    Test helper for dispatcher workers.

    This helper construct and wraps several lower-level helpers and provides
    higher-level functionality for dispatcher tests.

    :param dispatcher_class:
        The worker class for the dispatcher being tested.

    :param bool use_riak:
        Set to ``True`` if the test requires Riak. This is passed to the
        underlying :class:`~vumi.tests.helpers.PersistenceHelper`.

    :param \**msg_helper_args:
        All other keyword params are passed to the underlying
        :class:`~vumi.tests.helpers.MessageHelper`.
    """

    implements(IHelper)

    def __init__(self, dispatcher_class, use_riak=False, **msg_helper_args):
        self.dispatcher_class = dispatcher_class
        self.worker_helper = WorkerHelper()
        self.persistence_helper = PersistenceHelper(use_riak=use_riak)
        self.msg_helper = MessageHelper(**msg_helper_args)
        self.dispatch_helper = MessageDispatchHelper(self.msg_helper, self.worker_helper)

        # Proxy methods from our helpers.
        generate_proxies(self, self.msg_helper)
        generate_proxies(self, self.worker_helper)
        generate_proxies(self, self.dispatch_helper)

    def setup(self):
        self.persistence_helper.setup()
        self.worker_helper.setup()

    @inlineCallbacks
    def cleanup(self):
        yield self.worker_helper.cleanup()
        yield self.persistence_helper.cleanup()

    def get_dispatcher(self, config, cls=None, start=True):
        """
        Get an instance of a dispatcher class.

        :param dict config: Config dict.
        :param cls:
            The transport class to instantiate. Defaults to
            :attr:`dispatcher_class`
        :param bool start:
            ``True`` to start the dispatcher (default), ``False`` otherwise.
        """
        if cls is None:
            cls = self.dispatcher_class
        config = self.persistence_helper.mk_config(config)
        return self.get_worker(cls, config, start)

    def get_connector_helper(self, connector_name):
        """
        Construct a :class:`~DispatcherConnectorHelper` for the provided
        ``connector_name``.
        """
        return DispatcherConnectorHelper(self, connector_name)