diff --git a/tests/lettuce/features/multi_instance.feature b/tests/lettuce/features/multi_instance.feature index 3660f5836d..e8130d6f5b 100644 --- a/tests/lettuce/features/multi_instance.feature +++ b/tests/lettuce/features/multi_instance.feature @@ -7,7 +7,11 @@ Feature: Multiple instances Given I have bind10 running with configuration multi_instance/multi_auth.config And wait for bind10 stderr message BIND10_STARTED_CC And wait for bind10 stderr message CMDCTL_STARTED - And wait for bind10 stderr message AUTH_SERVER_STARTED + + # This is a hack. We should actually check if b10-auth and + # b10-auth-2 are started by name. But there's currently no way + # for a component to find out its name and log it. + And wait 2 times for bind10 stderr message AUTH_SERVER_STARTED bind10 module Auth should be running And bind10 module Resolver should not be running diff --git a/tests/lettuce/features/terrain/steps.py b/tests/lettuce/features/terrain/steps.py index 49ac3eedb8..8df0bae1b8 100644 --- a/tests/lettuce/features/terrain/steps.py +++ b/tests/lettuce/features/terrain/steps.py @@ -30,12 +30,13 @@ def stop_a_named_process(step, process_name): """ world.processes.stop_process(process_name) -@step('wait for (new )?(\w+) stderr message (\w+)(?: not (\w+))?') -def wait_for_stderr_message(step, new, process_name, message, not_message): +@step('wait (?:(\d+) times )?for (new )?(\w+) stderr message (\w+)(?: not (\w+))?') +def wait_for_stderr_message(step, times, new, process_name, message, not_message): """ Block until the given message is printed to the given process's stderr output. Parameter: + times: Check for the string this many times. new: (' new', optional): Only check the output printed since last time this step was used for this process. process_name (' stderr'): Name of the process to check the output of. @@ -46,16 +47,19 @@ def wait_for_stderr_message(step, new, process_name, message, not_message): strings = [message] if not_message is not None: strings.append(not_message) - (found, line) = world.processes.wait_for_stderr_str(process_name, strings, new) + if times is None: + times = 1 + (found, line) = world.processes.wait_for_stderr_str(process_name, strings, new, int(times)) if not_message is not None: assert found != not_message, line -@step('wait for (new )?(\w+) stdout message (\w+)(?: not (\w+))?') -def wait_for_stdout_message(step, new, process_name, message, not_message): +@step('wait (?:(\d+) times )?for (new )?(\w+) stdout message (\w+)(?: not (\w+))?') +def wait_for_stdout_message(step, times, new, process_name, message, not_message): """ Block until the given message is printed to the given process's stdout output. Parameter: + times: Check for the string this many times. new: (' new', optional): Only check the output printed since last time this step was used for this process. process_name (' stderr'): Name of the process to check the output of. @@ -66,7 +70,9 @@ def wait_for_stdout_message(step, new, process_name, message, not_message): strings = [message] if not_message is not None: strings.append(not_message) - (found, line) = world.processes.wait_for_stdout_str(process_name, strings, new) + if times is None: + times = 1 + (found, line) = world.processes.wait_for_stdout_str(process_name, strings, new, int(times)) if not_message is not None: assert found != not_message, line diff --git a/tests/lettuce/features/terrain/terrain.py b/tests/lettuce/features/terrain/terrain.py index a2721026cf..753d912591 100644 --- a/tests/lettuce/features/terrain/terrain.py +++ b/tests/lettuce/features/terrain/terrain.py @@ -166,7 +166,7 @@ class RunningProcess: os.remove(self.stderr_filename) os.remove(self.stdout_filename) - def _wait_for_output_str(self, filename, running_file, strings, only_new): + def _wait_for_output_str(self, filename, running_file, strings, only_new, matches = 1): """ Wait for a line of output in this process. This will (if only_new is False) first check all previous output from the process, and if not @@ -180,18 +180,22 @@ class RunningProcess: strings: Array of strings to look for. only_new: If true, only check output since last time this method was called. If false, first check earlier output. + matches: Check for the string this many times. Returns a tuple containing the matched string, and the complete line it was found in. Fails if none of the strings was read after 10 seconds (OUTPUT_WAIT_INTERVAL * OUTPUT_WAIT_MAX_INTERVALS). """ + match_count = 0 if not only_new: full_file = open(filename, "r") for line in full_file: for string in strings: if line.find(string) != -1: - full_file.close() - return (string, line) + match_count += 1 + if match_count >= matches: + full_file.close() + return (string, line) wait_count = 0 while wait_count < OUTPUT_WAIT_MAX_INTERVALS: where = running_file.tell() @@ -199,42 +203,46 @@ class RunningProcess: if line: for string in strings: if line.find(string) != -1: - return (string, line) + match_count += 1 + if match_count >= matches: + return (string, line) else: wait_count += 1 time.sleep(OUTPUT_WAIT_INTERVAL) running_file.seek(where) assert False, "Timeout waiting for process output: " + str(strings) - def wait_for_stderr_str(self, strings, only_new = True): + def wait_for_stderr_str(self, strings, only_new = True, matches = 1): """ Wait for one of the given strings in this process's stderr output. Parameters: strings: Array of strings to look for. only_new: If true, only check output since last time this method was called. If false, first check earlier output. + matches: Check for the string this many times. Returns a tuple containing the matched string, and the complete line it was found in. Fails if none of the strings was read after 10 seconds (OUTPUT_WAIT_INTERVAL * OUTPUT_WAIT_MAX_INTERVALS). """ return self._wait_for_output_str(self.stderr_filename, self.stderr, - strings, only_new) + strings, only_new, matches) - def wait_for_stdout_str(self, strings, only_new = True): + def wait_for_stdout_str(self, strings, only_new = True, matches = 1): """ Wait for one of the given strings in this process's stdout output. Parameters: strings: Array of strings to look for. only_new: If true, only check output since last time this method was called. If false, first check earlier output. + matches: Check for the string this many times. Returns a tuple containing the matched string, and the complete line it was found in. Fails if none of the strings was read after 10 seconds (OUTPUT_WAIT_INTERVAL * OUTPUT_WAIT_MAX_INTERVALS). """ return self._wait_for_output_str(self.stdout_filename, self.stdout, - strings, only_new) + strings, only_new, matches) # Container class for a number of running processes # i.e. servers like bind10, etc @@ -300,7 +308,7 @@ class RunningProcesses: for process in self.processes.values(): process.remove_files_on_exit = False - def wait_for_stderr_str(self, process_name, strings, only_new = True): + def wait_for_stderr_str(self, process_name, strings, only_new = True, matches = 1): """ Wait for one of the given strings in the given process's stderr output. Parameters: @@ -308,6 +316,7 @@ class RunningProcesses: strings: Array of strings to look for. only_new: If true, only check output since last time this method was called. If false, first check earlier output. + matches: Check for the string this many times. Returns the matched string. Fails if none of the strings was read after 10 seconds (OUTPUT_WAIT_INTERVAL * OUTPUT_WAIT_MAX_INTERVALS). @@ -316,9 +325,10 @@ class RunningProcesses: assert process_name in self.processes,\ "Process " + process_name + " unknown" return self.processes[process_name].wait_for_stderr_str(strings, - only_new) + only_new, + matches) - def wait_for_stdout_str(self, process_name, strings, only_new = True): + def wait_for_stdout_str(self, process_name, strings, only_new = True, matches = 1): """ Wait for one of the given strings in the given process's stdout output. Parameters: @@ -326,6 +336,7 @@ class RunningProcesses: strings: Array of strings to look for. only_new: If true, only check output since last time this method was called. If false, first check earlier output. + matches: Check for the string this many times. Returns the matched string. Fails if none of the strings was read after 10 seconds (OUTPUT_WAIT_INTERVAL * OUTPUT_WAIT_MAX_INTERVALS). @@ -334,7 +345,8 @@ class RunningProcesses: assert process_name in self.processes,\ "Process " + process_name + " unknown" return self.processes[process_name].wait_for_stdout_str(strings, - only_new) + only_new, + matches) @before.each_scenario def initialize(scenario):