Implement robust unit test cases for message queue timing

This commit is contained in:
Kristóf Tóth 2019-10-08 17:01:45 +02:00
parent 641709c04e
commit 628485cff1
2 changed files with 83 additions and 35 deletions

View File

@ -6,6 +6,7 @@ from threading import Thread
class MessageQueueHandler: class MessageQueueHandler:
keys = ['message.queue'] keys = ['message.queue']
type_id = 'ControlEventHandler' type_id = 'ControlEventHandler'
avg_word_len = 5
def __init__(self, wpm): def __init__(self, wpm):
self.connector = None self.connector = None
@ -15,11 +16,17 @@ class MessageQueueHandler:
def _dispatch_messages(self): def _dispatch_messages(self):
for message in iter(self._queue.get, None): for message in iter(self._queue.get, None):
wpm = message['wpm'] if 'wpm' in message else self.wpm
cps = 5 * wpm / 60
message['typing'] = not self._queue.empty() message['typing'] = not self._queue.empty()
self.connector.send_message(message) self.connector.send_message(message)
sleep(len(message['message']) / cps) self._sleep(self._get_sleep_time(message))
def _get_sleep_time(self, message):
words_per_min = message['wpm'] if 'wpm' in message else self.wpm
chars_per_min = self.avg_word_len * words_per_min / 60
return len(message['message']) / chars_per_min
def _sleep(self, seconds): # pylint: disable=no-self-use
sleep(seconds)
def handle_event(self, message, _): def handle_event(self, message, _):
for unpacked in self._generate_messages_from_queue(message): for unpacked in self._generate_messages_from_queue(message):

View File

@ -1,8 +1,8 @@
# pylint: disable=redefined-outer-name # pylint: disable=redefined-outer-name
from math import inf from time import time
from time import sleep
from os import urandom from os import urandom
from random import randint from random import randint
from queue import Queue
import pytest import pytest
@ -12,56 +12,97 @@ from .message_queue_handler import MessageQueueHandler
class MockConnector: class MockConnector:
def __init__(self): def __init__(self):
self.callback = None self.callback = None
self.messages = [] self.messages = Queue()
self.send_times = Queue()
def raise_event(self, message): def raise_event(self, message):
self.callback(message, self) self.callback(message, self)
sleep(0.01)
def send_message(self, message): def send_message(self, message):
self.messages.append(message) self.messages.put(message)
self.send_times.put(time())
@pytest.fixture @pytest.fixture
def handler(): def handler():
connector = MockConnector() class NoSleepMessageQueueHandler(MessageQueueHandler):
handler = MessageQueueHandler(inf) sleep_start_times = Queue()
handler.connector = connector sleep_seconds = Queue()
connector.callback = handler.handle_event sleep_end_times = Queue()
def _sleep(self, seconds):
self.sleep_start_times.put(time())
self.sleep_seconds.put(seconds)
super()._sleep(seconds)
self.sleep_end_times.put(time())
handler = NoSleepMessageQueueHandler(100000)
handler.connector = MockConnector()
handler.connector.callback = handler.handle_event
handler.start() handler.start()
yield handler yield handler
handler.cleanup() handler.cleanup()
@pytest.fixture def get_message_queue(*, size=None):
def queue(): size = randint(5, 10) if not size else size
yield { return {
'key': 'message.queue', 'key': 'message.queue',
'messages': [ 'messages': [
{'originator': urandom(4).hex(), 'message': urandom(16).hex()} {'originator': urandom(4).hex(), 'message': urandom(randint(10, 20)).hex()}
for _ in range(randint(5, 10)) for _ in range(size)
] ]
} }
def test_message_order(handler, queue): def test_order(handler):
queue = get_message_queue()
handler.connector.raise_event(queue) handler.connector.raise_event(queue)
old_list = queue['messages'] expected_messages = queue['messages']
new_list = handler.connector.messages
length = len(old_list) actual_messages = []
assert len(new_list) == length for _ in expected_messages:
for i in range(length): actual_messages.append(handler.connector.messages.get())
unpacked = new_list[i]
assert unpacked['key'] == 'message.send' assert len(actual_messages) == len(expected_messages)
assert unpacked['originator'] == old_list[i]['originator'] for i in range(len(expected_messages)): # pylint: disable=consider-using-enumerate
assert unpacked['typing'] == (i < length-1) message = actual_messages[i]
assert message['key'] == 'message.send'
assert message['originator'] == expected_messages[i]['originator']
assert message['typing'] == (i < len(expected_messages)-1)
def test_wpm(handler, queue): def test_timing(handler):
handler.wpm = 10000 q1 = get_message_queue(size=2)
handler.connector.raise_event(queue) q2 = get_message_queue(size=2)
assert len(handler.connector.messages) == 1 handler.connector.raise_event(q1)
handler.wpm = 100000000 handler.connector.raise_event(q2)
handler.connector.raise_event(queue)
sleep(0.25) messages = []
assert len(handler.connector.messages) == 2*len(queue['messages']) send_times = []
sleep_start_times = []
sleep_seconds = []
sleep_end_times = []
for _ in range(len(q1['messages']) + len(q2['messages'])):
messages.append(handler.connector.messages.get())
send_times.append(handler.connector.send_times.get())
sleep_start_times.append(handler.sleep_start_times.get())
sleep_seconds.append(handler.sleep_seconds.get())
sleep_end_times.append(handler.sleep_end_times.get())
# no sleep before first message
assert sleep_start_times[0] > send_times[0]
assert messages[0]['typing']
# at least 'seconds' sleep before sending next messages
assert (send_times[0] + sleep_seconds[0]) < sleep_end_times[0]
assert (send_times[0] + sleep_seconds[0]) < send_times[1]
assert messages[1]['typing']
assert (send_times[1] + sleep_seconds[1]) < sleep_end_times[1]
assert (send_times[1] + sleep_seconds[1]) < send_times[2]
assert messages[2]['typing']
# at least 'seconds' sleep after last message
assert (send_times[2] + sleep_seconds[2]) < sleep_end_times[3]
assert not messages[3]['typing']