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'))
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()
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()
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()
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)
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)
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)
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))
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
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
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")
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
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()
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()
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()
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
def get_router(self): """get_router() API wrapper.""" return get_router()
def _find_app(app_name): for app in get_router().apps: if app.name == name: app = app
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'))
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'))
def setUp(self): super(BroadcastScriptedTest, self).setUp() backends = {'mockbackend': {'ENGINE': MockBackend}} self.router = get_router()(backends=backends)
def tearDown (self): router = get_router() if router.running: router.stop()