pxmlw6n2f/Gazebo_Distributed_TCP/gazebo/util/LogPlay_TEST.cc

466 lines
15 KiB
C++

/*
* Copyright (C) 2015 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <gtest/gtest.h>
#include <boost/filesystem.hpp>
#include <string>
#include <thread>
#include "gazebo/common/CommonIface.hh"
#include "gazebo/common/Time.hh"
#include "gazebo/util/LogPlay.hh"
#include "test_config.h"
#include "test/util.hh"
class LogPlay_TEST : public gazebo::testing::AutoLogFixture { };
/////////////////////////////////////////////////
/// \brief Test LogPlay Open.
TEST_F(LogPlay_TEST, Open)
{
gazebo::util::LogPlay *player = gazebo::util::LogPlay::Instance();
EXPECT_FALSE(player->IsOpen());
// Open a file that does not exist.
EXPECT_ANY_THROW(player->Open("non-existing-file"));
EXPECT_FALSE(player->IsOpen());
boost::filesystem::path logFilePath(TEST_PATH);
// Open a file that is a directory.
EXPECT_ANY_THROW(player->Open(logFilePath.string()));
EXPECT_FALSE(player->IsOpen());
logFilePath = TEST_PATH / boost::filesystem::path("logs");
logFilePath /= boost::filesystem::path("invalidHeader.log");
// Open a malformed log file (incorrect header).
EXPECT_ANY_THROW(player->Open(logFilePath.string()));
EXPECT_FALSE(player->IsOpen());
logFilePath = TEST_PATH / boost::filesystem::path("logs");
logFilePath /= boost::filesystem::path("state.log");
// Open a correct log file.
EXPECT_NO_THROW(player->Open(logFilePath.string()));
EXPECT_TRUE(player->IsOpen());
}
/////////////////////////////////////////////////
/// \brief Test LogPlay accessors.
TEST_F(LogPlay_TEST, Accessors)
{
gazebo::common::Time expectedStartTime(28, 457000000);
gazebo::common::Time expectedEndTime(31, 745000000);
std::ostringstream expectedHeader;
expectedHeader << "<?xml version='1.0'?>\n"
<< "<gazebo_log>\n"
<< "<header>\n"
<< "<log_version>1.0</log_version>\n"
<< "<gazebo_version>6.0.0</gazebo_version>\n"
<< "<rand_seed>27838</rand_seed>\n"
<< "<log_start>" << expectedStartTime << "</log_start>\n"
<< "<log_end>" << expectedEndTime << "</log_end>\n"
<< "</header>\n";
gazebo::util::LogPlay *player = gazebo::util::LogPlay::Instance();
// Open a correct log file.
boost::filesystem::path logFilePath(TEST_PATH);
logFilePath /= boost::filesystem::path("logs");
logFilePath /= boost::filesystem::path("state.log");
EXPECT_NO_THROW(player->Open(logFilePath.string()));
// Test the accessors.
EXPECT_EQ(player->LogVersion(), "1.0");
EXPECT_EQ(player->GazeboVersion(), "6.0.0");
EXPECT_EQ(player->RandSeed(), 27838u);
EXPECT_EQ(player->LogStartTime(), expectedStartTime);
EXPECT_EQ(player->LogEndTime(), expectedEndTime);
EXPECT_EQ(player->Filename(), "state.log");
EXPECT_EQ(player->FullPathFilename(), logFilePath.string());
EXPECT_EQ(player->FileSize(), 341608u);
EXPECT_EQ(player->Encoding(), "zlib");
EXPECT_EQ(player->Header(), expectedHeader.str());
EXPECT_EQ(player->ChunkCount(), 5u);
EXPECT_FALSE(player->HasIterations());
EXPECT_EQ(player->InitialIterations(), 0u);
std::string chunk;
EXPECT_TRUE(player->Chunk(0, chunk));
// Open a correct log file including <iterations>.
logFilePath = TEST_PATH;
logFilePath /= boost::filesystem::path("logs");
logFilePath /= boost::filesystem::path("state2.log");
EXPECT_NO_THROW(player->Open(logFilePath.string()));
EXPECT_TRUE(player->HasIterations());
EXPECT_EQ(player->InitialIterations(), 23700u);
}
/////////////////////////////////////////////////
/// \brief Test LogPlay chunks.
TEST_F(LogPlay_TEST, Chunks)
{
std::string chunk;
gazebo::util::LogPlay *player = gazebo::util::LogPlay::Instance();
// Open a correct log file.
boost::filesystem::path logFilePath(TEST_PATH);
logFilePath /= boost::filesystem::path("logs");
logFilePath /= boost::filesystem::path("state.log");
EXPECT_NO_THROW(player->Open(logFilePath.string()));
// Verify the content of chunk #0.
player->Chunk(0, chunk);
std::string shasum = gazebo::common::get_sha1<std::string>(chunk);
EXPECT_EQ(shasum, "aa227eee0554b8ace3a033e90b4f0c247909db33");
// Make sure that the chunks returned are not empty.
for (unsigned int i = 0; i < player->ChunkCount(); ++i)
{
EXPECT_TRUE(player->Chunk(i, chunk));
EXPECT_TRUE(!chunk.empty());
}
// Try incorrect chunk indexes.
EXPECT_FALSE(player->Chunk(-1, chunk));
EXPECT_FALSE(player->Chunk(player->ChunkCount(), chunk));
}
/////////////////////////////////////////////////
/// \brief Test Rewind().
TEST_F(LogPlay_TEST, Rewind)
{
gazebo::util::LogPlay *player = gazebo::util::LogPlay::Instance();
// Open a correct log file.
boost::filesystem::path logFilePath(TEST_PATH);
logFilePath /= boost::filesystem::path("logs");
logFilePath /= boost::filesystem::path("state.log");
EXPECT_NO_THROW(player->Open(logFilePath.string()));
// Read the first entry in the log file.
std::string firstEntry;
// Consume the first frame because it does not have <state>
// ToDo: Fix this.
EXPECT_TRUE(player->Step(firstEntry));
// Read the first world state.
EXPECT_TRUE(player->Step(firstEntry));
// Step a few more times.
std::string logEntry;
for (int i = 0; i < 5; ++i)
EXPECT_TRUE(player->Step(logEntry));
// Rewind and read the first entry again.
EXPECT_TRUE(player->Rewind());
std::string entry;
EXPECT_TRUE(player->Step(entry));
EXPECT_EQ(entry, firstEntry);
}
/////////////////////////////////////////////////
/// \brief Test Forward().
TEST_F(LogPlay_TEST, Forward)
{
gazebo::util::LogPlay *player = gazebo::util::LogPlay::Instance();
// Open a correct log file.
boost::filesystem::path logFilePath(TEST_PATH);
logFilePath /= boost::filesystem::path("logs");
logFilePath /= boost::filesystem::path("state.log");
EXPECT_NO_THROW(player->Open(logFilePath.string()));
EXPECT_TRUE(player->Forward());
// Read the last frame.
std::string frame;
player->StepBack(frame);
std::string expectedShashum = "961cf9dcd38c12f33a8b2f3a3a6fdb879b2faa98";
std::string shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum);
// Try again if I'm already at the end of the log.
EXPECT_TRUE(player->Forward());
player->StepBack(frame);
shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum);
// Jump to the beginning and then to the end.
EXPECT_TRUE(player->Rewind());
EXPECT_TRUE(player->Forward());
player->StepBack(frame);
shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum);
}
/////////////////////////////////////////////////
/// \brief Test Step().
TEST_F(LogPlay_TEST, Step)
{
gazebo::util::LogPlay *player = gazebo::util::LogPlay::Instance();
// Open a correct log file.
boost::filesystem::path logFilePath(TEST_PATH);
logFilePath /= boost::filesystem::path("logs");
logFilePath /= boost::filesystem::path("state.log");
EXPECT_NO_THROW(player->Open(logFilePath.string()));
std::string frame;
// Consume the first frame because it does not have <state>
// ToDo: Fix this.
EXPECT_TRUE(player->Step(frame));
// Read the first world state.
EXPECT_TRUE(player->Step(frame));
std::string expectedShashum = "0a61e946f14f7395a8bdb7974cb1e18c0d9e3d22";
std::string shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum);
for (int i = 0; i < 1002; ++i)
EXPECT_TRUE(player->Step(frame));
// The last Step() should cause a transition to the next chunk.
expectedShashum = "290a6f04c4c10867d1ed1697d09a7287be3e5500";
shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum);
// You cannot Step() if you're at the end of the log file.
player->Forward();
EXPECT_FALSE(player->Step(frame));
}
/////////////////////////////////////////////////
/// \brief Test StepBack().
TEST_F(LogPlay_TEST, StepBack)
{
gazebo::util::LogPlay *player = gazebo::util::LogPlay::Instance();
// Open a correct log file.
boost::filesystem::path logFilePath(TEST_PATH);
logFilePath /= boost::filesystem::path("logs");
logFilePath /= boost::filesystem::path("state.log");
EXPECT_NO_THROW(player->Open(logFilePath.string()));
EXPECT_TRUE(player->Forward());
// This is the last frame (simulation time = 31.745).
std::string frame;
EXPECT_TRUE(player->StepBack(frame));
std::string expectedShashum = "961cf9dcd38c12f33a8b2f3a3a6fdb879b2faa98";
std::string shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum);
// Read another frame (simulation time = 31.744).
EXPECT_TRUE(player->StepBack(frame));
expectedShashum = "c1cf8582d0cb6b628b89c22f91bb9573ee804bf6";
shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum);
for (int i = 0; i < 284; ++i)
EXPECT_TRUE(player->StepBack(frame));
// The last StepBack() should cause a transition to a different chunk.
// Simulation time should be 31.460.
expectedShashum = "043e1f2975619bf5b25aefab749d66f3aa510ef6";
shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum);
// Rewind and try to StepBack().
EXPECT_TRUE(player->Rewind());
EXPECT_FALSE(player->StepBack(frame));
}
/////////////////////////////////////////////////
/// \brief Test multi-step().
TEST_F(LogPlay_TEST, MultiStep)
{
gazebo::util::LogPlay *player = gazebo::util::LogPlay::Instance();
// Open a correct log file.
boost::filesystem::path logFilePath(TEST_PATH);
logFilePath /= boost::filesystem::path("logs");
logFilePath /= boost::filesystem::path("state.log");
EXPECT_NO_THROW(player->Open(logFilePath.string()));
player->Rewind();
// Simulation time should be 28.465
std::string frame;
EXPECT_TRUE(player->Step(10, frame));
std::string expectedShashum = "960543e7ac9cb2bcab5a7ee0bec314efb8d07e97";
std::string shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum);
// Simulation time should be 28.462
EXPECT_TRUE(player->Step(-3, frame));
expectedShashum = "83e173d438cd268ca475ea36350c914da25b51ca";
shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum);
EXPECT_TRUE(player->Step(-10, frame));
// We should be at the beginning of the log file.
expectedShashum = "30a3c4c09922a4fd15070c9eed84c89a3d1e8b53";
shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum);
// We can't execute a single step here.
EXPECT_FALSE(player->Step(-2, frame));
EXPECT_TRUE(player->Forward());
// We can't execute a single step here.
EXPECT_FALSE(player->Step(5, frame));
EXPECT_TRUE(player->Step(-2, frame));
// Simulation time should be 31.745
EXPECT_TRUE(player->Step(10, frame));
// We should be at the end of the log file.
expectedShashum = "961cf9dcd38c12f33a8b2f3a3a6fdb879b2faa98";
shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum);
}
/////////////////////////////////////////////////
/// \brief Test Seek().
TEST_F(LogPlay_TEST, Seek)
{
gazebo::util::LogPlay *player = gazebo::util::LogPlay::Instance();
// Open a correct log file.
boost::filesystem::path logFilePath(TEST_PATH);
logFilePath /= boost::filesystem::path("logs");
logFilePath /= boost::filesystem::path("state.log");
EXPECT_NO_THROW(player->Open(logFilePath.string()));
std::string expectedShashum1 = "a2af44bc561194dfeae9526c224d56bb332a4233";
std::string expectedShashum2 = "113748a3c02575f514b27bc5b4307f621644ad41";
std::string expectedShashum3 = "0a61e946f14f7395a8bdb7974cb1e18c0d9e3d22";
std::string expectedShashum4 = "961cf9dcd38c12f33a8b2f3a3a6fdb879b2faa98";
std::string frame;
EXPECT_TRUE(player->Seek(common::Time(30.0)));
EXPECT_TRUE(player->Step(frame));
std::string shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum1);
EXPECT_TRUE(player->Seek(common::Time(31.5)));
EXPECT_TRUE(player->Step(frame));
shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum2);
EXPECT_TRUE(player->Seek(common::Time(30.0)));
EXPECT_TRUE(player->Step(frame));
shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum1);
// Seek the to the beginning of the log.
EXPECT_TRUE(player->Seek(common::Time(28.457)));
EXPECT_TRUE(player->Step(frame));
shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum3);
// Seek the to the end of the log.
EXPECT_TRUE(player->Seek(common::Time(31.745)));
EXPECT_TRUE(player->Step(frame));
shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum4);
// Try to seek before the beginning of the log.
EXPECT_TRUE(player->Seek(common::Time(25.0)));
EXPECT_TRUE(player->Step(frame));
shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum3);
// Try to seek after the end of the log.
EXPECT_TRUE(player->Seek(common::Time(35.0)));
EXPECT_TRUE(player->Step(frame));
shasum = gazebo::common::get_sha1<std::string>(frame);
EXPECT_EQ(shasum, expectedShashum4);
}
/////////////////////////////////////////////////
/// \brief Test reading a log file that is missing the closing </gazebo_log>
/// tag
TEST_F(LogPlay_TEST, NoEndTag)
{
// \todo Make temporary files work in windows.
#ifndef _WIN32
gazebo::util::LogPlay *player = gazebo::util::LogPlay::Instance();
// Open the log file that is missing the end tag
std::ifstream srcFile(std::string(TEST_PATH) + "/logs/state_no_end.log",
std::ios::binary);
ASSERT_TRUE(srcFile.good());
// Create a temporary test file.
std::ostringstream stream;
stream << "/tmp/__gz_log_test" << std::this_thread::get_id();
std::string tmpFilename = stream.str();
std::ofstream destFile(tmpFilename, std::ios::binary);
ASSERT_TRUE(destFile.good());
// Copy source to a temporary file so that we can modify it.
destFile << srcFile.rdbuf();
destFile.close();
// Make sure we can read the log file
EXPECT_NO_THROW(player->Open(tmpFilename));
// Open the temporary file, which should now have the proper end tag
std::ifstream inFile(tmpFilename);
std::string endTag = "</gazebo_log>";
// Back up the length of the closing tag.
int len = -1 - static_cast<int>(endTag.length());
inFile.seekg(len, std::ios::end);
// Get the last line
std::string lastLine;
std::getline(inFile, lastLine);
inFile.close();
// Remove the temp file
std::remove(tmpFilename.c_str());
// Check that the log file now has the closing end tag
EXPECT_EQ(lastLine, endTag);
#endif
}
/////////////////////////////////////////////////
int main(int argc, char **argv)
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}