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,61 @@
cmake_minimum_required(VERSION 2.8.3)
project(test_rosbag)
if(NOT WIN32)
set_directory_properties(PROPERTIES COMPILE_OPTIONS "-Wall;-Wextra")
endif()
find_package(catkin REQUIRED COMPONENTS message_generation rosbag rosconsole roscpp rosgraph_msgs rostest rosunit topic_tools xmlrpcpp)
if(CATKIN_ENABLE_TESTING)
find_package(Boost REQUIRED COMPONENTS regex program_options)
find_package(BZip2 REQUIRED)
add_subdirectory(bag_migration_tests)
endif()
catkin_package()
if(CATKIN_ENABLE_TESTING)
include_directories(${catkin_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS})
catkin_download_test_data(download_data_test_indexed_1.2.bag http://download.ros.org/data/rosbag/test_indexed_1.2.bag
FILENAME test/test_indexed_1.2.bag MD5 523cc0deb66269c84be4a7c605ff5eb3)
catkin_download_test_data(download_data_test_chatter_50hz.bag http://download.ros.org/data/rosbag/chatter_50hz.bag
FILENAME test/chatter_50hz.bag MD5 00844db3729b1b5f34e767dc691bd531)
catkin_download_test_data(download_data_test_future_version_2.1.bag http://download.ros.org/data/rosbag/test_future_version_2.1.bag
FILENAME test/test_future_version_2.1.bag MD5 ddcb5e8711b16514eb640330ed93c332)
catkin_download_test_data(download_data_test_rosbag_latched_pub.bag http://download.ros.org/data/rosbag/test_rosbag_latched_pub.bag
FILENAME test/test_rosbag_latched_pub.bag MD5 ed70b8cbb8a53220434aeb24bccf7342)
catkin_add_nosetests(test/test_bag.py)
configure_file(test/test_bag.cpp.in
${PROJECT_BINARY_DIR}/test/test_bag.cpp)
catkin_add_gtest(test_bag ${PROJECT_BINARY_DIR}/test/test_bag.cpp)
if(TARGET test_bag)
target_link_libraries(test_bag ${catkin_LIBRARIES})
endif()
configure_file(test/play_play.test.in
${PROJECT_BINARY_DIR}/test/play_play.test)
add_rostest(${PROJECT_BINARY_DIR}/test/play_play.test)
configure_file(test/rosbag_play.test.in
${PROJECT_BINARY_DIR}/test/rosbag_play.test)
add_rostest(${PROJECT_BINARY_DIR}/test/rosbag_play.test)
add_rostest(test/latched_pub.test)
configure_file(test/latched_sub.test.in ${PROJECT_BINARY_DIR}/test/latched_sub.test)
add_rostest(${PROJECT_BINARY_DIR}/test/latched_sub.test)
add_rostest(test/record_two_publishers.test)
add_rostest(test/record_one_publisher_two_topics.test)
include_directories(${GTEST_INCLUDE_DIRS})
add_executable(double_pub EXCLUDE_FROM_ALL test/double_pub.cpp)
target_link_libraries(double_pub ${GTEST_LIBRARIES} ${catkin_LIBRARIES})
add_dependencies(double_pub ${rosgraph_msgs_EXPORTED_TARGETS})
if(TARGET tests)
add_dependencies(tests double_pub)
endif()
endif()

View File

@@ -0,0 +1,69 @@
# This is going to need some work because the bag files on
# download.ros.org all have messages with the test_rosbag package
# name. Of course the package name for this package now is rosbag.
# If we can have a way to pass an override package name into
# generate_messages() it might make it work, or we can migrate the bag
# files themselves.
add_message_files(
DIRECTORY msg_current
FILES
Constants.msg
Converged.msg
MigratedAddSub.msg
MigratedExplicit.msg
MigratedImplicit.msg
MigratedMixed.msg
PartiallyMigrated.msg
Renamed4.msg
Simple.msg
SimpleMigrated.msg
SubUnmigrated.msg
Unmigrated.msg
)
generate_messages(DEPENDENCIES rosgraph_msgs std_msgs)
catkin_download_test_data(download_data_test_constants_gen1.bag http://download.ros.org/data/test_rosbag/constants_gen1.bag FILENAME test/constants_gen1.bag MD5 77ec8cb20e823ee3f3a87d07ea1132df )
catkin_download_test_data(download_data_test_constants_gen2.bag http://download.ros.org/data/test_rosbag/constants_gen2.bag FILENAME test/constants_gen2.bag MD5 4efd8459bf9403d1171dff06abcd6548 )
catkin_download_test_data(download_data_test_converged_gen1.bag http://download.ros.org/data/test_rosbag/converged_gen1.bag FILENAME test/converged_gen1.bag MD5 8e3524157d31b5761ac951fe16e03e12 )
catkin_download_test_data(download_data_test_converged_gen2.bag http://download.ros.org/data/test_rosbag/converged_gen2.bag FILENAME test/converged_gen2.bag MD5 0ad4041d2e3bab8262c12020ec3e048e )
catkin_download_test_data(download_data_test_converged_gen3.bag http://download.ros.org/data/test_rosbag/converged_gen3.bag FILENAME test/converged_gen3.bag MD5 90dd16cea5c51fca65be617654fb6b76 )
catkin_download_test_data(download_data_test_convergent_gen1.bag http://download.ros.org/data/test_rosbag/convergent_gen1.bag FILENAME test/convergent_gen1.bag MD5 a840aec95e50f3c828841b688dfab5a2 )
catkin_download_test_data(download_data_test_convergent_gen2.bag http://download.ros.org/data/test_rosbag/convergent_gen2.bag FILENAME test/convergent_gen2.bag MD5 fd84c135ba1548985b870d0d5f4113e9 )
catkin_download_test_data(download_data_test_migrated_addsub_gen1.bag http://download.ros.org/data/test_rosbag/migrated_addsub_gen1.bag FILENAME test/migrated_addsub_gen1.bag MD5 462e98cef72b5df56ce3feea9ddfc4d2 )
catkin_download_test_data(download_data_test_migrated_explicit_gen1.bag http://download.ros.org/data/test_rosbag/migrated_explicit_gen1.bag FILENAME test/migrated_explicit_gen1.bag MD5 0b77e45aec3ddb19a9f9771c945e2615 )
catkin_download_test_data(download_data_test_migrated_explicit_gen2.bag http://download.ros.org/data/test_rosbag/migrated_explicit_gen2.bag FILENAME test/migrated_explicit_gen2.bag MD5 b237680d6aae1b20355af097cf0f072b )
catkin_download_test_data(download_data_test_migrated_explicit_gen3.bag http://download.ros.org/data/test_rosbag/migrated_explicit_gen3.bag FILENAME test/migrated_explicit_gen3.bag MD5 8b883286e23779bbfc30b0e5588a4d64 )
catkin_download_test_data(download_data_test_migrated_implicit_gen1.bag http://download.ros.org/data/test_rosbag/migrated_implicit_gen1.bag FILENAME test/migrated_implicit_gen1.bag MD5 229d6cbd7dcec5e87fb2cf597b837243 )
catkin_download_test_data(download_data_test_migrated_implicit_gen2.bag http://download.ros.org/data/test_rosbag/migrated_implicit_gen2.bag FILENAME test/migrated_implicit_gen2.bag MD5 df60111e5f8034ba6259c4d76d07339b )
catkin_download_test_data(download_data_test_migrated_implicit_gen3.bag http://download.ros.org/data/test_rosbag/migrated_implicit_gen3.bag FILENAME test/migrated_implicit_gen3.bag MD5 d86f131070822f1673f7644bc28bfccd )
catkin_download_test_data(download_data_test_migrated_mixed_gen1.bag http://download.ros.org/data/test_rosbag/migrated_mixed_gen1.bag FILENAME test/migrated_mixed_gen1.bag MD5 2d0be37de2df6940b7bd93561dde7b51 )
catkin_download_test_data(download_data_test_migrated_mixed_gen2.bag http://download.ros.org/data/test_rosbag/migrated_mixed_gen2.bag FILENAME test/migrated_mixed_gen2.bag MD5 e000b2de3e4c417b0c9fbba9d2e92dc4 )
catkin_download_test_data(download_data_test_migrated_mixed_gen3.bag http://download.ros.org/data/test_rosbag/migrated_mixed_gen3.bag FILENAME test/migrated_mixed_gen3.bag MD5 6e1cbb529b7a45386589d00bf3908bdf )
catkin_download_test_data(download_data_test_partially_migrated_gen1.bag http://download.ros.org/data/test_rosbag/partially_migrated_gen1.bag FILENAME test/partially_migrated_gen1.bag MD5 dcfcf1e1c1f7ddc5ab723e171273a385 )
catkin_download_test_data(download_data_test_partially_migrated_gen2.bag http://download.ros.org/data/test_rosbag/partially_migrated_gen2.bag FILENAME test/partially_migrated_gen2.bag MD5 7b2d752559a7e3c724d8b2a032daf3c1 )
catkin_download_test_data(download_data_test_partially_migrated_gen3.bag http://download.ros.org/data/test_rosbag/partially_migrated_gen3.bag FILENAME test/partially_migrated_gen3.bag MD5 01161f84591bf956df7dff0a5e3fd2db )
catkin_download_test_data(download_data_test_renamed_gen1.bag http://download.ros.org/data/test_rosbag/renamed_gen1.bag FILENAME test/renamed_gen1.bag MD5 243d6109f3bfd2ad1af1337a776970e5 )
catkin_download_test_data(download_data_test_renamed_gen2.bag http://download.ros.org/data/test_rosbag/renamed_gen2.bag FILENAME test/renamed_gen2.bag MD5 229c79262e42b71f36e316ab1d1ad943 )
catkin_download_test_data(download_data_test_renamed_gen3.bag http://download.ros.org/data/test_rosbag/renamed_gen3.bag FILENAME test/renamed_gen3.bag MD5 c9c3d03807de367b533f5e0384b4d134 )
catkin_download_test_data(download_data_test_subunmigrated_gen1.bag http://download.ros.org/data/test_rosbag/subunmigrated_gen1.bag FILENAME test/subunmigrated_gen1.bag MD5 c78b85016aa34669e36d1eb5a7b5f2c7 )
catkin_download_test_data(download_data_test_unmigrated_gen1.bag http://download.ros.org/data/test_rosbag/unmigrated_gen1.bag FILENAME test/unmigrated_gen1.bag MD5 87d8d3a1c9679609533803709d21cea2 )
configure_file(test/migrate_test.py.in
${PROJECT_BINARY_DIR}/test/migrate_test.py)
catkin_add_nosetests(${PROJECT_BINARY_DIR}/test/migrate_test.py)
configure_file(test/random_record.xml.in
${PROJECT_BINARY_DIR}/test/random_record.xml)
add_rostest(${PROJECT_BINARY_DIR}/test/random_record.xml)
# Make sure that the random_record test runs before either of the random_play
# tests, both of which require a .bag file that the random_record test will
# write into /tmp. We're making an assumption about the target names generated
# by add_rostest(), but that naming scheme seems to be pretty stable.
configure_file(test/random_play.xml.in
${PROJECT_BINARY_DIR}/test/random_play.xml)
add_rostest(${PROJECT_BINARY_DIR}/test/random_play.xml
DEPENDENCIES run_tests_test_rosbag_rostest_test_random_record.xml)
configure_file(test/random_play_sim.xml.in
${PROJECT_BINARY_DIR}/test/random_play_sim.xml)
add_rostest(${PROJECT_BINARY_DIR}/test/random_play_sim.xml
DEPENDENCIES run_tests_test_rosbag_rostest_test_random_record.xml)

View File

@@ -0,0 +1,65 @@
In order to realistically test rosbagmigration, we had to create
several generations of messages which mutate and migrate and generate
bag files across all of them.
At each generation, we generate a bagfile with the contents of all of
the messages and the corresponding migration rules to migrate the
previous generation forward.
To use a particular generation script, move msgs_N to msgs, and then
run script/generate_data_N.py. The bash script "generate_data" does
this for all generations. The helper scripts, "gen1, gen2, gen3, and
current" switch the message context to that particular
GENERATION 1:
Unmigrated.msg
Subunmigrated.msg
PartiallyMigrated.msg
MigratedExplicit.msg
MigratedImplicit.msg
MigratedMixed.msg
Renamed1.msg
Convergent.msg
Converged.msg
Hierarchical.msg
SuperHierarchical.msg
GENERATION 2:
Unmigrated.msg
Subunmigrated.msg
PartiallyMigrated.msg - implicit
MigratedExplicit.msg - explicit
MigratedImplicit.msg - implicit
MigratedMixed.msg - implicit
Converged.msg - Rename from Convergent.msg
Renamed2.msg - Rename from Renamed1.msg
Hierarchical.msg
SuperHierarchical.msg
GENERATION 3
Unmigrated.msg
Subunmigrated.msg
PartiallyMigrated.msg - explicit
MigratedExplicit.msg - explicit
MigratedImplicit.msg - implicit
MigratedMixed.msg - explicit
Converged.msg - explicit
Renamed3.msg - rename from Renamed2.msg and explicit
Hierarchical.msg - explicit
SuperHierarchical.msg - implicit
CURRENT:
UnMigrated.msg - explicit (No corresponding rule)
Subunmigrated.msg
PartiallyMigrated.msg - explicit (No corresponding rule)
MigratedExplicit.msg - explicit
MigratedImplicit.msg - implicit
MigratedMixed.msg - implicit
Converged.msg - implicit
Renamed4.msg - rename from Renamed3.msg
Hierarchical.msg - implicit
SuperHierarchical.msg

View File

@@ -0,0 +1,6 @@
#!/bin/bash
make clean-msg-only;
rm -rf msg;
cp -r msg_current msg;
make

View File

@@ -0,0 +1,6 @@
#!/bin/bash
make clean-msg-only;
rm -rf msg;
cp -r msg_gen1 msg;
make;

View File

@@ -0,0 +1,6 @@
#!/bin/bash
make clean-msg-only;
rm -rf msg;
cp -r msg_gen2 msg;
make;

View File

@@ -0,0 +1,6 @@
#!/bin/bash
make clean-msg-only;
rm -rf msg;
cp -r msg_gen3 msg;
make;

View File

@@ -0,0 +1,24 @@
#!/bin/bash
make clean-msg-only;
rm -rf msg;
cp -r msg_gen1 msg;
make;
./scripts/generate_data_1.py
make clean-msg-only;
rm -rf msg;
cp -r msg_gen2 msg;
make;
./scripts/generate_data_2.py
make clean-msg-only;
rm -rf msg;
cp -r msg_gen3 msg;
make;
./scripts/generate_data_3.py
make clean-msg-only;
rm -rf msg;
cp -r msg_current msg;
make

View File

@@ -0,0 +1,3 @@
int32 CONSTANT=2
int32 CONSTANT_TWO=42
int32 value

View File

@@ -0,0 +1,2 @@
float32[4] field1 # [1.2, 3.4, 5.6, 7.8]
SimpleMigrated[4] field2 # [11, 22, 33, 44]

View File

@@ -0,0 +1,2 @@
Simple field1
Simple field2

View File

@@ -0,0 +1,4 @@
Header header
float32 afield2 #58.2
string combo_field3 #"aldfkja 17"
int32 afield4 #82

View File

@@ -0,0 +1,7 @@
Header header
MigratedExplicit field4 #(17, 58.2 "aldfkja", 82)
string field3 #"kljene"
float32 field2 #16.32
int32 field1 #34

View File

@@ -0,0 +1,3 @@
Header header
MigratedImplicit field1 #(34, 16.32, "kjljene", (17, 58.2, "aldfkja", 82))
int32 field2 #59

View File

@@ -0,0 +1,4 @@
int32 field1 # 40
MigratedExplicit field2 # (17, 58.2, "aldfkja", 82)
string field3 # "radasdk"
float32 field5 # 63.4

View File

@@ -0,0 +1,2 @@
float64 foo # 2.17
int32[4] bar # [8, 2, 5, 1]

View File

@@ -0,0 +1 @@
int32 field1 #42

View File

@@ -0,0 +1 @@
int32 data # 42

View File

@@ -0,0 +1,2 @@
int32 field1 # 92
Unmigrated field2 # (12, "uuiasjs", 61.7)

View File

@@ -0,0 +1,3 @@
int32 field1 #12
string field2 #"uuiasjs"
float32 field3 #61.7

View File

@@ -0,0 +1,2 @@
int32 CONSTANT=1
int32 value

View File

@@ -0,0 +1,2 @@
float32[] field1 # [1.2, 3.4, 5.6, 7.8]
SimpleMigrated[] field2 # [11, 22, 33, 44]

View File

@@ -0,0 +1,9 @@
float32 field1_a # 1.2
float32 field1_b # 3.4
float32 field1_c # 5.6
float32 field1_d # 7.8
SimpleMigrated field2_a # 11
SimpleMigrated field2_b # 22
SimpleMigrated field2_c # 33
SimpleMigrated field2_d # 44

View File

@@ -0,0 +1 @@
Simple field1

View File

@@ -0,0 +1,4 @@
Header header
int32 field1 #17
float32 field2 #58.2
string field3 #"aldfkja"

View File

@@ -0,0 +1,5 @@
Header header
int32 field1 #34
float32 field2 #16.32
string field3 #"kljene"
MigratedExplicit field4 #(17, 58.2 "aldfkja")

View File

@@ -0,0 +1,3 @@
Header header
MigratedImplicit field1 #(34, 16.32, "kjljene", (17, 58.2, "aldfkja"))

View File

@@ -0,0 +1,2 @@
int32 field1 # 40
MigratedExplicit field2 # (17, 58.2, "aldfkja")

View File

@@ -0,0 +1,2 @@
float64 foo # 2.17
int32[3] bar # [8, 2, 5]

View File

@@ -0,0 +1 @@
int32 field1 #42

View File

@@ -0,0 +1 @@
int32 data1 # 42

View File

@@ -0,0 +1,2 @@
int32 field1 # 92
Unmigrated field2 # (12, "uuiasjs", 61.7)

View File

@@ -0,0 +1,2 @@
int32 field1 #12
string field2 #"uuiasjs"

View File

@@ -0,0 +1,2 @@
int32 CONSTANT=2
int32 value

View File

@@ -0,0 +1,2 @@
float32[] field1 # [1.2, 3.4, 5.6, 7.8]
SimpleMigrated[] field2 # [11, 22, 33, 44]

View File

@@ -0,0 +1,9 @@
float32 field1_a # 1.2
float32 field1_b # 3.4
float32 field1_c # 5.6
float32 field1_d # 7.8
SimpleMigrated field2_a # 11
SimpleMigrated field2_b # 22
SimpleMigrated field2_c # 33
SimpleMigrated field2_d # 44

View File

@@ -0,0 +1,2 @@
Simple field1
Simple field2

View File

@@ -0,0 +1,5 @@
Header header
int32 field1 #17
float32 field2 #58.2
string field3 #"aldfkja"
int32 field4 #82

View File

@@ -0,0 +1,5 @@
Header header
int32 field1 #34
float32 field2 #16.32
string field3 #"kljene"
MigratedExplicit field4 #(17, 58.2 "aldfkja", 82)

View File

@@ -0,0 +1,3 @@
Header header
MigratedImplicit field1 #(34, 16.32, "kjljene", (17, 58.2, "aldfkja", 82))

View File

@@ -0,0 +1,2 @@
int32 field1 # 40
MigratedExplicit field2 # (17, 58.2, "aldfkja", 82)

View File

@@ -0,0 +1,2 @@
float64 foo # 2.17
int32[3] bar # [8, 2, 5]

View File

@@ -0,0 +1 @@
int32 field1 #42

View File

@@ -0,0 +1 @@
int32 data2 # 42

View File

@@ -0,0 +1,2 @@
int32 field1 # 92
Unmigrated field2 # (12, "uuiasjs", 61.7)

View File

@@ -0,0 +1,2 @@
int32 field1 #12
string field2 #"uuiasjs"

View File

@@ -0,0 +1,2 @@
float32[4] field1 # [1.2, 3.4, 5.6, 7.8]
SimpleMigrated[4] field2 # [11, 22, 33, 44]

View File

@@ -0,0 +1,2 @@
Simple field1
Simple field2

View File

@@ -0,0 +1,5 @@
Header header
int32 afield1 #17
float32 afield2 #58.2
string afield3 #"aldfkja"
int32 afield4 #82

View File

@@ -0,0 +1,7 @@
Header header
MigratedExplicit field4 #(17, 58.2 "aldfkja", 82)
string field3 #"kljene"
float32 field2 #16.32
int32 field1 #34

View File

@@ -0,0 +1,3 @@
Header header
MigratedImplicit field1 #((17, 58.2, "aldfkja", 82), "kjljene", 16.32, 34)
int32 field2 #59

View File

@@ -0,0 +1,3 @@
int32 field1 # 40
MigratedExplicit field2 # (17, 58.2, "aldfkja", 82)
string field3 # "radasdk"

View File

@@ -0,0 +1,2 @@
float64 foo # 2.17
int32[4] bar # [8, 2, 5, 1]

View File

@@ -0,0 +1 @@
int32 field1 #42

View File

@@ -0,0 +1 @@
int32 data3 # 42

View File

@@ -0,0 +1,2 @@
int32 field1 # 92
Unmigrated field2 # (12, "uuiasjs", 61.7)

View File

@@ -0,0 +1,2 @@
int32 field1 #12
string field2 #"uuiasjs"

View File

@@ -0,0 +1,98 @@
#!/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 rospy
from test_rosbag.msg import *
import genpy
import rosbag
def generate_data():
bag = rosbag.Bag("test/migrated_explicit_gen1.bag", "w")
m = MigratedExplicit(None, 17, 58.2, "aldfkja")
bag.write("migrated_explicit", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/migrated_implicit_gen1.bag", "w")
m = MigratedImplicit(None, 34, 16.32, "kljene", MigratedExplicit(None, 17, 58.2, "aldfkja"))
bag.write("migrated_implicit", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/migrated_mixed_gen1.bag", "w")
m = MigratedMixed(None, MigratedImplicit(None, 34, 16.32, "kljene", MigratedExplicit(None, 17, 58.2, "aldfkja")))
bag.write("migrated_mixed", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/migrated_addsub_gen1.bag", "w")
m = MigratedAddSub(Simple(42))
bag.write("migrated_addsub", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/unmigrated_gen1.bag", "w")
m = Unmigrated(12, "uuiasjs")
bag.write("unmigrated", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/subunmigrated_gen1.bag", "w")
m = SubUnmigrated(92, Unmigrated(12, "uuiasjs"))
bag.write("subunmigrated", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/partially_migrated_gen1.bag", "w")
m = PartiallyMigrated(40, MigratedExplicit(None, 17, 58.2, "aldfkja"))
bag.write("partially_migrated", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/renamed_gen1.bag", "w")
m = Renamed1(2.17, [8, 2, 5])
bag.write("renamed", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/convergent_gen1.bag", "w")
m = Convergent(1.2, 3.4, 5.6, 7.8, SimpleMigrated(11), SimpleMigrated(22), SimpleMigrated(33), SimpleMigrated(44))
bag.write("convergent", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/converged_gen1.bag", "w")
m = Converged([1.2, 3.4, 5.6, 7.8], [SimpleMigrated(11), SimpleMigrated(22), SimpleMigrated(33), SimpleMigrated(44)])
bag.write("converged", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/constants_gen1.bag", "w")
m = Constants(Constants.CONSTANT)
bag.write("constants", m, genpy.Time())
bag.close()
if __name__ == '__main__':
generate_data()

View File

@@ -0,0 +1,83 @@
#!/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 rospy
from test_rosbag.msg import *
import genpy
import rosbag
def generate_data():
bag = rosbag.Bag("test/migrated_explicit_gen2.bag", "w")
m = MigratedExplicit(None, 17, 58.2, "aldfkja", 82)
bag.write("migrated_explicit", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/migrated_implicit_gen2.bag", "w")
m = MigratedImplicit(None, 34, 16.32, "kljene", MigratedExplicit(None, 17, 58.2, "aldfkja", 82))
bag.write("migrated_implicit", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/migrated_mixed_gen2.bag", "w")
m = MigratedMixed(None, MigratedImplicit(None, 34, 16.32, "kljene", MigratedExplicit(None, 17, 58.2, "aldfkja", 82)))
bag.write("migrated_mixed", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/partially_migrated_gen2.bag", "w")
m = PartiallyMigrated(40, MigratedExplicit(None, 17, 58.2, "aldfkja", 82))
bag.write("partially_migrated", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/renamed_gen2.bag", "w")
m = Renamed2(2.17, [8, 2, 5])
bag.write("renamed", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/convergent_gen2.bag", "w")
m = Convergent(1.2, 3.4, 5.6, 7.8, SimpleMigrated(11), SimpleMigrated(22), SimpleMigrated(33), SimpleMigrated(44))
bag.write("convergent", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/converged_gen2.bag", "w")
m = Converged([1.2, 3.4, 5.6, 7.8], [SimpleMigrated(11), SimpleMigrated(22), SimpleMigrated(33), SimpleMigrated(44)])
bag.write("converged", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/constants_gen2.bag", "w")
m = Constants(Constants.CONSTANT)
bag.write("constants", m, genpy.Time())
bag.close()
if __name__ == '__main__':
generate_data()

View File

@@ -0,0 +1,71 @@
#!/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 rospy
from test_rosbag.msg import *
import rosbag
def generate_data():
bag = rosbag.Bag("test/migrated_explicit_gen3.bag", "w")
m = MigratedExplicit(None, 17, 58.2, "aldfkja", 82)
bag.write("migrated_explicit", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/migrated_implicit_gen3.bag", "w")
m = MigratedImplicit(None, MigratedExplicit(None, 17, 58.2, "aldfkja", 82), "kljene", 16.32, 34)
bag.write("migrated_implicit", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/migrated_mixed_gen3.bag", "w")
m = MigratedMixed(None, MigratedImplicit(None, MigratedExplicit(None, 17, 58.2, "aldfkja", 82), "kljene", 16.32, 34), 59)
bag.write("migrated_mixed", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/partially_migrated_gen3.bag", "w")
m = PartiallyMigrated(40, MigratedExplicit(None, 17, 58.2, "aldfkja", 82), "radasdk")
bag.write("partially_migrated", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/renamed_gen3.bag", "w")
m = Renamed3(2.17, [8, 2, 5, 1])
bag.write("renamed", m, genpy.Time())
bag.close()
bag = rosbag.Bag("test/converged_gen3.bag", "w")
m = Converged([1.2, 3.4, 5.6, 7.8], [SimpleMigrated(11), SimpleMigrated(22), SimpleMigrated(33), SimpleMigrated(44)])
bag.write("converged", m, genpy.Time())
bag.close()
if __name__ == '__main__':
generate_data()

View File

@@ -0,0 +1,23 @@
class update_test_rosbag_Constants_06a34bda7d4ea2950ab952e89ca35d7a(MessageUpdateRule):
old_type = "test_rosbag/Constants"
old_full_text = """
int32 CONSTANT=1
int32 value
"""
new_type = "test_rosbag/Constants"
new_full_text = """
int32 CONSTANT=2
int32 CONSTANT_TWO=42
int32 value
"""
order = 0
migrated_types = []
valid = True
def update(self, old_msg, new_msg):
#Constant 'CONSTANT' has changed
if (old_msg.value == old_msg.CONSTANT):
new_msg.value = new_msg.CONSTANT

View File

@@ -0,0 +1,63 @@
class update_test_rosbag_Convergent_fadc2231052dc3e2ecb5a84eea7e1e2d(MessageUpdateRule):
old_type = "test_rosbag/Convergent"
old_full_text = """
float32 field1_a # 1.2
float32 field1_b # 3.4
float32 field1_c # 5.6
float32 field1_d # 7.8
SimpleMigrated field2_a # 11
SimpleMigrated field2_b # 22
SimpleMigrated field2_c # 33
SimpleMigrated field2_d # 44
================================================================================
MSG: test_rosbag/SimpleMigrated
int32 data2 # 42
"""
new_type = "test_rosbag/Converged"
new_full_text = """
float32[] field1 # [1.2, 3.4, 5.6, 7.8]
SimpleMigrated[] field2 # [11, 22, 33, 44]
================================================================================
MSG: test_rosbag/SimpleMigrated
int32 data2 # 42
"""
order = 0
migrated_types = [('SimpleMigrated', 'SimpleMigrated')]
valid = True
def update(self, old_msg, new_msg):
new_msg.field1 = [old_msg.field1_a, old_msg.field1_b, old_msg.field1_c, old_msg.field1_d]
old_array = [old_msg.field2_a, old_msg.field2_b, old_msg.field2_c, old_msg.field2_d]
self.migrate_array(old_array, new_msg.field2, 'SimpleMigrated')
class update_test_rosbag_Converged_a47f409894343606276bb95cd2fd6b12(MessageUpdateRule):
old_type = "test_rosbag/Converged"
old_full_text = """
float32[] field1 # [1.2, 3.4, 5.6, 7.8]
SimpleMigrated[] field2 # [11, 22, 33, 44]
================================================================================
MSG: test_rosbag/SimpleMigrated
int32 data2 # 42
"""
new_type = "test_rosbag/Converged"
new_full_text = """
float32[4] field1 # [1.2, 3.4, 5.6, 7.8]
SimpleMigrated[4] field2 # [11, 22, 33, 44]
================================================================================
MSG: test_rosbag/SimpleMigrated
int32 data3 # 42
"""
order = 0
migrated_types = [('SimpleMigrated', 'SimpleMigrated')]
valid = True
def update(self, old_msg, new_msg):
new_msg.field1 = old_msg.field1
self.migrate_array(old_msg.field2, new_msg.field2, 'SimpleMigrated')

View File

@@ -0,0 +1,397 @@
#!/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 sys
import struct
import unittest
import rospkg
import rostest
import rosbag
class MigrationTest(unittest.TestCase):
def setUp(self):
self.pkg_dir = rospkg.RosPack().get_path('test_rosbag')
self.pkg_binary_dir = '@PROJECT_BINARY_DIR@'
def test_unmigrated(self):
tmp_rule_files = ['migrated_explicit_rules.bmr', 'migrated_mixed_rules.bmr', 'migrated_addsub_rules.bmr']
rule_files = ["%s/bag_migration_tests/test/%s"%(self.pkg_dir,r) for r in tmp_rule_files]
inbag = "%s/test/unmigrated_gen1.bag"%(self.pkg_binary_dir,)
mm = rosbag.migration.MessageMigrator(rule_files,False)
res = rosbag.migration.checkbag(mm, inbag)
self.assertTrue(len(res[0][1]) == 1)
self.assertTrue(not res[0][1][0].valid)
self.assertEqual(res[0][1][0].old_class._md5sum, '4b12e5ff694b0e2a31b2ea9e0bd900f4')
self.assertEqual(res[0][1][0].new_class._md5sum, 'b5d640967dccef2a24697ec4b8a571ec')
def test_subunmigrated(self):
tmp_rule_files = ['migrated_explicit_rules.bmr', 'migrated_mixed_rules.bmr', 'migrated_addsub_rules.bmr']
rule_files = ["%s/bag_migration_tests/test/%s"%(self.pkg_dir,r) for r in tmp_rule_files]
inbag = "%s/test/subunmigrated_gen1.bag"%(self.pkg_binary_dir,)
mm = rosbag.migration.MessageMigrator(rule_files, False)
res = rosbag.migration.checkbag(mm, inbag)
self.assertTrue(len(res[0][1]) == 1)
self.assertTrue(not res[0][1][0].valid)
self.assertEqual(res[0][1][0].old_class._md5sum, '4b12e5ff694b0e2a31b2ea9e0bd900f4')
self.assertEqual(res[0][1][0].new_class._md5sum, 'b5d640967dccef2a24697ec4b8a571ec')
def do_partially_migrated(self, N):
tmp_rule_files = ['migrated_explicit_rules.bmr', 'migrated_mixed_rules.bmr', 'migrated_addsub_rules.bmr', 'partially_migrated_rules.bmr']
rule_files = ["%s/bag_migration_tests/test/%s"%(self.pkg_dir,r) for r in tmp_rule_files]
inbag = "%s/test/partially_migrated_gen%d.bag"%(self.pkg_binary_dir,N)
mm = rosbag.migration.MessageMigrator(rule_files, False)
res = rosbag.migration.checkbag(mm, inbag)
self.assertTrue(len(res[0][1]) == 1)
self.assertTrue(not res[0][1][0].valid)
self.assertEqual(res[0][1][0].old_class._md5sum, 'aba12af164ecf3f5cd150fb990205c4b')
self.assertEqual(res[0][1][0].new_class._md5sum, 'b942bf4a41fb2bebc502889fd8981dfe')
def test_partially_migrated_gen1(self):
self.do_partially_migrated(1)
def test_partially_migrated_gen2(self):
self.do_partially_migrated(2)
def test_partially_migrated_gen3(self):
self.do_partially_migrated(3)
def test_addsub(self):
tmp_rule_files = ['migrated_explicit_rules.bmr', 'migrated_mixed_rules.bmr', 'migrated_addsub_rules.bmr']
rule_files = ["%s/bag_migration_tests/test/%s"%(self.pkg_dir,r) for r in tmp_rule_files]
inbag = "%s/test/migrated_addsub_gen1.bag"%(self.pkg_binary_dir,)
outbag = "%s/test/migrated_addsub_gen1.fixed.bag"%(self.pkg_binary_dir,)
mm = rosbag.migration.MessageMigrator(rule_files, False)
res = rosbag.migration.checkbag(mm, inbag)
self.assertTrue(not False in [m[1] == [] for m in res], 'Bag not ready to be migrated')
res = rosbag.migration.fixbag(mm, inbag, outbag)
self.assertTrue(res, 'Bag not converted successfully')
msgs = [msg for msg in rosbag.Bag(outbag).read_messages()]
self.assertTrue(len(msgs) > 0)
self.assertEqual(msgs[0][1].field1.field1, 42)
self.assertEqual(msgs[0][1].field2.field1, 42)
def do_migrated_explicit(self, N):
tmp_rule_files = ['migrated_explicit_rules.bmr', 'migrated_mixed_rules.bmr', 'migrated_addsub_rules.bmr']
rule_files = ["%s/bag_migration_tests/test/%s"%(self.pkg_dir,r) for r in tmp_rule_files]
inbag = "%s/test/migrated_explicit_gen%d.bag"%(self.pkg_binary_dir,N)
outbag = "%s/test/migrated_explicit_gen%d.fixed.bag"%(self.pkg_binary_dir,N)
mm = rosbag.migration.MessageMigrator(rule_files, False)
res = rosbag.migration.checkbag(mm, inbag)
self.assertTrue(not False in [m[1] == [] for m in res], 'Bag not ready to be migrated')
res = rosbag.migration.fixbag(mm, inbag, outbag)
self.assertTrue(res, 'Bag not converted successfully')
msgs = [msg for msg in rosbag.Bag(outbag).read_messages()]
self.assertTrue(len(msgs) > 0)
self.assertEqual(msgs[0][1].afield2, struct.unpack('<f',struct.pack('<f',58.2))[0])
self.assertEqual(msgs[0][1].combo_field3, "aldfkja 17")
self.assertEqual(msgs[0][1].afield4, 82)
def test_migrated_explicit_gen1(self):
self.do_migrated_explicit(1)
def test_migrated_explicit_gen2(self):
self.do_migrated_explicit(2)
def test_migrated_explicit_gen3(self):
self.do_migrated_explicit(3)
def do_migrated_implicit(self, N):
tmp_rule_files = ['migrated_explicit_rules.bmr', 'migrated_mixed_rules.bmr', 'migrated_addsub_rules.bmr']
rule_files = ["%s/bag_migration_tests/test/%s"%(self.pkg_dir,r) for r in tmp_rule_files]
inbag = "%s/test/migrated_implicit_gen%d.bag"%(self.pkg_binary_dir,N)
outbag = "%s/test/migrated_implicit_gen%d.fixed.bag"%(self.pkg_binary_dir,N)
mm = rosbag.migration.MessageMigrator(rule_files, False)
res = rosbag.migration.checkbag(mm, inbag
)
self.assertTrue(not False in [m[1] == [] for m in res], 'Bag not ready to be migrated')
res = rosbag.migration.fixbag(mm, inbag, outbag)
self.assertTrue(res, 'Bag not converted successfully')
msgs = [msg for msg in rosbag.Bag(outbag).read_messages()]
self.assertTrue(len(msgs) > 0)
self.assertEqual(msgs[0][1].field4.afield2, struct.unpack('<f',struct.pack('<f',58.2))[0])
self.assertEqual(msgs[0][1].field4.combo_field3, "aldfkja 17")
self.assertEqual(msgs[0][1].field4.afield4, 82)
self.assertEqual(msgs[0][1].field1, 34)
self.assertEqual(msgs[0][1].field2, struct.unpack('<f',struct.pack('<f',16.32))[0])
self.assertEqual(msgs[0][1].field3, "kljene")
def test_migrated_implicit_gen1(self):
self.do_migrated_implicit(1)
def test_migrated_implicit_gen2(self):
self.do_migrated_implicit(2)
def test_migrated_implicit_gen3(self):
self.do_migrated_implicit(3)
def do_migrated_mixed(self, N):
tmp_rule_files = ['migrated_explicit_rules.bmr', 'migrated_mixed_rules.bmr', 'migrated_addsub_rules.bmr']
rule_files = ["%s/bag_migration_tests/test/%s"%(self.pkg_dir,r) for r in tmp_rule_files]
inbag = "%s/test/migrated_mixed_gen%d.bag"%(self.pkg_binary_dir,N)
outbag = "%s/test/migrated_mixed_gen%d.fixed.bag"%(self.pkg_binary_dir,N)
mm = rosbag.migration.MessageMigrator(rule_files, False)
res = rosbag.migration.checkbag(mm, inbag)
self.assertTrue(not False in [m[1] == [] for m in res], 'Bag not ready to be migrated')
res = rosbag.migration.fixbag(mm, inbag, outbag)
self.assertTrue(res, 'Bag not converted successfully')
msgs = [msg for msg in rosbag.Bag(outbag).read_messages()]
self.assertTrue(len(msgs) > 0)
self.assertEqual(msgs[0][1].field1.field4.afield2, struct.unpack('<f',struct.pack('<f',58.2))[0])
self.assertEqual(msgs[0][1].field1.field4.combo_field3, "aldfkja 17")
self.assertEqual(msgs[0][1].field1.field4.afield4, 82)
self.assertEqual(msgs[0][1].field1.field1, 34)
self.assertEqual(msgs[0][1].field1.field2, struct.unpack('<f',struct.pack('<f',16.32))[0])
self.assertEqual(msgs[0][1].field1.field3, "kljene")
self.assertEqual(msgs[0][1].field2, 59)
def test_migrated_mixed_gen1(self):
self.do_migrated_mixed(1)
def test_migrated_mixed_gen2(self):
self.do_migrated_mixed(2)
def test_migrated_mixed_gen3(self):
self.do_migrated_mixed(3)
def do_renamed(self, N):
tmp_rule_files = ['migrated_explicit_rules.bmr', 'migrated_mixed_rules.bmr', 'migrated_addsub_rules.bmr', 'renamed_rules.bmr']
rule_files = ["%s/bag_migration_tests/test/%s"%(self.pkg_dir,r) for r in tmp_rule_files]
inbag = "%s/test/renamed_gen%d.bag"%(self.pkg_binary_dir,N)
outbag = "%s/test/renamed_gen%d.fixed.bag"%(self.pkg_binary_dir,N)
mm = rosbag.migration.MessageMigrator(rule_files, False)
res = rosbag.migration.checkbag(mm, inbag
)
self.assertTrue(not False in [m[1] == [] for m in res], 'Bag not ready to be migrated')
res = rosbag.migration.fixbag(mm, inbag, outbag)
self.assertTrue(res, 'Bag not converted successfully')
msgs = [msg for msg in rosbag.Bag(outbag).read_messages()]
self.assertTrue(len(msgs) > 0)
self.assertEqual(msgs[0][1]._type, 'test_rosbag/Renamed4', 'Type name is wrong')
self.assertEqual(msgs[0][1].foo, struct.unpack('<d',struct.pack('<d',2.17))[0])
self.assertEqual(msgs[0][1].bar, (8, 2, 5, 1))
def test_renamed_gen1(self):
self.do_renamed(1)
def test_renamed_gen2(self):
self.do_renamed(2)
def test_renamed_gen3(self):
self.do_renamed(3)
def do_converged(self, N):
tmp_rule_files = ['migrated_explicit_rules.bmr', 'migrated_mixed_rules.bmr', 'migrated_addsub_rules.bmr', 'renamed_rules.bmr', 'simple_migrated_rules.bmr', 'converged_rules.bmr']
rule_files = ["%s/bag_migration_tests/test/%s"%(self.pkg_dir,r) for r in tmp_rule_files]
inbag = "%s/test/converged_gen%d.bag"%(self.pkg_binary_dir,N)
outbag = "%s/test/converged_gen%d.fixed.bag"%(self.pkg_binary_dir,N)
mm = rosbag.migration.MessageMigrator(rule_files, False)
res = rosbag.migration.checkbag(mm, inbag)
self.assertTrue(not False in [m[1] == [] for m in res], 'Bag not ready to be migrated')
res = rosbag.migration.fixbag(mm, inbag, outbag)
self.assertTrue(res, 'Bag not converted successfully')
msgs = [msg for msg in rosbag.Bag(outbag).read_messages()]
self.assertTrue(len(msgs) > 0)
self.assertEqual(msgs[0][1]._type, 'test_rosbag/Converged', 'Type name is wrong')
self.assertEqual(msgs[0][1].field1[0], struct.unpack('<f',struct.pack('<f',1.2))[0])
self.assertEqual(msgs[0][1].field1[1], struct.unpack('<f',struct.pack('<f',3.4))[0])
self.assertEqual(msgs[0][1].field1[2], struct.unpack('<f',struct.pack('<f',5.6))[0])
self.assertEqual(msgs[0][1].field1[3], struct.unpack('<f',struct.pack('<f',7.8))[0])
self.assertEqual(msgs[0][1].field2[0].data, 11)
self.assertEqual(msgs[0][1].field2[1].data, 22)
self.assertEqual(msgs[0][1].field2[2].data, 33)
self.assertEqual(msgs[0][1].field2[3].data, 44)
def test_converged_gen1(self):
self.do_converged(1)
def test_converged_gen2(self):
self.do_converged(2)
def test_converged_gen3(self):
self.do_converged(3)
def do_convergent(self, N):
tmp_rule_files = ['migrated_explicit_rules.bmr', 'migrated_mixed_rules.bmr', 'migrated_addsub_rules.bmr', 'renamed_rules.bmr', 'simple_migrated_rules.bmr', 'converged_rules.bmr']
rule_files = ["%s/bag_migration_tests/test/%s"%(self.pkg_dir,r) for r in tmp_rule_files]
inbag = "%s/test/convergent_gen%d.bag"%(self.pkg_binary_dir,N)
outbag = "%s/test/convergent_gen%d.fixed.bag"%(self.pkg_binary_dir,N)
mm = rosbag.migration.MessageMigrator(rule_files, False)
res = rosbag.migration.checkbag(mm, inbag)
self.assertTrue(not False in [m[1] == [] for m in res], 'Bag not ready to be migrated')
res = rosbag.migration.fixbag(mm, inbag, outbag)
self.assertTrue(res, 'Bag not converted successfully')
msgs = [msg for msg in rosbag.Bag(outbag).read_messages()]
self.assertTrue(len(msgs) > 0)
self.assertEqual(msgs[0][1]._type, 'test_rosbag/Converged', 'Type name is wrong')
self.assertEqual(msgs[0][1].field1[0], struct.unpack('<f',struct.pack('<f',1.2))[0])
self.assertEqual(msgs[0][1].field1[1], struct.unpack('<f',struct.pack('<f',3.4))[0])
self.assertEqual(msgs[0][1].field1[2], struct.unpack('<f',struct.pack('<f',5.6))[0])
self.assertEqual(msgs[0][1].field1[3], struct.unpack('<f',struct.pack('<f',7.8))[0])
self.assertEqual(msgs[0][1].field2[0].data, 11)
self.assertEqual(msgs[0][1].field2[1].data, 22)
self.assertEqual(msgs[0][1].field2[2].data, 33)
self.assertEqual(msgs[0][1].field2[3].data, 44)
def test_convergent_gen1(self):
self.do_convergent(1)
def test_convergent_gen2(self):
self.do_convergent(2)
def do_constants_no_rules(self, N):
tmp_rule_files = []
rule_files = ["%s/bag_migration_tests/test/%s"%(self.pkg_dir,r) for r in tmp_rule_files]
inbag = "%s/test/constants_gen%d.bag"%(self.pkg_binary_dir,N)
outbag = "%s/test/constants_gen%d.fixed.bag"%(self.pkg_binary_dir,N)
mm = rosbag.migration.MessageMigrator(rule_files, False)
res = rosbag.migration.checkbag(mm, inbag)
self.assertTrue(len(res[0][1]) == 1)
self.assertTrue(not res[0][1][0].valid)
self.assertEqual(res[0][1][0].old_class._md5sum, '06a34bda7d4ea2950ab952e89ca35d7a')
self.assertEqual(res[0][1][0].new_class._md5sum, 'b45401c4d442c4da7b0a2a105075fa4a')
def do_constants_rules(self, N):
tmp_rule_files = ['constants.bmr']
rule_files = ["%s/bag_migration_tests/test/%s"%(self.pkg_dir,r) for r in tmp_rule_files]
inbag = "%s/test/constants_gen%d.bag"%(self.pkg_binary_dir,N)
outbag = "%s/test/constants_gen%d.fixed.bag"%(self.pkg_binary_dir,N)
mm = rosbag.migration.MessageMigrator(rule_files, False)
res = rosbag.migration.checkbag(mm, inbag)
self.assertTrue(not False in [m[1] == [] for m in res], 'Bag not ready to be migrated')
res = rosbag.migration.fixbag(mm, inbag, outbag)
self.assertTrue(res, 'Bag not converted successfully')
msgs = [msg for msg in rosbag.Bag(outbag).read_messages()]
self.assertTrue(len(msgs) > 0)
self.assertEqual(msgs[0][1]._type, 'test_rosbag/Constants', 'Type name is wrong')
self.assertEqual(msgs[0][1].value, msgs[0][1].CONSTANT)
def test_constants_no_rules_gen1(self):
self.do_constants_no_rules(1)
def test_constants_gen1(self):
self.do_constants_rules(1)
def test_constants_gen2(self):
self.do_constants_rules(2)
if __name__ == '__main__':
rostest.unitrun('test_rosbag', 'migration_test', MigrationTest, sys.argv)

View File

@@ -0,0 +1,26 @@
class update_test_rosbag_MigratedAddSub_c5d68a52143661d05909248952fc11f1(MessageUpdateRule):
old_type = "test_rosbag/MigratedAddSub"
old_full_text = """
Simple field1
================================================================================
MSG: test_rosbag/Simple
int32 field1 #42
"""
new_type = "test_rosbag/MigratedAddSub"
new_full_text = """
Simple field1
Simple field2
================================================================================
MSG: test_rosbag/Simple
int32 field1 #42
"""
order = 0
migrated_types = [("Simple","Simple"),]
valid = True
def update(self, old_msg, new_msg):
self.migrate(old_msg.field1, new_msg.field1)
new_msg.field2 = self.get_new_class('Simple')(42)

View File

@@ -0,0 +1,181 @@
class update_test_rosbag_MigratedExplicit_c7936d50a749a1f589d6fc81eae24b34(MessageUpdateRule):
old_type = "test_rosbag/MigratedExplicit"
new_type = "test_rosbag/MigratedExplicit"
old_full_text = """
Header header
int32 field1 #17
float32 field2 #58.2
string field3 #"aldfkja"
================================================================================
MSG: roslib/Header
#Standard metadata for higher-level flow data types
#sequence ID: consecutively increasing ID
uint32 seq
#Two-integer timestamp that is expressed as:
# * stamp.secs: seconds (stamp_secs) since epoch
# * stamp.nsecs: nanoseconds since stamp_secs
# time-handling sugar is provided by the client library
time stamp
#Frame this data is associated with
# 0: no frame
# 1: global frame
string frame_id
"""
new_full_text = """
Header header
int32 field1 #17
float32 field2 #58.2
string field3 #"aldfkja"
int32 field4 #82
================================================================================
MSG: roslib/Header
#Standard metadata for higher-level flow data types
#sequence ID: consecutively increasing ID
uint32 seq
#Two-integer timestamp that is expressed as:
# * stamp.secs: seconds (stamp_secs) since epoch
# * stamp.nsecs: nanoseconds since stamp_secs
# time-handling sugar is provided by the client library
time stamp
#Frame this data is associated with
# 0: no frame
# 1: global frame
string frame_id
"""
order = 0
migrated_types = [
("Header","Header"),
]
valid = True
def update(self, old_msg, new_msg):
self.migrate(old_msg.header, new_msg.header)
new_msg.field1 = old_msg.field1
new_msg.field2 = old_msg.field2
new_msg.field3 = old_msg.field3
new_msg.field4 = 82
class update_test_rosbag_MigratedExplicit_fa072fb3cfcf105e1e5609a7467e2a14(MessageUpdateRule):
old_type = "test_rosbag/MigratedExplicit"
new_type = "test_rosbag/MigratedExplicit"
old_full_text = """
Header header
int32 field1 #17
float32 field2 #58.2
string field3 #"aldfkja"
int32 field4 #82
================================================================================
MSG: roslib/Header
#Standard metadata for higher-level flow data types
#sequence ID: consecutively increasing ID
uint32 seq
#Two-integer timestamp that is expressed as:
# * stamp.secs: seconds (stamp_secs) since epoch
# * stamp.nsecs: nanoseconds since stamp_secs
# time-handling sugar is provided by the client library
time stamp
#Frame this data is associated with
# 0: no frame
# 1: global frame
string frame_id
"""
new_full_text = """
Header header
int32 afield1 #17
float32 afield2 #58.2
string afield3 #"aldfkja"
int32 afield4 #82
================================================================================
MSG: roslib/Header
#Standard metadata for higher-level flow data types
#sequence ID: consecutively increasing ID
uint32 seq
#Two-integer timestamp that is expressed as:
# * stamp.secs: seconds (stamp_secs) since epoch
# * stamp.nsecs: nanoseconds since stamp_secs
# time-handling sugar is provided by the client library
time stamp
#Frame this data is associated with
# 0: no frame
# 1: global frame
string frame_id
"""
order = 1
migrated_types = [
("Header","Header"),
]
valid = True
def update(self, old_msg, new_msg):
self.migrate(old_msg.header, new_msg.header)
new_msg.afield1 = old_msg.field1
new_msg.afield2 = old_msg.field2
new_msg.afield3 = old_msg.field3
new_msg.afield4 = old_msg.field4
class update_test_rosbag_MigratedExplicit_0a3e03fbb60b5f9abd4beedae6080fce(MessageUpdateRule):
old_type = "test_rosbag/MigratedExplicit"
new_type = "test_rosbag/MigratedExplicit"
old_full_text = """
Header header
int32 afield1 #17
float32 afield2 #58.2
string afield3 #"aldfkja"
int32 afield4 #82
================================================================================
MSG: roslib/Header
#Standard metadata for higher-level flow data types
#sequence ID: consecutively increasing ID
uint32 seq
#Two-integer timestamp that is expressed as:
# * stamp.secs: seconds (stamp_secs) since epoch
# * stamp.nsecs: nanoseconds since stamp_secs
# time-handling sugar is provided by the client library
time stamp
#Frame this data is associated with
# 0: no frame
# 1: global frame
string frame_id
"""
new_full_text = """
Header header
float32 afield2 #58.2
string combo_field3 #"aldfkja 17"
int32 afield4 #82
================================================================================
MSG: roslib/Header
#Standard metadata for higher-level flow data types
#sequence ID: consecutively increasing ID
uint32 seq
#Two-integer timestamp that is expressed as:
# * stamp.secs: seconds (stamp_secs) since epoch
# * stamp.nsecs: nanoseconds since stamp_secs
# time-handling sugar is provided by the client library
time stamp
#Frame this data is associated with
# 0: no frame
# 1: global frame
string frame_id
"""
order = 2
migrated_types = [
("Header","Header"),
]
valid = True
def update(self, old_msg, new_msg):
self.migrate(old_msg.header, new_msg.header)
new_msg.afield2 = old_msg.afield2
new_msg.combo_field3 = old_msg.afield3 + ' ' + str(old_msg.afield1)
new_msg.afield4 = old_msg.afield4

View File

@@ -0,0 +1,89 @@
class update_test_rosbag_MigratedMixed_5568494133a082ad58ef1aa391f47e2b(MessageUpdateRule):
old_type = "test_rosbag/MigratedMixed"
old_full_text = """
Header header
MigratedImplicit field1 #(34, 16.32, "kjljene", (17, 58.2, "aldfkja", 82))
================================================================================
MSG: roslib/Header
#Standard metadata for higher-level flow data types
#sequence ID: consecutively increasing ID
uint32 seq
#Two-integer timestamp that is expressed as:
# * stamp.secs: seconds (stamp_secs) since epoch
# * stamp.nsecs: nanoseconds since stamp_secs
# time-handling sugar is provided by the client library
time stamp
#Frame this data is associated with
# 0: no frame
# 1: global frame
string frame_id
================================================================================
MSG: test_rosbag/MigratedImplicit
Header header
int32 field1 #34
float32 field2 #16.32
string field3 #"kljene"
MigratedExplicit field4 #(17, 58.2 "aldfkja", 82)
================================================================================
MSG: test_rosbag/MigratedExplicit
Header header
int32 field1 #17
float32 field2 #58.2
string field3 #"aldfkja"
int32 field4 #82
"""
new_type = "test_rosbag/MigratedMixed"
new_full_text = """
Header header
MigratedImplicit field1 #((17, 58.2, "aldfkja", 82), "kjljene", 16.32, 34)
int32 field2 #59
================================================================================
MSG: roslib/Header
#Standard metadata for higher-level flow data types
#sequence ID: consecutively increasing ID
uint32 seq
#Two-integer timestamp that is expressed as:
# * stamp.secs: seconds (stamp_secs) since epoch
# * stamp.nsecs: nanoseconds since stamp_secs
# time-handling sugar is provided by the client library
time stamp
#Frame this data is associated with
# 0: no frame
# 1: global frame
string frame_id
================================================================================
MSG: test_rosbag/MigratedImplicit
Header header
MigratedExplicit field4 #(17, 58.2 "aldfkja", 82)
string field3 #"kljene"
float32 field2 #16.32
int32 field1 #34
================================================================================
MSG: test_rosbag/MigratedExplicit
Header header
int32 afield1 #17
float32 afield2 #58.2
string afield3 #"aldfkja"
int32 afield4 #82
"""
order = 0
migrated_types = [
("Header","Header"),
("MigratedImplicit","MigratedImplicit"),
]
valid = True
def update(self, old_msg, new_msg):
self.migrate(old_msg.header, new_msg.header)
self.migrate(old_msg.field1, new_msg.field1)
new_msg.field2 = 59

View File

@@ -0,0 +1,67 @@
class update_test_rosbag_PartiallyMigrated_e6d73341e7b3f15f987c0cf194f97350(MessageUpdateRule):
old_type = "test_rosbag/PartiallyMigrated"
old_full_text = """
int32 field1 # 40
MigratedExplicit field2 # (17, 58.2, "aldfkja", 82)
================================================================================
MSG: test_rosbag/MigratedExplicit
Header header
int32 field1 #17
float32 field2 #58.2
string field3 #"aldfkja"
int32 field4 #82
================================================================================
MSG: roslib/Header
#Standard metadata for higher-level flow data types
#sequence ID: consecutively increasing ID
uint32 seq
#Two-integer timestamp that is expressed as:
# * stamp.secs: seconds (stamp_secs) since epoch
# * stamp.nsecs: nanoseconds since stamp_secs
# time-handling sugar is provided by the client library
time stamp
#Frame this data is associated with
# 0: no frame
# 1: global frame
string frame_id
"""
new_type = "test_rosbag/PartiallyMigrated"
new_full_text = """
int32 field1 # 40
MigratedExplicit field2 # (17, 58.2, "aldfkja", 82)
string field3 # "radasdk"
================================================================================
MSG: test_rosbag/MigratedExplicit
Header header
int32 afield1 #17
float32 afield2 #58.2
string afield3 #"aldfkja"
int32 afield4 #82
================================================================================
MSG: roslib/Header
#Standard metadata for higher-level flow data types
#sequence ID: consecutively increasing ID
uint32 seq
#Two-integer timestamp that is expressed as:
# * stamp.secs: seconds (stamp_secs) since epoch
# * stamp.nsecs: nanoseconds since stamp_secs
# time-handling sugar is provided by the client library
time stamp
#Frame this data is associated with
# 0: no frame
# 1: global frame
string frame_id
"""
order = 0
migrated_types = [("MigratedExplicit","MigratedExplicit"),]
valid = True
def update(self, old_msg, new_msg):
new_msg.field1 = old_msg.field1
self.migrate(old_msg.field2, new_msg.field2)
new_msg.field3 = 'radasdk'

View File

@@ -0,0 +1,198 @@
# 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 rospy
import random
import genmsg.msgs
import genpy.dynamic
def get_sub_defs(msg_fqn, msg_txt):
def_dict = {}
defs = msg_txt.split("\n" + "="*80 + "\n")
def_dict[msg_fqn] = defs[0]
for d in defs[1:]:
lines = d.splitlines()
if not lines[0].startswith("MSG: "):
raise Exception("Invalid sub definition!")
type = lines[0][5:].strip()
def_txt = "\n".join(lines[1:])
def_dict[type] = def_txt
return def_dict
class RandomMsgGen(object):
def randstr(self, length=0):
if length == 0:
length = self.rand.randint(3,10)
return ''.join([chr(self.rand.randint(ord('a'), ord('z'))) for i in range(length)])
def __init__(self, seed, num_topics, duration):
self.message_defs = {}
self.message_dict = {}
self.topic_dict = {}
self.duration = duration
self.output = []
self.rand = random.Random(seed)
for i in range(num_topics):
msg_pkg = self.randstr()
msg_name = self.randstr()
msg_fqn = "%s/%s"%(msg_pkg,msg_name)
msg_fields = []
msg_def = ""
msg_sub_defs = {}
for j in range(self.rand.randint(3,5)):
field_name = self.randstr()
field_type = self.rand.choice(genmsg.msgs.BUILTIN_TYPES + list(self.message_defs.keys()))
field_array = self.rand.choice(5*[""]+["[]","[%d]"%self.rand.randint(1,10)])
if (field_type not in genmsg.msgs.BUILTIN_TYPES):
tmp = get_sub_defs(field_type, self.message_defs[field_type])
for (sm_type, sm_def) in tmp.items():
msg_sub_defs[sm_type] = sm_def
msg_def = msg_def + "%s%s %s\n"%(field_type, field_array, field_name)
for (t,d) in msg_sub_defs.items():
msg_def = msg_def + "\n" + "="*80 + "\n"
msg_def = msg_def + "MSG: %s\n"%(t)
msg_def = msg_def + d
self.message_defs[msg_fqn] = msg_def
topic_name = self.randstr()
self.message_dict[msg_fqn] = genpy.dynamic.generate_dynamic(msg_fqn, msg_def)[msg_fqn]
self.topic_dict[topic_name] = self.message_dict[msg_fqn]
time = 0.0
while time < duration:
topic = self.rand.choice(list(self.topic_dict.keys()))
msg_inst = self.rand_value(self.topic_dict[topic]._type)
self.output.append((topic, msg_inst, time))
time = time + self.rand.random()*.01
def topics(self):
return self.topic_dict.items()
def messages(self):
for m in self.output:
yield m
def message_count(self):
return len(self.output)
def rand_value(self, field_type):
if field_type == 'bool':
return self.rand.randint(0,1)
elif field_type == 'byte':
return self.rand.randint(0,2**7-1)
elif field_type == 'int8':
return self.rand.randint(-2**7,2**7-1)
elif field_type == 'int16':
return self.rand.randint(-2**15,2**15-1)
elif field_type == 'int32':
return self.rand.randint(-2**31,2**31-1)
elif field_type == 'int64':
return self.rand.randint(-2**63,2**63-1)
elif field_type == 'char':
return self.rand.randint(0,2**8-1)
elif field_type == 'uint8':
return self.rand.randint(0,2**8-1)
elif field_type == 'uint16':
return self.rand.randint(0,2**16-1)
elif field_type == 'uint32':
return self.rand.randint(0,2**32-1)
elif field_type == 'uint64':
return self.rand.randint(0,2**64-1)
elif field_type == 'float32':
return self.rand.random()
elif field_type == 'float64':
return self.rand.random()
elif field_type == 'string':
return self.randstr(100)
elif field_type == 'duration':
return rospy.Duration.from_sec(self.rand.random())
elif field_type == 'time':
return rospy.Time.from_sec(self.rand.random()*1000)
elif field_type.endswith(']'): # array type
base_type, is_array, array_len = genmsg.msgs.parse_type(field_type)
if array_len is None:
array_len = self.rand.randint(1,100)
# Make this more efficient rather than depend on recursion inside the array check
if field_type == 'bool':
return [ self.rand.randint(0,1) for i in range(0,array_len) ]
elif field_type == 'byte':
return [ self.rand.randint(-2**7,2**7-1) for i in range(0,array_len) ]
elif field_type == 'int8':
return [ self.rand.randint(-2**7,2**7-1) for i in range(0,array_len) ]
elif field_type == 'int16':
return [ self.rand.randint(-2**15,2**15-1) for i in range(0,array_len) ]
elif field_type == 'int32':
return [ self.rand.randint(-2**31,2**31-1) for i in range(0,array_len) ]
elif field_type == 'int64':
return [ self.rand.randint(-2**63,2**63-1) for i in range(0,array_len) ]
elif field_type == 'char':
return [ self.rand.randint(0,2**8-1) for i in range(0,array_len) ]
elif field_type == 'uint8':
return [ self.rand.randint(0,2**8-1) for i in range(0,array_len) ]
elif field_type == 'uint16':
return [ self.rand.randint(0,2**16-1) for i in range(0,array_len) ]
elif field_type == 'uint32':
return [ self.rand.randint(0,2**32-1) for i in range(0,array_len) ]
elif field_type == 'uint64':
return [ self.rand.randint(0,2**64-1) for i in range(0,array_len) ]
elif field_type == 'float32':
return [ self.rand.random() for i in range(0,array_len) ]
elif field_type == 'float64':
return [ self.rand.random() for i in range(0,array_len) ]
elif field_type == 'string':
return [ self.randstr(100) for i in range(0,array_len) ]
elif field_type == 'duration':
return [ rospy.Duration.from_sec(self.rand.random()) for i in range(0,array_len) ]
elif field_type == 'time':
return [ rospy.Time.from_sec(self.rand.random()*1000) for i in range(0,array_len) ]
else:
return [ self.rand_value(base_type) for i in range(0,array_len) ]
else:
msg_class = self.message_dict[field_type]
msg_inst = msg_class()
for s in msg_inst.__slots__:
ind = msg_inst.__slots__.index(s)
msg_inst.__setattr__(s,self.rand_value(msg_inst._slot_types[ind]))
return msg_inst

View File

@@ -0,0 +1,171 @@
#!/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
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import time
from random_messages import RandomMsgGen
import subprocess
import os
import genpy
DELAY = 0.5
class RandomPlay(unittest.TestCase):
def msg_cb_topic(self, topic):
def msg_cb(msg):
nowtime = rospy.Time.now()
if self.start is None:
self.start = nowtime
nowtime -= self.start
self.input.append((topic, msg, nowtime.to_sec()))
return msg_cb
def test_random_play(self):
rospy.init_node('random_sub', anonymous=True)
self.start = None
self.input = []
self.assertTrue(len(sys.argv[1]) > 3)
seed = int(sys.argv[1])
topics = int(sys.argv[2])
length = float(sys.argv[3])
scale = float(sys.argv[4])
self.use_clock = bool(int(sys.argv[5]))
rmg = RandomMsgGen(int(seed), topics, length)
subscribers = {}
for (topic, msg_class) in rmg.topics():
subscribers[topic] = rospy.Subscriber(topic, msg_class, self.msg_cb_topic(topic))
bagpath = os.path.join('/tmp', 'test_rosbag_random_record_%d.bag'%seed)
cmd = ['rosbag', 'play', '-d', str(DELAY), '-r', str(scale)]
rospy.loginfo(str(cmd))
if (self.use_clock):
cmd += ['--clock', '--hz', '100']
cmd += [bagpath]
try:
f1 = subprocess.Popen(cmd)
last_input_count = 0
while (len(self.input) < rmg.message_count()):
# print "\n%d/%d\n"%(len(self.input), rmg.message_count())
time.sleep(1.0)
# abort loop if no input is coming in anymore and process has finished
if len(self.input) == last_input_count:
rc = f1.poll()
if rc is not None:
self.assertEqual(rc, 0)
break
last_input_count = len(self.input)
self.assertEqual(len(self.input), rmg.message_count())
max_late = 0
max_early = 0
avg_off = 0
power = 0
for (expect_topic, expect_msg, expect_time) in rmg.messages():
if (not self.use_clock):
expect_time /= scale
buff = StringIO()
expect_msg.serialize(buff)
expect_msg.deserialize(buff.getvalue())
msg_match = False
for ind in range(0,100):
(input_topic, input_msg, input_time) = self.input[ind]
if (genpy.message.strify_message(expect_msg) == genpy.message.strify_message(input_msg)):
msg_match = True
del self.input[ind]
# stats
diff = input_time - expect_time
if (diff < max_early):
max_early = diff
if (diff > max_late):
max_late = diff
avg_off += diff / rmg.message_count()
power += (diff**2) / rmg.message_count()
# Messages can arrive late, but never very early Both of
# these bounds are much larger than they ought to be, but
# you never know with a heavily loaded system.
self.assertTrue(input_time - expect_time > -.5)
self.assertTrue(abs(input_time - expect_time) < 5.0)
break
if not msg_match:
print("No match at time: %f" % expect_time)
self.assertTrue(msg_match)
print("%f %f %f %f"%(max_early, max_late, avg_off, power))
finally:
f1.communicate()
self.assertEqual(f1.returncode, 0)
if __name__ == '__main__':
rostest.rosrun('test_rosbag', 'random_record_play', RandomPlay, sys.argv)

View File

@@ -0,0 +1,11 @@
<launch>
<test time-limit="120" test-name="r02random_play" pkg="test_rosbag" type="random_play.py" args="54321 10 10.0 1.0 0" retry="3">
<env name="PYTHONPATH" value="@PROJECT_SOURCE_DIR@/src:$(env PYTHONPATH)"/>
</test>
<test time-limit="120" test-name="r03random_play" pkg="test_rosbag" type="random_play.py" args="54321 10 10.0 0.5 0" retry="3">
<env name="PYTHONPATH" value="@PROJECT_SOURCE_DIR@/src:$(env PYTHONPATH)"/>
</test>
<test time-limit="120" test-name="r04random_play" pkg="test_rosbag" type="random_play.py" args="54321 10 10.0 2.0 0" retry="3">
<env name="PYTHONPATH" value="@PROJECT_SOURCE_DIR@/src:$(env PYTHONPATH)"/>
</test>
</launch>

View File

@@ -0,0 +1,12 @@
<launch>
<param name="use_sim_time" value="true"/>
<test time-limit="100" test-name="random_play05" pkg="test_rosbag" type="random_play.py" args="54321 10 10.0 1.0 1" retry="3">
<env name="PYTHONPATH" value="@PROJECT_SOURCE_DIR@/src:$(env PYTHONPATH)"/>
</test>
<test time-limit="100" test-name="random_play06" pkg="test_rosbag" type="random_play.py" args="54321 10 10.0 0.5 1" retry="3">
<env name="PYTHONPATH" value="@PROJECT_SOURCE_DIR@/src:$(env PYTHONPATH)"/>
</test>
<test time-limit="100" test-name="random_play07" pkg="test_rosbag" type="random_play.py" args="54321 10 10.0 2.0 1" retry="3">
<env name="PYTHONPATH" value="@PROJECT_SOURCE_DIR@/src:$(env PYTHONPATH)"/>
</test>
</launch>

View File

@@ -0,0 +1,112 @@
#!/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
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO
import time
from random_messages import RandomMsgGen
import subprocess
import signal
import os
import atexit
class RandomRecord(unittest.TestCase):
def test_random_record(self):
rospy.init_node('random_pub')
if (len(sys.argv) < 2):
raise Exception("Expected seed as first argument")
seed = int(sys.argv[1])
seed = int(sys.argv[1])
topics = int(sys.argv[2])
length = float(sys.argv[3])
rmg = RandomMsgGen(seed, topics, length)
publishers = {}
for (topic, msg_class) in rmg.topics():
publishers[topic] = rospy.Publisher(topic, msg_class)
bagpath = os.path.join('/tmp', 'test_rosbag_random_record_%d'%seed)
cmd = ['rosbag', 'record', '-a', '-O', bagpath]
f1 = subprocess.Popen(cmd)
def finalkill():
try:
os.kill(f1.pid, signal.SIGKILL)
except:
pass
atexit.register(finalkill)
# Sleep an extra 5 seconds for good measure
rospy.sleep(rospy.Duration.from_sec(5.0))
start = rospy.Time.now()
for (topic, msg, time) in rmg.messages():
d = start + rospy.Duration.from_sec(time) - rospy.Time.now()
rospy.sleep(d)
publishers[topic].publish(msg)
# Sleep an extra 5 seconds for good measure
rospy.sleep(rospy.Duration.from_sec(5.0))
# Initial terminate using SIGINT so bag clean up nicely
os.kill(-os.getpgrp(), signal.SIGINT)
# Sleep an extra 5 seconds for good measure
rospy.sleep(rospy.Duration.from_sec(5.0))
# Keep trying to kill until it's dead instead of blocking on communicate
while (f1.poll() is None):
try:
os.kill(f1.pid, signal.SIGKILL)
except:
pass
rospy.sleep(rospy.Duration.from_sec(1.0))
self.assertEqual(f1.returncode, 0)
if __name__ == '__main__':
rostest.rosrun('test_rosbag', 'random_record_play', RandomRecord, sys.argv)

View File

@@ -0,0 +1,5 @@
<launch>
<test time-limit="100" test-name="random_record_01" pkg="test_rosbag" type="random_record.py" args="54321 10 10.0">
<env name="PYTHONPATH" value="@PROJECT_SOURCE_DIR@/src:$(env PYTHONPATH)"/>
</test>
</launch>

View File

@@ -0,0 +1,65 @@
class update_test_rosbag_Renamed1_2fbee7c2602a76620804dfad673383b9(MessageUpdateRule):
old_type = "test_rosbag/Renamed1"
old_full_text = """
float64 foo # 2.17
int32[3] bar # [8, 2, 5]
"""
new_type = "test_rosbag/Renamed2"
new_full_text = """
float64 foo # 2.17
int32[3] bar # [8, 2, 5]
"""
order = 0
migrated_types = []
valid = True
def update(self, old_msg, new_msg):
new_msg.foo = old_msg.foo
new_msg.bar = old_msg.bar
class update_test_rosbag_Renamed2_2fbee7c2602a76620804dfad673383b9(MessageUpdateRule):
old_type = "test_rosbag/Renamed2"
old_full_text = """
float64 foo # 2.17
int32[3] bar # [8, 2, 5]
"""
new_type = "test_rosbag/Renamed3"
new_full_text = """
float64 foo # 2.17
int32[4] bar # [8, 2, 5, 1]
"""
order = 0
migrated_types = []
valid = True
def update(self, old_msg, new_msg):
new_msg.foo = old_msg.foo
new_msg.bar = [old_msg.bar[0], old_msg.bar[1], old_msg.bar[2], 1]
class update_test_rosbag_Renamed3_dd19d6452bb5e45bb900f81fed30ae83(MessageUpdateRule):
old_type = "test_rosbag/Renamed3"
old_full_text = """
float64 foo # 2.17
int32[4] bar # [8, 2, 5, 1]
"""
new_type = "test_rosbag/Renamed4"
new_full_text = """
float64 foo # 2.17
int32[4] bar # [8, 2, 5, 1]
"""
order = 0
migrated_types = []
valid = True
def update(self, old_msg, new_msg):
new_msg.foo = old_msg.foo
new_msg.bar = old_msg.bar

View File

@@ -0,0 +1,58 @@
class update_test_rosbag_SimpleMigrated_f3d103d10e4d7f4e5c4b19aa46d9a9dd(MessageUpdateRule):
old_type = "test_rosbag/SimpleMigrated"
old_full_text = """
int32 data1 # 42
"""
new_type = "test_rosbag/SimpleMigrated"
new_full_text = """
int32 data2 # 42
"""
order = 0
migrated_types = [
]
valid = True
def update(self, old_msg, new_msg):
new_msg.data2 = old_msg.data1
class update_test_rosbag_SimpleMigrated_01dfc3630b3a6d483b2f36047889c82c(MessageUpdateRule):
old_type = "test_rosbag/SimpleMigrated"
old_full_text = """
int32 data2 # 42
"""
new_type = "test_rosbag/SimpleMigrated"
new_full_text = """
int32 data3 # 42
"""
order = 1
migrated_types = []
valid = True
def update(self, old_msg, new_msg):
new_msg.data3 = old_msg.data2
class update_test_rosbag_SimpleMigrated_e6246c5a2c249e1dd0fa12bf54357ad2(MessageUpdateRule):
old_type = "test_rosbag/SimpleMigrated"
old_full_text = """
int32 data3 # 42
"""
new_type = "test_rosbag/SimpleMigrated"
new_full_text = """
int32 data # 42
"""
order = 2
migrated_types = []
valid = True
def update(self, old_msg, new_msg):
new_msg.data = old_msg.data3

View File

@@ -0,0 +1,42 @@
<package>
<name>test_rosbag</name>
<version>1.12.14</version>
<description>
A package containing the unit tests for rosbag.
</description>
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
<license>BSD</license>
<url>http://ros.org/wiki/rosbag</url>
<author>Tim Field</author>
<author>Jeremy Leibs</author>
<author>James Bowman</author>
<buildtool_depend version_gte="0.5.68">catkin</buildtool_depend>
<build_depend>boost</build_depend>
<build_depend>bzip2</build_depend>
<build_depend>cpp_common</build_depend>
<build_depend>message_generation</build_depend>
<build_depend>python-imaging</build_depend>
<build_depend>rosbag</build_depend>
<build_depend>rosconsole</build_depend>
<build_depend>roscpp</build_depend>
<build_depend>roscpp_serialization</build_depend>
<build_depend>rosgraph_msgs</build_depend>
<build_depend>rostest</build_depend>
<build_depend>rosunit</build_depend>
<build_depend>topic_tools</build_depend>
<build_depend>xmlrpcpp</build_depend>
<test_depend>genmsg</test_depend>
<test_depend>genpy</test_depend>
<test_depend>message_runtime</test_depend>
<test_depend>python-rospkg</test_depend>
<test_depend>roslib</test_depend>
<test_depend>rospy</test_depend>
<export>
<rosdoc config="${prefix}/rosdoc.yaml"/>
</export>
</package>

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)

View File

@@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 2.8.3)
project(test_rosbag_storage)
find_package(catkin REQUIRED COMPONENTS rosbag_storage std_msgs)
find_package(Boost REQUIRED)
catkin_package()
if(CATKIN_ENABLE_TESTING)
include_directories(include ${catkin_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
catkin_add_gtest(create_and_iterate_bag src/create_and_iterate_bag.cpp)
if(TARGET create_and_iterate_bag)
target_link_libraries(create_and_iterate_bag ${catkin_LIBRARIES})
endif()
catkin_add_gtest(swap_bags src/swap_bags.cpp)
if(TARGET swap_bags)
target_link_libraries(swap_bags ${catkin_LIBRARIES})
endif()
endif()

View File

@@ -0,0 +1,17 @@
<package>
<name>test_rosbag_storage</name>
<version>1.12.14</version>
<description>
A package containing the unit tests for rosbag_storage.
</description>
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
<license>BSD</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>rosbag_storage</build_depend>
<build_depend>std_msgs</build_depend>
<run_depend>rosbag_storage</run_depend>
<run_depend>std_msgs</run_depend>
</package>

View File

@@ -0,0 +1,114 @@
#include "ros/time.h"
#include "rosbag/bag.h"
#include "rosbag/view.h"
#include "std_msgs/Int32.h"
#include "std_msgs/String.h"
#include <string>
#include <vector>
#include "boost/foreach.hpp"
#include <gtest/gtest.h>
void create_test_bag(const std::string &filename)
{
rosbag::Bag bag;
bag.open(filename, rosbag::bagmode::Write);
std_msgs::String str;
str.data = std::string("foo");
std_msgs::Int32 i;
i.data = 42;
bag.write("chatter", ros::Time::now(), str);
bag.write("numbers", ros::Time::now(), i);
bag.close();
}
const char* bag_filename = "/tmp/rosbag_storage_create_and_iterate_bag.bag";
TEST(rosbag_storage, iterator_copy_constructor)
{
// copy ctor
rosbag::Bag bag;
bag.open(bag_filename, rosbag::bagmode::Read);
rosbag::View view(bag, rosbag::TopicQuery("numbers"));
rosbag::View::const_iterator it0 = view.begin();
EXPECT_EQ(42, it0->instantiate<std_msgs::Int32>()->data);
rosbag::View::const_iterator it1(it0);
EXPECT_EQ(it0, it1);
EXPECT_EQ(42, it1->instantiate<std_msgs::Int32>()->data);
++it1;
EXPECT_NE(it0, it1);
EXPECT_EQ(42, it0->instantiate<std_msgs::Int32>()->data);
}
TEST(rosbag_storage, iterator_copy_assignment)
{
// copy assignment
rosbag::Bag bag;
bag.open(bag_filename, rosbag::bagmode::Read);
rosbag::View view(bag, rosbag::TopicQuery("numbers"));
rosbag::View::const_iterator it0 = view.begin();
EXPECT_EQ(42, it0->instantiate<std_msgs::Int32>()->data);
rosbag::View::const_iterator it1;
it1 = it0;
EXPECT_EQ(it0, it1);
EXPECT_EQ(42, it1->instantiate<std_msgs::Int32>()->data);
++it1;
EXPECT_NE(it0, it1);
EXPECT_EQ(42, it0->instantiate<std_msgs::Int32>()->data);
}
TEST(rosbag_storage, iterate_bag)
{
rosbag::Bag bag;
bag.open(bag_filename, rosbag::bagmode::Read);
std::vector<std::string> topics;
topics.push_back(std::string("chatter"));
topics.push_back(std::string("numbers"));
rosbag::View view(bag, rosbag::TopicQuery(topics));
BOOST_FOREACH(rosbag::MessageInstance const m, view)
{
std_msgs::String::ConstPtr s = m.instantiate<std_msgs::String>();
if (s != NULL)
{
if(s->data == std::string("foo")) {
printf("Successfully checked string foo\n");
}
else
{
printf("Failed checked string foo\n");
FAIL();
}
}
std_msgs::Int32::ConstPtr i = m.instantiate<std_msgs::Int32>();
if (i != NULL)
{
if (i->data == 42) {
printf("Successfully checked value 42\n");
}
else
{
printf("Failed checked value 42.\n");
FAIL();
}
}
}
bag.close();
}
int main(int argc, char **argv) {
ros::Time::init();
create_test_bag(bag_filename);
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,101 @@
#include "ros/time.h"
#include "rosbag/bag.h"
#include "rosbag/view.h"
#include "std_msgs/Int32.h"
#include "boost/foreach.hpp"
#include <gtest/gtest.h>
void writeBags(rosbag::CompressionType a, rosbag::CompressionType b) {
using std::swap;
rosbag::Bag bag1("/tmp/swap1.bag", rosbag::bagmode::Write);
rosbag::Bag bag2("/tmp/swap2.bag", rosbag::bagmode::Write);
// In the end "/tmp/swap1.bag" should have CompressionType a and contain two messages of value a.
// "/tmp/swap2.bag" should have CompressionType b and contain two messages of value b.
// We use these pointers to track the bags accordingly.
rosbag::Bag* a_bag = &bag1;
rosbag::Bag* b_bag = &bag2;
std_msgs::Int32 a_msg, b_msg;
a_msg.data = a;
b_msg.data = b;
swap(bag1, bag2);
swap(a_bag, b_bag);
a_bag->setCompression(a);
b_bag->setCompression(b);
swap(bag1, bag2);
swap(a_bag, b_bag);
a_bag->write("/data", ros::Time::now(), a_msg);
b_bag->write("/data", ros::Time::now(), b_msg);
swap(bag1, bag2);
swap(a_bag, b_bag);
a_bag->write("/data", ros::Time::now(), a_msg);
b_bag->write("/data", ros::Time::now(), b_msg);
swap(bag1, bag2);
bag1.close();
bag2.close();
swap(bag1, bag2);
}
void readBags(rosbag::CompressionType a, rosbag::CompressionType b) {
using std::swap;
rosbag::Bag bag1("/tmp/swap1.bag", rosbag::bagmode::Read);
rosbag::Bag bag2("/tmp/swap2.bag", rosbag::bagmode::Read);
rosbag::Bag* a_bag = &bag1;
rosbag::Bag* b_bag = &bag2;
swap(bag1, bag2);
swap(a_bag, b_bag);
// only valid when writing
//EXPECT_EQ(a_bag->getCompression(), a);
//EXPECT_EQ(b_bag->getCompression(), b);
std::vector<std::string> topics;
topics.push_back("data");
rosbag::View a_view(*a_bag, rosbag::TopicQuery(topics));
rosbag::View b_view(*b_bag, rosbag::TopicQuery(topics));
BOOST_FOREACH(rosbag::MessageInstance const m, a_view)
{
std_msgs::Int32::ConstPtr i = m.instantiate<std_msgs::Int32>();
ASSERT_TRUE(i);
EXPECT_EQ(i->data, a);
}
BOOST_FOREACH(rosbag::MessageInstance const m, b_view)
{
std_msgs::Int32::ConstPtr i = m.instantiate<std_msgs::Int32>();
ASSERT_TRUE(i);
EXPECT_EQ(i->data, b);
}
}
TEST(rosbag_storage, swap_bags)
{
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
writeBags(rosbag::CompressionType(i), rosbag::CompressionType(j));
readBags(rosbag::CompressionType(i), rosbag::CompressionType(j));
}
}
}
int main(int argc, char **argv) {
ros::Time::init();
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,95 @@
cmake_minimum_required(VERSION 2.8.3)
project(test_roscpp)
if(NOT WIN32)
set_directory_properties(PROPERTIES COMPILE_OPTIONS "-Wall;-Wextra")
endif()
find_package(catkin REQUIRED COMPONENTS
message_generation roscpp rostest rosunit std_srvs
)
if(CATKIN_ENABLE_TESTING)
find_package(Boost REQUIRED COMPONENTS signals filesystem system)
include_directories(include ${catkin_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
# Testing message and service files. See comment below about subdirectory support.
add_message_files(
NOINSTALL
DIRECTORY test/msg
FILES
TestArray.msg
TestEmpty.msg
TestStringInt.msg
TestWithHeader.msg
)
add_service_files(
NOINSTALL
DIRECTORY test/srv
FILES
BadTestStringString.srv
TestStringString.srv
)
# Serialization testing message files.
add_message_files(
NOINSTALL
DIRECTORY test_serialization/msg
FILES
ArrayOfFixedLength.msg
ArrayOfVariableLength.msg
Constants.msg
CustomHeader.msg
EmbeddedExternal.msg
EmbeddedFixedLength.msg
EmbeddedVariableLength.msg
FixedLengthArrayOfExternal.msg
FixedLength.msg
FixedLengthStringArray.msg
HeaderNotFirstMember.msg
VariableLengthArrayOfExternal.msg
VariableLength.msg
VariableLengthStringArray.msg
WithDuration.msg
WithHeader.msg
WithMemberNamedHeaderThatIsNotAHeader.msg
WithTime.msg
)
# Performance testing message files. add_message_files() does not
# currently support being called from a subdirectory, so this is here
# for now.
add_message_files(
NOINSTALL
DIRECTORY perf/msg
FILES
LatencyMessage.msg
ThroughputMessage.msg
)
# Message files for testing the performance of serialization.
add_message_files(
NOINSTALL
DIRECTORY perf_serialization/msg
FILES
ChannelFloat32.msg
Point32.msg
PointCloud.msg
)
# dependencies std_msgs and rosgraph_msgs are needed by tests, but not by roscpp otherwise.
generate_messages(DEPENDENCIES rosgraph_msgs std_msgs)
endif()
catkin_package(
CATKIN_DEPENDS message_runtime rosconsole rosgraph_msgs std_msgs xmlrpcpp
)
if(CATKIN_ENABLE_TESTING)
add_subdirectory(test)
add_subdirectory(perf)
add_subdirectory(test_serialization)
add_subdirectory(perf_serialization)
endif()

View File

@@ -0,0 +1,40 @@
<package>
<name>test_roscpp</name>
<version>1.12.14</version>
<description>
Tests for roscpp which depend on rostest.
</description>
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
<license>BSD</license>
<url>http://ros.org/wiki/roscpp</url>
<author>Morgan Quigley</author>
<author>Josh Faust</author>
<author>Brian Gerkey</author>
<author>Troy Straszheim</author>
<buildtool_depend version_gte="0.5.68">catkin</buildtool_depend>
<build_depend>cpp_common</build_depend>
<build_depend>message_generation</build_depend>
<build_depend>pkg-config</build_depend>
<build_depend>rosconsole</build_depend>
<build_depend>roscpp</build_depend>
<build_depend>roscpp_serialization</build_depend>
<build_depend>roscpp_traits</build_depend>
<build_depend>rosgraph_msgs</build_depend>
<build_depend>roslang</build_depend>
<build_depend>rostest</build_depend>
<build_depend>rostime</build_depend>
<build_depend>rosunit</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>std_srvs</build_depend>
<build_depend>xmlrpcpp</build_depend>
<run_depend>message_runtime</run_depend>
<run_depend>rosconsole</run_depend>
<run_depend>rosgraph_msgs</run_depend>
<run_depend>std_msgs</run_depend>
<run_depend>std_srvs</run_depend>
<run_depend>xmlrpcpp</run_depend>
</package>

View File

@@ -0,0 +1,23 @@
find_package(Boost REQUIRED COMPONENTS thread)
include_directories(include ${catkin_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS})
# Can't call add_message_files() here because CMake context is lost when we leave this subdir.
# add_message_files(
# DIRECTORY msg
# FILES
# LatencyMessage.msg
# ThroughputMessage.msg
# )
# Can't call generate_messages() here, because currently can only have one instance of it per project.
# This means this file must be included before generate_messages() in the parent.
#common commands for building c++ executables and libraries
add_library(${PROJECT_NAME}_perf EXCLUDE_FROM_ALL src/intra.cpp src/inter.cpp)
add_dependencies(${PROJECT_NAME}_perf ${${PROJECT_NAME}_EXPORTED_TARGETS})
target_link_libraries(${PROJECT_NAME}_perf ${Boost_LIBRARIES} ${catkin_LIBRARIES})
# These performance tests will not be built or executed automatically.
# TODO: automate them in some useful way.
add_executable(${PROJECT_NAME}-intra_suite EXCLUDE_FROM_ALL src/intra_suite.cpp)
target_link_libraries(${PROJECT_NAME}-intra_suite ${PROJECT_NAME}_perf ${catkin_LIBRARIES})

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,102 @@
/*
* Software License Agreement (BSD License)
*
* Copyright (c) 2009, 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.
*/
#ifndef PERF_ROSCPP_INTRA_H
#define PERF_ROSCPP_INTRA_H
#include <ros/types.h>
#include <ros/time.h>
namespace perf_roscpp
{
namespace intra
{
struct ThroughputResult
{
double test_duration;
uint64_t streams;
uint64_t message_size;
uint32_t sender_threads;
uint32_t receiver_threads;
uint64_t messages_sent;
uint64_t messages_received;
uint64_t total_bytes_sent;
uint64_t total_bytes_received;
uint64_t bytes_per_second;
ros::WallTime test_start;
ros::WallTime test_end;
};
ThroughputResult throughput(double duration, uint32_t streams, uint32_t message_size, uint32_t sender_threads, uint32_t receiver_threads);
struct LatencyResult
{
uint64_t count_per_stream;
uint64_t streams;
uint64_t message_size;
uint32_t sender_threads;
uint32_t receiver_threads;
uint64_t total_message_count;
double latency_avg;
double latency_min;
double latency_max;
ros::WallTime test_start;
ros::WallTime test_end;
};
LatencyResult latency(uint32_t count_per_stream, uint32_t streams, uint32_t message_size, uint32_t sender_threads, uint32_t receiver_threads);
struct STLatencyResult
{
uint64_t total_message_count;
double latency_avg;
double latency_min;
double latency_max;
ros::WallTime test_start;
ros::WallTime test_end;
};
STLatencyResult stlatency(uint32_t message_count);
} // namespace intra
} // namespace perf_roscpp
#endif // PERF_ROSCPP_INTRA_H

View File

@@ -0,0 +1,6 @@
float64 publish_time
float64 receipt_time
uint64 count
uint32 thread_index
uint8[] array

View File

@@ -0,0 +1,2 @@
uint8[] array

Some files were not shown because too many files have changed in this diff Show More