Skip to content
This repository has been archived by the owner on Sep 8, 2024. It is now read-only.

Commit

Permalink
Merge pull request #2951 from forslund/feature/then-wait-with-event-h…
Browse files Browse the repository at this point in the history
…andler

Use event handler to capture messages in then_wait()
  • Loading branch information
krisgesling authored Aug 5, 2021
2 parents e40530a + b40fcf0 commit 170ebc4
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 32 deletions.
2 changes: 0 additions & 2 deletions test/integrationtests/voight_kampff/features/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,11 @@ def after_all(context):
def after_feature(context, feature):
context.log.info('Result: {} ({:.2f}s)'.format(str(feature.status.name),
feature.duration))
sleep(1)


def after_scenario(context, scenario):
"""Wait for mycroft completion and reset any changed state."""
# TODO wait for skill handler complete
sleep(0.5)
wait_while_speaking()
context.bus.clear_all_messages()
context.matched_message = None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@
then_wait_fail)


TIMEOUT = 10
SLEEP_LENGTH = 0.25


def find_dialog(skill_path, dialog, lang):
"""Check the usual location for dialogs.
Expand Down Expand Up @@ -253,13 +249,10 @@ def then_user_follow_up(context, text):

@then('mycroft should send the message "{message_type}"')
def then_messagebus_message(context, message_type):
"""Set a timeout for the current Scenario."""
cnt = 0
while context.bus.get_messages(message_type) == []:
if cnt > int(TIMEOUT * (1.0 / SLEEP_LENGTH)):
assert False, "Message not found"
break
else:
cnt += 1

time.sleep(SLEEP_LENGTH)
"""Verify a specific message is sent."""
def check_dummy(message):
"""We are just interested in the message data, just the type."""
return True, ""

message_found, _ = then_wait(message_type, check_dummy, context)
assert message_found, "No matching message received."
143 changes: 127 additions & 16 deletions test/integrationtests/voight_kampff/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#
"""Common tools to use when creating step files for behave tests."""

from threading import Event
import time

from mycroft.audio.utils import wait_while_speaking
Expand All @@ -23,8 +24,129 @@
DEFAULT_TIMEOUT = 10


class CriteriaWaiter:
"""Wait for a message to meet a certain criteria.
Args:
msg_type: message type to watch
criteria_func: Function to determine if a message fulfilling the
test case has been found.
context: behave context
"""
def __init__(self, msg_type, criteria_func, context):
self.msg_type = msg_type
self.criteria_func = criteria_func
self.context = context
self.result = Event()

def reset(self):
"""Reset the wait state."""
self.result.clear()

# TODO: Remove in 21.08
def wait_unspecific(self, timeout):
"""
Wait for a specified time for criteria to be fulfilled by any message.
This use case is deprecated and only for backward compatibility
Args:
timeout: Time allowance for a message fulfilling the criteria, if
provided will override the normal normal step timeout.
Returns:
tuple (bool, str) test status and debug output
"""
timeout = timeout or self.context.step_timeout
start_time = time.monotonic()
debug = ''
while time.monotonic() < start_time + timeout:
for message in self.context.bus.get_messages(None):
status, test_dbg = self.criteria_func(message)
debug += test_dbg
if status:
self.context.matched_message = message
self.context.bus.remove_message(message)
return True, debug
self.context.bus.new_message_available.wait(0.5)
# Timed out return debug from test
return False, debug

def _check_historical_messages(self):
"""Search through the already received messages for a match.
Returns:
tuple (bool, str) test status and debug output
"""
debug = ''
for message in self.context.bus.get_messages(self.msg_type):
status, test_dbg = self.criteria_func(message)
debug += test_dbg
if status:
self.context.matched_message = message
self.context.bus.remove_message(message)
self.result.set()
break
return debug

def wait_specific(self, timeout=None):
"""Wait for a specific message type to fullfil a criteria.
Uses an event-handler to not repeatedly loop.
Args:
timeout: Time allowance for a message fulfilling the criteria, if
provided will override the normal normal step timeout.
Returns:
tuple (bool, str) test status and debug output
"""
timeout = timeout or self.context.step_timeout

debug = ''

def on_message(message):
nonlocal debug
status, test_dbg = self.criteria_func(message)
debug += test_dbg
if status:
self.context.matched_message = message
self.result.set()

self.context.bus.on(self.msg_type, on_message)
# Check historical messages
historical_debug = self._check_historical_messages()

# If no matching message was already caught, wait for it
if not self.result.is_set():
self.result.wait(timeout=timeout)
self.context.bus.remove(self.msg_type, on_message)
return self.result.is_set(), historical_debug + debug

def wait(self, timeout=None):
"""Wait for a specific message type to fullfil a criteria.
Uses an event-handler to not repeatedly loop.
Args:
timeout: Time allowance for a message fulfilling the criteria, if
provided will override the normal normal step timeout.
Returns:
(result (bool), debug (str)) Result containing status and debug
message.
"""
if self.msg_type is None:
return self.wait_unspecific(timeout)
else:
return self.wait_specific(timeout)


def then_wait(msg_type, criteria_func, context, timeout=None):
"""Wait for a specified time for criteria to be fulfilled.
"""Wait for a specific message type to fullfil a criteria.
Uses an event-handler to not repeatedly loop.
Args:
msg_type: message type to watch
Expand All @@ -35,22 +157,11 @@ def then_wait(msg_type, criteria_func, context, timeout=None):
provided will override the normal normal step timeout.
Returns:
tuple (bool, str) test status and debug output
(result (bool), debug (str)) Result containing status and debug
message.
"""
timeout = timeout or context.step_timeout
start_time = time.monotonic()
debug = ''
while time.monotonic() < start_time + timeout:
for message in context.bus.get_messages(msg_type):
status, test_dbg = criteria_func(message)
debug += test_dbg
if status:
context.matched_message = message
context.bus.remove_message(message)
return True, debug
context.bus.new_message_available.wait(0.5)
# Timed out return debug from test
return False, debug
waiter = CriteriaWaiter(msg_type, criteria_func, context)
return waiter.wait(timeout)


def then_wait_fail(msg_type, criteria_func, context, timeout=None):
Expand Down

0 comments on commit 170ebc4

Please sign in to comment.