Program Listing for File testing_utils.hpp
↰ Return to documentation for file (/tmp/ws/src/gazebo_ros_pkgs/gazebo_ros/include/gazebo_ros/testing_utils.hpp
)
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef GAZEBO_ROS__TESTING_UTILS_HPP_
#define GAZEBO_ROS__TESTING_UTILS_HPP_
#include <unistd.h>
#include <stdlib.h>
#include <gtest/gtest.h>
#include <rclcpp/rclcpp.hpp>
#include <utility>
#include <vector>
#include <string>
namespace gazebo_ros
{
class GazeboProcess
{
public:
explicit GazeboProcess(const std::vector<const char *> & args);
~GazeboProcess();
int Run();
int Terminate();
private:
std::vector<const char *> arguments;
// pid of gzserver
int pid_ = -1;
};
GazeboProcess::GazeboProcess(const std::vector<const char *> & args)
{
arguments = {"/usr/bin/gzserver", "--verbose"};
arguments.insert(arguments.end(), args.begin(), args.end());
arguments.push_back(nullptr);
}
GazeboProcess::~GazeboProcess()
{
Terminate();
}
int GazeboProcess::Run()
{
// Fork process so gazebo can be run as child
pid_ = fork();
// Child process
if (0 == pid_) {
// Run gazebo with arguments
if (execvp("gzserver", const_cast<char **>(arguments.data()))) {
// Exec failed, cannot return (in separate process), so just print errno
printf("gzserver failed with errno=%d", errno);
exit(1);
}
}
if (pid_ < 0) {
return errno;
}
// Parent process, return pid of child (or error produced by fork())
return pid_;
}
int GazeboProcess::Terminate()
{
// Return -1
if (pid_ < 0) {
return ECHILD;
}
// Kill gazebo (simulating ^C command)
if (kill(pid_, SIGINT)) {
return errno;
}
// Wait for gazebo to terminate
if (waitpid(pid_, nullptr, 0) < 0) {
return errno;
}
return 0;
}
template<typename T>
typename T::SharedPtr
get_message_or_timeout(
rclcpp::Node::SharedPtr node, const std::string & topic,
rclcpp::Duration timeout = rclcpp::Duration(10, 0))
{
rclcpp::Clock clock;
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(node);
std::atomic_bool msg_received(false);
typename T::SharedPtr msg = nullptr;
auto sub = node->create_subscription<T>(
topic, rclcpp::QoS(rclcpp::KeepLast(1)).transient_local(),
[&msg_received, &msg](typename T::SharedPtr _msg) {
// If this is the first message from this topic, increment the counter
if (!msg_received.exchange(true)) {
msg = _msg;
}
});
// Wait for topic to be available
using namespace std::literals::chrono_literals; // NOLINT
auto timeout_absolute = clock.now() + timeout * 0.5;
while (node->count_publishers(topic) == 0) {
executor.spin_once(200ms);
}
EXPECT_GT(node->count_publishers(topic), 0u);
// Wait until message is received or timeout occurs
timeout_absolute = clock.now() + timeout * 0.5;
while (false == msg_received && clock.now() < timeout_absolute) {
executor.spin_once(200ms);
}
return msg;
}
} // namespace gazebo_ros
#endif // GAZEBO_ROS__TESTING_UTILS_HPP_