Пример #1
0
 def test_outgoing(self):
     """is_eager should return True if router.celery.eager is set."""
     self.backends = {'mockbackend': {'ENGINE': harness.MockBackend,
                                      'router.celery.eager': True}}
     self.set_backends()
     router = get_router()
     self.assertTrue(router.is_eager('mockbackend'))
Пример #2
0
 def runParsedScript (self, cmds):
     router = get_router()
     router.start()
     last_msg = ''
     for num, date, dir, txt in cmds:
         if dir == '>':
             last_received = txt
             msg = self.backend.message(num, txt)
             msg.date = date 
             self.backend.route(msg)  
             router.run()
         elif dir == '<':
             msg = self.backend.next_message()
             # smart_str is a django util that prevents dumb terminals
             # from barfing on strange character sets 
             # see http://code.djangoproject.com/ticket/10183
             last_msg, msg.text, txt = map(smart_str, [last_msg, msg.text, txt])
             self.assertTrue(msg is not None, 
                 "message was returned.\nMessage: '%s'\nExpecting: '%s')" % (last_msg, txt))
             try:
                 self.assertEquals(msg.peer, num,
                     "Expected to send to %s, but message was sent to %s\nMessage: '%s'\nReceived: '%s'\nExpecting: '%s'" 
                     % (num, msg.peer,last_msg, msg.text, txt))
                 self.assertEquals(msg.text.strip(), txt.strip(),
                     "\nMessage: %s\nReceived text: %s\nExpected text: %s\n"
                     % (last_msg, msg.text,txt))
             except UnicodeDecodeError:
                 raise Exception("There has been a problem interpreting non-ascii characters for your display. " +
                                 "Please use a console with support for utf-8.")            
             last_msg = txt
     router.stop()
Пример #3
0
def send_transmissions(backend_id, message_id, transmission_ids):
    """Send message to backend with provided transmissions. Retry if failed."""
    from rapidsms.models import Backend
    from rapidsms.router.db.models import Message, Transmission
    from rapidsms.router import get_router
    backend = Backend.objects.get(pk=backend_id)
    dbm = Message.objects.select_related('in_response_to').get(pk=message_id)
    transmissions = Transmission.objects.filter(id__in=transmission_ids)
    # set (possibly reset) status to processing
    transmissions.update(status='P')
    identities = transmissions.values_list('connection__identity', flat=True)
    router = get_router()
    context = {}
    if dbm.in_response_to:
        context['external_id'] = dbm.in_response_to.external_id
    try:
        router.send_to_backend(backend_name=backend.name,
                               id_=dbm.pk,
                               text=dbm.text,
                               identities=list(identities),
                               context=context)
    except MessageSendingError as exc:
        # update database statuses, and re-execute this task
        logger.warning("Re-trying send_transmissions")
        Message.objects.filter(pk=message_id).update(status='E')
        transmissions.update(status='E', updated=now())
        raise send_transmissions.retry(exc=exc)
    # no error occured, so mark these transmissions as sent
    transmissions.update(status='S', sent=now())
    # we don't know if there are more transmissions pending, so
    # we always set the status at the end of each batch
    dbm.set_status()
Пример #4
0
 def runParsedScript (self, cmds):
     router = get_router()
     router.start()
     last_msg = ''
     for num, date, dir, txt in cmds:
         if dir == '>':
             last_received = txt
             msg = self.backend.message(num, txt)
             msg.date = date 
             self.backend.route(msg)  
             router.run()
         elif dir == '<':
             msg = self.backend.next_message()
             if msg is None:
                 self.fail("Message expected but none returned. Last message sent was: %s" % last_msg)
             last_msg, msg.text, txt = map(smart_str, [last_msg, msg.text, txt])
             self.assertTrue(msg is not None, 
                 "message was returned.\nMessage: '%s'\nExpecting: '%s')" % (last_msg, txt))
             try:
                 self.assertEquals(msg.peer, num,
                     "Expected to send to %s, but message was sent to %s\nMessage: '%s'\nReceived: '%s'\nExpecting: '%s'" 
                     % (num, msg.peer,last_msg, msg.text, txt))
                 self.assertEquals(msg.text.strip(), txt.strip(),
                     "\nMessage: %s\nReceived text: %s\nExpected text: %s\n"
                     % (last_msg, msg.text,txt))
             except UnicodeDecodeError:
                 raise Exception("There has been a problem interpreting non-ascii characters for your display. " +
                                 "Please use a console with support for utf-8.")            
             last_msg = txt
     router.stop()
Пример #5
0
    def setUp(self):
        # For now, default to using the old global router during unit tests,
        # but let users change that by setting TEST_RAPIDSMS_ROUTER
        # to a new router in their settings file
        router_cls = getattr(settings, 'TEST_RAPIDSMS_ROUTER', 'global')
        if router_cls == 'global':
            from rapidsms.router import router as globalrouter
            self.router = globalrouter
        else:
            self.router = get_router(router_cls)()

        self._init_log(logging.WARNING)

        if self.router.backends or self.router.apps:
            self.error("Found existing backends or apps in the test router! "
                       "Did you override tearDown and forget to call the base "
                       "class?  Test behavior may not be as expected.")

        # setup the mock backend
        self.router.add_backend("mockbackend", "rapidsms.tests.harness", {})
        self.backend = self.router.backends["mockbackend"]

        # add each application from conf
        for name in [app_name for app_name in settings.INSTALLED_APPS \
                     if not app_name in settings.TEST_EXCLUDED_APPS]:
            self.router.add_app(name)
Пример #6
0
    def setUp (self):
        # For now, default to using the old global router during unit tests,
        # but let users change that by setting TEST_RAPIDSMS_ROUTER
        # to a new router in their settings file
        router_cls = getattr(settings, 'TEST_RAPIDSMS_ROUTER', 'global')
        if router_cls == 'global':
            from rapidsms.router import router as globalrouter
            self.router = globalrouter
        else:
            self.router = get_router(router_cls)()

        self._init_log(logging.WARNING)
        
        if self.router.backends or self.router.apps:
            self.error("Found existing backends or apps in the test router! "
                       "Did you override tearDown and forget to call the base "
                       "class?  Test behavior may not be as expected.")
                       
        # setup the mock backend
        self.router.add_backend("mockbackend", "rapidsms.tests.harness", {})
        self.backend = self.router.backends["mockbackend"]
        
        # add each application from conf
        for name in [app_name for app_name in settings.INSTALLED_APPS \
                     if not app_name in settings.TEST_EXCLUDED_APPS]:
            self.router.add_app(name)
Пример #7
0
def send_transmissions(backend_id, message_id, transmission_ids):
    """Send message to backend with provided transmissions. Retry if failed."""
    from rapidsms.models import Backend
    from rapidsms.router.db.models import Message, Transmission
    from rapidsms.router import get_router
    backend = Backend.objects.get(pk=backend_id)
    dbm = Message.objects.select_related('in_response_to').get(pk=message_id)
    transmissions = Transmission.objects.filter(id__in=transmission_ids)
    # set (possibly reset) status to processing
    transmissions.update(status='P')
    identities = transmissions.values_list('connection__identity', flat=True)
    router = get_router()
    context = {}
    if dbm.in_response_to:
        context['external_id'] = dbm.in_response_to.external_id
    try:
        router.send_to_backend(backend_name=backend.name, id_=dbm.pk,
                               text=dbm.text, identities=list(identities),
                               context=context)
    except MessageSendingError as exc:
        # update database statuses, and re-execute this task
        logger.warning("Re-trying send_transmissions")
        Message.objects.filter(pk=message_id).update(status='E')
        transmissions.update(status='E', updated=now())
        raise send_transmissions.retry(exc=exc)
    # no error occured, so mark these transmissions as sent
    transmissions.update(status='S', sent=now())
    # we don't know if there are more transmissions pending, so
    # we always set the status at the end of each batch
    dbm.set_status()
Пример #8
0
 def test_outgoing(self):
     """is_eager should return True if router.celery.eager is set."""
     self.backends = {'mockbackend': {'ENGINE': harness.MockBackend,
                                      'router.celery.eager': True}}
     self.set_backends()
     router = get_router()
     self.assertTrue(router.is_eager('mockbackend'))
Пример #9
0
 def setUp (self):
     set_router(MockRouter())
     router = get_router()
     self.backend = Backend(router)
     router.add_backend(self.backend)
     if not self.apps:
         raise Exception(
             "You must define a list of apps in your TestScript class!")
     for app_class in self.apps:
         app = app_class(router)
         router.add_app(app)
Пример #10
0
 def test_get_router(self):
     """Test exceptions for bad input given to get_router()"""
     bad_module_router = 'rapidsms.tests.router.bad_module.MockRouter'
     bad_class_router = 'rapidsms.tests.router.test_base.BadClassName'
     good_mock_router = 'rapidsms.router.test_api.MockRouter'
     with override_settings(RAPIDSMS_ROUTER=bad_module_router):
             self.assertRaises(ImproperlyConfigured, get_router)
     with override_settings(RAPIDSMS_ROUTER=bad_class_router):
             self.assertRaises(ImproperlyConfigured, get_router)
     with override_settings(RAPIDSMS_ROUTER=good_mock_router):
             self.assertTrue(isinstance(get_router(), MockRouter))
Пример #11
0
 def test_get_router(self):
     """Test exceptions for bad input given to get_router()"""
     bad_module_router = 'rapidsms.tests.router.bad_module.MockRouter'
     bad_class_router = 'rapidsms.tests.router.test_base.BadClassName'
     good_mock_router = 'rapidsms.router.test_api.MockRouter'
     with override_settings(RAPIDSMS_ROUTER=bad_module_router):
         self.assertRaises(ImproperlyConfigured, get_router)
     with override_settings(RAPIDSMS_ROUTER=bad_class_router):
         self.assertRaises(ImproperlyConfigured, get_router)
     with override_settings(RAPIDSMS_ROUTER=good_mock_router):
         self.assertTrue(isinstance(get_router(), MockRouter))
Пример #12
0
def send_async(backend_name, id_, text, identities, context):
    """Task used to send outgoing messages to backends."""
    logger.debug('send_async: %s' % text)
    from rapidsms.router import get_router
    router = get_router()
    try:
        router.send_to_backend(backend_name=backend_name, id_=id_, text=text,
                               identities=identities, context=context)
    except MessageSendingError:
        # This exception has already been logged in send_to_backend.
        # We'll simply pass here and not re-raise or log the exception again.
        pass
Пример #13
0
def receive(text, connection, fields=None):
    """
    Creates an incoming message and passes it to the router for processing.
    """
    from rapidsms.router import get_router
    from rapidsms.messages import IncomingMessage
    router = get_router()()
    router.start()
    message = IncomingMessage(connection, text, datetime.datetime.now(),
                              fields=fields)
    router.receive_incoming(message)
    router.stop()
    return message
Пример #14
0
def receive(text, connection, fields=None):
    """
    Creates an incoming message and passes it to the router for processing.
    """
    from rapidsms.router import get_router
    from rapidsms.messages import IncomingMessage
    router = get_router()()
    router.start()
    message = IncomingMessage(connection,
                              text,
                              datetime.datetime.now(),
                              fields=fields)
    router.receive_incoming(message)
    router.stop()
    return message
Пример #15
0
def receive_async(text, connection_id, message_id, fields):
    """Task used to send inbound message through router phases."""
    from rapidsms.models import Connection
    from rapidsms.router import get_router
    logger.debug('receive_async: %s' % text)
    router = get_router()
    # reconstruct incoming message
    connection = Connection.objects.select_related().get(pk=connection_id)
    message = router.new_incoming_message(text=text, connections=[connection],
                                          id_=message_id, fields=fields)
    try:
        # call process_incoming directly to skip receive_incoming
        router.process_incoming(message)
    except Exception:
        logger.exception("Exception processing incoming message")
Пример #16
0
def send(text, connections):
    """
    Creates an outgoing message and passes it to the router to be processed
    and sent via the respective backend.
    """
    from rapidsms.router import get_router
    from rapidsms.messages import OutgoingMessage
    if not isinstance(connections, collections.Iterable):
        connections = [connections]
    router = get_router()()
    router.start()
    messages = []
    for connection in connections:
        message = OutgoingMessage(connection, text)
        router.send_outgoing(message)
        messages.append(message)
    router.stop()
    return messages
Пример #17
0
def receive_async(message_id, fields):
    """Retrieve message from DB and pass to BlockingRouter for processing."""
    from rapidsms.router.db.models import Message
    from rapidsms.router import get_router
    dbm = Message.objects.get(pk=message_id)
    router = get_router()
    message = router.create_message_from_dbm(dbm, fields)
    try:
        # call process_incoming directly to skip receive_incoming
        router.process_incoming(message)
    except Exception:
        logger.exception("Exception in router.process_incoming")
        dbm.transmissions.update(status='E', updated=now())
        dbm.set_status()
    if dbm.status != 'E':
        # mark message as being received
        dbm.transmissions.update(status='R', updated=now())
        dbm.set_status()
Пример #18
0
def receive_async(message_id, fields):
    """Retrieve message from DB and pass to BlockingRouter for processing."""
    from rapidsms.router.db.models import Message
    from rapidsms.router import get_router
    dbm = Message.objects.get(pk=message_id)
    router = get_router()
    message = router.create_message_from_dbm(dbm, fields)
    try:
        # call process_incoming directly to skip receive_incoming
        router.process_incoming(message)
    except Exception:
        logger.exception("Exception in router.process_incoming")
        dbm.transmissions.update(status='E', updated=now())
        dbm.set_status()
    if dbm.status != 'E':
        # mark message as being received
        dbm.transmissions.update(status='R', updated=now())
        dbm.set_status()
Пример #19
0
def send(text, connections):
    """
    Creates an outgoing message and passes it to the router to be processed
    and sent via the respective backend.
    """
    from rapidsms.router import get_router
    from rapidsms.messages import OutgoingMessage
    if not isinstance(connections, collections.Iterable):
        connections = [connections]
    router = get_router()()
    router.start()
    messages = []
    for connection in connections:
        message = OutgoingMessage(connection, text)
        router.send_outgoing(message)
        messages.append(message)
    router.stop()
    return messages
Пример #20
0
def send_transmissions(backend_id, message_id, transmission_ids):
    """Send message to backend with provided transmissions. Retry if failed."""
    from rapidsms.models import Backend
    from rapidsms.router.db.models import Message, Transmission
    from rapidsms.router import get_router
    backend = Backend.objects.get(pk=backend_id)
    dbm = Message.objects.select_related('in_response_to').get(pk=message_id)
    # this might be a retry, so exclude transmissions which were successful
    transmissions = Transmission.objects.filter(
        id__in=transmission_ids).exclude(status='S')
    # set (possibly reset) status to processing
    transmissions.update(status='P')
    identities = transmissions.values_list('connection__identity', flat=True)
    router = get_router()
    context = {}
    if dbm.in_response_to:
        context['external_id'] = dbm.in_response_to.external_id
    try:
        router.send_to_backend(backend_name=backend.name,
                               id_=dbm.pk,
                               text=dbm.text,
                               identities=list(identities),
                               context=context)
    except MessageSendingError as exc:
        # some or all transmissions failed: mark the Message group as failed
        Message.objects.filter(pk=message_id).update(status='E')
        if hasattr(exc, 'failed_identities') and exc.failed_identities:
            # Backend explicitly said these ids failed, so mark all others sent
            transmissions.exclude(
                connection__identity__in=exc.failed_identities).update(
                    status='S', sent=now())
            # regenerate the transmissions QS, with only the failed transmissions
            transmissions = transmissions.exclude(status='S')
        # else:
        #     Backend didn't provide failed_identities, so we assume all failed
        transmissions.update(status='E', updated=now())
        # Retry the task
        raise send_transmissions.retry(exc=exc)
    # no error occured, so mark these transmissions as sent
    transmissions.update(status='S', sent=now())
    # we don't know if there are more transmissions pending, so
    # we always set the status at the end of each batch
    dbm.set_status()
Пример #21
0
def send_transmissions(backend_id, message_id, transmission_ids):
    """Send message to backend with provided transmissions. Retry if failed."""
    from rapidsms.models import Backend
    from rapidsms.router.db.models import Message, Transmission
    from rapidsms.router import get_router
    backend = Backend.objects.get(pk=backend_id)
    dbm = Message.objects.select_related('in_response_to').get(pk=message_id)
    # this might be a retry, so exclude transmissions which were successful
    transmissions = Transmission.objects.filter(id__in=transmission_ids).exclude(status='S')
    # set (possibly reset) status to processing
    transmissions.update(status='P')
    identities = transmissions.values_list('connection__identity', flat=True)
    router = get_router()
    context = {}
    if dbm.in_response_to:
        context['external_id'] = dbm.in_response_to.external_id
    try:
        router.send_to_backend(backend_name=backend.name, id_=dbm.pk,
                               text=dbm.text, identities=list(identities),
                               context=context)
    except MessageSendingError as exc:
        # some or all transmissions failed: mark the Message group as failed
        Message.objects.filter(pk=message_id).update(status='E')
        if hasattr(exc, 'failed_identities') and exc.failed_identities:
            # Backend explicitly said these ids failed, so mark all others sent
            transmissions.exclude(
                connection__identity__in=exc.failed_identities
            ).update(status='S', sent=now())
            # regenerate the transmissions QS, with only the failed transmissions
            transmissions = transmissions.exclude(status='S')
        # else:
        #     Backend didn't provide failed_identities, so we assume all failed
        transmissions.update(status='E', updated=now())
        # Retry the task
        raise send_transmissions.retry(exc=exc)
    # no error occured, so mark these transmissions as sent
    transmissions.update(status='S', sent=now())
    # we don't know if there are more transmissions pending, so
    # we always set the status at the end of each batch
    dbm.set_status()
Пример #22
0
def send_message_by_id(bmsg_pk):
    """
    Send a specific ``BulkMessage`` object based on the provided primary key,
    ``bmsg_pk``. Intended to be called from a separate process or thread that
    might not inherit the caller's database connection.

    Returns the number of messages sent (0 or 1).
    """
    num_sent = 0
    try:
        # include a few sanity checks when retrieving this message, just in case
        # the database changed since this ``bmsg_pk`` was queued
        bmsg = BulkMessage.objects.unsent().select_related('batch')\
                          .get(pk=bmsg_pk, batch__status=Batch.APPROVED)
    except BulkMessage.DoesNotExist:
        bmsg = None
    if bmsg:
        connection = best_connection_for_phone_number(bmsg.phone_number, settings.BULKSMS_BACKENDS)
        # create a RapidSMS message object
        router = get_router()
        out_msg = router.new_outgoing_message(text=bmsg.message, connections=[connection])
        # setup the from_number
        out_msg.fields['endpoint'] = bmsg.from_shortcode
        # process the RapidSMS outgoing phases
        continue_sending = router.process_outgoing_phases(out_msg)
        if continue_sending:
            try:
                router.send_to_backend(backend_name=connection.backend.name,
                                       id_=out_msg.id,
                                       text=out_msg.text,
                                       identities=[connection.identity],
                                       context=out_msg.fields)
            except MessageSendingError:
                logger.exception("Error sending bulk_sms message: id %d, batch %s" %
                                 (bmsg.pk, bmsg.batch))
            else:
                BulkMessage.objects.filter(pk=bmsg_pk).update(sms=out_msg.sms)
                num_sent = 1
    return num_sent
Пример #23
0
 def get_router(self):
     """get_router() API wrapper."""
     return get_router()
Пример #24
0
def _find_app(app_name):
    for app in get_router().apps:
        if app.name == name:
            app = app
Пример #25
0
 def test_eager_invalid_backend(self):
     """is_eager should return False if backend doesn't exist."""
     self.backends = {'mockbackend': {'ENGINE': harness.MockBackend}}
     self.set_backends()
     router = get_router()
     self.assertFalse(router.is_eager('foo'))
Пример #26
0
 def test_eager_not_set(self):
     """is_eager should return False if not set for specified backend."""
     self.backends = {'mockbackend': {'ENGINE': harness.MockBackend}}
     self.set_backends()
     router = get_router()
     self.assertFalse(router.is_eager('mockbackend'))
Пример #27
0
 def test_eager_invalid_backend(self):
     """is_eager should return False if backend doesn't exist."""
     self.backends = {'mockbackend': {'ENGINE': harness.MockBackend}}
     self.set_backends()
     router = get_router()
     self.assertFalse(router.is_eager('foo'))
Пример #28
0
 def test_eager_not_set(self):
     """is_eager should return False if not set for specified backend."""
     self.backends = {'mockbackend': {'ENGINE': harness.MockBackend}}
     self.set_backends()
     router = get_router()
     self.assertFalse(router.is_eager('mockbackend'))
Пример #29
0
 def get_router(self):
     """get_router() API wrapper."""
     return get_router()
Пример #30
0
 def setUp(self):
     super(BroadcastScriptedTest, self).setUp()
     backends = {'mockbackend': {'ENGINE': MockBackend}}
     self.router = get_router()(backends=backends)
Пример #31
0
 def tearDown (self):
     router = get_router()
     if router.running:
         router.stop()