Example #1
0
 def setUp(self):
     self.today = datetime.utcnow().date()
     self.port = 9999
     self.path = '/api/v1/sms/vas2nets/receive/'
     self.config = {
         'transport_name': 'vas2nets',
         'url': 'http://localhost:%s%s' % (self.port, self.path),
         'username': '******',
         'password': '******',
         'owner': 'owner',
         'service': 'service',
         'subservice': 'subservice',
         'web_receive_path': '/receive',
         'web_receipt_path': '/receipt',
         'web_port': 9998,
     }
     self.fail_config = {
         'transport_name': 'vas2nets',
         'retry_routing_key': '%(transport_name)s.outbound',
         'failures_routing_key': '%(transport_name)s.failures',
         }
     self.workers = []
     self.broker = FakeAMQPBroker()
     self.redis = FakeRedis()
     self.worker = yield self.mk_transport_worker(self.config, self.broker)
     self.fail_worker = yield self.mk_failure_worker(
         self.fail_config, self.broker, self.redis)
Example #2
0
 def setUp(self):
     warnings.warn(
         "VumiWorkerTestCase and its subclasses are deprecated. "
         "Use VumiTestCase and other tools from "
         "vumi.tests.helpers instead.",
         category=DeprecationWarning)
     self._workers = []
     self._amqp = FakeAMQPBroker()
Example #3
0
    def test_publish_heartbeat(self):
        self.broker = FakeAMQPBroker()
        channel = yield get_stubbed_channel(self.broker)
        pub = MockHeartBeatPublisher(self.gen_fake_attrs)
        pub.start(channel)
        pub._beat()

        [msg] = self.broker.get_dispatched("vumi.health", "heartbeat.inbound")
        self.assertEqual(json.loads(msg.body), self.gen_fake_attrs())
Example #4
0
    def test_publish_heartbeat(self):
        broker = FakeAMQPBroker()
        client = WorkerHelper.get_fake_amqp_client(broker)
        channel = yield client.get_channel()
        pub = MockHeartBeatPublisher(self.gen_fake_attrs)
        pub.start(channel)
        pub._beat()

        [msg] = broker.get_dispatched("vumi.health", "heartbeat.inbound")
        self.assertEqual(json.loads(msg.body), self.gen_fake_attrs())
Example #5
0
    def test_publish_heartbeat(self):
        broker = FakeAMQPBroker()
        client = WorkerHelper.get_fake_amqp_client(broker)
        channel = yield client.get_channel()
        pub = MockHeartBeatPublisher(self.gen_fake_attrs)
        pub.start(channel)
        pub._beat()

        [msg] = broker.get_dispatched("vumi.health", "heartbeat.inbound")
        self.assertEqual(json.loads(msg.body), self.gen_fake_attrs())
Example #6
0
 def setUp(self):
     warnings.warn("VumiWorkerTestCase and its subclasses are deprecated. "
                   "Use VumiTestCase and other tools from "
                   "vumi.tests.helpers instead.",
                   category=DeprecationWarning)
     self._workers = []
     self._amqp = FakeAMQPBroker()
Example #7
0
 def setUp(self):
     self.today = datetime.utcnow().date()
     self.port = 9999
     self.path = '/api/v1/sms/vas2nets/receive/'
     self.config = {
         'transport_name': 'vas2nets',
         'url': 'http://localhost:%s%s' % (self.port, self.path),
         'username': '******',
         'password': '******',
         'owner': 'owner',
         'service': 'service',
         'subservice': 'subservice',
         'web_receive_path': '/receive',
         'web_receipt_path': '/receipt',
         'web_port': 9998,
     }
     self.fail_config = {
         'transport_name': 'vas2nets',
         'retry_routing_key': '%(transport_name)s.outbound',
         'failures_routing_key': '%(transport_name)s.failures',
         }
     self.workers = []
     self.broker = FakeAMQPBroker()
     self.redis = FakeRedis()
     self.worker = yield self.mk_transport_worker(self.config, self.broker)
     self.fail_worker = yield self.mk_failure_worker(
         self.fail_config, self.broker, self.redis)
Example #8
0
    def _setup_workers(self, bucketters, aggregators, bucket_size):
        broker = FakeAMQPBroker()
        self.broker = BrokerWrapper(broker)

        bucket_config = {
            'buckets': aggregators,
            'bucket_size': bucket_size,
        }
        for _i in range(bucketters):
            worker = get_stubbed_worker(metrics_workers.MetricTimeBucket,
                                        config=bucket_config,
                                        broker=broker)
            yield worker.startWorker()
            self.bucket_workers.append(worker)

        aggregator_config = {
            'bucket_size': bucket_size,
        }
        for i in range(aggregators):
            config = aggregator_config.copy()
            config['bucket'] = i
            worker = get_stubbed_worker(metrics_workers.MetricAggregator,
                                        config=config,
                                        broker=broker)
            worker._time = self.fake_time
            yield worker.startWorker()
            self.aggregator_workers.append(worker)
Example #9
0
 def setUp(self):
     self.today = datetime.utcnow().date()
     self.port = 9999
     self.path = "/api/v1/sms/vas2nets/receive/"
     self.config = {
         "transport_name": "vas2nets",
         "url": "http://localhost:%s%s" % (self.port, self.path),
         "username": "******",
         "password": "******",
         "owner": "owner",
         "service": "service",
         "subservice": "subservice",
         "web_receive_path": "/receive",
         "web_receipt_path": "/receipt",
         "web_port": 9998,
     }
     self.fail_config = {
         "transport_name": "vas2nets",
         "retry_routing_key": "sms.outbound.%(transport_name)s",
         "failures_routing_key": "sms.outbound.%(transport_name)s.failures",
     }
     self.workers = []
     self.broker = FakeAMQPBroker()
     self.redis = FakeRedis()
     self.worker = yield self.mk_transport_worker(self.config, self.broker)
     self.fail_worker = yield self.mk_failure_worker(self.fail_config, self.broker, self.redis)
Example #10
0
    def test_publish_heartbeat(self):
        self.broker = FakeAMQPBroker()
        channel = yield get_stubbed_channel(self.broker)
        pub = MockHeartBeatPublisher(self.gen_fake_attrs)
        pub.start(channel)
        pub._beat()

        [msg] = self.broker.get_dispatched("vumi.health", "heartbeat.inbound")
        self.assertEqual(json.loads(msg.body), self.gen_fake_attrs())
Example #11
0
 def setUp(self):
     self.path = '/api/v1/sms/vas2nets/receive/'
     self.port = 9999
     self.config = {
         'transport_name': 'vas2nets',
         'url': 'http://localhost:%s%s' % (self.port, self.path),
         'username': '******',
         'password': '******',
         'owner': 'owner',
         'service': 'service',
         'subservice': 'subservice',
         'web_receive_path': '/receive',
         'web_receipt_path': '/receipt',
         'web_port': 9998,
     }
     self.broker = FakeAMQPBroker()
     self.worker = get_stubbed_worker(Vas2NetsTransport, self.config,
                                      self.broker)
     self.publisher = yield self.worker.publish_to('some.routing.key')
     self.today = datetime.utcnow().date()
     self.workers = [self.worker]
Example #12
0
class TestHeartBeatPublisher(VumiTestCase):

    def gen_fake_attrs(self):
        attrs = {
            'version': publisher.HeartBeatMessage.VERSION_20130319,
            'system_id': "system-1",
            'worker_id': "worker-1",
            'worker_name': "worker-1",
            'hostname': "test-host-1",
            'timestamp': 100,
            'pid': 43,
        }
        return attrs

    @inlineCallbacks
    def test_publish_heartbeat(self):
        self.broker = FakeAMQPBroker()
        channel = yield get_stubbed_channel(self.broker)
        pub = MockHeartBeatPublisher(self.gen_fake_attrs)
        pub.start(channel)
        pub._beat()

        [msg] = self.broker.get_dispatched("vumi.health", "heartbeat.inbound")
        self.assertEqual(json.loads(msg.body), self.gen_fake_attrs())

    def test_message_validation(self):
        attrs = self.gen_fake_attrs()
        attrs.pop("version")
        self.assertRaises(MissingMessageField, publisher.HeartBeatMessage,
                          **attrs)
        attrs = self.gen_fake_attrs()
        attrs.pop("system_id")
        self.assertRaises(MissingMessageField, publisher.HeartBeatMessage,
                          **attrs)
        attrs = self.gen_fake_attrs()
        attrs.pop("worker_id")
        self.assertRaises(MissingMessageField, publisher.HeartBeatMessage,
                          **attrs)
Example #13
0
class TestHeartBeatPublisher(VumiTestCase):
    def gen_fake_attrs(self):
        attrs = {
            'version': publisher.HeartBeatMessage.VERSION_20130319,
            'system_id': "system-1",
            'worker_id': "worker-1",
            'worker_name': "worker-1",
            'hostname': "test-host-1",
            'timestamp': 100,
            'pid': 43,
        }
        return attrs

    @inlineCallbacks
    def test_publish_heartbeat(self):
        self.broker = FakeAMQPBroker()
        channel = yield get_stubbed_channel(self.broker)
        pub = MockHeartBeatPublisher(self.gen_fake_attrs)
        pub.start(channel)
        pub._beat()

        [msg] = self.broker.get_dispatched("vumi.health", "heartbeat.inbound")
        self.assertEqual(json.loads(msg.body), self.gen_fake_attrs())

    def test_message_validation(self):
        attrs = self.gen_fake_attrs()
        attrs.pop("version")
        self.assertRaises(MissingMessageField, publisher.HeartBeatMessage,
                          **attrs)
        attrs = self.gen_fake_attrs()
        attrs.pop("system_id")
        self.assertRaises(MissingMessageField, publisher.HeartBeatMessage,
                          **attrs)
        attrs = self.gen_fake_attrs()
        attrs.pop("worker_id")
        self.assertRaises(MissingMessageField, publisher.HeartBeatMessage,
                          **attrs)
Example #14
0
class TransportTestCase(unittest.TestCase):
    """
    This is a base class for testing transports.

    Not to be confused with BaseTransportTestCase below.
    """

    # have transport tests timeout after 5s by default
    timeout = 5

    transport_name = "sphex"
    transport_type = None
    transport_class = None

    def setUp(self):
        self._workers = []
        self._amqp = FakeAMQPBroker()

    @inlineCallbacks
    def tearDown(self):
        for worker in self._workers:
            yield worker.stopWorker()

    def rkey(self, name):
        return "%s.%s" % (self.transport_name, name)

    @inlineCallbacks
    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.setdefault('transport_name', self.transport_name)
        worker = get_stubbed_worker(cls, config, self._amqp)
        self._workers.append(worker)
        if start:
            yield worker.startWorker()
        returnValue(worker)

    def assert_rkey_attr(self, rkey_suffix, obj, tr_name=None):
        if tr_name is None:
            tr_name = self.transport_name
        self.assertEqual("%s.%s" % (tr_name, rkey_suffix), obj.routing_key)

    def assert_basic_rkeys(self, transport):
        self.assert_rkey_attr('event', transport.event_publisher)
        self.assert_rkey_attr('inbound', transport.message_publisher)
        self.assert_rkey_attr('failures', transport.failure_publisher)
        self.assert_rkey_attr('outbound', transport.message_consumer)

    def mkmsg_ack(self, user_message_id='1', sent_message_id='abc',
                  transport_metadata=None):
        if transport_metadata is None:
            transport_metadata = {}
        return TransportEvent(
            event_id=RegexMatcher(r'^[0-9a-fA-F]{32}$'),
            event_type='ack',
            user_message_id=user_message_id,
            sent_message_id=sent_message_id,
            timestamp=UTCNearNow(),
            transport_name=self.transport_name,
            transport_metadata=transport_metadata,
            )

    def mkmsg_delivery(self, status='delivered', user_message_id='abc',
                       transport_metadata=None):
        if transport_metadata is None:
            transport_metadata = {}
        return TransportEvent(
            event_id=RegexMatcher(r'^[0-9a-fA-F]{32}$'),
            event_type='delivery_report',
            transport_name=self.transport_name,
            user_message_id=user_message_id,
            delivery_status=status,
            to_addr='+41791234567',
            timestamp=UTCNearNow(),
            transport_metadata=transport_metadata,
            )

    def mkmsg_in(self, content='hello world',
                 session_event=TransportUserMessage.SESSION_NONE,
                 message_id='abc', transport_type=None,
                 transport_metadata=None):
        if transport_type is None:
            transport_type = self.transport_type
        if transport_metadata is None:
            transport_metadata = {}
        return TransportUserMessage(
            from_addr='+41791234567',
            to_addr='9292',
            group=None,
            message_id=message_id,
            transport_name=self.transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            content=content,
            session_event=session_event,
            timestamp=UTCNearNow(),
            )

    def mkmsg_out(self, content='hello world',
                  session_event=TransportUserMessage.SESSION_NONE,
                  message_id='1', to_addr='+41791234567', from_addr='9292',
                  group=None, in_reply_to=None, transport_type=None,
                  transport_metadata=None, helper_metadata=None):
        if transport_type is None:
            transport_type = self.transport_type
        if transport_metadata is None:
            transport_metadata = {}
        if helper_metadata is None:
            helper_metadata = {}
        params = dict(
            to_addr=to_addr,
            from_addr=from_addr,
            group=group,
            message_id=message_id,
            transport_name=self.transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            content=content,
            session_event=session_event,
            in_reply_to=in_reply_to,
            helper_metadata=helper_metadata,
            )
        return TransportUserMessage(**params)

    def mkmsg_fail(self, message, reason,
                   failure_code=FailureMessage.FC_UNSPECIFIED):
        return FailureMessage(
            timestamp=UTCNearNow(),
            failure_code=failure_code,
            message=message,
            reason=reason,
            )

    def get_dispatched_events(self):
        return self._amqp.get_messages('vumi', self.rkey('event'))

    def get_dispatched_messages(self):
        return self._amqp.get_messages('vumi', self.rkey('inbound'))

    def get_dispatched_failures(self):
        return self._amqp.get_messages('vumi', self.rkey('failures'))

    def wait_for_dispatched_messages(self, amount):
        return self._amqp.wait_messages('vumi', self.rkey('inbound'), amount)

    def clear_dispatched_messages(self):
        self._amqp.clear_messages('vumi', self.rkey('inbound'))

    def dispatch(self, message, rkey=None, exchange='vumi'):
        if rkey is None:
            rkey = self.rkey('outbound')
        self._amqp.publish_message(exchange, rkey, message)
        return self._amqp.kick_delivery()
Example #15
0
class VumiWorkerTestCase(VumiTestCase):
    """Base test class for vumi workers.

    This (or a subclass of this) should be the starting point for any test
    cases that involve vumi workers.
    """

    transport_name = "sphex"
    transport_type = None

    MSG_ID_MATCHER = RegexMatcher(r'^[0-9a-fA-F]{32}$')

    def setUp(self):
        warnings.warn(
            "VumiWorkerTestCase and its subclasses are deprecated. "
            "Use VumiTestCase and other tools from "
            "vumi.tests.helpers instead.",
            category=DeprecationWarning)
        self._workers = []
        self._amqp = FakeAMQPBroker()

    @inlineCallbacks
    def tearDown(self):
        yield super(VumiWorkerTestCase, self).tearDown()
        # Wait for any pending message deliveries to avoid a race with a dirty
        # reactor.
        yield self._amqp.wait_delivery()
        # Now stop all the workers.
        for worker in self._workers:
            yield worker.stopWorker()

    def rkey(self, name):
        return "%s.%s" % (self.transport_name, name)

    def _rkey(self, name, connector_name=None):
        if connector_name is None:
            return self.rkey(name)
        return "%s.%s" % (connector_name, name)

    @inlineCallbacks
    def get_worker(self, config, cls, start=True):
        """Create and return an instance of a vumi worker.

        :param config: Config dict.
        :param cls: The worker class to instantiate.
        :param start: True to start the worker (default), False otherwise.
        """

        # When possible, always try and enable heartbeat setup in tests.
        # so make sure worker_name is set
        if (config is not None) and ('worker_name' not in config):
            config['worker_name'] = "unnamed"

        worker = get_stubbed_worker(cls, config, self._amqp)
        self._workers.append(worker)
        if start:
            yield worker.startWorker()
        returnValue(worker)

    def mkmsg_ack(self,
                  user_message_id='1',
                  sent_message_id='abc',
                  transport_metadata=None,
                  transport_name=None):
        if transport_metadata is None:
            transport_metadata = {}
        if transport_name is None:
            transport_name = self.transport_name
        return TransportEvent(
            event_type='ack',
            user_message_id=user_message_id,
            sent_message_id=sent_message_id,
            transport_name=transport_name,
            transport_metadata=transport_metadata,
        )

    def mkmsg_nack(self,
                   user_message_id='1',
                   transport_metadata=None,
                   transport_name=None,
                   nack_reason='unknown'):
        if transport_metadata is None:
            transport_metadata = {}
        if transport_name is None:
            transport_name = self.transport_name
        return TransportEvent(
            event_type='nack',
            nack_reason=nack_reason,
            user_message_id=user_message_id,
            transport_name=transport_name,
            transport_metadata=transport_metadata,
        )

    def mkmsg_delivery(self,
                       status='delivered',
                       user_message_id='abc',
                       transport_metadata=None,
                       transport_name=None):
        if transport_metadata is None:
            transport_metadata = {}
        if transport_name is None:
            transport_name = self.transport_name
        return TransportEvent(
            event_type='delivery_report',
            transport_name=transport_name,
            user_message_id=user_message_id,
            delivery_status=status,
            to_addr='+41791234567',
            transport_metadata=transport_metadata,
        )

    def mkmsg_in(self,
                 content='hello world',
                 message_id='abc',
                 to_addr='9292',
                 from_addr='+41791234567',
                 group=None,
                 session_event=None,
                 transport_type=None,
                 helper_metadata=None,
                 transport_metadata=None,
                 transport_name=None):
        if transport_type is None:
            transport_type = self.transport_type
        if helper_metadata is None:
            helper_metadata = {}
        if transport_metadata is None:
            transport_metadata = {}
        if transport_name is None:
            transport_name = self.transport_name
        return TransportUserMessage(
            from_addr=from_addr,
            to_addr=to_addr,
            group=group,
            message_id=message_id,
            transport_name=transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            helper_metadata=helper_metadata,
            content=content,
            session_event=session_event,
            timestamp=datetime.now(),
        )

    def mkmsg_out(
        self,
        content='hello world',
        message_id='1',
        to_addr='+41791234567',
        from_addr='9292',
        group=None,
        session_event=None,
        in_reply_to=None,
        transport_type=None,
        transport_metadata=None,
        transport_name=None,
        helper_metadata=None,
    ):
        if transport_type is None:
            transport_type = self.transport_type
        if transport_metadata is None:
            transport_metadata = {}
        if transport_name is None:
            transport_name = self.transport_name
        if helper_metadata is None:
            helper_metadata = {}
        params = dict(
            to_addr=to_addr,
            from_addr=from_addr,
            group=group,
            message_id=message_id,
            transport_name=transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            content=content,
            session_event=session_event,
            in_reply_to=in_reply_to,
            helper_metadata=helper_metadata,
        )
        return TransportUserMessage(**params)

    def _make_matcher(self, msg, *id_fields):
        msg['timestamp'] = UTCNearNow()
        for field in id_fields:
            msg[field] = self.MSG_ID_MATCHER
        return msg

    def _get_dispatched(self, name, connector_name=None):
        rkey = self._rkey(name, connector_name)
        return self._amqp.get_messages('vumi', rkey)

    def _wait_for_dispatched(self, name, amount, connector_name=None):
        rkey = self._rkey(name, connector_name)
        return self._amqp.wait_messages('vumi', rkey, amount)

    def clear_all_dispatched(self):
        self._amqp.clear_messages('vumi')

    def _clear_dispatched(self, name, connector_name=None):
        rkey = self._rkey(name, connector_name)
        return self._amqp.clear_messages('vumi', rkey)

    def get_dispatched_events(self, connector_name=None):
        return self._get_dispatched('event', connector_name)

    def get_dispatched_inbound(self, connector_name=None):
        return self._get_dispatched('inbound', connector_name)

    def get_dispatched_outbound(self, connector_name=None):
        return self._get_dispatched('outbound', connector_name)

    def get_dispatched_failures(self, connector_name=None):
        return self._get_dispatched('failures', connector_name)

    def wait_for_dispatched_events(self, amount, connector_name=None):
        return self._wait_for_dispatched('event', amount, connector_name)

    def wait_for_dispatched_inbound(self, amount, connector_name=None):
        return self._wait_for_dispatched('inbound', amount, connector_name)

    def wait_for_dispatched_outbound(self, amount, connector_name=None):
        return self._wait_for_dispatched('outbound', amount, connector_name)

    def wait_for_dispatched_failures(self, amount, connector_name=None):
        return self._wait_for_dispatched('failures', amount, connector_name)

    def clear_dispatched_events(self, connector_name=None):
        return self._clear_dispatched('event', connector_name)

    def clear_dispatched_inbound(self, connector_name=None):
        return self._clear_dispatched('inbound', connector_name)

    def clear_dispatched_outbound(self, connector_name=None):
        return self._clear_dispatched('outbound', connector_name)

    def clear_dispatched_failures(self, connector_name=None):
        return self._clear_dispatched('failures', connector_name)

    def _dispatch(self, message, rkey, exchange='vumi'):
        self._amqp.publish_message(exchange, rkey, message)
        return self._amqp.kick_delivery()

    def dispatch_inbound(self, message, connector_name=None):
        rkey = self._rkey('inbound', connector_name)
        return self._dispatch(message, rkey)

    def dispatch_outbound(self, message, connector_name=None):
        rkey = self._rkey('outbound', connector_name)
        return self._dispatch(message, rkey)

    def dispatch_event(self, message, connector_name=None):
        rkey = self._rkey('event', connector_name)
        return self._dispatch(message, rkey)

    def dispatch_failure(self, message, connector_name=None):
        rkey = self._rkey('failure', connector_name)
        return self._dispatch(message, rkey)
Example #16
0
class TransportTestCase(unittest.TestCase):
    """
    This is a base class for testing transports.

    Not to be confused with BaseTransportTestCase below.
    """

    # have transport tests timeout after 5s by default
    timeout = 5

    transport_name = "sphex"
    transport_type = None
    transport_class = None

    def setUp(self):
        self._workers = []
        self._amqp = FakeAMQPBroker()

    @inlineCallbacks
    def tearDown(self):
        for worker in self._workers:
            yield worker.stopWorker()

    def rkey(self, name):
        return "%s.%s" % (self.transport_name, name)

    @inlineCallbacks
    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.setdefault('transport_name', self.transport_name)
        worker = get_stubbed_worker(cls, config, self._amqp)
        self._workers.append(worker)
        if start:
            yield worker.startWorker()
        returnValue(worker)

    def assert_rkey_attr(self, rkey_suffix, obj, tr_name=None):
        if tr_name is None:
            tr_name = self.transport_name
        self.assertEqual("%s.%s" % (tr_name, rkey_suffix), obj.routing_key)

    def assert_basic_rkeys(self, transport):
        self.assert_rkey_attr('event', transport.event_publisher)
        self.assert_rkey_attr('inbound', transport.message_publisher)
        self.assert_rkey_attr('failures', transport.failure_publisher)
        self.assert_rkey_attr('outbound', transport.message_consumer)

    def mkmsg_ack(self,
                  user_message_id='1',
                  sent_message_id='abc',
                  transport_metadata=None):
        if transport_metadata is None:
            transport_metadata = {}
        return TransportEvent(
            event_id=RegexMatcher(r'^[0-9a-fA-F]{32}$'),
            event_type='ack',
            user_message_id=user_message_id,
            sent_message_id=sent_message_id,
            timestamp=UTCNearNow(),
            transport_name=self.transport_name,
            transport_metadata=transport_metadata,
        )

    def mkmsg_delivery(self,
                       status='delivered',
                       user_message_id='abc',
                       transport_metadata=None):
        if transport_metadata is None:
            transport_metadata = {}
        return TransportEvent(
            event_id=RegexMatcher(r'^[0-9a-fA-F]{32}$'),
            event_type='delivery_report',
            transport_name=self.transport_name,
            user_message_id=user_message_id,
            delivery_status=status,
            to_addr='+41791234567',
            timestamp=UTCNearNow(),
            transport_metadata=transport_metadata,
        )

    def mkmsg_in(self,
                 content='hello world',
                 session_event=TransportUserMessage.SESSION_NONE,
                 message_id='abc',
                 transport_type=None,
                 transport_metadata=None):
        if transport_type is None:
            transport_type = self.transport_type
        if transport_metadata is None:
            transport_metadata = {}
        return TransportUserMessage(
            from_addr='+41791234567',
            to_addr='9292',
            group=None,
            message_id=message_id,
            transport_name=self.transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            content=content,
            session_event=session_event,
            timestamp=UTCNearNow(),
        )

    def mkmsg_out(self,
                  content='hello world',
                  session_event=TransportUserMessage.SESSION_NONE,
                  message_id='1',
                  to_addr='+41791234567',
                  from_addr='9292',
                  group=None,
                  in_reply_to=None,
                  transport_type=None,
                  transport_metadata=None,
                  helper_metadata=None):
        if transport_type is None:
            transport_type = self.transport_type
        if transport_metadata is None:
            transport_metadata = {}
        if helper_metadata is None:
            helper_metadata = {}
        params = dict(
            to_addr=to_addr,
            from_addr=from_addr,
            group=group,
            message_id=message_id,
            transport_name=self.transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            content=content,
            session_event=session_event,
            in_reply_to=in_reply_to,
            helper_metadata=helper_metadata,
        )
        return TransportUserMessage(**params)

    def mkmsg_fail(self,
                   message,
                   reason,
                   failure_code=FailureMessage.FC_UNSPECIFIED):
        return FailureMessage(
            timestamp=UTCNearNow(),
            failure_code=failure_code,
            message=message,
            reason=reason,
        )

    def get_dispatched_events(self):
        return self._amqp.get_messages('vumi', self.rkey('event'))

    def get_dispatched_messages(self):
        return self._amqp.get_messages('vumi', self.rkey('inbound'))

    def get_dispatched_failures(self):
        return self._amqp.get_messages('vumi', self.rkey('failures'))

    def wait_for_dispatched_messages(self, amount):
        return self._amqp.wait_messages('vumi', self.rkey('inbound'), amount)

    def clear_dispatched_messages(self):
        self._amqp.clear_messages('vumi', self.rkey('inbound'))

    def dispatch(self, message, rkey=None, exchange='vumi'):
        if rkey is None:
            rkey = self.rkey('outbound')
        self._amqp.publish_message(exchange, rkey, message)
        return self._amqp.kick_delivery()
Example #17
0
class ApplicationTestCase(TestCase):
    """
    This is a base class for testing application workers.

    """

    # base timeout of 5s for all application tests
    timeout = 5

    transport_name = "sphex"
    transport_type = None
    application_class = None

    def setUp(self):
        self._workers = []
        self._amqp = FakeAMQPBroker()

    def tearDown(self):
        for worker in self._workers:
            worker.stopWorker()

    def rkey(self, name):
        return "%s.%s" % (self.transport_name, name)

    @inlineCallbacks
    def get_application(self, config, cls=None, start=True):
        """
        Get an instance of a worker class.

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

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

        * ``transport_name`` defaults to :attr:`self.transport_name`
        * ``send_to`` defaults to a dictionary with config for each tag
          defined in worker's SEND_TO_TAGS attribute. Each tag's config
          contains a transport_name set to ``<tag>_outbound``.
        """

        if cls is None:
            cls = self.application_class
        config.setdefault('transport_name', self.transport_name)
        if 'send_to' not in config and cls.SEND_TO_TAGS:
            config['send_to'] = {}
            for tag in cls.SEND_TO_TAGS:
                config['send_to'][tag] = {
                    'transport_name': '%s_outbound' % tag
                }
        worker = get_stubbed_worker(cls, config, self._amqp)
        self._workers.append(worker)
        if start:
            yield worker.startWorker()
        returnValue(worker)

    def mkmsg_in(self,
                 content='hello world',
                 message_id='abc',
                 to_addr='9292',
                 from_addr='+41791234567',
                 group=None,
                 session_event=None,
                 transport_type=None,
                 helper_metadata=None,
                 transport_metadata=None):
        if transport_type is None:
            transport_type = self.transport_type
        if helper_metadata is None:
            helper_metadata = {}
        if transport_metadata is None:
            transport_metadata = {}
        return TransportUserMessage(
            from_addr=from_addr,
            to_addr=to_addr,
            group=group,
            message_id=message_id,
            transport_name=self.transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            helper_metadata=helper_metadata,
            content=content,
            session_event=session_event,
            timestamp=datetime.now(),
        )

    def mkmsg_out(
        self,
        content='hello world',
        message_id='1',
        to_addr='+41791234567',
        from_addr='9292',
        group=None,
        session_event=None,
        in_reply_to=None,
        transport_type=None,
        transport_metadata=None,
    ):
        if transport_type is None:
            transport_type = self.transport_type
        if transport_metadata is None:
            transport_metadata = {}
        params = dict(
            to_addr=to_addr,
            from_addr=from_addr,
            group=group,
            message_id=message_id,
            transport_name=self.transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            content=content,
            session_event=session_event,
            in_reply_to=in_reply_to,
        )
        return TransportUserMessage(**params)

    def mkmsg_ack(self,
                  user_message_id='1',
                  sent_message_id='abc',
                  transport_metadata=None):
        if transport_metadata is None:
            transport_metadata = {}
        return TransportEvent(
            event_type='ack',
            user_message_id=user_message_id,
            sent_message_id=sent_message_id,
            transport_name=self.transport_name,
            transport_metadata=transport_metadata,
        )

    def mkmsg_delivery(self,
                       status='delivered',
                       user_message_id='abc',
                       transport_metadata=None):
        if transport_metadata is None:
            transport_metadata = {}
        return TransportEvent(
            event_type='delivery_report',
            transport_name=self.transport_name,
            user_message_id=user_message_id,
            delivery_status=status,
            to_addr='+41791234567',
            transport_metadata=transport_metadata,
        )

    def get_dispatched_messages(self):
        return self._amqp.get_messages('vumi', self.rkey('outbound'))

    def wait_for_dispatched_messages(self, amount):
        return self._amqp.wait_messages('vumi', self.rkey('outbound'), amount)

    def dispatch(self, message, rkey=None, exchange='vumi'):
        if rkey is None:
            rkey = self.rkey('inbound')
        self._amqp.publish_message(exchange, rkey, message)
        return self._amqp.kick_delivery()
Example #18
0
class Vas2NetsFailureWorkerTestCase(unittest.TestCase):
    @inlineCallbacks
    def setUp(self):
        self.today = datetime.utcnow().date()
        self.port = 9999
        self.path = "/api/v1/sms/vas2nets/receive/"
        self.config = {
            "transport_name": "vas2nets",
            "url": "http://localhost:%s%s" % (self.port, self.path),
            "username": "******",
            "password": "******",
            "owner": "owner",
            "service": "service",
            "subservice": "subservice",
            "web_receive_path": "/receive",
            "web_receipt_path": "/receipt",
            "web_port": 9998,
        }
        self.fail_config = {
            "transport_name": "vas2nets",
            "retry_routing_key": "sms.outbound.%(transport_name)s",
            "failures_routing_key": "sms.outbound.%(transport_name)s.failures",
        }
        self.workers = []
        self.broker = FakeAMQPBroker()
        self.redis = FakeRedis()
        self.worker = yield self.mk_transport_worker(self.config, self.broker)
        self.fail_worker = yield self.mk_failure_worker(self.fail_config, self.broker, self.redis)

    def tearDown(self):
        for worker in self.workers:
            worker.stopWorker()

    @inlineCallbacks
    def mk_transport_worker(self, config, broker):
        worker = get_stubbed_worker(Vas2NetsTransport, config, broker)
        self.workers.append(worker)
        yield worker.startWorker()
        returnValue(worker)

    @inlineCallbacks
    def mk_failure_worker(self, config, broker, redis):
        w = get_stubbed_worker(Vas2NetsFailureWorker, config, broker)
        self.workers.append(w)
        yield w.startWorker()
        w.retry_publisher = yield self.worker.publish_to("foo")
        w.r_server = redis
        returnValue(w)

    @inlineCallbacks
    def mk_resource_worker(self, body, headers=None, code=http.OK):
        w = get_stubbed_worker(TestResourceWorker, {}, self.broker)
        self.workers.append(w)
        w.set_resources([(self.path, BadVas2NetsResource, (body, headers, code))])
        yield w.startWorker()
        returnValue(w)

    def get_dispatched(self, rkey):
        return self.broker.get_dispatched("vumi", rkey)

    def get_retry_keys(self):
        timestamps = self.redis.zrange(self.fail_worker._retry_timestamps_key, 0, 0)
        retry_keys = set()
        for timestamp in timestamps:
            bucket_key = self.fail_worker.r_key("retry_keys." + timestamp)
            retry_keys.update(self.redis.smembers(bucket_key))
        return retry_keys

    def mkmsg_out(self, in_reply_to=None):
        msg = TransportSMS(
            transport="vas2nets",
            to_addr="+27761234567",
            from_addr="9292",
            message_id="1",
            in_reply_to=in_reply_to,
            transport_metadata={"network_id": "network-id"},
            message="hello world",
        )
        return msg

    def assert_dispatched_count(self, count, routing_key):
        self.assertEqual(count, len(self.get_dispatched(routing_key)))

    @inlineCallbacks
    def test_send_sms_success(self):
        yield self.mk_resource_worker("Result_code: 00, Message OK")
        yield self.worker.handle_outbound_message(self.mkmsg_out())
        self.assert_dispatched_count(1, "sms.ack.vas2nets")
        self.assert_dispatched_count(0, "sms.failures.vas2nets")

    @inlineCallbacks
    def test_send_sms_fail(self):
        """
        A 'No SmsId Header' error should not be retried.
        """
        self.worker.failure_published = FailureCounter(1)
        self.worker.SUPPRESS_EXCEPTIONS = True
        yield self.mk_resource_worker("Result_code: 04, Internal system error " "occurred while processing message", {})
        yield self.worker.handle_outbound_message(self.mkmsg_out())
        yield self.worker.failure_published.deferred
        self.assert_dispatched_count(0, "sms.ack.vas2nets")
        self.assert_dispatched_count(1, "sms.outbound.vas2nets.failures")
        [fmsg] = self.get_dispatched("sms.outbound.vas2nets.failures")
        fmsg = from_json(fmsg.body)
        self.assertTrue("Vas2NetsTransportError: No SmsId Header" in fmsg["reason"])

        yield self.broker.kick_delivery()
        [key] = self.fail_worker.get_failure_keys()
        self.assertEqual(set(), self.get_retry_keys())

    @inlineCallbacks
    def test_send_sms_noconn(self):
        """
        A 'connection refused' error should be retried.
        """
        self.worker.failure_published = FailureCounter(1)
        self.worker.SUPPRESS_EXCEPTIONS = True
        msg = self.mkmsg_out()
        yield self.worker.handle_outbound_message(msg)
        yield self.worker.failure_published.deferred
        self.assert_dispatched_count(0, "sms.ack.vas2nets")
        self.assert_dispatched_count(1, "sms.outbound.vas2nets.failures")
        [fmsg] = self.get_dispatched("sms.outbound.vas2nets.failures")
        fmsg = from_json(fmsg.body)
        self.assertEqual(msg, fmsg["message"])
        self.assertEqual("connection refused", fmsg["reason"])

        yield self.broker.kick_delivery()
        [key] = self.fail_worker.get_failure_keys()
        self.assertEqual(set([key]), self.get_retry_keys())
Example #19
0
 def setUp(self):
     self.broker = FakeAMQPBroker()
     self._workers = []
     self.worker = yield self.get_worker()
Example #20
0
 def __init__(self, spec):
     super(FakeAmqpClient, self).__init__(TwistedDelegate(), '', spec)
     self.broker = FakeAMQPBroker()
Example #21
0
 def setUp(self):
     self._workers = []
     self._amqp = FakeAMQPBroker()
Example #22
0
class WikipediaWorkerTestCase(TestCase):
    transport_name = 'sphex'

    timeout = 10

    @inlineCallbacks
    def setUp(self):
        self.broker = FakeAMQPBroker()
        self._workers = []
        self.worker = yield self.get_worker()

    @inlineCallbacks
    def tearDown(self):
        for w in self._workers:
            yield w.stopWorker()

    @inlineCallbacks
    def get_worker(self, config=None):
        if not config:
            config = {
                'worker_name': 'wikitest',
                'sms_transport': 'sphex',
                }
        config.setdefault('transport_name', self.transport_name)
        worker = get_stubbed_worker(WikipediaWorker, config, self.broker)
        self._workers.append(worker)
        yield worker.startWorker()
        returnValue(worker)

    def mkmsg_in(self, content):
        return TransportUserMessage(
            from_addr='+41791234567',
            to_addr='9292',
            message_id='abc',
            transport_name=self.transport_name,
            transport_type='ussd',
            transport_metadata={},
            content=content,
            )

    def rkey(self, name):
        return "%s.%s" % (self.transport_name, name)

    def dispatch(self, message, rkey=None, exchange='vumi'):
        if rkey is None:
            rkey = self.rkey('inbound')
        self.broker.publish_message(exchange, rkey, message)
        return self.broker.kick_delivery()

    def get_dispatched_messages(self):
        return self.broker.get_messages('vumi', self.rkey('outbound'))

    @inlineCallbacks
    def test_happy_flow(self):
        # TODO: Stub out the API calls.
        yield self.dispatch(self.mkmsg_in(None))
        self.assertEqual('What would you like to search Wikipedia for?',
                         self.get_dispatched_messages()[-1]['content'])
        yield self.dispatch(self.mkmsg_in('africa'))
        self.assertEqual('\n'.join([
                    '1. Africa',
                    '2. .africa',
                    '3. African American',
                    '4. North Africa',
                    '5. Kenya',
                    '6. Sub-Saharan Africa',
                    '7. Africa (Roman province)',
                    '8. African people',
                    '9. Confederation of African Football']),
                         self.get_dispatched_messages()[-1]['content'])
        yield self.dispatch(self.mkmsg_in('1'))
        self.assertEqual('\n'.join([
                    '1. Africa',
                    '2. Etymology',
                    '3. History',
                    '4. Geography',
                    '5. Biodiversity',
                    '6. Politics',
                    '7. Economy',
                    '8. Demographics',
                    '9. Languages',
                    '10. Culture',
                    '11. Religion',
                    '12. Territories and regions',
                    '13. See also',
                    '14. References',
                    '15. Further reading',
                    '16. External links',
                    ]),
                         self.get_dispatched_messages()[-1]['content'])
        yield self.dispatch(self.mkmsg_in('2'))
        content = (
            u'==Etymology==\n\n[[Afri]] was a Latin name used to refer to the '
            u'[[Carthaginians]] who dwelt in [[North Africa]] in modern-day '
            u'[[Tunisia]]. Their name is usually connected with [[Phoenician '
            u'language|Phoenician]] \'\'afar\'\', "dust", but a 1981 '
            u'hypothesis<ref>[http://michel-desfayes.org/namesofcountries.html'
            u' Names of countries], Decret and Fantar, 1981</ref> has '
            u'asserted that it stems from the [[Berber language|Berber]] word '
            u'\'\'ifri\'\' or \'\'ifran\'\' meaning "cave" and "caves", in '
            u'reference to cave dweller')
        self.assertEqual(
            "%s...\n(Full content sent by SMS.)" % (content[:100],),
            self.get_dispatched_messages()[-2]['content'])
        self.assertEqual(content[:250],
                         self.get_dispatched_messages()[-1]['content'])
Example #23
0
class ApplicationTestCase(TestCase):

    """
    This is a base class for testing application workers.

    """

    # base timeout of 5s for all application tests
    timeout = 5

    transport_name = "sphex"
    transport_type = None
    application_class = None

    def setUp(self):
        self._workers = []
        self._amqp = FakeAMQPBroker()

    def tearDown(self):
        for worker in self._workers:
            worker.stopWorker()

    def rkey(self, name):
        return "%s.%s" % (self.transport_name, name)

    @inlineCallbacks
    def get_application(self, config, cls=None, start=True):
        """
        Get an instance of a worker class.

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

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

        * ``transport_name`` defaults to :attr:`self.transport_name`
        * ``send_to`` defaults to a dictionary with config for each tag
          defined in worker's SEND_TO_TAGS attribute. Each tag's config
          contains a transport_name set to ``<tag>_outbound``.
        """

        if cls is None:
            cls = self.application_class
        config.setdefault('transport_name', self.transport_name)
        if 'send_to' not in config and cls.SEND_TO_TAGS:
            config['send_to'] = {}
            for tag in cls.SEND_TO_TAGS:
                config['send_to'][tag] = {
                    'transport_name': '%s_outbound' % tag}
        worker = get_stubbed_worker(cls, config, self._amqp)
        self._workers.append(worker)
        if start:
            yield worker.startWorker()
        returnValue(worker)

    def mkmsg_in(self, content='hello world', message_id='abc',
                 to_addr='9292', from_addr='+41791234567', group=None,
                 session_event=None, transport_type=None,
                 helper_metadata=None, transport_metadata=None):
        if transport_type is None:
            transport_type = self.transport_type
        if helper_metadata is None:
            helper_metadata = {}
        if transport_metadata is None:
            transport_metadata = {}
        return TransportUserMessage(
            from_addr=from_addr,
            to_addr=to_addr,
            group=group,
            message_id=message_id,
            transport_name=self.transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            helper_metadata=helper_metadata,
            content=content,
            session_event=session_event,
            timestamp=datetime.now(),
            )

    def mkmsg_out(self, content='hello world', message_id='1',
                  to_addr='+41791234567', from_addr='9292', group=None,
                  session_event=None, in_reply_to=None,
                  transport_type=None, transport_metadata=None,
                  ):
        if transport_type is None:
            transport_type = self.transport_type
        if transport_metadata is None:
            transport_metadata = {}
        params = dict(
            to_addr=to_addr,
            from_addr=from_addr,
            group=group,
            message_id=message_id,
            transport_name=self.transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            content=content,
            session_event=session_event,
            in_reply_to=in_reply_to,
            )
        return TransportUserMessage(**params)

    def mkmsg_ack(self, user_message_id='1', sent_message_id='abc',
                  transport_metadata=None):
        if transport_metadata is None:
            transport_metadata = {}
        return TransportEvent(
            event_type='ack',
            user_message_id=user_message_id,
            sent_message_id=sent_message_id,
            transport_name=self.transport_name,
            transport_metadata=transport_metadata,
            )

    def mkmsg_delivery(self, status='delivered', user_message_id='abc',
                       transport_metadata=None):
        if transport_metadata is None:
            transport_metadata = {}
        return TransportEvent(
            event_type='delivery_report',
            transport_name=self.transport_name,
            user_message_id=user_message_id,
            delivery_status=status,
            to_addr='+41791234567',
            transport_metadata=transport_metadata,
            )

    def get_dispatched_messages(self):
        return self._amqp.get_messages('vumi', self.rkey('outbound'))

    def wait_for_dispatched_messages(self, amount):
        return self._amqp.wait_messages('vumi', self.rkey('outbound'), amount)

    def dispatch(self, message, rkey=None, exchange='vumi'):
        if rkey is None:
            rkey = self.rkey('inbound')
        self._amqp.publish_message(exchange, rkey, message)
        return self._amqp.kick_delivery()
Example #24
0
class Vas2NetsFailureWorkerTestCase(unittest.TestCase):

    @inlineCallbacks
    def setUp(self):
        self.today = datetime.utcnow().date()
        self.port = 9999
        self.path = '/api/v1/sms/vas2nets/receive/'
        self.config = {
            'transport_name': 'vas2nets',
            'url': 'http://localhost:%s%s' % (self.port, self.path),
            'username': '******',
            'password': '******',
            'owner': 'owner',
            'service': 'service',
            'subservice': 'subservice',
            'web_receive_path': '/receive',
            'web_receipt_path': '/receipt',
            'web_port': 9998,
        }
        self.fail_config = {
            'transport_name': 'vas2nets',
            'retry_routing_key': '%(transport_name)s.outbound',
            'failures_routing_key': '%(transport_name)s.failures',
            }
        self.workers = []
        self.broker = FakeAMQPBroker()
        self.redis = FakeRedis()
        self.worker = yield self.mk_transport_worker(self.config, self.broker)
        self.fail_worker = yield self.mk_failure_worker(
            self.fail_config, self.broker, self.redis)

    def tearDown(self):
        for worker in self.workers:
            worker.stopWorker()

    @inlineCallbacks
    def mk_transport_worker(self, config, broker):
        worker = get_stubbed_worker(Vas2NetsTransport, config, broker)
        self.workers.append(worker)
        yield worker.startWorker()
        returnValue(worker)

    @inlineCallbacks
    def mk_failure_worker(self, config, broker, redis):
        w = get_stubbed_worker(FailureWorker, config, broker)
        self.workers.append(w)
        yield w.startWorker()
        w.retry_publisher = yield self.worker.publish_to("foo")
        w.r_server = redis
        returnValue(w)

    @inlineCallbacks
    def mk_resource_worker(self, body, headers=None, code=http.OK):
        w = get_stubbed_worker(TestResourceWorker, {}, self.broker)
        self.workers.append(w)
        w.set_resources([(self.path, BadVas2NetsResource,
                          (body, headers, code))])
        yield w.startWorker()
        returnValue(w)

    def get_dispatched(self, rkey):
        return self.broker.get_dispatched('vumi', rkey)

    def get_retry_keys(self):
        timestamps = self.redis.zrange(
            self.fail_worker._retry_timestamps_key, 0, 0)
        retry_keys = set()
        for timestamp in timestamps:
            bucket_key = self.fail_worker.r_key("retry_keys." + timestamp)
            retry_keys.update(self.redis.smembers(bucket_key))
        return retry_keys

    def mkmsg_out(self, in_reply_to=None):
        return TransportUserMessage(
            to_addr='+41791234567',
            from_addr='9292',
            message_id='1',
            transport_name='vas2nets',
            transport_type='sms',
            transport_metadata={
               'network_id': 'network-id',
               },
            content='hello world',
            in_reply_to=in_reply_to,
            )

    def assert_dispatched_count(self, count, routing_key):
        self.assertEqual(count, len(self.get_dispatched(routing_key)))

    @inlineCallbacks
    def test_send_sms_success(self):
        yield self.mk_resource_worker("Result_code: 00, Message OK")
        yield self.worker._process_message(self.mkmsg_out())
        self.assert_dispatched_count(1, 'vas2nets.event')
        self.assert_dispatched_count(0, 'vas2nets.failures')

    @inlineCallbacks
    def test_send_sms_fail(self):
        """
        A 'No SmsId Header' error should not be retried.
        """
        self.worker.failure_published = FailureCounter(1)
        yield self.mk_resource_worker("Result_code: 04, Internal system error "
                                      "occurred while processing message",
                                      {})
        yield self.worker._process_message(self.mkmsg_out())
        yield self.worker.failure_published.deferred
        yield self.broker.kick_delivery()
        self.assert_dispatched_count(0, 'vas2nets.event')
        self.assert_dispatched_count(1, 'vas2nets.failures')
        [fmsg] = self.get_dispatched('vas2nets.failures')
        fmsg = from_json(fmsg.body)
        self.assertTrue(
            "Vas2NetsTransportError: No SmsId Header" in fmsg['reason'])

        yield self.broker.kick_delivery()
        [key] = self.fail_worker.get_failure_keys()
        self.assertEqual(set(), self.get_retry_keys())

    @inlineCallbacks
    def test_send_sms_noconn(self):
        """
        A 'connection refused' error should be retried.
        """
        self.worker.failure_published = FailureCounter(1)
        msg = self.mkmsg_out()
        yield self.worker._process_message(msg)
        yield self.worker.failure_published.deferred
        self.assert_dispatched_count(0, 'vas2nets.event')
        self.assert_dispatched_count(1, 'vas2nets.failures')
        [fmsg] = self.get_dispatched('vas2nets.failures')
        fmsg = from_json(fmsg.body)
        self.assertEqual(msg.payload, fmsg['message'])
        self.assertEqual(FailureMessage.FC_TEMPORARY,
                         fmsg['failure_code'])
        self.assertTrue(fmsg['reason'].strip().endswith("connection refused"))

        yield self.broker.kick_delivery()
        [key] = self.fail_worker.get_failure_keys()
        self.assertEqual(set([key]), self.get_retry_keys())
Example #25
0
class Vas2NetsFailureWorkerTestCase(unittest.TestCase):

    @inlineCallbacks
    def setUp(self):
        self.today = datetime.utcnow().date()
        self.port = 9999
        self.path = '/api/v1/sms/vas2nets/receive/'
        self.config = {
            'transport_name': 'vas2nets',
            'url': 'http://localhost:%s%s' % (self.port, self.path),
            'username': '******',
            'password': '******',
            'owner': 'owner',
            'service': 'service',
            'subservice': 'subservice',
            'web_receive_path': '/receive',
            'web_receipt_path': '/receipt',
            'web_port': 9998,
        }
        self.fail_config = {
            'transport_name': 'vas2nets',
            'retry_routing_key': '%(transport_name)s.outbound',
            'failures_routing_key': '%(transport_name)s.failures',
            }
        self.workers = []
        self.broker = FakeAMQPBroker()
        self.redis = FakeRedis()
        self.worker = yield self.mk_transport_worker(self.config, self.broker)
        self.fail_worker = yield self.mk_failure_worker(
            self.fail_config, self.broker, self.redis)

    def tearDown(self):
        for worker in self.workers:
            worker.stopWorker()

    @inlineCallbacks
    def mk_transport_worker(self, config, broker):
        worker = get_stubbed_worker(Vas2NetsTransport, config, broker)
        self.workers.append(worker)
        yield worker.startWorker()
        returnValue(worker)

    @inlineCallbacks
    def mk_failure_worker(self, config, broker, redis):
        w = get_stubbed_worker(FailureWorker, config, broker)
        self.workers.append(w)
        w.retry_publisher = yield self.worker.publish_to("foo")
        w.r_server = redis
        yield w.startWorker()
        returnValue(w)

    @inlineCallbacks
    def mk_resource_worker(self, body, headers=None, code=http.OK):
        w = get_stubbed_worker(TestResourceWorker, {}, self.broker)
        self.workers.append(w)
        w.set_resources([(self.path, BadVas2NetsResource,
                          (body, headers, code))])
        yield w.startWorker()
        returnValue(w)

    def get_dispatched(self, rkey):
        return self.broker.get_dispatched('vumi', rkey)

    def get_retry_keys(self):
        timestamps = self.redis.zrange(
            self.fail_worker._retry_timestamps_key, 0, 0)
        retry_keys = set()
        for timestamp in timestamps:
            bucket_key = self.fail_worker.r_key("retry_keys." + timestamp)
            retry_keys.update(self.redis.smembers(bucket_key))
        return retry_keys

    def mkmsg_out(self, in_reply_to=None):
        return TransportUserMessage(
            to_addr='+41791234567',
            from_addr='9292',
            message_id='1',
            transport_name='vas2nets',
            transport_type='sms',
            transport_metadata={
               'network_id': 'network-id',
               },
            content='hello world',
            in_reply_to=in_reply_to,
            )

    def assert_dispatched_count(self, count, routing_key):
        self.assertEqual(count, len(self.get_dispatched(routing_key)))

    @inlineCallbacks
    def test_send_sms_success(self):
        yield self.mk_resource_worker("Result_code: 00, Message OK")
        yield self.worker._process_message(self.mkmsg_out())
        self.assert_dispatched_count(1, 'vas2nets.event')
        self.assert_dispatched_count(0, 'vas2nets.failures')

    @inlineCallbacks
    def test_send_sms_fail(self):
        """
        A 'No SmsId Header' error should not be retried.
        """
        self.worker.failure_published = FailureCounter(1)
        yield self.mk_resource_worker("Result_code: 04, Internal system error "
                                      "occurred while processing message",
                                      {})
        yield self.worker._process_message(self.mkmsg_out())
        yield self.worker.failure_published.deferred
        yield self.broker.kick_delivery()
        self.assert_dispatched_count(0, 'vas2nets.event')
        self.assert_dispatched_count(1, 'vas2nets.failures')

        [twisted_failure] = self.flushLoggedErrors(Vas2NetsTransportError)
        failure = twisted_failure.value
        self.assertTrue("No SmsId Header" in str(failure))

        [fmsg] = self.get_dispatched('vas2nets.failures')
        fmsg = from_json(fmsg.body)
        self.assertTrue(
            "Vas2NetsTransportError: No SmsId Header" in fmsg['reason'])

        yield self.broker.kick_delivery()
        [key] = self.fail_worker.get_failure_keys()
        self.assertEqual(set(), self.get_retry_keys())

    @inlineCallbacks
    def test_send_sms_noconn(self):
        """
        A 'connection refused' error should be retried.
        """
        self.worker.failure_published = FailureCounter(1)
        msg = self.mkmsg_out()
        yield self.worker._process_message(msg)
        yield self.worker.failure_published.deferred
        self.assert_dispatched_count(0, 'vas2nets.event')
        self.assert_dispatched_count(1, 'vas2nets.failures')

        [twisted_failure] = self.flushLoggedErrors(TemporaryFailure)
        failure = twisted_failure.value
        self.assertTrue("connection refused" in str(failure))

        [fmsg] = self.get_dispatched('vas2nets.failures')
        fmsg = from_json(fmsg.body)
        self.assertEqual(msg.payload, fmsg['message'])
        self.assertEqual(FailureMessage.FC_TEMPORARY,
                         fmsg['failure_code'])
        self.assertTrue(fmsg['reason'].strip().endswith("connection refused"))

        yield self.broker.kick_delivery()
        [key] = self.fail_worker.get_failure_keys()
        self.assertEqual(set([key]), self.get_retry_keys())
Example #26
0
class VumiWorkerTestCase(VumiTestCase):
    """Base test class for vumi workers.

    This (or a subclass of this) should be the starting point for any test
    cases that involve vumi workers.
    """

    transport_name = "sphex"
    transport_type = None

    MSG_ID_MATCHER = RegexMatcher(r'^[0-9a-fA-F]{32}$')

    def setUp(self):
        warnings.warn("VumiWorkerTestCase and its subclasses are deprecated. "
                      "Use VumiTestCase and other tools from "
                      "vumi.tests.helpers instead.",
                      category=DeprecationWarning)
        self._workers = []
        self._amqp = FakeAMQPBroker()

    @inlineCallbacks
    def tearDown(self):
        yield super(VumiWorkerTestCase, self).tearDown()
        # Wait for any pending message deliveries to avoid a race with a dirty
        # reactor.
        yield self._amqp.wait_delivery()
        # Now stop all the workers.
        for worker in self._workers:
            yield worker.stopWorker()

    def rkey(self, name):
        return "%s.%s" % (self.transport_name, name)

    def _rkey(self, name, connector_name=None):
        if connector_name is None:
            return self.rkey(name)
        return "%s.%s" % (connector_name, name)

    @inlineCallbacks
    def get_worker(self, config, cls, start=True):
        """Create and return an instance of a vumi worker.

        :param config: Config dict.
        :param cls: The worker class to instantiate.
        :param start: True to start the worker (default), False otherwise.
        """

        # When possible, always try and enable heartbeat setup in tests.
        # so make sure worker_name is set
        if (config is not None) and ('worker_name' not in config):
            config['worker_name'] = "unnamed"

        worker = get_stubbed_worker(cls, config, self._amqp)
        self._workers.append(worker)
        if start:
            yield worker.startWorker()
        returnValue(worker)

    def mkmsg_ack(self, user_message_id='1', sent_message_id='abc',
                  transport_metadata=None, transport_name=None):
        if transport_metadata is None:
            transport_metadata = {}
        if transport_name is None:
            transport_name = self.transport_name
        return TransportEvent(
            event_type='ack',
            user_message_id=user_message_id,
            sent_message_id=sent_message_id,
            transport_name=transport_name,
            transport_metadata=transport_metadata,
            )

    def mkmsg_nack(self, user_message_id='1', transport_metadata=None,
                    transport_name=None, nack_reason='unknown'):
        if transport_metadata is None:
            transport_metadata = {}
        if transport_name is None:
            transport_name = self.transport_name
        return TransportEvent(
            event_type='nack',
            nack_reason=nack_reason,
            user_message_id=user_message_id,
            transport_name=transport_name,
            transport_metadata=transport_metadata,
            )

    def mkmsg_delivery(self, status='delivered', user_message_id='abc',
                       transport_metadata=None, transport_name=None):
        if transport_metadata is None:
            transport_metadata = {}
        if transport_name is None:
            transport_name = self.transport_name
        return TransportEvent(
            event_type='delivery_report',
            transport_name=transport_name,
            user_message_id=user_message_id,
            delivery_status=status,
            to_addr='+41791234567',
            transport_metadata=transport_metadata,
            )

    def mkmsg_in(self, content='hello world', message_id='abc',
                 to_addr='9292', from_addr='+41791234567', group=None,
                 session_event=None, transport_type=None,
                 helper_metadata=None, transport_metadata=None,
                 transport_name=None):
        if transport_type is None:
            transport_type = self.transport_type
        if helper_metadata is None:
            helper_metadata = {}
        if transport_metadata is None:
            transport_metadata = {}
        if transport_name is None:
            transport_name = self.transport_name
        return TransportUserMessage(
            from_addr=from_addr,
            to_addr=to_addr,
            group=group,
            message_id=message_id,
            transport_name=transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            helper_metadata=helper_metadata,
            content=content,
            session_event=session_event,
            timestamp=datetime.now(),
            )

    def mkmsg_out(self, content='hello world', message_id='1',
                  to_addr='+41791234567', from_addr='9292', group=None,
                  session_event=None, in_reply_to=None,
                  transport_type=None, transport_metadata=None,
                  transport_name=None, helper_metadata=None,
                  ):
        if transport_type is None:
            transport_type = self.transport_type
        if transport_metadata is None:
            transport_metadata = {}
        if transport_name is None:
            transport_name = self.transport_name
        if helper_metadata is None:
            helper_metadata = {}
        params = dict(
            to_addr=to_addr,
            from_addr=from_addr,
            group=group,
            message_id=message_id,
            transport_name=transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            content=content,
            session_event=session_event,
            in_reply_to=in_reply_to,
            helper_metadata=helper_metadata,
            )
        return TransportUserMessage(**params)

    def _make_matcher(self, msg, *id_fields):
        msg['timestamp'] = UTCNearNow()
        for field in id_fields:
            msg[field] = self.MSG_ID_MATCHER
        return msg

    def _get_dispatched(self, name, connector_name=None):
        rkey = self._rkey(name, connector_name)
        return self._amqp.get_messages('vumi', rkey)

    def _wait_for_dispatched(self, name, amount, connector_name=None):
        rkey = self._rkey(name, connector_name)
        return self._amqp.wait_messages('vumi', rkey, amount)

    def clear_all_dispatched(self):
        self._amqp.clear_messages('vumi')

    def _clear_dispatched(self, name, connector_name=None):
        rkey = self._rkey(name, connector_name)
        return self._amqp.clear_messages('vumi', rkey)

    def get_dispatched_events(self, connector_name=None):
        return self._get_dispatched('event', connector_name)

    def get_dispatched_inbound(self, connector_name=None):
        return self._get_dispatched('inbound', connector_name)

    def get_dispatched_outbound(self, connector_name=None):
        return self._get_dispatched('outbound', connector_name)

    def get_dispatched_failures(self, connector_name=None):
        return self._get_dispatched('failures', connector_name)

    def wait_for_dispatched_events(self, amount, connector_name=None):
        return self._wait_for_dispatched('event', amount, connector_name)

    def wait_for_dispatched_inbound(self, amount, connector_name=None):
        return self._wait_for_dispatched('inbound', amount, connector_name)

    def wait_for_dispatched_outbound(self, amount, connector_name=None):
        return self._wait_for_dispatched('outbound', amount, connector_name)

    def wait_for_dispatched_failures(self, amount, connector_name=None):
        return self._wait_for_dispatched('failures', amount, connector_name)

    def clear_dispatched_events(self, connector_name=None):
        return self._clear_dispatched('event', connector_name)

    def clear_dispatched_inbound(self, connector_name=None):
        return self._clear_dispatched('inbound', connector_name)

    def clear_dispatched_outbound(self, connector_name=None):
        return self._clear_dispatched('outbound', connector_name)

    def clear_dispatched_failures(self, connector_name=None):
        return self._clear_dispatched('failures', connector_name)

    def _dispatch(self, message, rkey, exchange='vumi'):
        self._amqp.publish_message(exchange, rkey, message)
        return self._amqp.kick_delivery()

    def dispatch_inbound(self, message, connector_name=None):
        rkey = self._rkey('inbound', connector_name)
        return self._dispatch(message, rkey)

    def dispatch_outbound(self, message, connector_name=None):
        rkey = self._rkey('outbound', connector_name)
        return self._dispatch(message, rkey)

    def dispatch_event(self, message, connector_name=None):
        rkey = self._rkey('event', connector_name)
        return self._dispatch(message, rkey)

    def dispatch_failure(self, message, connector_name=None):
        rkey = self._rkey('failure', connector_name)
        return self._dispatch(message, rkey)
Example #27
0
class DispatcherTestCase(TestCase):
    """
    This is a base class for testing dispatcher workers.

    """

    # base timeout of 5s for all dispatcher tests
    timeout = 5

    dispatcher_name = "sphex_dispatcher"
    dispatcher_class = None

    def setUp(self):
        self._workers = []
        self._amqp = FakeAMQPBroker()

    def tearDown(self):
        for worker in self._workers:
            worker.stopWorker()

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

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

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

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

        if cls is None:
            cls = self.dispatcher_class
        config.setdefault('dispatcher_name', self.dispatcher_name)
        worker = get_stubbed_worker(cls, config, self._amqp)
        self._workers.append(worker)
        if start:
            yield worker.startWorker()
        returnValue(worker)

    def mkmsg_in(self,
                 content='hello world',
                 message_id='abc',
                 to_addr='9292',
                 from_addr='+41791234567',
                 session_event=None,
                 transport_type=None,
                 helper_metadata=None,
                 transport_metadata=None,
                 transport_name=None):
        if helper_metadata is None:
            helper_metadata = {}
        if transport_metadata is None:
            transport_metadata = {}
        return TransportUserMessage(
            from_addr=from_addr,
            to_addr=to_addr,
            message_id=message_id,
            transport_name=transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            helper_metadata=helper_metadata,
            content=content,
            session_event=session_event,
            timestamp=datetime.now(),
        )

    def mkmsg_out(self,
                  content='hello world',
                  message_id='1',
                  to_addr='+41791234567',
                  from_addr='9292',
                  session_event=None,
                  in_reply_to=None,
                  transport_type=None,
                  transport_metadata=None,
                  transport_name=None):
        if transport_metadata is None:
            transport_metadata = {}
        params = dict(
            to_addr=to_addr,
            from_addr=from_addr,
            message_id=message_id,
            transport_name=transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            content=content,
            session_event=session_event,
            in_reply_to=in_reply_to,
        )
        return TransportUserMessage(**params)

    def mkmsg_ack(self,
                  event_type='ack',
                  user_message_id='1',
                  send_message_id='abc',
                  transport_name=None,
                  transport_metadata=None):
        if transport_metadata is None:
            transport_metadata = {}
        params = dict(
            event_type=event_type,
            user_message_id=user_message_id,
            sent_message_id=send_message_id,
            transport_name=transport_name,
            transport_metadata=transport_metadata,
        )
        return TransportEvent(**params)

    def get_dispatched_messages(self, transport_name, direction='outbound'):
        return self._amqp.get_messages('vumi',
                                       '%s.%s' % (transport_name, direction))

    def wait_for_dispatched_messages(self,
                                     transport_name,
                                     amount,
                                     direction='outbound'):
        return self._amqp.wait_messages('vumi',
                                        '%s.%s' % (transport_name, direction),
                                        amount)

    def dispatch(self,
                 message,
                 transport_name,
                 direction='inbound',
                 exchange='vumi'):
        rkey = '%s.%s' % (transport_name, direction)
        self._amqp.publish_message(exchange, rkey, message)
        return self._amqp.kick_delivery()
Example #28
0
class DispatcherTestCase(TestCase):

    """
    This is a base class for testing dispatcher workers.

    """

    # base timeout of 5s for all dispatcher tests
    timeout = 5

    dispatcher_name = "sphex_dispatcher"
    dispatcher_class = None

    def setUp(self):
        self._workers = []
        self._amqp = FakeAMQPBroker()

    def tearDown(self):
        for worker in self._workers:
            worker.stopWorker()

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

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

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

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

        if cls is None:
            cls = self.dispatcher_class
        config.setdefault('dispatcher_name', self.dispatcher_name)
        worker = get_stubbed_worker(cls, config, self._amqp)
        self._workers.append(worker)
        if start:
            yield worker.startWorker()
        returnValue(worker)

    def mkmsg_in(self, content='hello world', message_id='abc',
                 to_addr='9292', from_addr='+41791234567',
                 session_event=None, transport_type=None,
                 helper_metadata=None, transport_metadata=None,
                 transport_name=None):
        if helper_metadata is None:
            helper_metadata = {}
        if transport_metadata is None:
            transport_metadata = {}
        return TransportUserMessage(
            from_addr=from_addr,
            to_addr=to_addr,
            message_id=message_id,
            transport_name=transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            helper_metadata=helper_metadata,
            content=content,
            session_event=session_event,
            timestamp=datetime.now(),
            )

    def mkmsg_out(self, content='hello world', message_id='1',
                  to_addr='+41791234567', from_addr='9292',
                  session_event=None, in_reply_to=None,
                  transport_type=None, transport_metadata=None,
                  transport_name=None):
        if transport_metadata is None:
            transport_metadata = {}
        params = dict(
            to_addr=to_addr,
            from_addr=from_addr,
            message_id=message_id,
            transport_name=transport_name,
            transport_type=transport_type,
            transport_metadata=transport_metadata,
            content=content,
            session_event=session_event,
            in_reply_to=in_reply_to,
            )
        return TransportUserMessage(**params)

    def mkmsg_ack(self, event_type='ack', user_message_id='1',
                  send_message_id='abc', transport_name=None,
                  transport_metadata=None):
        if transport_metadata is None:
            transport_metadata = {}
        params = dict(
            event_type=event_type,
            user_message_id=user_message_id,
            sent_message_id=send_message_id,
            transport_name=transport_name,
            transport_metadata=transport_metadata,
            )
        return TransportEvent(**params)

    def get_dispatched_messages(self, transport_name, direction='outbound'):
        return self._amqp.get_messages('vumi', '%s.%s' % (
            transport_name, direction))

    def wait_for_dispatched_messages(self, transport_name, amount,
                                        direction='outbound'):
        return self._amqp.wait_messages('vumi', '%s.%s' % (
            transport_name, direction), amount)

    def dispatch(self, message, transport_name, direction='inbound',
                    exchange='vumi'):
        rkey = '%s.%s' % (transport_name, direction)
        self._amqp.publish_message(exchange, rkey, message)
        return self._amqp.kick_delivery()
Example #29
0
class Vas2NetsTransportTestCase(unittest.TestCase):

    @inlineCallbacks
    def setUp(self):
        self.path = '/api/v1/sms/vas2nets/receive/'
        self.port = 9999
        self.config = {
            'transport_name': 'vas2nets',
            'url': 'http://localhost:%s%s' % (self.port, self.path),
            'username': '******',
            'password': '******',
            'owner': 'owner',
            'service': 'service',
            'subservice': 'subservice',
            'web_receive_path': '/receive',
            'web_receipt_path': '/receipt',
            'web_port': 9998,
        }
        self.broker = FakeAMQPBroker()
        self.worker = get_stubbed_worker(Vas2NetsTransport, self.config,
                                         self.broker)
        self.publisher = yield self.worker.publish_to('some.routing.key')
        self.today = datetime.utcnow().date()
        self.workers = [self.worker]

    def tearDown(self):
        for worker in self.workers:
            worker.stopWorker()

    def make_resource_worker(self, msg_id, msg, code=http.OK, send_id=None):
        w = get_stubbed_worker(TestResourceWorker, {})
        w.set_resources([
                (self.path, TestResource, (msg_id, msg, code, send_id))])
        self.workers.append(w)
        return w.startWorker()

    def get_dispatched(self, rkey):
        return self.broker.get_dispatched('vumi', rkey)

    def create_request(self, dictionary={}, path='/', method='POST'):
        """
        Creates a dummy Vas2Nets request for testing our resources with
        """
        request = DummyRequest(path)
        request.method = method
        args = {
            'messageid': [str(uuid4())],
            'time': [self.today.strftime('%Y.%m.%d %H:%M:%S')],
            'sender': ['0041791234567'],
            'destination': ['9292'],
            'provider': ['provider'],
            'keyword': [''],
            'header': [''],
            'text': [''],
            'keyword': [''],
        }
        args.update(dictionary)
        request.args = args
        return request

    def make_delivery_message(self, status, tr_status, tr_message):
        return TransportSMSDeliveryReport(
            transport='vas2nets',
            transport_message_id='1',
            transport_metadata={
               'delivery_status': tr_status,
               'network_id': 'provider',
               'timestamp': self.today.strftime('%Y-%m-%dT%H:%M:%S'),
               'delivery_message': tr_message,
               },
            to_addr='+41791234567',
            message_id='internal id',
            delivery_status=status,
            timestamp=UTCNearNow(),
            )

    def mkmsg_in(self):
        msg = TransportSMS(
            message_type='sms',
            message_version='20110907',
            from_addr='+41791234567',
            to_addr='9292',
            message_id='1',
            transport='vas2nets',
            transport_message_id='1',
            transport_metadata={
                'network_id': 'provider',
                'keyword': '',
                'timestamp': self.today.strftime('%Y-%m-%dT%H:%M:%S'),
                },
            message='hello world',
            timestamp=UTCNearNow(),
            )
        return msg

    def mkmsg_out(self, in_reply_to=None):
        msg = TransportSMS(
            transport='vas2nets',
            to_addr='+27761234567',
            from_addr='9292',
            message_id='1',
            in_reply_to=in_reply_to,
            transport_metadata={
               'network_id': 'network-id',
               },
            message='hello world',
            )
        return msg

    @inlineCallbacks
    def test_receive_sms(self):
        resource = ReceiveSMSResource(self.config, self.publisher)
        request = self.create_request({
            'messageid': ['1'],
            'text': ['hello world'],
        })
        d = request.notifyFinish()
        response = resource.render(request)
        self.assertEquals(response, NOT_DONE_YET)
        yield d
        self.assertEquals('', ''.join(request.written))
        self.assertEquals(request.outgoingHeaders['content-type'],
                          'text/plain')
        self.assertEquals(request.responseCode, http.OK)
        msg = self.mkmsg_in()

        [smsg] = self.get_dispatched('sms.inbound.vas2nets.9292')
        self.assertEquals(msg.payload, from_json(smsg.body))

    @inlineCallbacks
    def test_delivery_receipt_pending(self):
        resource = DeliveryReceiptResource(self.config, self.publisher)

        request = self.create_request({
            'smsid': ['1'],
            'messageid': ['internal id'],
            'sender': ['+41791234567'],
            'status': ['1'],
            'text': ['Message submitted to Provider for delivery.'],
        })
        d = request.notifyFinish()
        response = resource.render(request)
        self.assertEquals(response, NOT_DONE_YET)
        yield d
        self.assertEquals('', ''.join(request.written))
        self.assertEquals(request.outgoingHeaders['content-type'],
                          'text/plain')
        self.assertEquals(request.responseCode, http.OK)
        msg = self.make_delivery_message(
            'pending', '1', 'Message submitted to Provider for delivery.')
        [smsg] = self.get_dispatched('sms.receipt.vas2nets')
        self.assertEquals(msg, from_json(smsg.body))

    @inlineCallbacks
    def test_delivery_receipt_failed(self):
        resource = DeliveryReceiptResource(self.config, self.publisher)

        request = self.create_request({
            'smsid': ['1'],
            'messageid': ['internal id'],
            'sender': ['+41791234567'],
            'status': ['-9'],
            'text': ['Message could not be delivered.'],
        })
        d = request.notifyFinish()
        response = resource.render(request)
        self.assertEquals(response, NOT_DONE_YET)
        yield d
        self.assertEquals('', ''.join(request.written))
        self.assertEquals(request.outgoingHeaders['content-type'],
                          'text/plain')
        self.assertEquals(request.responseCode, http.OK)
        msg = self.make_delivery_message(
            'failed', '-9', 'Message could not be delivered.')
        [smsg] = self.get_dispatched('sms.receipt.vas2nets')
        self.assertEquals(from_json(smsg.body), msg)

    @inlineCallbacks
    def test_delivery_receipt_delivered(self):
        resource = DeliveryReceiptResource(self.config, self.publisher)

        request = self.create_request({
            'smsid': ['1'],
            'messageid': ['internal id'],
            'sender': ['+41791234567'],
            'status': ['2'],
            'text': ['Message delivered to MSISDN.'],
        })
        d = request.notifyFinish()
        response = resource.render(request)
        self.assertEquals(response, NOT_DONE_YET)
        yield d
        self.assertEquals('', ''.join(request.written))
        self.assertEquals(request.outgoingHeaders['content-type'],
                          'text/plain')
        self.assertEquals(request.responseCode, http.OK)
        msg = self.make_delivery_message(
            'delivered', '2', 'Message delivered to MSISDN.')
        [smsg] = self.get_dispatched('sms.receipt.vas2nets')
        self.assertEquals(from_json(smsg.body), msg)

    def test_validate_characters(self):
        self.assertRaises(Vas2NetsEncodingError, validate_characters,
                            u"ïøéå¬∆˚")
        self.assertTrue(validate_characters(string.ascii_lowercase))
        self.assertTrue(validate_characters(string.ascii_uppercase))
        self.assertTrue(validate_characters('0123456789'))
        self.assertTrue(validate_characters(u'äöü ÄÖÜ àùò ìèé §Ññ £$@'))
        self.assertTrue(validate_characters(u'/?!#%&()*+,-:;<=>.'))
        self.assertTrue(validate_characters(u'testing\ncarriage\rreturns'))
        self.assertTrue(validate_characters(u'testing "quotes"'))
        self.assertTrue(validate_characters(u"testing 'quotes'"))

    @inlineCallbacks
    def test_send_sms_success(self):
        mocked_message_id = str(uuid4())
        mocked_message = "Result_code: 00, Message OK"

        # open an HTTP resource that mocks the Vas2Nets response for the
        # duration of this test
        yield self.make_resource_worker(mocked_message_id, mocked_message)
        yield self.worker.startWorker()

        yield self.worker.handle_outbound_message(self.mkmsg_out())

        [smsg] = self.get_dispatched('sms.ack.vas2nets')
        self.assertEqual(TransportSMSAck(
                message_id='1',
                transport_message_id=mocked_message_id,
                timestamp=UTCNearNow(),
                transport='vas2nets',
                ), from_json(smsg.body))

    @inlineCallbacks
    def test_send_sms_reply_success(self):
        mocked_message_id = str(uuid4())
        reply_to_msgid = str(uuid4())
        mocked_message = "Result_code: 00, Message OK"

        # open an HTTP resource that mocks the Vas2Nets response for the
        # duration of this test
        yield self.make_resource_worker(mocked_message_id, mocked_message,
                                        send_id=reply_to_msgid)
        yield self.worker.startWorker()

        yield self.worker.handle_outbound_message(self.mkmsg_out(
                    in_reply_to=reply_to_msgid))

        [smsg] = self.get_dispatched('sms.ack.vas2nets')
        self.assertEqual(TransportSMSAck(
                message_id='1',
                transport_message_id=mocked_message_id,
                timestamp=UTCNearNow(),
                transport='vas2nets',
                ), from_json(smsg.body))

    @inlineCallbacks
    def test_send_sms_fail(self):
        mocked_message_id = False
        mocked_message = "Result_code: 04, Internal system error occurred " \
                            "while processing message"
        yield self.make_resource_worker(mocked_message_id, mocked_message)
        yield self.worker.startWorker()

        msg = self.mkmsg_out()
        deferred = self.worker.handle_outbound_message(msg)
        yield deferred
        [fmsg] = self.get_dispatched('sms.outbound.vas2nets.failures')
        fmsg = from_json(fmsg.body)
        self.assertEqual(msg.payload, fmsg['message'])
        self.assertTrue(
            "Vas2NetsTransportError: No SmsId Header" in fmsg['reason'])

    @inlineCallbacks
    def test_send_sms_noconn(self):
        yield self.worker.startWorker()

        msg = self.mkmsg_out()
        deferred = self.worker.handle_outbound_message(msg)
        yield deferred
        [fmsg] = self.get_dispatched('sms.outbound.vas2nets.failures')
        fmsg = from_json(fmsg.body)
        self.assertEqual(msg, fmsg['message'])
        self.assertEqual("connection refused", fmsg['reason'])

    @inlineCallbacks
    def test_send_sms_not_OK(self):
        mocked_message = "Page not found."
        yield self.make_resource_worker(None, mocked_message, http.NOT_FOUND)
        yield self.worker.startWorker()

        msg = self.mkmsg_out()
        deferred = self.worker.handle_outbound_message(msg)
        yield deferred
        [fmsg] = self.get_dispatched('sms.outbound.vas2nets.failures')
        fmsg = from_json(fmsg.body)
        self.assertEqual(msg, fmsg['message'])
        self.assertTrue(fmsg['reason'].startswith("server error"))

    def test_normalize_outbound_msisdn(self):
        self.assertEquals(normalize_outbound_msisdn('+27761234567'),
                          '0027761234567')
Example #30
0
 def setUp(self):
     self._workers = []
     self._amqp = FakeAMQPBroker()
Example #31
0
class TestRockPaperScissorsWorker(unittest.TestCase):
    def setUp(self):
        self._amqp = FakeAMQPBroker()
        self._workers = []

    def tearDown(self):
        for worker in self._workers:
            worker.stopWorker()

    def get_worker(self):
        worker = get_stubbed_worker(RockPaperScissorsWorker, {
                'transport_name': 'foo',
                'ussd_code': '99999',
                }, self._amqp)
        self._workers.append(worker)
        worker.startWorker()
        return worker

    def mkmsg(self, from_addr, sid, content='', sev=None):
        if sev is None:
            sev = TransportUserMessage.SESSION_RESUME
        return TransportUserMessage(
            transport_name='sphex',
            transport_type='ussd',
            transport_metadata={},
            from_addr=from_addr,
            to_addr='12345',
            content=content,
            session_id=sid,
            session_event=sev,
            )

    def get_msgs(self):
        return self._amqp.get_messages('vumi', 'foo.outbound')

    def test_new_sessions(self):
        worker = self.get_worker()
        self.assertEquals({}, worker.games)
        self.assertEquals(None, worker.open_game)

        worker.dispatch_user_message(self.mkmsg(
                '+27831234567', 'sp1', sev=TransportUserMessage.SESSION_NEW))
        self.assertNotEquals(None, worker.open_game)
        game = worker.open_game
        self.assertEquals({'sp1': game}, worker.games)

        worker.dispatch_user_message(self.mkmsg(
                '+27831234568', 'sp2', sev=TransportUserMessage.SESSION_NEW))
        self.assertEquals(None, worker.open_game)
        self.assertEquals({'sp1': game, 'sp2': game}, worker.games)

        self.assertEquals(2, len(self.get_msgs()))

    def test_moves(self):
        worker = self.get_worker()
        worker.dispatch_user_message(self.mkmsg(
                '+27831234567', 'sp1', sev=TransportUserMessage.SESSION_NEW))
        game = worker.open_game
        worker.dispatch_user_message(self.mkmsg(
                '+27831234568', 'sp2', sev=TransportUserMessage.SESSION_NEW))

        self.assertEquals(2, len(self.get_msgs()))
        worker.dispatch_user_message(self.mkmsg(
                '+27831234568', 'sp2', content='1'))
        self.assertEquals(2, len(self.get_msgs()))
        worker.dispatch_user_message(self.mkmsg(
                '+27831234567', 'sp1', content='2'))
        self.assertEquals(4, len(self.get_msgs()))
        self.assertEquals((0, 1), game.scores)