def test_bulk_sms_send_multiproc(self): # close database connections manually to make sure they're not passed # to subprocesses for conn in django_db_connections.all(): conn.close() # send the messages in parallel using 10 processes. use # multiprocessing rather than threads so we don't have to clean # up database connections that the threads might leave open. cache.close() pool = multiprocessing.Pool(10) try: for i in range(30): BulkMessageFactory(batch=self.batch, sms=None) for j in range(10): BulkMessageFactory(batch=self.batch, sms=None, deleted=True) # 40 is the first multiple of 10 greater than or equal to 31 num_sent = send_messages(self.batch, num_to_send=40, map_=pool.map) batch = Batch.objects.get(pk=self.batch.pk) self.assertEqual(batch.errors, 0) self.assertEqual(batch.status, Batch.COMPLETED) # assert that we report the right number sent too self.assertEqual(num_sent, 30) self.assertEqual(len(self.outbound), 30) finally: pool.terminate() pool.join()
def test_unsent(self): msg1 = BulkMessageFactory(phone_number=u'555-1212', sms=None) BulkMessageFactory(phone_number=u'555-1212', sms=None) # ensure the manager method works self.assertEqual(BulkMessage.objects.unsent().count(), 2) # ensure the queryset method works on a filtered queryset self.assertEqual( BulkMessage.objects.filter(batch=msg1.batch).unsent().count(), 1)
def test_active(self): msg1 = BulkMessageFactory(phone_number=u'555-1212', deleted=True) msg2 = BulkMessageFactory(phone_number=u'555-1212', batch=msg1.batch) BulkMessageFactory(phone_number=u'555-1212') # ensure the manager method works self.assertEqual(BulkMessage.objects.active().count(), 2) # ensure the queryset method works on a filtered queryset self.assertEqual( BulkMessage.objects.filter(batch=msg2.batch).active().count(), 1)
def test_time_remaining(self): batch = BatchFactory(status=Batch.PENDING) [ BulkMessageFactory(deleted=True, batch=batch, sms=None) for i in range(5) ] msgs = [BulkMessageFactory(batch=batch, sms=None) for i in range(10)] self.assertEqual(batch.time_remaining(), datetime.timedelta(seconds=len(msgs) / 2))
def test_bulk_sms_send_one_proc(self): for i in range(30): BulkMessageFactory(batch=self.batch, sms=None) for j in range(10): BulkMessageFactory(batch=self.batch, sms=None, deleted=True) num_sent = send_messages(self.batch) # 31 messages sent (30 + 1 from setUp) self.assertEqual(len(self.outbound), 31) # assert that we report the right number sent too self.assertEqual(num_sent, 31)
def test_sent_messages_dont_get_resent(self): for i in range(20): BulkMessageFactory(batch=self.batch, sms=None) for i in range(10): sms = SMSFactory() BulkMessageFactory(batch=self.batch, sms=sms) BulkMessageFactory(batch=self.batch, sms=SMSFactory(), deleted=True) send_messages(self.batch) # only 21 messages get sent out (20 + 1 from setUp) self.assertEqual(len(self.outbound), 21)
def test_once_all_are_sent_next_send_completes_batch(self): for i in range(20): BulkMessageFactory(batch=self.batch, sms=None) BulkMessageFactory(batch=self.batch, sms=None, deleted=True) # send out all the messages (21) send_messages(self.batch) self.assertEqual(len(self.outbound), 21) # send again BulkMessageFactory(batch=self.batch, sms=None, deleted=True) send_messages(self.batch) # now batch should be completed batch = Batch.objects.get(pk=self.batch.pk) self.assertEqual(batch.status, Batch.COMPLETED)
def test_send_is_threadsafe(self): """ Ensure send_message_by_id does not accidentally send more than one SMS to the same user if it happens to be running more than once with the same ID. """ trigger = threading.Event() def target(pk): # wait until all threads have started before attempting to send trigger.wait() send_message_by_id(pk) # workaround https://code.djangoproject.com/ticket/22420 for conn in django_db_connections.all(): conn.close() m = BulkMessageFactory(batch=self.batch, sms=None) threads = [ threading.Thread(target=target, args=(m.pk, )) for i in range(10) ] for t in threads: t.start() # wake up all threads at the same time trigger.set() for t in threads: t.join() # only 1 message should be sent out in total self.assertEqual(len(self.outbound), 1)
def test_time_remaining_one_message(self): # if there are any messages at all, should still return a True value for the template batch = BatchFactory(status=Batch.PENDING) BulkMessageFactory(batch=batch, sms=None) # using assertTrue because the key is that we want the return value to be boolean True # for the template to NOT display the 'Finished' default self.assertTrue(batch.time_remaining())
def setUp(self): # create an approved Batch self.batch = BatchFactory(status=Batch.APPROVED) # add message to batch self.bulk_msg = BulkMessageFactory( batch=self.batch, phone_number=get_random_number_string(), message=u'.نآسف، مرحلة التسجيل عن طريق الرسائل النصية ليست متاحة', sms=None)
def test_management_cmd(self): # Make sure the bulk sending management command works (for a single batch, at least). for i in range(50): BulkMessageFactory(batch=self.batch, sms=None) call_command('send_bulk_messages', concurrent_workers=10, msgs_per_sec=50, send_forever=False) batch = Batch.objects.get(pk=self.batch.pk) self.assertEqual(batch.errors, 0) self.assertEqual(batch.status, Batch.COMPLETED) self.assertEqual(len(self.outbound), 50)
def test_get_random_messages_from_batch(self): batch = BatchFactory(status=Batch.PENDING) BatchFactory(status=Batch.PENDING, deleted=True) msgs = [BulkMessageFactory(batch=batch, sms=None) for i in range(10)] # the random message is one of our messages first_random_msg = batch.random_n_messages(n=1)[0] self.assertIn(first_random_msg, msgs) # get random message up to 10 times: shouldn't all be the same for i in range(10): next_random_msg = batch.random_n_messages(n=1)[0] if first_random_msg != next_random_msg: break self.assertNotEqual(first_random_msg, next_random_msg) # if we ask for more than exist, we only get the number that actually exist self.assertTrue(len(batch.random_n_messages(n=20)), 10)
def test_send_finite_number_each_time(self): for i in range(20): BulkMessageFactory(batch=self.batch, sms=None) send_messages(self.batch, num_to_send=10) # only 10 messages should be sent out each call self.assertEqual(len(self.outbound), 10)
def test_from_shortcode_validation(self): msg = BulkMessageFactory() msg.from_shortcode = get_random_number_string(length=5) with self.assertRaisesRegexp(ValidationError, 'Invalid shortcode'): msg.full_clean()
def test_from_shortcode_default(self): msg = BulkMessageFactory() self.assertEqual(msg.from_shortcode, settings.REGISTRATION_SHORT_CODE)
def test_unicode_method(self): msg = BulkMessageFactory(phone_number=u'555-1212') self.assertIn('555-1212', str(msg))
def test_dont_get_deleted_bulkmessage_by_default(self): bulkmessage = BulkMessageFactory(deleted=True) self.assertNotIn(bulkmessage, BulkMessage.objects.all())