auto_roll_logger_test to move away from real sleep

Summary:
auto_roll_logger_test relies on timing conditon that some operations finish within 1 seconds. This caused flaky tests. Move away from real timing and sleep and use fake time to verify the time-based rolling.
Closes https://github.com/facebook/rocksdb/pull/2066

Differential Revision: D4810647

Pulled By: siying

fbshipit-source-id: c54d994
This commit is contained in:
Siying Dong 2017-04-03 11:24:39 -07:00 committed by Facebook Github Bot
parent d25e28d584
commit 88cc81df5c
2 changed files with 70 additions and 62 deletions

View File

@ -91,6 +91,8 @@ class AutoRollLogger : public Logger {
return log_fname_; return log_fname_;
} }
uint64_t TEST_ctime() const { return ctime_; }
private: private:
bool LogExpired(); bool LogExpired();
Status ResetLogger(); Status ResetLogger();

View File

@ -17,6 +17,7 @@
#include <string> #include <string>
#include <thread> #include <thread>
#include <vector> #include <vector>
#include "db/db_test_util.h"
#include "port/port.h" #include "port/port.h"
#include "rocksdb/db.h" #include "rocksdb/db.h"
#include "util/logging.h" #include "util/logging.h"
@ -24,6 +25,22 @@
#include "util/testharness.h" #include "util/testharness.h"
namespace rocksdb { namespace rocksdb {
namespace {
class NoSleepEnv : public EnvWrapper {
public:
NoSleepEnv(Env* base) : EnvWrapper(base) {}
virtual void SleepForMicroseconds(int micros) override {
fake_time_ += static_cast<uint64_t>(micros);
}
virtual uint64_t NowNanos() override { return fake_time_ * 1000; }
virtual uint64_t NowMicros() override { return fake_time_; }
private:
uint64_t fake_time_ = 6666666666;
};
} // namespace
class AutoRollLoggerTest : public testing::Test { class AutoRollLoggerTest : public testing::Test {
public: public:
@ -44,13 +61,13 @@ class AutoRollLoggerTest : public testing::Test {
void RollLogFileBySizeTest(AutoRollLogger* logger, size_t log_max_size, void RollLogFileBySizeTest(AutoRollLogger* logger, size_t log_max_size,
const std::string& log_message); const std::string& log_message);
uint64_t RollLogFileByTimeTest(AutoRollLogger* logger, size_t time, void RollLogFileByTimeTest(Env*, AutoRollLogger* logger, size_t time,
const std::string& log_message); const std::string& log_message);
static const std::string kSampleMessage; static const std::string kSampleMessage;
static const std::string kTestDir; static const std::string kTestDir;
static const std::string kLogFile; static const std::string kLogFile;
static Env* env; static Env* default_env;
}; };
const std::string AutoRollLoggerTest::kSampleMessage( const std::string AutoRollLoggerTest::kSampleMessage(
@ -58,7 +75,7 @@ const std::string AutoRollLoggerTest::kSampleMessage(
const std::string AutoRollLoggerTest::kTestDir(test::TmpDir() + "/db_log_test"); const std::string AutoRollLoggerTest::kTestDir(test::TmpDir() + "/db_log_test");
const std::string AutoRollLoggerTest::kLogFile(test::TmpDir() + const std::string AutoRollLoggerTest::kLogFile(test::TmpDir() +
"/db_log_test/LOG"); "/db_log_test/LOG");
Env* AutoRollLoggerTest::env = Env::Default(); Env* AutoRollLoggerTest::default_env = Env::Default();
// In this test we only want to Log some simple log message with // In this test we only want to Log some simple log message with
// no format. LogMessage() provides such a simple interface and // no format. LogMessage() provides such a simple interface and
@ -75,16 +92,6 @@ void LogMessage(const InfoLogLevel log_level, Logger* logger,
} }
} // namespace } // namespace
namespace {
void GetFileCreateTime(const std::string& fname, uint64_t* file_ctime) {
struct stat s;
if (stat(fname.c_str(), &s) != 0) {
*file_ctime = (uint64_t)0;
}
*file_ctime = static_cast<uint64_t>(s.st_ctime);
}
} // namespace
void AutoRollLoggerTest::RollLogFileBySizeTest(AutoRollLogger* logger, void AutoRollLoggerTest::RollLogFileBySizeTest(AutoRollLogger* logger,
size_t log_max_size, size_t log_max_size,
const std::string& log_message) { const std::string& log_message) {
@ -111,45 +118,42 @@ void AutoRollLoggerTest::RollLogFileBySizeTest(AutoRollLogger* logger,
ASSERT_TRUE(message_size == logger->GetLogFileSize()); ASSERT_TRUE(message_size == logger->GetLogFileSize());
} }
uint64_t AutoRollLoggerTest::RollLogFileByTimeTest( void AutoRollLoggerTest::RollLogFileByTimeTest(Env* env, AutoRollLogger* logger,
AutoRollLogger* logger, size_t time, const std::string& log_message) { size_t time,
uint64_t expected_create_time; const std::string& log_message) {
uint64_t actual_create_time; uint64_t expected_ctime;
uint64_t actual_ctime;
uint64_t total_log_size; uint64_t total_log_size;
EXPECT_OK(env->GetFileSize(kLogFile, &total_log_size)); EXPECT_OK(env->GetFileSize(kLogFile, &total_log_size));
GetFileCreateTime(kLogFile, &expected_create_time); expected_ctime = logger->TEST_ctime();
logger->SetCallNowMicrosEveryNRecords(0); logger->SetCallNowMicrosEveryNRecords(0);
// -- Write to the log for several times, which is supposed // -- Write to the log for several times, which is supposed
// to be finished before time. // to be finished before time.
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
LogMessage(logger, log_message.c_str()); env->SleepForMicroseconds(50000);
EXPECT_OK(logger->GetStatus()); LogMessage(logger, log_message.c_str());
// Make sure we always write to the same log file (by EXPECT_OK(logger->GetStatus());
// checking the create time); // Make sure we always write to the same log file (by
GetFileCreateTime(kLogFile, &actual_create_time); // checking the create time);
// Also make sure the log size is increasing. actual_ctime = logger->TEST_ctime();
EXPECT_EQ(expected_create_time, actual_create_time);
EXPECT_GT(logger->GetLogFileSize(), total_log_size); // Also make sure the log size is increasing.
total_log_size = logger->GetLogFileSize(); EXPECT_EQ(expected_ctime, actual_ctime);
EXPECT_GT(logger->GetLogFileSize(), total_log_size);
total_log_size = logger->GetLogFileSize();
} }
// -- Make the log file expire // -- Make the log file expire
#ifdef OS_WIN env->SleepForMicroseconds(static_cast<int>(time * 1000000));
Sleep(static_cast<unsigned int>(time) * 1000);
#else
sleep(static_cast<unsigned int>(time));
#endif
LogMessage(logger, log_message.c_str()); LogMessage(logger, log_message.c_str());
// At this time, the new log file should be created. // At this time, the new log file should be created.
GetFileCreateTime(kLogFile, &actual_create_time); actual_ctime = logger->TEST_ctime();
EXPECT_GT(actual_create_time, expected_create_time); EXPECT_LT(expected_ctime, actual_ctime);
EXPECT_LT(logger->GetLogFileSize(), total_log_size); EXPECT_LT(logger->GetLogFileSize(), total_log_size);
expected_create_time = actual_create_time;
return expected_create_time;
} }
TEST_F(AutoRollLoggerTest, RollLogFileBySize) { TEST_F(AutoRollLoggerTest, RollLogFileBySize) {
@ -163,16 +167,19 @@ TEST_F(AutoRollLoggerTest, RollLogFileBySize) {
} }
TEST_F(AutoRollLoggerTest, RollLogFileByTime) { TEST_F(AutoRollLoggerTest, RollLogFileByTime) {
size_t time = 2; NoSleepEnv nse(Env::Default());
size_t log_size = 1024 * 5;
InitTestDb(); size_t time = 2;
// -- Test the existence of file during the server restart. size_t log_size = 1024 * 5;
ASSERT_EQ(Status::NotFound(), env->FileExists(kLogFile));
AutoRollLogger logger(Env::Default(), kTestDir, "", log_size, time);
ASSERT_OK(env->FileExists(kLogFile));
RollLogFileByTimeTest(&logger, time, kSampleMessage + ":RollLogFileByTime"); InitTestDb();
// -- Test the existence of file during the server restart.
ASSERT_EQ(Status::NotFound(), default_env->FileExists(kLogFile));
AutoRollLogger logger(&nse, kTestDir, "", log_size, time);
ASSERT_OK(default_env->FileExists(kLogFile));
RollLogFileByTimeTest(&nse, &logger, time,
kSampleMessage + ":RollLogFileByTime");
} }
TEST_F(AutoRollLoggerTest, OpenLogFilesMultipleTimesWithOptionLog_max_size) { TEST_F(AutoRollLoggerTest, OpenLogFilesMultipleTimesWithOptionLog_max_size) {
@ -205,16 +212,16 @@ TEST_F(AutoRollLoggerTest, CompositeRollByTimeAndSizeLogger) {
InitTestDb(); InitTestDb();
AutoRollLogger logger(Env::Default(), kTestDir, "", log_max_size, time); NoSleepEnv nse(Env::Default());
AutoRollLogger logger(&nse, kTestDir, "", log_max_size, time);
// Test the ability to roll by size // Test the ability to roll by size
RollLogFileBySizeTest( RollLogFileBySizeTest(&logger, log_max_size,
&logger, log_max_size, kSampleMessage + ":CompositeRollByTimeAndSizeLogger");
kSampleMessage + ":CompositeRollByTimeAndSizeLogger");
// Test the ability to roll by Time // Test the ability to roll by Time
RollLogFileByTimeTest( &logger, time, RollLogFileByTimeTest(&nse, &logger, time,
kSampleMessage + ":CompositeRollByTimeAndSizeLogger"); kSampleMessage + ":CompositeRollByTimeAndSizeLogger");
} }
#ifndef OS_WIN #ifndef OS_WIN
@ -222,6 +229,7 @@ TEST_F(AutoRollLoggerTest, CompositeRollByTimeAndSizeLogger) {
// port // port
TEST_F(AutoRollLoggerTest, CreateLoggerFromOptions) { TEST_F(AutoRollLoggerTest, CreateLoggerFromOptions) {
DBOptions options; DBOptions options;
NoSleepEnv nse(Env::Default());
shared_ptr<Logger> logger; shared_ptr<Logger> logger;
// Normal logger // Normal logger
@ -240,15 +248,15 @@ TEST_F(AutoRollLoggerTest, CreateLoggerFromOptions) {
kSampleMessage + ":CreateLoggerFromOptions - size"); kSampleMessage + ":CreateLoggerFromOptions - size");
// Only roll by Time // Only roll by Time
options.env = &nse;
InitTestDb(); InitTestDb();
options.max_log_file_size = 0; options.max_log_file_size = 0;
options.log_file_time_to_roll = 2; options.log_file_time_to_roll = 2;
ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger)); ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
auto_roll_logger = auto_roll_logger =
dynamic_cast<AutoRollLogger*>(logger.get()); dynamic_cast<AutoRollLogger*>(logger.get());
RollLogFileByTimeTest( RollLogFileByTimeTest(&nse, auto_roll_logger, options.log_file_time_to_roll,
auto_roll_logger, options.log_file_time_to_roll, kSampleMessage + ":CreateLoggerFromOptions - time");
kSampleMessage + ":CreateLoggerFromOptions - time");
// roll by both Time and size // roll by both Time and size
InitTestDb(); InitTestDb();
@ -257,12 +265,10 @@ TEST_F(AutoRollLoggerTest, CreateLoggerFromOptions) {
ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger)); ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));
auto_roll_logger = auto_roll_logger =
dynamic_cast<AutoRollLogger*>(logger.get()); dynamic_cast<AutoRollLogger*>(logger.get());
RollLogFileBySizeTest( RollLogFileBySizeTest(auto_roll_logger, options.max_log_file_size,
auto_roll_logger, options.max_log_file_size, kSampleMessage + ":CreateLoggerFromOptions - both");
kSampleMessage + ":CreateLoggerFromOptions - both"); RollLogFileByTimeTest(&nse, auto_roll_logger, options.log_file_time_to_roll,
RollLogFileByTimeTest( kSampleMessage + ":CreateLoggerFromOptions - both");
auto_roll_logger, options.log_file_time_to_roll,
kSampleMessage + ":CreateLoggerFromOptions - both");
} }
TEST_F(AutoRollLoggerTest, LogFlushWhileRolling) { TEST_F(AutoRollLoggerTest, LogFlushWhileRolling) {
@ -462,7 +468,7 @@ TEST_F(AutoRollLoggerTest, LogFileExistence) {
options.max_log_file_size = 100 * 1024 * 1024; options.max_log_file_size = 100 * 1024 * 1024;
options.create_if_missing = true; options.create_if_missing = true;
ASSERT_OK(rocksdb::DB::Open(options, kTestDir, &db)); ASSERT_OK(rocksdb::DB::Open(options, kTestDir, &db));
ASSERT_OK(env->FileExists(kLogFile)); ASSERT_OK(default_env->FileExists(kLogFile));
delete db; delete db;
} }