This commit is contained in:
Ivan
2022-04-05 11:42:28 +03:00
commit 6dc0eb0fcf
5565 changed files with 1200500 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import unittest
import rosunit
import sys
import time
import subprocess
class ConnectionCount(unittest.TestCase):
def test_connection_count(self):
# Wait while the recorder creates a bag for us to examine
time.sleep(10.0)
# Check the connection count returned by `rosbag info`
# We could probably do this through the rosbag Python API...
cmd = ['rosbag', 'info',
'/tmp/test_rosbag_record_two_publishers.bag',
'-y', '-k', 'topics']
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out,err = p.communicate()
self.assertEqual(p.returncode, 0, 'Failed to check bag\ncmd=%s\nstdout=%s\nstderr=%s'%(cmd,out,err))
conns = False
for l in out.decode().split('\n'):
f = l.strip().split(': ')
if len(f) == 2 and f[0] == 'connections':
conns = int(f[1])
break
self.assertEqual(conns, 2)
if __name__ == '__main__':
rosunit.unitrun('test_rosbag', 'connection_count', ConnectionCount, sys.argv)

View File

@@ -0,0 +1,22 @@
#include <ros/ros.h>
#include <std_msgs/String.h>
int
main(int argc, char** argv)
{
ros::init(argc, argv, "double_pub");
ros::NodeHandle n;
ros::Publisher p1 = n.advertise<std_msgs::String>("chatter", 1);
ros::Publisher p2 = n.advertise<std_msgs::String>("rettahc", 1);
ros::Rate r(10.0);
while(ros::ok())
{
std_msgs::String s;
s.data = "hello";
p1.publish(s);
s.data = "goodbye";
p2.publish(s);
}
return 0;
}

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import unittest
import rospy
import rostest
import sys
from std_msgs.msg import *
class LatchedPub(unittest.TestCase):
def test_latched_pub(self):
rospy.init_node('latched_pub')
# Wait a while before publishing
rospy.sleep(rospy.Duration.from_sec(5.0))
pub= rospy.Publisher("chatter", String, latch=True)
pub.publish(String("hello"))
rospy.sleep(rospy.Duration.from_sec(5.0))
if __name__ == '__main__':
rostest.rosrun('test_rosbag', 'latched_pub', LatchedPub, sys.argv)

View File

@@ -0,0 +1,4 @@
<launch>
<node name="recorder" pkg="rosbag" type="record" args="chatter -O /tmp/test_rosbag_latched_pub"/>
<test test-name="latched_pub" pkg="test_rosbag" type="latched_pub.py"/>
</launch>

View File

@@ -0,0 +1,60 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
import unittest
import rospy
import rostest
import sys
from std_msgs.msg import *
class LatchedSub(unittest.TestCase):
def msg_cb(self, msg):
self.success = True
def test_latched_sub(self):
rospy.init_node('random_sub')
self.success = False
rospy.sleep(rospy.Duration.from_sec(5.0))
sub = rospy.Subscriber("chatter", String, self.msg_cb)
rospy.sleep(rospy.Duration.from_sec(5.0))
self.assertEqual(self.success, True)
if __name__ == '__main__':
rostest.rosrun('rosbag', 'lateched_sub', LatchedSub, sys.argv)

View File

@@ -0,0 +1,4 @@
<launch>
<node name="player" pkg="rosbag" type="play" args="@PROJECT_BINARY_DIR@/test/test_rosbag_latched_pub.bag --keep-alive"/>
<test test-name="latched_sub" pkg="test_rosbag" type="latched_sub.py"/>
</launch>

View File

@@ -0,0 +1,9 @@
<launch>
<node name="player" pkg="rosbag" type="play" args="@PROJECT_BINARY_DIR@/test/chatter_50hz.bag"/>
<test test-name="play_hztest" pkg="rostest" type="hztest">
<param name="topic" value="chatter"/>
<param name="hz" value="50.0"/>
<param name="hzerror" value="5"/>
<param name="test_duration" value="7.0" />
</test>
</launch>

View File

@@ -0,0 +1,7 @@
<launch>
<node pkg="test_rosbag" type="double_pub" name="double_pub"/>
<node name="recorder" pkg="rosbag" type="record" output="screen"
args="chatter rettahc -O /tmp/test_rosbag_record_one_publisher_two_topics --duration=5"/>
<test test-name="topic_count" pkg="test_rosbag" type="topic_count.py"/>
</launch>

View File

@@ -0,0 +1,10 @@
<launch>
<node pkg="rostopic" type="rostopic" name="rostopic_pub1"
args="pub -r 10 chatter std_msgs/String chatter1"/>
<node pkg="rostopic" type="rostopic" name="rostopic_pub2"
args="pub -r 10 chatter std_msgs/String chatter2"/>
<node name="recorder" pkg="rosbag" type="record"
args="chatter -O /tmp/test_rosbag_record_two_publishers --duration=5"/>
<test test-name="connection_count" pkg="test_rosbag" type="connection_count.py"/>
</launch>

View File

@@ -0,0 +1,9 @@
<launch>
<node name="player" pkg="rosbag" type="rosbag" args="play @PROJECT_BINARY_DIR@/test/chatter_50hz.bag"/>
<test test-name="rosbag_play_hztest" pkg="rostest" type="hztest">
<param name="topic" value="chatter"/>
<param name="hz" value="50.0"/>
<param name="hzerror" value="5"/>
<param name="test_duration" value="7.0" />
</test>
</launch>

View File

@@ -0,0 +1,657 @@
// Copyright (c) 2010, Willow Garage, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of Willow Garage, Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include "ros/ros.h"
#include "rosbag/bag.h"
#include "rosbag/chunked_file.h"
#include "rosbag/view.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <iostream>
#include <set>
#include <boost/assign/list_of.hpp>
#include <boost/foreach.hpp>
#include <gtest/gtest.h>
#include "std_msgs/String.h"
#include "std_msgs/Int32.h"
#define foreach BOOST_FOREACH
class BagTest : public testing::Test
{
protected:
std_msgs::String foo_, bar_;
std_msgs::Int32 i_;
virtual void SetUp() {
foo_.data = std::string("foo");
bar_.data = std::string("bar");
i_.data = 42;
}
void dumpContents(std::string const& filename) {
rosbag::Bag b;
b.open(filename, rosbag::bagmode::Read);
dumpContents(b);
b.close();
}
void dumpContents(rosbag::Bag& b) {
rosbag::View view(b);
foreach(rosbag::MessageInstance m, view)
std::cout << m.getTime() << ": [" << m.getTopic() << "]" << std::endl;
}
void checkContents(std::string const& filename) {
rosbag::Bag b;
b.open(filename, rosbag::bagmode::Read);
int message_count = 0;
rosbag::View view(b);
foreach(rosbag::MessageInstance m, view) {
std_msgs::String::ConstPtr s = m.instantiate<std_msgs::String>();
if (s != NULL) {
ASSERT_EQ(s->data, foo_.data);
message_count++;
}
std_msgs::Int32::ConstPtr i = m.instantiate<std_msgs::Int32>();
if (i != NULL) {
ASSERT_EQ(i->data, i_.data);
message_count++;
}
}
ASSERT_EQ(message_count, 2);
b.close();
}
};
TEST_F(BagTest, write_then_read_works) {
std::string filename("/tmp/write_then_read_works.bag");
rosbag::Bag b1;
b1.open(filename, rosbag::bagmode::Write);
b1.write("chatter", ros::Time::now(), foo_);
b1.write("numbers", ros::Time::now(), i_);
b1.close();
checkContents(filename);
}
TEST_F(BagTest, append_works) {
std::string filename("/tmp/append_works.bag");
rosbag::Bag b1;
b1.open(filename, rosbag::bagmode::Write);
b1.write("chatter", ros::Time::now(), foo_);
b1.close();
rosbag::Bag b2;
b2.open(filename, rosbag::bagmode::Append);
b2.write("numbers", ros::Time::now(), i_);
b2.close();
checkContents(filename);
}
TEST_F(BagTest, different_writes) {
std::string filename("/tmp/different_writes.bag");
rosbag::Bag b1;
b1.open(filename, rosbag::bagmode::Write | rosbag::bagmode::Read);
std_msgs::String msg1;
std_msgs::String::Ptr msg2 = boost::make_shared<std_msgs::String>();
std_msgs::String::ConstPtr msg3 = boost::make_shared<std_msgs::String const>();
rosbag::View view;
view.addQuery(b1);
b1.write("t1", ros::Time::now(), msg1);
b1.write("t2", ros::Time::now(), msg2);
b1.write("t3", ros::Time::now(), msg3);
b1.write("t4", ros::Time::now(), *view.begin());
ASSERT_EQ(view.size(), (uint32_t)(4));
b1.close();
}
TEST_F(BagTest, reopen_works) {
rosbag::Bag b;
std::string filename1("/tmp/reopen_works1.bag");
b.open(filename1, rosbag::bagmode::Write);
b.write("chatter", ros::Time::now(), foo_);
b.write("numbers", ros::Time::now(), i_);
b.close();
std::string filename2("/tmp/reopen_works1.bag");
b.open(filename2, rosbag::bagmode::Write);
b.write("chatter", ros::Time::now(), foo_);
b.write("numbers", ros::Time::now(), i_);
b.close();
checkContents(filename1);
checkContents(filename2);
}
TEST_F(BagTest, bag_not_open_fails) {
rosbag::Bag b;
try
{
b.write("/test", ros::Time::now(), foo_);
FAIL();
}
catch (rosbag::BagIOException ex) {
SUCCEED();
}
}
TEST(rosbag, simple_write_and_read_works) {
rosbag::Bag b1("/tmp/simple_write_and_read_works.bag", rosbag::bagmode::Write);
std_msgs::String str;
str.data = std::string("foo");
std_msgs::Int32 i;
i.data = 42;
b1.write("chatter", ros::Time::now(), str);
b1.write("numbers", ros::Time::now(), i);
b1.close();
rosbag::Bag b2("/tmp/simple_write_and_read_works.bag", rosbag::bagmode::Read);
std::vector<std::string> topics;
topics.push_back(std::string("chatter"));
topics.push_back(std::string("numbers"));
int count = 0;
rosbag::View view(b2, rosbag::TopicQuery(topics));
foreach(rosbag::MessageInstance const m, view) {
std_msgs::String::ConstPtr s = m.instantiate<std_msgs::String>();
if (s != NULL)
{
count++;
ASSERT_EQ(s->data, std::string("foo"));
}
std_msgs::Int32::ConstPtr i = m.instantiate<std_msgs::Int32>();
if (i != NULL)
{
count++;
ASSERT_EQ(i->data, 42);
}
}
ASSERT_EQ(count,2);
b2.close();
}
TEST(rosbag, append_indexed_1_2_fails) {
try{
rosbag::Bag b("@PROJECT_BINARY_DIR@/test/test_indexed_1.2.bag", rosbag::bagmode::Append);
FAIL();
}
catch (rosbag::BagException ex) {
SUCCEED();
}
}
TEST(rosbag, read_indexed_1_2_succeeds) {
rosbag::Bag b("@PROJECT_BINARY_DIR@/test/test_indexed_1.2.bag", rosbag::bagmode::Read);
rosbag::View view(b);
int32_t i = 0;
foreach(rosbag::MessageInstance const m, view) {
std_msgs::Int32::ConstPtr imsg = m.instantiate<std_msgs::Int32>();
if (imsg != NULL)
ASSERT_EQ(imsg->data, i++);
}
b.close();
}
TEST(rosbag, write_then_read_without_read_mode_fails) {
rosbag::Bag b("/tmp/write_then_read_without_read_mode_fails.bag", rosbag::bagmode::Write);
std_msgs::String str;
str.data = std::string("foo");
b.write("chatter", ros::Time::now(), str);
try
{
rosbag::View view(b);
foreach(rosbag::MessageInstance const m, view) {
std_msgs::String::ConstPtr s = m.instantiate<std_msgs::String>();
if (s != NULL)
ASSERT_EQ(s->data, std::string("foo"));
}
FAIL();
}
catch (rosbag::BagException ex) {
SUCCEED();
}
}
TEST_F(BagTest, read_then_write_without_write_mode_fails) {
rosbag::Bag b1("/tmp/read_then_write_without_write_mode_fails.bag", rosbag::bagmode::Write);
b1.write("chatter", ros::Time::now(), foo_);
b1.close();
rosbag::Bag b2("/tmp/read_then_write_without_write_mode_fails.bag", rosbag::bagmode::Read);
try
{
b2.write("chatter", ros::Time::now(), foo_);
FAIL();
}
catch (rosbag::BagException ex) {
SUCCEED();
}
}
TEST(rosbag, time_query_works) {
rosbag::Bag outbag;
outbag.open("/tmp/time_query_works.bag", rosbag::bagmode::Write);
std_msgs::Int32 imsg;
for (int i = 0; i < 1000; i++) {
imsg.data = i;
switch (rand() % 5) {
case 0: outbag.write("t0", ros::Time(i, 1), imsg); break;
case 1: outbag.write("t1", ros::Time(i, 1), imsg); break;
case 2: outbag.write("t2", ros::Time(i, 1), imsg); break;
case 3: outbag.write("t2", ros::Time(i, 1), imsg); break;
case 4: outbag.write("t4", ros::Time(i, 1), imsg); break;
}
}
outbag.close();
rosbag::Bag bag;
bag.open("/tmp/time_query_works.bag", rosbag::bagmode::Read);
int i = 23;
rosbag::View view(bag, ros::Time(23, 1), ros::Time(782, 1));
foreach(rosbag::MessageInstance const m, view) {
std_msgs::Int32::ConstPtr imsg = m.instantiate<std_msgs::Int32>();
if (imsg != NULL) {
ASSERT_EQ(imsg->data, i++);
ASSERT_TRUE(m.getTime() < ros::Time(783,0));
}
}
bag.close();
}
TEST(rosbag, topic_query_works) {
rosbag::Bag outbag;
outbag.open("/tmp/topic_query_works.bag", rosbag::bagmode::Write);
std_msgs::Int32 imsg;
int j0 = 0;
int j1 = 0;
for (int i = 0; i < 10; i++) {
switch (rand() % 5) {
case 0: imsg.data = j0++; outbag.write("t0", ros::Time(i, 1), imsg); break;
case 1: imsg.data = j0++; outbag.write("t1", ros::Time(i, 1), imsg); break;
case 2: imsg.data = j1++; outbag.write("t2", ros::Time(i, 1), imsg); break;
case 3: imsg.data = j1++; outbag.write("t3", ros::Time(i, 1), imsg); break;
case 4: imsg.data = j1++; outbag.write("t4", ros::Time(i, 1), imsg); break;
}
}
outbag.close();
rosbag::Bag bag;
bag.open("/tmp/topic_query_works.bag", rosbag::bagmode::Read);
std::vector<std::string> t = boost::assign::list_of("t0")("t1");
int i = 0;
rosbag::View view(bag, rosbag::TopicQuery(t));
foreach(rosbag::MessageInstance const m, view) {
std_msgs::Int32::ConstPtr imsg = m.instantiate<std_msgs::Int32>();
if (imsg != NULL)
ASSERT_EQ(imsg->data, i++);
}
bag.close();
}
TEST(rosbag, bad_topic_query_works) {
rosbag::Bag outbag;
outbag.open("/tmp/bad_topic_query_works.bag", rosbag::bagmode::Write);
std_msgs::Int32 imsg;
for (int i = 0; i < 10; i++) {
outbag.write("t0", ros::Time(i, 1), imsg);
}
outbag.close();
rosbag::Bag bag;
bag.open("/tmp/bad_topic_query_works.bag", rosbag::bagmode::Read);
std::vector<std::string> t = boost::assign::list_of("t1");
rosbag::View view(bag, rosbag::TopicQuery(t));
foreach(rosbag::MessageInstance const m, view) {
(void)m;
FAIL();
}
bag.close();
}
//This test fails on the storm machines
/*
TEST(rosbag, incremental_time) {
ros::Time last = ros::Time::now();
ros::Time next = ros::Time::now();
for (int i = 0; i < 1000; i++) {
next = ros::Time::now();
ASSERT_TRUE(last != next);
last = next;
}
}
*/
TEST(rosbag, multiple_bag_works) {
rosbag::Bag outbag1("/tmp/multiple_bag_works1.bag", rosbag::bagmode::Write);
rosbag::Bag outbag2("/tmp/multiple_bag_works2.bag", rosbag::bagmode::Write);
std_msgs::Int32 imsg;
for (int i = 0; i < 1000; i++) {
imsg.data = i;
switch (rand() % 5) {
case 0: outbag1.write("t0", ros::Time(0,i+1), imsg); break;
case 1: outbag1.write("t1", ros::Time(0,i+1), imsg); break;
case 2: outbag1.write("t2", ros::Time(0,i+1), imsg); break;
case 3: outbag2.write("t0", ros::Time(0,i+1), imsg); break;
case 4: outbag2.write("t1", ros::Time(0,i+1), imsg); break;
}
}
outbag1.close();
outbag2.close();
rosbag::Bag bag1("/tmp/multiple_bag_works1.bag", rosbag::bagmode::Read);
rosbag::Bag bag2("/tmp/multiple_bag_works2.bag", rosbag::bagmode::Read);
rosbag::View view;
view.addQuery(bag1);
view.addQuery(bag2);
int i = 0;
foreach(rosbag::MessageInstance const m, view) {
std_msgs::Int32::ConstPtr imsg = m.instantiate<std_msgs::Int32>();
if (imsg != NULL)
ASSERT_EQ(imsg->data, i++);
}
bag1.close();
bag2.close();
}
TEST(rosbag, overlapping_query_works) {
rosbag::Bag outbag1("/tmp/overlapping_query_1.bag", rosbag::bagmode::Write);
rosbag::Bag outbag2("/tmp/overlapping_query_2.bag", rosbag::bagmode::Write);
std_msgs::Int32 imsg;
for (int i = 0; i < 1000; i++) {
imsg.data = i;
switch (rand() % 5) {
case 0: outbag1.write("t0", ros::Time(i+1), imsg); break;
case 1: outbag1.write("t1", ros::Time(i+1), imsg); break;
case 2: outbag1.write("t2", ros::Time(i+1), imsg); break;
case 3: outbag2.write("t0", ros::Time(i+1), imsg); break;
case 4: outbag2.write("t1", ros::Time(i+1), imsg); break;
}
}
outbag1.close();
outbag2.close();
rosbag::Bag bag1("/tmp/overlapping_query_1.bag", rosbag::bagmode::Read);
rosbag::Bag bag2("/tmp/overlapping_query_2.bag", rosbag::bagmode::Read);
rosbag::View view1(false);
view1.addQuery(bag1, ros::Time(1), ros::Time(750));
view1.addQuery(bag1, ros::Time(251), ros::Time(1002));
view1.addQuery(bag2, ros::Time(1), ros::Time(750));
view1.addQuery(bag2, ros::Time(251), ros::Time(1002));
rosbag::View view2(true);
view2.addQuery(bag1, ros::Time(1), ros::Time(750));
view2.addQuery(bag1, ros::Time(251), ros::Time(1002));
view2.addQuery(bag2, ros::Time(1), ros::Time(750));
view2.addQuery(bag2, ros::Time(251), ros::Time(1002));
int i = 0;
int j = 0;
foreach(rosbag::MessageInstance const m, view1) {
std_msgs::Int32::ConstPtr imsg = m.instantiate<std_msgs::Int32>();
if (imsg != NULL)
ASSERT_EQ(imsg->data, i);
if (i >= 250 && i < 750)
{
i += (j++ % 2);
} else {
i++;
}
}
i = 0;
foreach(rosbag::MessageInstance const m, view2) {
std_msgs::Int32::ConstPtr imsg = m.instantiate<std_msgs::Int32>();
if (imsg != NULL)
ASSERT_EQ(imsg->data, i++);
}
bag1.close();
bag2.close();
}
TEST(rosbag, no_min_time) {
rosbag::Bag outbag("/tmp/no_min_time.bag", rosbag::bagmode::Write);
std_msgs::Int32 imsg;
try
{
outbag.write("t0", ros::Time(0,0), imsg);
FAIL();
} catch (rosbag::BagException& e)
{
SUCCEED();
}
outbag.close();
}
TEST(rosbag, modify_view_works) {
rosbag::Bag outbag;
outbag.open("/tmp/modify_view_works.bag", rosbag::bagmode::Write);
std_msgs::Int32 imsg;
int j0 = 0;
int j1 = 1;
// Create a bag with 2 interlaced topics
for (int i = 0; i < 100; i++) {
imsg.data = j0;
j0 += 2;
outbag.write("t0", ros::Time(2 * i + 1, 0), imsg);
imsg.data = j1;
j1 += 2;
outbag.write("t1", ros::Time(2 * i + 2, 0), imsg);
}
outbag.close();
rosbag::Bag bag;
bag.open("/tmp/modify_view_works.bag", rosbag::bagmode::Read);
std::vector<std::string> t0 = boost::assign::list_of("t0");
std::vector<std::string> t1 = boost::assign::list_of("t1");
// We're going to skip the t1 for the first half
j0 = 0;
j1 = 101;
rosbag::View view(bag, rosbag::TopicQuery(t0));
rosbag::View::iterator iter = view.begin();
for (int i = 0; i < 50; i++) {
std_msgs::Int32::ConstPtr imsg = iter->instantiate<std_msgs::Int32>();
if (imsg != NULL) {
ASSERT_EQ(imsg->data, j0);
j0 += 2;
}
iter++;
}
// We now add our query, and expect it to show up
view.addQuery(bag, rosbag::TopicQuery(t1));
for (int i = 0; i < 50; i++) {
std_msgs::Int32::ConstPtr imsg = iter->instantiate<std_msgs::Int32>();
if (imsg != NULL) {
ASSERT_EQ(imsg->data, j0);
j0 += 2;
}
iter++;
imsg = iter->instantiate<std_msgs::Int32>();
if (imsg != NULL) {
ASSERT_EQ(imsg->data, j1);
j1 += 2;
}
iter++;
}
bag.close();
}
TEST(rosbag, modify_bag_works) {
rosbag::Bag rwbag("/tmp/modify_bag_works.bag", rosbag::bagmode::Write | rosbag::bagmode::Read);
rwbag.setChunkThreshold(1);
std::vector<std::string> t0 = boost::assign::list_of("t0");
rosbag::View view(rwbag, rosbag::TopicQuery(t0));
std_msgs::Int32 omsg;
// Put a message at time 5
omsg.data = 5;
rwbag.write("t0", ros::Time(5 + 1, 0), omsg);
// Verify begin gets us to 5
rosbag::View::iterator iter1 = view.begin();
std_msgs::Int32::ConstPtr imsg = iter1->instantiate<std_msgs::Int32>();
ASSERT_EQ(imsg->data, 5);
for (int i = 0; i < 5; i++) {
omsg.data = i;
rwbag.write("t0", ros::Time(i + 1, 0), omsg);
}
// New iterator should be at 0
rosbag::View::iterator iter2 = view.begin();
imsg = iter2->instantiate<std_msgs::Int32>();
ASSERT_EQ(imsg->data, 0);
// Increment it once
iter2++;
// Output additional messages after time 5
for (int i = 6; i < 10; i++) {
omsg.data = i;
rwbag.write("t0", ros::Time(i + 1, 0), omsg);
}
// Iter2 should contain 1->10
for (int i = 1; i < 10; i++) {
imsg = iter2->instantiate<std_msgs::Int32>();
ASSERT_EQ(imsg->data, i);
iter2++;
}
// Iter1 should contain 5->10
for (int i = 5; i < 10; i++) {
imsg = iter1->instantiate<std_msgs::Int32>();
ASSERT_EQ(imsg->data, i);
iter1++;
}
rwbag.close();
rosbag::Bag rwbag2("/tmp/modify_bag_works.bag", rosbag::bagmode::Read);
rosbag::View view2(rwbag2, rosbag::TopicQuery(t0));
rosbag::View::iterator iter3 = view2.begin();
imsg = iter3->instantiate<std_msgs::Int32>();
// Iter2 should contain 1->10
for (int i = 0; i < 10; i++) {
imsg = iter3->instantiate<std_msgs::Int32>();
ASSERT_EQ(imsg->data, i);
iter3++;
}
}
int main(int argc, char **argv) {
ros::init(argc, argv, "test_bag");
ros::Time::init();
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,438 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# test_bag.py
import hashlib
import heapq
import os
import shutil
import sys
import tempfile
import time
import unittest
import genpy
import rosbag
from rosbag import bag
import rospy
from std_msgs.msg import Int32
from std_msgs.msg import ColorRGBA
from std_msgs.msg import String
class TestRosbag(unittest.TestCase):
def setUp(self):
pass
def test_opening_stream_works(self):
f = open('/tmp/test_opening_stream_works.bag', 'wb')
with rosbag.Bag(f, 'w') as b:
for i in range(10):
msg = Int32()
msg.data = i
b.write('/int', msg)
f = open('/tmp/test_opening_stream_works.bag', 'rb')
b = rosbag.Bag(f, 'r')
self.assert_(len(list(b.read_messages())) == 10)
b.close()
def test_invalid_bag_arguments_fails(self):
f = '/tmp/test_invalid_bad_arguments_fails.bag'
def fn1(): rosbag.Bag('')
def fn2(): rosbag.Bag(None)
def fn3(): rosbag.Bag(f, 'z')
def fn4(): rosbag.Bag(f, 'r', compression='foobar')
def fn5(): rosbag.Bag(f, 'r', chunk_threshold=-1000)
for fn in [fn1, fn2, fn3, fn4, fn5]:
self.failUnlessRaises(ValueError, fn)
def test_io_on_close_fails(self):
def fn():
b = rosbag.Bag('/tmp/test_io_close_fails.bag', 'w')
b.close()
size = b.size()
self.failUnlessRaises(ValueError, fn)
def test_write_invalid_message_fails(self):
def fn():
with rosbag.Bag('/tmp/test_write_invalid_message_fails.bag', 'w') as b:
b.write(None, None, None)
self.failUnlessRaises(ValueError, fn)
def test_simple_write_uncompressed_works(self):
with rosbag.Bag('/tmp/test_simple_write_uncompressed_works.bag', 'w') as b:
msg_count = 0
for i in range(5, 0, -1):
msg = Int32()
msg.data = i
t = genpy.Time.from_sec(i)
b.write('/ints' + str(i), msg, t)
msg_count += 1
msgs = list(rosbag.Bag('/tmp/test_simple_write_uncompressed_works.bag').read_messages())
self.assert_(len(msgs) == msg_count, 'not all messages written: expected %d, got %d' % (msg_count, len(msgs)))
for (_, _, t1), (_, _, t2) in zip(msgs, msgs[1:]):
self.assert_(t1 < t2, 'messages returned unordered: got timestamp %s before %s' % (str(t1), str(t2)))
def test_writing_nonchronological_works(self):
with rosbag.Bag('/tmp/test_writing_nonchronological_works.bag', 'w') as b:
msg_count = 0
for i in range(5, 0, -1):
msg = Int32()
msg.data = i
t = genpy.Time.from_sec(i)
b.write('/ints', msg, t)
msg_count += 1
msgs = list(rosbag.Bag('/tmp/test_writing_nonchronological_works.bag').read_messages())
self.assert_(len(msgs) == msg_count, 'not all messages written: expected %d, got %d' % (msg_count, len(msgs)))
for (_, _, t1), (_, _, t2) in zip(msgs, msgs[1:]):
self.assert_(t1 < t2, 'messages returned unordered: got timestamp %s before %s' % (str(t1), str(t2)))
def test_large_write_works(self):
for compression in [rosbag.Compression.NONE, rosbag.Compression.BZ2]:
with rosbag.Bag('/tmp/test_large_write_works.bag', 'w', compression=compression) as b:
msg_count = 0
for i in range(10000):
msg = Int32()
msg.data = i
t = genpy.Time.from_sec(i)
b.write('/ints', msg, t)
msg_count += 1
msgs = list(rosbag.Bag('/tmp/test_large_write_works.bag').read_messages())
self.assertEquals(len(msgs), msg_count, 'not all messages written: expected %d, got %d' % (msg_count, len(msgs)))
for (_, _, t1), (_, _, t2) in zip(msgs, msgs[1:]):
self.assert_(t1 < t2, 'messages returned unordered: got timestamp %s before %s' % (str(t1), str(t2)))
def test_get_messages_time_range_works(self):
with rosbag.Bag('/tmp/test_get_messages_time_range_works.bag', 'w') as b:
for i in range(30):
msg = Int32()
msg.data = i
t = genpy.Time.from_sec(i)
b.write('/ints', msg, t)
start_time = genpy.Time.from_sec(3)
end_time = genpy.Time.from_sec(7)
msgs = list(rosbag.Bag('/tmp/test_get_messages_time_range_works.bag').read_messages(topics='/ints', start_time=start_time, end_time=end_time))
self.assertEquals(len(msgs), 5)
def test_get_messages_filter_works(self):
with rosbag.Bag('/tmp/test_get_messages_filter_works.bag', 'w') as b:
for i in range(30):
msg = Int32()
msg.data = i
t = genpy.Time.from_sec(i)
b.write('/ints' + str(i), msg, t)
def filter(topic, datatype, md5sum, msg_def, header):
return '5' in topic and datatype == Int32._type and md5sum == Int32._md5sum and msg_def == Int32._full_text
self.assertEquals(len(list(rosbag.Bag('/tmp/test_get_messages_filter_works.bag').read_messages(connection_filter=filter))), 3)
def test_rosbag_filter(self):
inbag_filename = '/tmp/test_rosbag_filter__1.bag'
outbag_filename = '/tmp/test_rosbag_filter__2.bag'
with rosbag.Bag(inbag_filename, 'w') as b:
for i in range(30):
msg = Int32()
msg.data = i
t = genpy.Time.from_sec(i)
b.write('/ints' + str(i), msg, t)
expression = "(int(t.secs) == m.data) and (topic == '/ints' + str(m.data)) and (m.data >= 15 and m.data < 20)"
os.system('rosbag filter %s %s "%s"' % (inbag_filename, outbag_filename, expression))
msgs = list(rosbag.Bag(outbag_filename).read_messages())
self.assertEquals(len(msgs), 5)
# Regression test for issue #736
def test_trivial_rosbag_filter(self):
tempdir = tempfile.mkdtemp()
try:
inbag_filename = os.path.join(tempdir, 'test_rosbag_filter__1.bag')
outbag1_filename = os.path.join(tempdir, 'test_rosbag_filter__2.bag')
outbag2_filename = os.path.join(tempdir, 'test_rosbag_filter__3.bag')
with rosbag.Bag(inbag_filename, 'w') as b:
for i in range(30):
msg = ColorRGBA()
t = genpy.Time.from_sec(i)
b.write('/ints' + str(i), msg, t)
# filtering multiple times should not affect the filtered rosbag
cmd = 'rosbag filter %s %s "True"'
os.system(cmd % (inbag_filename, outbag1_filename))
os.system(cmd % (outbag1_filename, outbag2_filename))
with open(outbag1_filename, 'r') as h:
outbag1_md5 = hashlib.md5(h.read()).hexdigest()
with open(outbag2_filename, 'r') as h:
outbag2_md5 = hashlib.md5(h.read()).hexdigest()
self.assertEquals(outbag1_md5, outbag2_md5)
finally:
shutil.rmtree(tempdir)
def test_reindex_works(self):
fn = '/tmp/test_reindex_works.bag'
chunk_threshold = 1024
with rosbag.Bag(fn, 'w', chunk_threshold=chunk_threshold) as b:
for i in range(100):
for j in range(5):
msg = Int32()
msg.data = i
b.write('/topic%d' % j, msg)
file_header_pos = b._file_header_pos
start_index = 4117 + chunk_threshold * 2 + int(chunk_threshold / 2)
trunc_filename = '%s.trunc%s' % os.path.splitext(fn)
reindex_filename = '%s.reindex%s' % os.path.splitext(fn)
for trunc_index in range(start_index, start_index + chunk_threshold):
shutil.copy(fn, trunc_filename)
with open(trunc_filename, 'r+b') as f:
f.seek(file_header_pos)
header = {
'op': bag._pack_uint8(bag._OP_FILE_HEADER),
'index_pos': bag._pack_uint64(0),
'conn_count': bag._pack_uint32(0),
'chunk_count': bag._pack_uint32(0)
}
bag._write_record(f, header, padded_size=bag._FILE_HEADER_LENGTH)
f.truncate(trunc_index)
shutil.copy(trunc_filename, reindex_filename)
try:
b = rosbag.Bag(reindex_filename, 'a', allow_unindexed=True)
except Exception as ex:
pass
for done in b.reindex():
pass
b.close()
msgs = list(rosbag.Bag(reindex_filename, 'r'))
def test_future_version_works(self):
fn = '/tmp/test_future_version_2.1.bag'
with rosbag.Bag(fn, 'w', chunk_threshold=256) as b:
for i in range(10):
msg = Int32()
msg.data = i
b.write('/int', msg)
header = { 'op': bag._pack_uint8(max(bag._OP_CODES.keys()) + 1) }
data = 'ABCDEFGHI123456789'
bag._write_record(b._file, header, data)
b._file.seek(0)
data = '#ROSBAG V%d.%d\n' % (int(b._version / 100), (b._version % 100) + 1) # increment the minor version
data = data.encode()
b._file.write(data)
b._file.seek(0, os.SEEK_END)
with rosbag.Bag(fn) as b:
for topic, msg, t in b:
pass
def test_get_message_count(self):
fn = '/tmp/test_get_message_count.bag'
with rosbag.Bag(fn, mode='w') as bag:
for i in range(100):
bag.write("/test_bag", Int32(data=i))
bag.write("/test_bag", String(data='also'))
bag.write("/test_bag/more", String(data='alone'))
with rosbag.Bag(fn) as bag:
self.assertEquals(bag.get_message_count(), 300)
self.assertEquals(bag.get_message_count(topic_filters='/test_bag'), 200)
self.assertEquals(bag.get_message_count(topic_filters=['/test_bag', '/test_bag/more']), 300)
self.assertEquals(bag.get_message_count(topic_filters=['/none']), 0)
def test_get_compression_info(self):
fn = '/tmp/test_get_compression_info.bag'
# No Compression
with rosbag.Bag(fn, mode='w') as bag:
for i in range(100):
bag.write("/test_bag", Int32(data=i))
with rosbag.Bag(fn) as bag:
info = bag.get_compression_info()
self.assertEquals(info.compression, rosbag.Compression.NONE)
# 167 Bytes of overhead, 50 Bytes per Int32.
self.assertEquals(info.uncompressed, 5166)
self.assertEquals(info.compressed, 5166)
with rosbag.Bag(fn, mode='w', compression=rosbag.Compression.BZ2) as bag:
for i in range(100):
bag.write("/test_bag", Int32(data=i))
with rosbag.Bag(fn) as bag:
info = bag.get_compression_info()
self.assertEquals(info.compression, rosbag.Compression.BZ2)
self.assertEquals(info.uncompressed, 5166)
# the value varies each run, I suspect based on rand, but seems
# to generally be around 960 to 980 on my comp
self.assertLess(info.compressed, 1050)
self.assertGreater(info.compressed, 850)
def test_get_time(self):
fn = '/tmp/test_get_time.bag'
with rosbag.Bag(fn, mode='w') as bag:
for i in range(100):
bag.write("/test_bag", Int32(data=i), t=genpy.Time.from_sec(i))
with rosbag.Bag(fn) as bag:
start_stamp = bag.get_start_time()
end_stamp = bag.get_end_time()
self.assertEquals(start_stamp, 0.0)
self.assertEquals(end_stamp, 99.0)
def test_get_time_empty_bag(self):
"""Test for issue #657"""
fn = '/tmp/test_get_time_emtpy_bag.bag'
with rosbag.Bag(fn, mode='w') as bag:
self.assertRaisesRegexp(rosbag.ROSBagException,
'Bag contains no message',
bag.get_start_time)
self.assertRaisesRegexp(rosbag.ROSBagException,
'Bag contains no message',
bag.get_end_time)
def test_get_type_and_topic_info(self):
fn = '/tmp/test_get_type_and_topic_info.bag'
topic_1 = "/test_bag"
topic_2 = "/test_bag/more"
with rosbag.Bag(fn, mode='w') as bag:
for i in range(100):
bag.write(topic_1, Int32(data=i))
bag.write(topic_1, String(data='also'))
bag.write(topic_2, String(data='alone'))
with rosbag.Bag(fn) as bag:
msg_types, topics = bag.get_type_and_topic_info()
self.assertEquals(len(msg_types), 2)
self.assertTrue("std_msgs/Int32" in msg_types)
self.assertTrue("std_msgs/String" in msg_types)
self.assertEquals(len(topics), 2)
self.assertTrue(topic_1 in topics)
self.assertTrue(topic_2 in topics)
self.assertEquals(topics[topic_1].message_count, 200)
self.assertEquals(topics[topic_1].msg_type, "std_msgs/Int32")
self.assertEquals(topics[topic_2].message_count, 100)
self.assertEquals(topics[topic_2].msg_type, "std_msgs/String")
#filter on topic 1
msg_types, topics = bag.get_type_and_topic_info(topic_1)
# msg_types should be unaffected by the filter
self.assertEquals(len(msg_types), 2)
self.assertTrue("std_msgs/Int32" in msg_types)
self.assertTrue("std_msgs/String" in msg_types)
self.assertEquals(len(topics), 1)
self.assertTrue(topic_1 in topics)
self.assertEquals(topics[topic_1].message_count, 200)
self.assertEquals(topics[topic_1].msg_type, "std_msgs/Int32")
#filter on topic 2
msg_types, topics = bag.get_type_and_topic_info(topic_2)
# msg_types should be unaffected by the filter
self.assertEquals(len(msg_types), 2)
self.assertTrue("std_msgs/Int32" in msg_types)
self.assertTrue("std_msgs/String" in msg_types)
self.assertEquals(len(topics), 1)
self.assertTrue(topic_2 in topics)
self.assertEquals(topics[topic_2].message_count, 100)
self.assertEquals(topics[topic_2].msg_type, "std_msgs/String")
#filter on missing topic
msg_types, topics = bag.get_type_and_topic_info("/none")
# msg_types should be unaffected by the filter
self.assertEquals(len(msg_types), 2)
self.assertTrue("std_msgs/Int32" in msg_types)
self.assertTrue("std_msgs/String" in msg_types)
# topics should be empty
self.assertEquals(len(topics), 0)
def _print_bag_records(self, fn):
with open(fn) as f:
f.seek(0, os.SEEK_END)
size = f.tell()
f.seek(0)
version_line = f.readline().rstrip()
print(version_line)
while f.tell() < size:
header = bag._read_header(f)
op = bag._read_uint8_field(header, 'op')
data = bag._read_record_data(f)
print(bag._OP_CODES.get(op, op))
if __name__ == '__main__':
import rostest
PKG='rosbag'
rostest.run(PKG, 'TestRosbag', TestRosbag, sys.argv)

View File

@@ -0,0 +1,66 @@
#!/usr/bin/env python
# Software License Agreement (BSD License)
#
# Copyright (c) 2008, Willow Garage, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Willow Garage, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
import roslib
roslib.load_manifest('rosbag')
import unittest
import rostest
import sys
import time
import subprocess
class TopicCount(unittest.TestCase):
def test_topic_count(self):
# Wait while the recorder creates a bag for us to examine
time.sleep(10.0)
# Check the topic count returned by `rosbag info`
# We could probably do this through the rosbag Python API...
cmd = ['rosbag', 'info',
'/tmp/test_rosbag_record_one_publisher_two_topics.bag',
'-y', '-k', 'topics']
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out,err = p.communicate()
topic_count = 0
for l in out.decode().split('\n'):
f = l.strip().split(': ')
if len(f) == 2 and f[0] == '- topic':
topic_count += 1
self.assertEqual(topic_count, 2)
if __name__ == '__main__':
rostest.unitrun('test_rosbag', 'topic_count', TopicCount, sys.argv)