daphne/channels/tests/test_delay.py
Sam Bolgert 3dddefa845 Delay Protocol Server (#401)
* Add Delay Protocol Server

Add a process that listens to a specific channel
and delays incoming messages by a given time.

* Add custom django command rundelay
* Add test suite
* Implements #115

* Add channels.delay app

* Add AppConfig

* Move rundelay command to channels.delay app

* Refactor DelayedMessage into model

Move login into a database backed model.
* Update Worker
* Add migration

* Add delay docs page

* Add to TOC

* Fix import sorting

* Add ASGI spec document for Delay Protocol

* Update channels.delay doc with new channel name
* remove interval docs

* Refactor Delay to use milliseconds instead of seconds

Use milliseconds as the default unit. Gives more control to developers.

* Remove interval logic from DelayedMessage
* Remove interval tests
* Tweak test logic to use milliseconds
2016-11-24 10:54:03 -08:00

103 lines
2.8 KiB
Python

from __future__ import unicode_literals
import json
from datetime import timedelta
from django.utils import timezone
from channels import DEFAULT_CHANNEL_LAYER, Channel, channel_layers
from channels.delay.models import DelayedMessage
from channels.delay.worker import Worker
from channels.tests import ChannelTestCase
try:
from unittest import mock
except ImportError:
import mock
class PatchedWorker(Worker):
"""Worker with specific numbers of loops"""
def get_termed(self):
if not self.__iters:
return True
self.__iters -= 1
return False
def set_termed(self, value):
self.__iters = value
termed = property(get_termed, set_termed)
class WorkerTests(ChannelTestCase):
def test_invalid_message(self):
"""
Tests the worker won't delay an invalid message
"""
Channel('asgi.delay').send({'test': 'value'}, immediately=True)
worker = PatchedWorker(channel_layers[DEFAULT_CHANNEL_LAYER])
worker.termed = 1
worker.run()
self.assertEqual(DelayedMessage.objects.count(), 0)
def test_delay_message(self):
"""
Tests the message is delayed and dispatched when due
"""
Channel('asgi.delay').send({
'channel': 'test',
'delay': 1000,
'content': {'test': 'value'}
}, immediately=True)
worker = PatchedWorker(channel_layers[DEFAULT_CHANNEL_LAYER])
worker.termed = 1
worker.run()
self.assertEqual(DelayedMessage.objects.count(), 1)
with mock.patch('django.utils.timezone.now', return_value=timezone.now() + timedelta(milliseconds=1001)):
worker.termed = 1
worker.run()
self.assertEqual(DelayedMessage.objects.count(), 0)
message = self.get_next_message('test', require=True)
self.assertEqual(message.content, {'test': 'value'})
class DelayedMessageTests(ChannelTestCase):
def _create_message(self):
kwargs = {
'content': json.dumps({'test': 'data'}),
'channel_name': 'test',
'delay': 1000 * 5
}
delayed_message = DelayedMessage(**kwargs)
delayed_message.save()
return delayed_message
def test_is_due(self):
message = self._create_message()
self.assertEqual(DelayedMessage.objects.is_due().count(), 0)
with mock.patch('django.utils.timezone.now', return_value=message.due_date + timedelta(milliseconds=1)):
self.assertEqual(DelayedMessage.objects.is_due().count(), 1)
def test_send(self):
message = self._create_message()
message.send(channel_layer=channel_layers[DEFAULT_CHANNEL_LAYER])
self.get_next_message(message.channel_name, require=True)
self.assertEqual(DelayedMessage.objects.count(), 0)