#include "util/repeatable_thread.h"
#include <atomic>
#include <memory>
#include "db/db_test_util.h"
#include "test_util/mock_time_env.h"
#include "test_util/sync_point.h"
#include "test_util/testharness.h"
class RepeatableThreadTest : public testing::Test {
public:
RepeatableThreadTest()
: mock_clock_(std::make_shared<ROCKSDB_NAMESPACE::MockSystemClock>(
ROCKSDB_NAMESPACE::SystemClock::Default())) {}
protected:
std::shared_ptr<ROCKSDB_NAMESPACE::MockSystemClock> mock_clock_;
};
TEST_F(RepeatableThreadTest, TimedTest) {
constexpr uint64_t kSecond = 1000000; constexpr int kIteration = 3;
const auto& clock = ROCKSDB_NAMESPACE::SystemClock::Default();
ROCKSDB_NAMESPACE::port::Mutex mutex;
ROCKSDB_NAMESPACE::port::CondVar test_cv(&mutex);
int count = 0;
uint64_t prev_time = clock->NowMicros();
ROCKSDB_NAMESPACE::RepeatableThread thread(
[&] {
ROCKSDB_NAMESPACE::MutexLock l(&mutex);
count++;
uint64_t now = clock->NowMicros();
assert(count == 1 || prev_time + 1 * kSecond <= now);
prev_time = now;
if (count >= kIteration) {
test_cv.SignalAll();
}
},
"rt_test", clock.get(), 1 * kSecond);
{
ROCKSDB_NAMESPACE::MutexLock l(&mutex);
while (count < kIteration) {
test_cv.Wait();
}
}
thread.cancel();
}
TEST_F(RepeatableThreadTest, MockEnvTest) {
constexpr uint64_t kSecond = 1000000; constexpr int kIteration = 3;
mock_clock_->SetCurrentTime(0); std::atomic<int> count{0};
#if defined(OS_MACOSX) && !defined(NDEBUG)
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
"InstrumentedCondVar::TimedWaitInternal", [&](void* arg) {
uint64_t time_us = *static_cast<uint64_t*>(arg);
if (time_us < mock_clock_->RealNowMicros()) {
*static_cast<uint64_t*>(arg) = mock_clock_->RealNowMicros() + 1000;
}
});
ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
#endif
ROCKSDB_NAMESPACE::RepeatableThread thread(
[&] { count++; }, "rt_test", mock_clock_.get(), 1 * kSecond, 1 * kSecond);
for (int i = 1; i <= kIteration; i++) {
thread.TEST_WaitForRun([&] { mock_clock_->SetCurrentTime(i); });
}
ASSERT_EQ(kIteration, count.load());
thread.cancel();
}
int main(int argc, char** argv) {
ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}