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)
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)
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)
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)
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)
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)