Example #1
0
    def setUpClass(cls):
        # It's easier to actually capture some IO from the launch system than it is to fake it
        # but it takes a few seconds.  We'll do it once and run tests on the same captured
        # IO

        proc_env = os.environ.copy()
        proc_env['PYTHONUNBUFFERED'] = '1'

        cls.proc_output = ActiveIoHandler()

        cls.proc_1 = launch.actions.ExecuteProcess(cmd=TEST_CMD,
                                                   name='terminating_proc',
                                                   env=proc_env)

        # This process should be distinguishable by its cmd line args
        cls.proc_2 = launch.actions.ExecuteProcess(cmd=TEST_CMD + ['--extra'],
                                                   name='terminating_proc',
                                                   env=proc_env)

        # This process should be distinguishable by its different name
        cls.proc_3 = launch.actions.ExecuteProcess(cmd=TEST_CMD +
                                                   ['node:=different_name'],
                                                   name='terminating_proc',
                                                   env=proc_env)

        launch_description = launch.LaunchDescription([
            cls.proc_1,
            cls.proc_2,
            cls.proc_3,
            # This plumbs all the output to our IoHandler just like the LaunchTestRunner does
            RegisterEventHandler(
                OnProcessStart(on_start=lambda event, _: cls.proc_output.track(
                    event.process_name))),
            RegisterEventHandler(
                OnProcessIO(
                    on_stdout=cls.proc_output.append,
                    on_stderr=cls.proc_output.append,
                ))
        ])

        launch_service = launch.LaunchService()
        launch_service.include_launch_description(launch_description)
        launch_service.run()
Example #2
0
    def setUpClass(cls):
        # It's easier to actually capture some IO from the launch system than it is to fake it
        # but it takes a few seconds.  We'll do it once and run tests on the same captured
        # IO

        proc_env = os.environ.copy()
        proc_env["PYTHONUNBUFFERED"] = "1"

        cls.proc_output = ActiveIoHandler()

        cls.proc_1 = launch.actions.ExecuteProcess(
            cmd=[TEST_PROC_PATH],
            env=proc_env
        )

        # This process should be distinguishable by its cmd line args
        cls.proc_2 = launch.actions.ExecuteProcess(
            cmd=[TEST_PROC_PATH, '--extra'],
            env=proc_env
        )

        # This process should be distinguishable by its different name
        cls.proc_3 = launch.actions.ExecuteProcess(
            cmd=[TEST_PROC_PATH, 'node:=different_name'],
            env=proc_env
        )

        launch_description = launch.LaunchDescription([
            cls.proc_1,
            cls.proc_2,
            cls.proc_3,
            # This plumbs all the output to our IoHandler just like the ApexRunner does
            RegisterEventHandler(
                OnProcessIO(
                    on_stdout=cls.proc_output.append,
                    on_stderr=cls.proc_output.append,
                )
            )
        ])

        launch_service = launch.LaunchService()
        launch_service.include_launch_description(launch_description)
        launch_service.run()
Example #3
0
    def setUpClass(cls):
        # It's easier to actually capture some IO from the launch system than it is to fake it
        # but it takes a few seconds.  We'll do it once and run tests on the same captured
        # IO

        node_env = os.environ.copy()
        node_env["PYTHONUNBUFFERED"] = "1"

        cls.proc_output = ActiveIoHandler()

        cls.node_1 = Node(package='apex_rostest',
                          node_executable='terminating_node',
                          env=node_env)

        # This node should be distinguishable by its cmd line args
        cls.node_2 = Node(package='apex_rostest',
                          node_executable='terminating_node',
                          arguments=['--extra'],
                          env=node_env)

        # This node should be distinguishable by its diffetent node name
        cls.node_3 = Node(package='apex_rostest',
                          node_executable='terminating_node',
                          node_name='different_name',
                          env=node_env)

        launch_description = LaunchDescription([
            cls.node_1,
            cls.node_2,
            cls.node_3,
            # This plumbs all the output to our IoHandler just like the ApexRunner does
            RegisterEventHandler(
                OnProcessIO(
                    on_stdout=cls.proc_output.append,
                    on_stderr=cls.proc_output.append,
                ))
        ])

        launch_service = LaunchService()
        launch_service.include_launch_description(launch_description)
        launch_service.run()
Example #4
0
    def run(self):
        """
        Launch the processes under test and run the tests.

        :return: A tuple of two unittest.Results - one for tests that ran while processes were
        active, and another set for tests that ran after processes were shutdown
        """
        test_ld, test_context = _normalize_ld(self._gen_launch_description_fn)(
            lambda: self._processes_launched.set())

        # Data to squirrel away for post-shutdown tests
        self.proc_info = ActiveProcInfoHandler()
        self.proc_output = ActiveIoHandler()
        self.test_context = test_context
        parsed_launch_arguments = parse_launch_arguments(
            self._launch_file_arguments)
        self.test_args = {}
        for k, v in parsed_launch_arguments:
            self.test_args[k] = v

        # Wrap the test_ld in another launch description so we can bind command line arguments to
        # the test and add our own event handlers for process IO and process exit:
        launch_description = LaunchDescription([
            launch.actions.IncludeLaunchDescription(
                launch.LaunchDescriptionSource(launch_description=test_ld),
                launch_arguments=parsed_launch_arguments),
            RegisterEventHandler(
                OnProcessExit(
                    on_exit=lambda info, unused: self.proc_info.append(info))),
            RegisterEventHandler(
                OnProcessIO(
                    on_stdout=self.proc_output.append,
                    on_stderr=self.proc_output.append,
                )),
        ])

        self._launch_service.include_launch_description(launch_description)

        self._test_tr.start()  # Run the tests on another thread
        self._launch_service.run(
        )  # This will block until the test thread stops it

        if not self._tests_completed.wait(timeout=0):
            # LaunchService.run returned before the tests completed.  This can be because the user
            # did ctrl+c, or because all of the launched nodes died before the tests completed
            print("Processes under test stopped before tests completed")
            self._print_process_output_summary(
            )  # <-- Helpful to debug why processes died early
            # We treat this as a test failure and return some test results indicating such
            return FailResult(), FailResult()

        # Now, run the post-shutdown tests
        inactive_suite = PostShutdownTestLoader(
            injected_attributes={
                "proc_info": self.proc_info,
                "proc_output": self.proc_output._io_handler,
                "test_args": self.test_args,
            },
            injected_args=dict(
                self.test_context,
                # Add a few more things to the args dictionary:
                **{
                    "proc_info": self.proc_info,
                    "proc_output": self.proc_output._io_handler,
                    "test_args": self.test_args
                })).loadTestsFromModule(self._test_module)
        inactive_results = unittest.TextTestRunner(
            verbosity=2, resultclass=TestResult).run(inactive_suite)

        return self._results, inactive_results
Example #5
0
    def add_output_test(
        self,
        launch_description,
        action,
        output_test,
        test_suffix='output',
        output_filter=None,
        side_effect=None,
    ):
        """
        Test an action process' output against a given test.

        :param launch_description: test launch description that owns the given action.
        :param action: launch action to test whose output is to be tested.
        :param output_test: test tuple as returned by launch_testing.output.create_* functions.
        :param test_suffix: an optional test suffix to disambiguate multiple test instances,
        defaults to 'output'.
        :param output_filter: an optional function to filter out i.e. ignore output lines for
        the test.
        :param side_effect: an optional side effect of a passing test, currently only 'shutdown'
        is supported.
        """
        assert isinstance(action, ExecuteProcess)
        test_name = 'test_{}_{}'.format(id(action), test_suffix)
        out, collate_output, match_output, match_patterns = output_test
        if not output_filter:
            output_filter = (lambda x: x)
        assert any(match_patterns)

        def on_process_exit(event, context):
            nonlocal match_patterns
            if any(match_patterns):
                # Finish test instead of failing to prevent process exit
                # and process output event handlers from racing.
                return self._finish(test_name)

        launch_description.add_action(
            RegisterEventHandler(
                OnProcessExit(target_action=action, on_exit=on_process_exit)))

        def on_shutdown(event, context):
            nonlocal match_patterns
            if any(match_patterns):
                process_name = action.process_details['name']
                reason = 'not all {} output matched!'.format(process_name)
                self._fail(test_name, reason)
            self._succeed(test_name, side_effect)

        launch_description.add_action(
            RegisterEventHandler(OnShutdown(on_shutdown=on_shutdown)))

        def on_process_stdout(event):
            nonlocal out
            nonlocal match_patterns

            out = collate_output(out, output_filter(event.text))
            match_patterns = [
                pattern for pattern in match_patterns
                if not match_output(out, pattern)
            ]
            if not any(match_patterns):
                return self._succeed(test_name, side_effect)
            return None

        launch_description.add_action(
            RegisterEventHandler(
                OnProcessIO(target_action=action,
                            on_stdout=on_process_stdout)))
        self._arm(test_name)

        return action
Example #6
0
    def run(self):
        """
        Launch the processes under test and run the tests.

        :return: A tuple of two unittest.Results - one for tests that ran while processes were
        active, and another set for tests that ran after processes were shutdown
        """
        test_ld, test_context = self._test_run.normalized_test_description(
            ready_fn=lambda: self._processes_launched.set())

        # Data that needs to be bound to the tests:
        proc_info = ActiveProcInfoHandler()
        proc_output = ActiveIoHandler()
        full_context = dict(test_context, **self._test_run.param_args)
        # TODO pete: this can be simplified as a call to the dict ctor:
        parsed_launch_arguments = parse_launch_arguments(
            self._launch_file_arguments)
        test_args = {}

        for k, v in parsed_launch_arguments:
            test_args[k] = v

        self._test_run.bind(
            self._test_run.pre_shutdown_tests,
            injected_attributes={
                'proc_info': proc_info,
                'proc_output': proc_output,
                'test_args': test_args,
            },
            injected_args=dict(
                full_context,
                # Add a few more things to the args dictionary:
                **{
                    'proc_info': proc_info,
                    'proc_output': proc_output,
                    'test_args': test_args
                }))
        self._test_run.bind(
            self._test_run.post_shutdown_tests,
            injected_attributes={
                'proc_info': proc_info._proc_info_handler,
                'proc_output': proc_output._io_handler,
                'test_args': test_args,
            },
            injected_args=dict(
                full_context,
                # Add a few more things to the args dictionary:
                **{
                    'proc_info': proc_info._proc_info_handler,
                    'proc_output': proc_output._io_handler,
                    'test_args': test_args
                }))

        # Wrap the test_ld in another launch description so we can bind command line arguments to
        # the test and add our own event handlers for process IO and process exit:
        launch_description = LaunchDescription([
            launch.actions.IncludeLaunchDescription(
                launch.LaunchDescriptionSource(launch_description=test_ld),
                launch_arguments=parsed_launch_arguments),
            RegisterEventHandler(
                OnProcessExit(
                    on_exit=lambda info, unused: proc_info.append(info))),
            RegisterEventHandler(
                OnProcessIO(
                    on_stdout=proc_output.append,
                    on_stderr=proc_output.append,
                )),
        ])

        self._launch_service.include_launch_description(launch_description)

        self._test_tr.start()  # Run the tests on another thread
        self._launch_service.run(
        )  # This will block until the test thread stops it

        if not self._tests_completed.wait(timeout=0):
            # LaunchService.run returned before the tests completed.  This can be because the user
            # did ctrl+c, or because all of the launched nodes died before the tests completed
            print('Processes under test stopped before tests completed')
            # Give some extra help debugging why processes died early
            self._print_process_output_summary(proc_info, proc_output)
            # We treat this as a test failure and return some test results indicating such
            raise _LaunchDiedException()

        inactive_results = unittest.TextTestRunner(
            verbosity=2,
            resultclass=TestResult).run(self._test_run.post_shutdown_tests)

        self._results.append(inactive_results)

        return self._results
Example #7
0
    def run(self):
        """
        Launch the nodes under test and run the tests.

        :return: A tuple of two unittest.Results - one for tests that ran while nodes were
        active, and another set for tests that ran after nodes were shutdown
        """
        test_ld = self._gen_launch_description_fn(
            lambda: self._nodes_launched.set())

        # Data to squirrel away for post-shutdown tests
        self.proc_info = ActiveProcInfoHandler()
        self.proc_output = ActiveIoHandler()
        parsed_launch_arguments = parse_launch_arguments(
            self._launch_file_arguments)
        self.test_args = {}
        for k, v in parsed_launch_arguments:
            self.test_args[k] = v

        # Wrap the test_ld in another launch description so we can bind command line arguments to
        # the test and add our own event handlers for process IO and process exit:
        launch_description = LaunchDescription([
            launch.actions.IncludeLaunchDescription(
                launch.LaunchDescriptionSource(launch_description=test_ld),
                launch_arguments=parsed_launch_arguments),
            RegisterEventHandler(
                OnProcessExit(
                    on_exit=lambda info, unused: self.proc_info.append(info))),
            RegisterEventHandler(
                OnProcessIO(
                    on_stdout=self.proc_output.append,
                    on_stderr=self.proc_output.append,
                )),
        ])

        self._launch_service.include_launch_description(launch_description)

        self._test_tr.start()  # Run the tests on another thread
        self._launch_service.run(
        )  # This will block until the test thread stops it

        if not self._tests_completed.wait(timeout=0):
            # LaunchService.run returned before the tests completed.  This can be because the user
            # did ctrl+c, or because all of the launched nodes died before the tests completed

            # We should treat this as a test failure and return some test results indicating such
            print("Nodes under test stopped before tests completed")
            # TODO: This will make the program exit with an exit code, but it's not apparent
            # why.  Consider having apex_rostest_main print some summary
            return _fail_result(), _fail_result()

        # Now, run the post-shutdown tests
        inactive_suite = PostShutdownTestLoader().loadTestsFromModule(
            self._test_module)
        self._give_attribute_to_tests(self.proc_info, "proc_info",
                                      inactive_suite)
        self._give_attribute_to_tests(self.proc_output._io_handler,
                                      "proc_output", inactive_suite)
        self._give_attribute_to_tests(self.test_args, "test_args",
                                      inactive_suite)
        inactive_results = unittest.TextTestRunner(
            verbosity=2, resultclass=TestResult).run(inactive_suite)

        return self._results, inactive_results
Example #8
0
def generate_launch_description():
    timeout = LaunchConfiguration("timeout", default=10.0)
    scenario = LaunchConfiguration("scenario", default="")
    scenario_package = LaunchConfiguration("package",
                                           default="cpp_mock_scenarios")
    junit_path = LaunchConfiguration("junit_path",
                                     default="/tmp/output.xunit.xml")
    launch_rviz = LaunchConfiguration("launch_rviz", default=False)
    scenario_node = Node(
        package=scenario_package,
        executable=scenario,
        name=scenario,
        output="screen",
        arguments=[("__log_level:=info")],
        parameters=[{
            "junit_path": junit_path,
            "timeout": timeout
        }],
    )
    io_handler = OnProcessIO(
        target_action=scenario_node,
        on_stderr=on_stderr_output,
        on_stdout=on_stdout_output,
    )
    shutdown_handler = OnProcessExit(target_action=scenario_node,
                                     on_exit=[EmitEvent(event=Shutdown())])
    description = LaunchDescription([
        DeclareLaunchArgument("scenario",
                              default_value=scenario,
                              description="Name of the scenario."),
        DeclareLaunchArgument(
            "package",
            default_value=scenario_package,
            description="Name of package your scenario exists",
        ),
        DeclareLaunchArgument("timeout",
                              default_value=timeout,
                              description="Timeout in seconds."),
        DeclareLaunchArgument(
            "junit_path",
            default_value=junit_path,
            description="Path of the junit output.",
        ),
        DeclareLaunchArgument(
            "launch_rviz",
            default_value=launch_rviz,
            description="If true, launch with rviz.",
        ),
        scenario_node,
        RegisterEventHandler(event_handler=io_handler),
        RegisterEventHandler(event_handler=shutdown_handler),
        Node(
            package="simple_sensor_simulator",
            executable="simple_sensor_simulator_node",
            name="simple_sensor_simulator_node",
            output="log",
            arguments=[("__log_level:=warn")],
        ),
        Node(
            package="openscenario_visualization",
            executable="openscenario_visualization_node",
            name="openscenario_visualization_node",
            output="screen",
        ),
        Node(
            package="rviz2",
            executable="rviz2",
            name="rviz2",
            output={
                "stderr": "log",
                "stdout": "log"
            },
            condition=IfCondition(launch_rviz),
            arguments=[
                "-d",
                str(
                    Path(get_package_share_directory("cpp_mock_scenarios")) /
                    "rviz/mock_test.rviz"),
            ],
        ),
    ])
    return description