diff --git a/launch_testing/launch_testing/__init__.py b/launch_testing/launch_testing/__init__.py index 54bd71d6a..6e4892fd5 100644 --- a/launch_testing/launch_testing/__init__.py +++ b/launch_testing/launch_testing/__init__.py @@ -26,8 +26,10 @@ class InMemoryHandler(LineOutput): :param filtered_prefixes: A list of byte strings representing prefixes that will cause output lines to be ignored if they start with one of the prefixes. By default lines starting with the process ID (`b'pid'`) and return code (`b'rc'`) will be ignored. + :param filtered_patterns: A list of byte strings representing regexes that will cause output + lines to be ignored if they match one of the regexes. :param filtered_rmw_implementation: RMW implementation for which the output will be ignored - in addition to the default/`filtered_prefixes`. + in addition to the `filtered_prefixes`/`filtered_patterns`. :param exit_on_match: If True, then when its output is matched, this handler will terminate; otherwise it will simply keep track of the match. :raises: :py:class:`UnmatchedOutputError` if :py:meth:`check` does not find that the output @@ -40,17 +42,18 @@ class InMemoryHandler(LineOutput): def __init__( self, name, launch_descriptor, expected_lines, regex_match=False, - filtered_prefixes=None, filtered_rmw_implementation=None, exit_on_match=True + filtered_prefixes=None, filtered_patterns=None, filtered_rmw_implementation=None, + exit_on_match=True, ): super(LineOutput, self).__init__() - if filtered_prefixes is None: - self.filtered_prefixes = get_default_filtered_prefixes() - else: - self.filtered_prefixes = filtered_prefixes + self.filtered_prefixes = filtered_prefixes or get_default_filtered_prefixes() + self.filtered_patterns = filtered_patterns or get_default_filtered_patterns() if filtered_rmw_implementation: - rmw_output_filter = get_rmw_output_filter(filtered_rmw_implementation) - self.filtered_prefixes.extend(rmw_output_filter) + self.filtered_prefixes.extend( + get_rmw_output_filter(filtered_rmw_implementation, 'prefixes')) + self.filtered_patterns.extend( + get_rmw_output_filter(filtered_rmw_implementation, 'patterns')) self.name = name self.launch_descriptor = launch_descriptor @@ -70,8 +73,11 @@ def on_stdout_lines(self, lines): for line in lines.splitlines(): # Filter out stdout that comes from underlying DDS implementation + # Note: we do not currently support matching filters across multiple stdout lines. if any(line.startswith(prefix) for prefix in self.filtered_prefixes): continue + if any(re.match(pattern, line) for pattern in self.filtered_patterns): + continue self.stdout_data.write(line + b'\n') if not self.regex_match and not self.matched: output_lines = self.stdout_data.getvalue().splitlines() @@ -112,21 +118,30 @@ def get_default_filtered_prefixes(): ] -def get_rmw_output_filter(rmw_implementation): +def get_default_filtered_patterns(): + return [] + + +def get_rmw_output_filter(rmw_implementation, filter_type): + supported_filter_types = ['prefixes', 'patterns'] + if filter_type not in supported_filter_types: + raise TypeError( + 'Unsupported filter_type "{0}". Supported types: {1}' + .format(filter_type, supported_filter_types)) + resource_name = 'rmw_output_' + filter_type prefix_with_resource = ament_index_python.has_resource( - 'rmw_output_filter', rmw_implementation) + resource_name, rmw_implementation) if not prefix_with_resource: return [] - rmw_output_filter, _ = ament_index_python.get_resource('rmw_output_filter', rmw_implementation) - additional_filtered_prefixes = [ - str.encode(l) for l in rmw_output_filter.splitlines()] - return additional_filtered_prefixes + # Treat each line of the resource as an independent filter. + rmw_output_filter, _ = ament_index_python.get_resource(resource_name, rmw_implementation) + return [str.encode(l) for l in rmw_output_filter.splitlines()] def create_handler( name, launch_descriptor, output_file, exit_on_match=True, filtered_prefixes=None, - filtered_rmw_implementation=None + filtered_patterns=None, filtered_rmw_implementation=None ): literal_file = output_file + '.txt' if os.path.isfile(literal_file): @@ -134,7 +149,8 @@ def create_handler( expected_output = f.read().splitlines() return InMemoryHandler( name, launch_descriptor, expected_output, regex_match=False, - exit_on_match=exit_on_match, filtered_prefixes=filtered_prefixes, + exit_on_match=exit_on_match, + filtered_prefixes=filtered_prefixes, filtered_patterns=filtered_patterns, filtered_rmw_implementation=filtered_rmw_implementation) regex_file = output_file + '.regex' if os.path.isfile(regex_file): @@ -142,7 +158,8 @@ def create_handler( expected_output = f.read().splitlines() return InMemoryHandler( name, launch_descriptor, expected_output, regex_match=True, - exit_on_match=exit_on_match, filtered_prefixes=filtered_prefixes, + exit_on_match=exit_on_match, + filtered_prefixes=filtered_prefixes, filtered_patterns=filtered_patterns, filtered_rmw_implementation=filtered_rmw_implementation) py_file = output_file + '.py' if os.path.isfile(py_file):