794 lines
21 KiB
C++
794 lines
21 KiB
C++
|
/*
|
||
|
* Copyright (C) 2012 Open Source Robotics Foundation
|
||
|
*
|
||
|
* 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.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <unistd.h>
|
||
|
#include "gazebo/test/ServerFixture.hh"
|
||
|
|
||
|
using namespace gazebo;
|
||
|
|
||
|
class TransportTest : public ServerFixture
|
||
|
{
|
||
|
};
|
||
|
|
||
|
bool g_worldStatsMsg2 = false;
|
||
|
bool g_sceneMsg = false;
|
||
|
bool g_worldStatsMsg = false;
|
||
|
bool g_worldStatsDebugMsg = false;
|
||
|
bool g_stringMsg = false;
|
||
|
bool g_stringMsg2 = false;
|
||
|
bool g_stringMsg3 = false;
|
||
|
bool g_stringMsg4 = false;
|
||
|
int g_createdBeforePub = 0;
|
||
|
int g_noLatchCreatedAfterPub = 0;
|
||
|
int g_latchCreatedAfterPub = 0;
|
||
|
int g_latchCreatedAfterPub2 = 0;
|
||
|
int g_subBeforeClear = 0;
|
||
|
int g_subAfterClear = 0;
|
||
|
|
||
|
void ReceiveBeforeClear(ConstVector3dPtr &/*_msg*/)
|
||
|
{
|
||
|
g_subBeforeClear++;
|
||
|
}
|
||
|
|
||
|
void ReceiveAfterClear(ConstVector3dPtr &/*_msg*/)
|
||
|
{
|
||
|
g_subAfterClear++;
|
||
|
}
|
||
|
|
||
|
void ReceiveNoLatchCreatedAfterPub(ConstVector3dPtr &/*_msg*/)
|
||
|
{
|
||
|
g_noLatchCreatedAfterPub++;
|
||
|
}
|
||
|
|
||
|
void ReceiveLatchCreatedAfterPub2(ConstVector3dPtr &/*_msg*/)
|
||
|
{
|
||
|
g_latchCreatedAfterPub2++;
|
||
|
}
|
||
|
|
||
|
void ReceiveLatchCreatedAfterPub(ConstVector3dPtr &/*_msg*/)
|
||
|
{
|
||
|
g_latchCreatedAfterPub++;
|
||
|
}
|
||
|
|
||
|
void ReceiveCreatedBeforePub(ConstVector3dPtr &/*_msg*/)
|
||
|
{
|
||
|
g_createdBeforePub++;
|
||
|
}
|
||
|
|
||
|
void ReceiveStringMsg(ConstGzStringPtr &/*_msg*/)
|
||
|
{
|
||
|
g_stringMsg = true;
|
||
|
}
|
||
|
|
||
|
void ReceiveStringMsg2(ConstGzStringPtr &/*_msg*/)
|
||
|
{
|
||
|
g_stringMsg2 = true;
|
||
|
}
|
||
|
|
||
|
void ReceiveStringMsg3(ConstGzStringPtr &/*_msg*/)
|
||
|
{
|
||
|
g_stringMsg3 = true;
|
||
|
}
|
||
|
|
||
|
void ReceiveStringMsg4(ConstGzStringPtr &/*_msg*/)
|
||
|
{
|
||
|
g_stringMsg4 = true;
|
||
|
}
|
||
|
|
||
|
void ReceiveSceneMsg(ConstScenePtr &/*_msg*/)
|
||
|
{
|
||
|
g_sceneMsg = true;
|
||
|
}
|
||
|
|
||
|
void ReceiveWorldStatsMsg(ConstWorldStatisticsPtr &/*_msg*/)
|
||
|
{
|
||
|
g_worldStatsMsg = true;
|
||
|
}
|
||
|
|
||
|
void ReceiveWorldStatsMsg2(ConstWorldStatisticsPtr &/*_msg*/)
|
||
|
{
|
||
|
g_worldStatsMsg2 = true;
|
||
|
}
|
||
|
|
||
|
void ReceiveWorldStatsDebugMsg(ConstGzStringPtr &/*_data*/)
|
||
|
{
|
||
|
g_worldStatsDebugMsg = true;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
TEST_F(TransportTest, Load)
|
||
|
{
|
||
|
for (unsigned int i = 0; i < 2; ++i)
|
||
|
{
|
||
|
Load("worlds/empty.world");
|
||
|
Unload();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
// Standard pub/sub
|
||
|
TEST_F(TransportTest, PubSub)
|
||
|
{
|
||
|
Load("worlds/empty.world");
|
||
|
|
||
|
transport::NodePtr node = transport::NodePtr(new transport::Node());
|
||
|
node->Init();
|
||
|
transport::PublisherPtr scenePub = node->Advertise<msgs::Scene>("~/scene");
|
||
|
transport::SubscriberPtr sceneSub = node->Subscribe("~/scene",
|
||
|
&ReceiveSceneMsg);
|
||
|
|
||
|
msgs::Scene msg;
|
||
|
msgs::Init(msg, "test");
|
||
|
msg.set_name("default");
|
||
|
|
||
|
scenePub->Publish(msg);
|
||
|
|
||
|
std::vector<transport::PublisherPtr> pubs;
|
||
|
std::vector<transport::SubscriberPtr> subs;
|
||
|
|
||
|
for (unsigned int i = 0; i < 10; ++i)
|
||
|
{
|
||
|
pubs.push_back(node->Advertise<msgs::Scene>("~/scene"));
|
||
|
subs.push_back(node->Subscribe("~/scene", &ReceiveSceneMsg));
|
||
|
scenePub->Publish(msg);
|
||
|
}
|
||
|
|
||
|
pubs.clear();
|
||
|
subs.clear();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
TEST_F(TransportTest, DirectPublish)
|
||
|
{
|
||
|
Load("worlds/empty.world");
|
||
|
|
||
|
g_sceneMsg = false;
|
||
|
|
||
|
msgs::Scene msg;
|
||
|
msgs::Init(msg, "test");
|
||
|
msg.set_name("default");
|
||
|
|
||
|
transport::NodePtr node = transport::NodePtr(new transport::Node());
|
||
|
node->Init();
|
||
|
|
||
|
transport::SubscriberPtr sceneSub = node->Subscribe("~/scene",
|
||
|
&ReceiveSceneMsg);
|
||
|
transport::publish<msgs::Scene>("~/scene", msg);
|
||
|
|
||
|
// Not nice to time check here but 10 seconds should be 'safe' to check
|
||
|
// against
|
||
|
int timeout = 1000;
|
||
|
while (not g_sceneMsg)
|
||
|
{
|
||
|
common::Time::MSleep(10);
|
||
|
|
||
|
timeout--;
|
||
|
if (timeout == 0)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ASSERT_GT(timeout, 0) << "Not received a message in 10 seconds";
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void SinglePub()
|
||
|
{
|
||
|
transport::NodePtr node(new transport::Node());
|
||
|
node->Init();
|
||
|
|
||
|
transport::PublisherPtr pub = node->Advertise<msgs::GzString>("~/test");
|
||
|
|
||
|
msgs::GzString msg;
|
||
|
msg.set_data("Child process sending message.");
|
||
|
pub->Publish(msg);
|
||
|
}
|
||
|
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
// This test creates a child process to test interprocess communication
|
||
|
TEST_F(TransportTest, ThreadedSinglePubSub)
|
||
|
{
|
||
|
g_stringMsg = false;
|
||
|
|
||
|
Load("worlds/empty.world");
|
||
|
|
||
|
transport::NodePtr node(new transport::Node());
|
||
|
node->Init();
|
||
|
|
||
|
transport::SubscriberPtr sub =
|
||
|
node->Subscribe("~/test", &ReceiveStringMsg, true);
|
||
|
|
||
|
EXPECT_STREQ("gazebo.msgs.GzString",
|
||
|
node->GetMsgType("/gazebo/default/test").c_str());
|
||
|
|
||
|
boost::thread *thread = new boost::thread(boost::bind(&SinglePub));
|
||
|
|
||
|
for (int i = 0; i < 10 && !g_stringMsg; ++i)
|
||
|
common::Time::MSleep(100);
|
||
|
|
||
|
EXPECT_TRUE(g_stringMsg);
|
||
|
|
||
|
thread->join();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
TEST_F(TransportTest, ThreadedMultiSubSinglePub)
|
||
|
{
|
||
|
g_stringMsg = false;
|
||
|
g_stringMsg2 = false;
|
||
|
|
||
|
Load("worlds/empty.world");
|
||
|
|
||
|
transport::NodePtr node(new transport::Node());
|
||
|
node->Init();
|
||
|
|
||
|
transport::SubscriberPtr sub =
|
||
|
node->Subscribe("~/test", &ReceiveStringMsg, true);
|
||
|
|
||
|
transport::SubscriberPtr sub2 =
|
||
|
node->Subscribe("~/test", &ReceiveStringMsg2, true);
|
||
|
|
||
|
EXPECT_STREQ("gazebo.msgs.GzString",
|
||
|
node->GetMsgType("/gazebo/default/test").c_str());
|
||
|
|
||
|
boost::thread *thread = new boost::thread(boost::bind(&SinglePub));
|
||
|
|
||
|
for (int i = 0; i < 10 && !g_stringMsg && !g_stringMsg2; ++i)
|
||
|
common::Time::MSleep(100);
|
||
|
|
||
|
EXPECT_TRUE(g_stringMsg);
|
||
|
|
||
|
thread->join();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void MultiPub()
|
||
|
{
|
||
|
transport::NodePtr node(new transport::Node());
|
||
|
node->Init();
|
||
|
|
||
|
transport::PublisherPtr pub = node->Advertise<msgs::GzString>("~/test");
|
||
|
transport::PublisherPtr pub2 = node->Advertise<msgs::GzString>("~/test");
|
||
|
|
||
|
msgs::GzString msg;
|
||
|
msg.set_data("Child process sending message.");
|
||
|
pub->Publish(msg);
|
||
|
pub2->Publish(msg);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
TEST_F(TransportTest, ThreadedMultiPubSub)
|
||
|
{
|
||
|
g_stringMsg = false;
|
||
|
g_stringMsg2 = false;
|
||
|
|
||
|
Load("worlds/empty.world");
|
||
|
|
||
|
transport::NodePtr node(new transport::Node());
|
||
|
node->Init();
|
||
|
|
||
|
transport::SubscriberPtr sub =
|
||
|
node->Subscribe("~/test", &ReceiveStringMsg, true);
|
||
|
|
||
|
transport::SubscriberPtr sub2 =
|
||
|
node->Subscribe("~/test", &ReceiveStringMsg2, true);
|
||
|
|
||
|
EXPECT_STREQ("gazebo.msgs.GzString",
|
||
|
node->GetMsgType("/gazebo/default/test").c_str());
|
||
|
|
||
|
boost::thread *thread = new boost::thread(boost::bind(&MultiPub));
|
||
|
|
||
|
for (int i = 0; i < 10 && !g_stringMsg && !g_stringMsg2; ++i)
|
||
|
common::Time::MSleep(100);
|
||
|
|
||
|
EXPECT_TRUE(g_stringMsg);
|
||
|
|
||
|
thread->join();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void MultiPubSub()
|
||
|
{
|
||
|
transport::NodePtr node(new transport::Node());
|
||
|
node->Init("default");
|
||
|
|
||
|
transport::PublisherPtr pub = node->Advertise<msgs::GzString>("~/test");
|
||
|
transport::PublisherPtr pub2 = node->Advertise<msgs::GzString>("~/test");
|
||
|
|
||
|
transport::SubscriberPtr sub =
|
||
|
node->Subscribe("~/testO", &ReceiveStringMsg3, true);
|
||
|
|
||
|
transport::SubscriberPtr sub2 =
|
||
|
node->Subscribe("~/testO", &ReceiveStringMsg4, true);
|
||
|
|
||
|
EXPECT_STREQ("gazebo.msgs.GzString",
|
||
|
node->GetMsgType("/gazebo/default/testO").c_str());
|
||
|
|
||
|
msgs::GzString msg;
|
||
|
msg.set_data("Child process sending message.");
|
||
|
pub->Publish(msg);
|
||
|
pub2->Publish(msg);
|
||
|
|
||
|
int i = 0;
|
||
|
for (; i < 10 && (!g_stringMsg3 && !g_stringMsg4); ++i)
|
||
|
common::Time::MSleep(100);
|
||
|
|
||
|
EXPECT_TRUE(g_stringMsg3);
|
||
|
EXPECT_TRUE(g_stringMsg4);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
TEST_F(TransportTest, ThreadedMultiPubSubBidirectional)
|
||
|
{
|
||
|
Load("worlds/empty.world");
|
||
|
|
||
|
g_stringMsg = false;
|
||
|
g_stringMsg2 = false;
|
||
|
g_stringMsg3 = false;
|
||
|
g_stringMsg4 = false;
|
||
|
|
||
|
transport::NodePtr node(new transport::Node());
|
||
|
node->Init("default");
|
||
|
|
||
|
transport::SubscriberPtr sub =
|
||
|
node->Subscribe("~/test", &ReceiveStringMsg, true);
|
||
|
transport::SubscriberPtr sub2 =
|
||
|
node->Subscribe("~/test", &ReceiveStringMsg2, true);
|
||
|
|
||
|
transport::PublisherPtr pub = node->Advertise<msgs::GzString>("~/testO");
|
||
|
transport::PublisherPtr pub2 = node->Advertise<msgs::GzString>("~/testO");
|
||
|
|
||
|
EXPECT_STREQ("gazebo.msgs.GzString",
|
||
|
node->GetMsgType("/gazebo/default/test").c_str());
|
||
|
|
||
|
msgs::GzString msg;
|
||
|
msg.set_data("Parent send message");
|
||
|
pub->Publish(msg);
|
||
|
pub2->Publish(msg);
|
||
|
|
||
|
boost::thread *thread = new boost::thread(boost::bind(&MultiPubSub));
|
||
|
|
||
|
for (int i = 0; i < 10 && !g_stringMsg && !g_stringMsg2; ++i)
|
||
|
common::Time::MSleep(100);
|
||
|
|
||
|
EXPECT_TRUE(g_stringMsg);
|
||
|
EXPECT_TRUE(g_stringMsg2);
|
||
|
|
||
|
thread->join();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
TEST_F(TransportTest, PublicationTransportNoConnection)
|
||
|
{
|
||
|
Load("worlds/empty.world");
|
||
|
transport::PublicationTransport pubTransport("~/no_topic", "msg::Scene");
|
||
|
ASSERT_EQ("~/no_topic", pubTransport.GetTopic());
|
||
|
ASSERT_EQ("msg::Scene", pubTransport.GetMsgType());
|
||
|
|
||
|
ASSERT_NO_THROW(pubTransport.Fini());
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
TEST_F(TransportTest, PublicationTransportFiniConnection)
|
||
|
{
|
||
|
Load("worlds/empty.world");
|
||
|
transport::PublicationTransport pubTransport("~/no_topic", "msg::Scene");
|
||
|
ASSERT_EQ("~/no_topic", pubTransport.GetTopic());
|
||
|
ASSERT_EQ("msg::Scene", pubTransport.GetMsgType());
|
||
|
|
||
|
transport::ConnectionPtr conn(new transport::Connection);
|
||
|
ASSERT_NO_THROW(pubTransport.Init(conn, false));
|
||
|
|
||
|
ASSERT_NO_THROW(pubTransport.Fini());
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
TEST_F(TransportTest, IfaceGetMsgTyp)
|
||
|
{
|
||
|
Load("worlds/empty.world");
|
||
|
std::string type;
|
||
|
|
||
|
type = transport::getTopicMsgType("/gazebo/default/world_stats");
|
||
|
EXPECT_EQ(type, "gazebo.msgs.WorldStatistics");
|
||
|
|
||
|
type = transport::getTopicMsgType("garbage");
|
||
|
EXPECT_TRUE(type.empty());
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
TEST_F(TransportTest, IfaceGetTopicNameSpaces)
|
||
|
{
|
||
|
Load("worlds/empty.world");
|
||
|
std::list<std::string> ns;
|
||
|
|
||
|
transport::get_topic_namespaces(ns);
|
||
|
EXPECT_FALSE(ns.empty());
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
TEST_F(TransportTest, IfaceGetAdvertisedTopics)
|
||
|
{
|
||
|
Load("worlds/empty.world");
|
||
|
std::list<std::string> topics;
|
||
|
|
||
|
topics = transport::getAdvertisedTopics("");
|
||
|
EXPECT_FALSE(topics.empty());
|
||
|
|
||
|
topics = transport::getAdvertisedTopics("no_msgs_of_this_type");
|
||
|
EXPECT_TRUE(topics.empty());
|
||
|
|
||
|
topics = transport::getAdvertisedTopics("gazebo.msgs.WorldStatistics");
|
||
|
EXPECT_FALSE(topics.empty());
|
||
|
EXPECT_EQ(topics.size(), 1u);
|
||
|
|
||
|
topics = transport::getAdvertisedTopics("gazebo.msgs.PosesStamped");
|
||
|
EXPECT_FALSE(topics.empty());
|
||
|
EXPECT_EQ(topics.size(), 2u);
|
||
|
|
||
|
std::map<std::string, std::list<std::string> > topicMap =
|
||
|
transport::getAdvertisedTopics();
|
||
|
|
||
|
EXPECT_FALSE(topics.empty());
|
||
|
EXPECT_TRUE(topicMap.find("gazebo.msgs.PosesStamped") != topicMap.end());
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
// Test clearing buffers
|
||
|
TEST_F(TransportTest, ClearBuffers)
|
||
|
{
|
||
|
this->Load("worlds/empty.world");
|
||
|
|
||
|
// Check that transport is running and there are advertised topics
|
||
|
EXPECT_FALSE(transport::is_stopped());
|
||
|
EXPECT_TRUE(transport::ConnectionManager::Instance()->IsRunning());
|
||
|
EXPECT_FALSE(transport::getAdvertisedTopics().empty());
|
||
|
|
||
|
std::string fullTopic = "/gazebo/" + node->GetTopicNamespace() +
|
||
|
"/test_topic";
|
||
|
|
||
|
// Initialize transport node
|
||
|
auto node = transport::NodePtr(new transport::Node());
|
||
|
node->Init();
|
||
|
ASSERT_TRUE(node != NULL);
|
||
|
|
||
|
// Advertise publisher
|
||
|
auto pub = node->Advertise<msgs::Vector3d>(fullTopic);
|
||
|
ASSERT_TRUE(pub != NULL);
|
||
|
|
||
|
// Publish a message
|
||
|
msgs::Vector3d msg;
|
||
|
msg.set_x(1);
|
||
|
msg.set_y(2);
|
||
|
msg.set_z(3);
|
||
|
pub->Publish(msg);
|
||
|
|
||
|
// FIXME: Need to sleep a bit before creating the latched subscriber,
|
||
|
// otherwise it might receive the message twice.
|
||
|
common::Time::MSleep(100);
|
||
|
|
||
|
// Check that no messages have been received in callback yet
|
||
|
EXPECT_EQ(g_subBeforeClear, 0);
|
||
|
|
||
|
// Create a latched subscriber after publishing
|
||
|
auto subBeforeClear = node->Subscribe(fullTopic,
|
||
|
&ReceiveBeforeClear, true);
|
||
|
ASSERT_TRUE(subBeforeClear != NULL);
|
||
|
|
||
|
// Check that message is in buffer, since it's received by latched subscriber
|
||
|
int sleep = 0;
|
||
|
int maxSleep = 30;
|
||
|
while (g_subBeforeClear != 1 && sleep < maxSleep)
|
||
|
{
|
||
|
common::Time::MSleep(100);
|
||
|
sleep++;
|
||
|
}
|
||
|
EXPECT_EQ(g_subBeforeClear, 1);
|
||
|
|
||
|
// Clear buffers
|
||
|
transport::clear_buffers();
|
||
|
|
||
|
// Check that transport is still running
|
||
|
EXPECT_FALSE(transport::is_stopped());
|
||
|
EXPECT_TRUE(transport::ConnectionManager::Instance()->IsRunning());
|
||
|
EXPECT_FALSE(transport::getAdvertisedTopics().empty());
|
||
|
|
||
|
// Create another latched subscriber after publishing
|
||
|
auto subAfterClear = node->Subscribe(fullTopic, &ReceiveAfterClear, true);
|
||
|
ASSERT_TRUE(subAfterClear != NULL);
|
||
|
|
||
|
// Check that previous message is not received by new latched subscriber
|
||
|
sleep = 0;
|
||
|
while (g_subAfterClear != 1 && sleep < maxSleep)
|
||
|
{
|
||
|
common::Time::MSleep(100);
|
||
|
sleep++;
|
||
|
}
|
||
|
EXPECT_EQ(g_subBeforeClear, 1);
|
||
|
EXPECT_EQ(g_subAfterClear, 0);
|
||
|
|
||
|
pub.reset();
|
||
|
subBeforeClear.reset();
|
||
|
subAfterClear.reset();
|
||
|
node.reset();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
// Test latching
|
||
|
TEST_F(TransportTest, Latching)
|
||
|
{
|
||
|
this->Load("worlds/empty.world");
|
||
|
|
||
|
// Check that transport is running and there are advertised topics
|
||
|
EXPECT_FALSE(transport::is_stopped());
|
||
|
EXPECT_TRUE(transport::ConnectionManager::Instance()->IsRunning());
|
||
|
EXPECT_FALSE(transport::getAdvertisedTopics().empty());
|
||
|
|
||
|
// Check that our topic is not advertised yet
|
||
|
auto topics = transport::getAdvertisedTopics("gazebo.msgs.Vector3d");
|
||
|
EXPECT_TRUE(topics.empty());
|
||
|
|
||
|
// Initialize transport node
|
||
|
transport::NodePtr node1 = transport::NodePtr(new transport::Node());
|
||
|
node1->Init();
|
||
|
ASSERT_TRUE(node1 != NULL);
|
||
|
|
||
|
std::string fullTopic = "/gazebo/" + node1->GetTopicNamespace() +
|
||
|
"/test_topic";
|
||
|
|
||
|
// Create a non latched subscriber before publishing
|
||
|
auto subCreatedBeforePub = node1->Subscribe(fullTopic,
|
||
|
&ReceiveCreatedBeforePub);
|
||
|
ASSERT_TRUE(subCreatedBeforePub != NULL);
|
||
|
|
||
|
// Advertise publisher
|
||
|
auto pub1 = node1->Advertise<msgs::Vector3d>(fullTopic);
|
||
|
ASSERT_TRUE(pub1 != NULL);
|
||
|
|
||
|
// Check that topic has been advertised
|
||
|
topics = transport::getAdvertisedTopics("gazebo.msgs.Vector3d");
|
||
|
int sleep = 0;
|
||
|
int maxSleep = 30;
|
||
|
while (topics.empty() && sleep < maxSleep)
|
||
|
{
|
||
|
topics = transport::getAdvertisedTopics("gazebo.msgs.Vector3d");
|
||
|
common::Time::MSleep(100);
|
||
|
sleep++;
|
||
|
}
|
||
|
EXPECT_FALSE(topics.empty());
|
||
|
EXPECT_TRUE(std::find(topics.begin(), topics.end(),
|
||
|
fullTopic) != topics.end());
|
||
|
|
||
|
// Check no message has been received by subCreatedBeforePub
|
||
|
EXPECT_EQ(g_createdBeforePub, 0);
|
||
|
|
||
|
// Publish a message
|
||
|
msgs::Vector3d msg;
|
||
|
msg.set_x(1);
|
||
|
msg.set_y(2);
|
||
|
msg.set_z(3);
|
||
|
pub1->Publish(msg);
|
||
|
|
||
|
// Wait for message to be received
|
||
|
sleep = 0;
|
||
|
while (g_createdBeforePub != 1 && sleep < maxSleep)
|
||
|
{
|
||
|
common::Time::MSleep(100);
|
||
|
sleep++;
|
||
|
}
|
||
|
EXPECT_EQ(g_createdBeforePub, 1);
|
||
|
|
||
|
// Create a non latched subscriber after publishing
|
||
|
auto subNoLatchCreatedAfterPub = node1->Subscribe(fullTopic,
|
||
|
&ReceiveNoLatchCreatedAfterPub, false);
|
||
|
ASSERT_TRUE(subNoLatchCreatedAfterPub != NULL);
|
||
|
|
||
|
// Create a latched subscriber after publishing
|
||
|
auto subLatchCreatedAfterPub = node1->Subscribe(fullTopic,
|
||
|
&ReceiveLatchCreatedAfterPub, true);
|
||
|
ASSERT_TRUE(subLatchCreatedAfterPub != NULL);
|
||
|
|
||
|
// Wait for message to be received by latched subscriber
|
||
|
sleep = 0;
|
||
|
while (g_latchCreatedAfterPub != 1 && sleep < maxSleep)
|
||
|
{
|
||
|
common::Time::MSleep(100);
|
||
|
sleep++;
|
||
|
}
|
||
|
EXPECT_EQ(g_createdBeforePub, 1);
|
||
|
EXPECT_EQ(g_latchCreatedAfterPub, 1);
|
||
|
EXPECT_EQ(g_noLatchCreatedAfterPub, 0);
|
||
|
|
||
|
// Create another latched subscriber after publishing
|
||
|
auto subLatchCreatedAfterPub2 = node1->Subscribe(fullTopic,
|
||
|
&ReceiveLatchCreatedAfterPub2, true);
|
||
|
ASSERT_TRUE(subLatchCreatedAfterPub2 != NULL);
|
||
|
|
||
|
// Wait for message to be received only by new latched subscriber
|
||
|
sleep = 0;
|
||
|
while (g_latchCreatedAfterPub2 != 1 && sleep < maxSleep)
|
||
|
{
|
||
|
common::Time::MSleep(100);
|
||
|
sleep++;
|
||
|
}
|
||
|
EXPECT_EQ(g_createdBeforePub, 1);
|
||
|
EXPECT_EQ(g_latchCreatedAfterPub, 1);
|
||
|
EXPECT_EQ(g_noLatchCreatedAfterPub, 0);
|
||
|
EXPECT_EQ(g_latchCreatedAfterPub2, 1);
|
||
|
|
||
|
// Publish another message
|
||
|
msgs::Vector3d msg2;
|
||
|
msg2.set_x(4);
|
||
|
msg2.set_y(5);
|
||
|
msg2.set_z(6);
|
||
|
pub1->Publish(msg2);
|
||
|
|
||
|
// Wait for message to be received by all subscribers
|
||
|
sleep = 0;
|
||
|
while (g_latchCreatedAfterPub2 != 2 && sleep < maxSleep)
|
||
|
{
|
||
|
common::Time::MSleep(100);
|
||
|
sleep++;
|
||
|
}
|
||
|
EXPECT_EQ(g_createdBeforePub, 2);
|
||
|
EXPECT_EQ(g_latchCreatedAfterPub, 2);
|
||
|
EXPECT_EQ(g_noLatchCreatedAfterPub, 1);
|
||
|
EXPECT_EQ(g_latchCreatedAfterPub2, 2);
|
||
|
|
||
|
// Initialize another transport node
|
||
|
transport::NodePtr node2 = transport::NodePtr(new transport::Node());
|
||
|
node2->Init();
|
||
|
ASSERT_TRUE(node2 != NULL);
|
||
|
|
||
|
// Advertise another publisher
|
||
|
auto pub2 = node2->Advertise<msgs::Vector3d>(fullTopic);
|
||
|
ASSERT_TRUE(pub2 != NULL);
|
||
|
|
||
|
// Check that the subscribers didn't get latched messages again
|
||
|
sleep = 0;
|
||
|
while (sleep < maxSleep)
|
||
|
{
|
||
|
common::Time::MSleep(100);
|
||
|
sleep++;
|
||
|
}
|
||
|
EXPECT_EQ(g_createdBeforePub, 2);
|
||
|
EXPECT_EQ(g_latchCreatedAfterPub, 2);
|
||
|
EXPECT_EQ(g_noLatchCreatedAfterPub, 1);
|
||
|
EXPECT_EQ(g_latchCreatedAfterPub2, 2);
|
||
|
|
||
|
// Publish with new publisher
|
||
|
msgs::Vector3d msg3;
|
||
|
msg3.set_x(4);
|
||
|
msg3.set_y(5);
|
||
|
msg3.set_z(6);
|
||
|
pub2->Publish(msg3);
|
||
|
|
||
|
// Wait for message to be received
|
||
|
sleep = 0;
|
||
|
while (g_createdBeforePub != 3 && sleep < maxSleep)
|
||
|
{
|
||
|
common::Time::MSleep(100);
|
||
|
sleep++;
|
||
|
}
|
||
|
EXPECT_EQ(g_createdBeforePub, 3);
|
||
|
EXPECT_EQ(g_latchCreatedAfterPub, 3);
|
||
|
EXPECT_EQ(g_noLatchCreatedAfterPub, 2);
|
||
|
EXPECT_EQ(g_latchCreatedAfterPub2, 3);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
// Test error cases
|
||
|
// This test must be run after all the others, because it messes up
|
||
|
// GAZEO_MASTER_URI
|
||
|
TEST_F(TransportTest, Errors)
|
||
|
{
|
||
|
Load("worlds/empty.world");
|
||
|
transport::NodePtr testNode = transport::NodePtr(new transport::Node());
|
||
|
testNode->Init("default");
|
||
|
transport::PublisherPtr scenePub;
|
||
|
|
||
|
transport::SubscriberPtr statsSub =
|
||
|
testNode->Subscribe("~/world_stats", &ReceiveWorldStatsMsg);
|
||
|
EXPECT_STREQ("/gazebo/default/world_stats", statsSub->GetTopic().c_str());
|
||
|
|
||
|
// This generates a warning message
|
||
|
// EXPECT_THROW(testNode->Advertise<math::Vector3>("~/scene"),
|
||
|
// common::Exception);
|
||
|
|
||
|
scenePub = testNode->Advertise<msgs::Scene>("~/scene");
|
||
|
EXPECT_THROW(testNode->Advertise<msgs::Factory>("~/scene"),
|
||
|
common::Exception);
|
||
|
|
||
|
transport::PublisherPtr factoryPub =
|
||
|
testNode->Advertise<msgs::Factory>("~/factory");
|
||
|
factoryPub->WaitForConnection();
|
||
|
EXPECT_EQ(static_cast<unsigned int>(0), factoryPub->GetOutgoingCount());
|
||
|
EXPECT_STREQ("/gazebo/default/factory", factoryPub->GetTopic().c_str());
|
||
|
EXPECT_STREQ("gazebo.msgs.Factory", factoryPub->GetMsgType().c_str());
|
||
|
|
||
|
EXPECT_STREQ("default", testNode->GetTopicNamespace().c_str());
|
||
|
EXPECT_STREQ("/gazebo/default/factory",
|
||
|
testNode->DecodeTopicName("~/factory").c_str());
|
||
|
EXPECT_STREQ("~/factory",
|
||
|
testNode->EncodeTopicName("/gazebo/default/factory").c_str());
|
||
|
|
||
|
// Get the original URI
|
||
|
char *uri = getenv("GAZEBO_MASTER_URI");
|
||
|
std::string origURI = "GAZEBO_MASTER_URI=";
|
||
|
if (uri)
|
||
|
origURI += uri;
|
||
|
|
||
|
int i = 0;
|
||
|
while (!g_worldStatsMsg && !g_sceneMsg && !g_worldStatsDebugMsg && i < 20)
|
||
|
{
|
||
|
common::Time::MSleep(100);
|
||
|
++i;
|
||
|
}
|
||
|
EXPECT_LT(i, 20);
|
||
|
|
||
|
putenv(const_cast<char*>("GAZEBO_MASTER_URI="));
|
||
|
std::string masterHost;
|
||
|
unsigned int masterPort;
|
||
|
EXPECT_FALSE(transport::get_master_uri(masterHost, masterPort));
|
||
|
EXPECT_STREQ("localhost", masterHost.c_str());
|
||
|
EXPECT_EQ(static_cast<unsigned int>(11345), masterPort);
|
||
|
|
||
|
// restore original URI
|
||
|
putenv(const_cast<char*>(origURI.c_str()));
|
||
|
|
||
|
transport::clear_buffers();
|
||
|
transport::pause_incoming(true);
|
||
|
transport::TopicManager::Instance()->ProcessNodes();
|
||
|
transport::pause_incoming(false);
|
||
|
|
||
|
transport::stop();
|
||
|
EXPECT_TRUE(transport::init(masterHost, masterPort));
|
||
|
|
||
|
scenePub.reset();
|
||
|
statsSub.reset();
|
||
|
testNode.reset();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
TEST_F(TransportTest, TryInit)
|
||
|
{
|
||
|
// If the ConnectionManager has not been initialized, then TryInit() is
|
||
|
// certain to fail.
|
||
|
transport::NodePtr node = transport::NodePtr(new transport::Node);
|
||
|
EXPECT_FALSE(node->IsInitialized());
|
||
|
EXPECT_FALSE(node->TryInit(common::Time(0.01)));
|
||
|
EXPECT_FALSE(node->IsInitialized());
|
||
|
|
||
|
// Loading the server will initialize the ConnectionManager
|
||
|
this->Load("worlds/empty.world");
|
||
|
|
||
|
// The server will initialize some Nodes, so a namespace will be available now
|
||
|
EXPECT_FALSE(node->IsInitialized());
|
||
|
EXPECT_TRUE(node->TryInit(common::Time(0.01)));
|
||
|
EXPECT_TRUE(node->IsInitialized());
|
||
|
|
||
|
// The namespace of the Node should match the name of the world that we loaded
|
||
|
EXPECT_EQ(physics::get_world()->GetName(), node->GetTopicNamespace());
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
// Main
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
::testing::InitGoogleTest(&argc, argv);
|
||
|
return RUN_ALL_TESTS();
|
||
|
}
|