Adding the ability to use a simulated clock for unit tests.
This will be useful for any tests that test objects with time-dependent behavior. It will allow such tests to be written in such a way that their outcome is more repeatable (less flaky), and will also allow such tests to finish quicker. For example, a test for STUN timeout doesn't need to wait the full timeout interval in real time; it can simply advance the simulated clock. BUG=webrtc:4925 R=pthatcher@webrtc.org Review URL: https://codereview.webrtc.org/1895933003 . Cr-Commit-Position: refs/heads/master@{#12950}
This commit is contained in:
parent
1c20610ede
commit
b3c6810be3
@ -64,6 +64,8 @@
|
||||
'event_tracer_unittest.cc',
|
||||
'event_unittest.cc',
|
||||
'exp_filter_unittest.cc',
|
||||
'fakeclock.cc',
|
||||
'fakeclock.h',
|
||||
'filerotatingstream_unittest.cc',
|
||||
'fileutils_unittest.cc',
|
||||
'helpers_unittest.cc',
|
||||
@ -113,6 +115,7 @@
|
||||
'testclient_unittest.cc',
|
||||
'thread_checker_unittest.cc',
|
||||
'thread_unittest.cc',
|
||||
'timedelta.h',
|
||||
'timeutils_unittest.cc',
|
||||
'urlencode_unittest.cc',
|
||||
'versionparsing_unittest.cc',
|
||||
|
||||
40
webrtc/base/fakeclock.cc
Normal file
40
webrtc/base/fakeclock.cc
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/base/fakeclock.h"
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/messagequeue.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
uint64_t FakeClock::TimeNanos() const {
|
||||
CritScope cs(&lock_);
|
||||
return time_;
|
||||
}
|
||||
|
||||
void FakeClock::SetTimeNanos(uint64_t nanos) {
|
||||
{
|
||||
CritScope cs(&lock_);
|
||||
RTC_DCHECK(nanos >= time_);
|
||||
time_ = nanos;
|
||||
}
|
||||
// If message queues are waiting in a socket select() with a timeout provided
|
||||
// by the OS, they should wake up to check if there are any messages ready to
|
||||
// be dispatched based on the fake time.
|
||||
MessageQueueManager::WakeAllMessageQueues();
|
||||
}
|
||||
|
||||
void FakeClock::AdvanceTime(TimeDelta delta) {
|
||||
CritScope cs(&lock_);
|
||||
SetTimeNanos(time_ + delta.ToNanoseconds());
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
43
webrtc/base/fakeclock.h
Normal file
43
webrtc/base/fakeclock.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_BASE_FAKECLOCK_H_
|
||||
#define WEBRTC_BASE_FAKECLOCK_H_
|
||||
|
||||
#include "webrtc/base/criticalsection.h"
|
||||
#include "webrtc/base/timedelta.h"
|
||||
#include "webrtc/base/timeutils.h"
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// Fake clock for use with unit tests, which does not tick on its own.
|
||||
// Starts at time 0.
|
||||
class FakeClock : public ClockInterface {
|
||||
public:
|
||||
~FakeClock() override {}
|
||||
|
||||
// ClockInterface implementation.
|
||||
uint64_t TimeNanos() const override;
|
||||
|
||||
// Methods that can be used by the test to control the time.
|
||||
|
||||
// Should only be used to set a time in the future.
|
||||
void SetTimeNanos(uint64_t nanos);
|
||||
|
||||
void AdvanceTime(TimeDelta delta);
|
||||
|
||||
private:
|
||||
CriticalSection lock_;
|
||||
uint64_t time_ GUARDED_BY(lock_) = 0u;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // WEBRTC_BASE_FAKECLOCK_H_
|
||||
@ -15,6 +15,11 @@
|
||||
#include "webrtc/base/messagequeue.h"
|
||||
#include "webrtc/base/trace_event.h"
|
||||
|
||||
namespace {
|
||||
|
||||
enum { MSG_WAKE_MESSAGE_QUEUE = 1 };
|
||||
}
|
||||
|
||||
namespace rtc {
|
||||
|
||||
const int kMaxMsgLatency = 150; // 150 ms
|
||||
@ -103,6 +108,28 @@ void MessageQueueManager::ClearInternal(MessageHandler *handler) {
|
||||
(*iter)->Clear(handler);
|
||||
}
|
||||
|
||||
void MessageQueueManager::WakeAllMessageQueues() {
|
||||
if (!instance_) {
|
||||
return;
|
||||
}
|
||||
return Instance()->WakeAllMessageQueuesInternal();
|
||||
}
|
||||
|
||||
void MessageQueueManager::WakeAllMessageQueuesInternal() {
|
||||
#if CS_DEBUG_CHECKS // CurrentThreadIsOwner returns true by default.
|
||||
ASSERT(!crit_.CurrentThreadIsOwner()); // See note above.
|
||||
#endif
|
||||
CritScope cs(&crit_);
|
||||
for (MessageQueue* queue : message_queues_) {
|
||||
// Posting an arbitrary message will force the message queue to wake up.
|
||||
queue->Post(this, MSG_WAKE_MESSAGE_QUEUE);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageQueueManager::OnMessage(Message* pmsg) {
|
||||
RTC_DCHECK(pmsg->message_id == MSG_WAKE_MESSAGE_QUEUE);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// MessageQueue
|
||||
MessageQueue::MessageQueue(SocketServer* ss, bool init_queue)
|
||||
|
||||
@ -37,7 +37,7 @@ class MessageQueue;
|
||||
|
||||
// MessageQueueManager does cleanup of of message queues
|
||||
|
||||
class MessageQueueManager {
|
||||
class MessageQueueManager : public MessageHandler {
|
||||
public:
|
||||
static void Add(MessageQueue *message_queue);
|
||||
static void Remove(MessageQueue *message_queue);
|
||||
@ -49,15 +49,22 @@ class MessageQueueManager {
|
||||
// MessageQueueManager instance when necessary.
|
||||
static bool IsInitialized();
|
||||
|
||||
// Mainly for testing purposes, for use with a simulated clock.
|
||||
// Posts a no-op event on all message queues so they will wake from the
|
||||
// socket server select() and process messages again.
|
||||
static void WakeAllMessageQueues();
|
||||
|
||||
private:
|
||||
static MessageQueueManager* Instance();
|
||||
|
||||
MessageQueueManager();
|
||||
~MessageQueueManager();
|
||||
~MessageQueueManager() override;
|
||||
|
||||
void AddInternal(MessageQueue *message_queue);
|
||||
void RemoveInternal(MessageQueue *message_queue);
|
||||
void ClearInternal(MessageHandler *handler);
|
||||
void WakeAllMessageQueuesInternal();
|
||||
void OnMessage(Message* pmsg) override;
|
||||
|
||||
static MessageQueueManager* instance_;
|
||||
// This list contains all live MessageQueues.
|
||||
|
||||
128
webrtc/base/timedelta.h
Normal file
128
webrtc/base/timedelta.h
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2016 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_BASE_TIMEDELTA_H_
|
||||
#define WEBRTC_BASE_TIMEDELTA_H_
|
||||
|
||||
#include "webrtc/base/basictypes.h"
|
||||
#include "webrtc/base/timeutils.h"
|
||||
|
||||
// Convenience class to convert between different units of relative time.
|
||||
// Stores time to precision of nanoseconds, as int64_t internally.
|
||||
// Doesn't check for overflow/underflow.
|
||||
//
|
||||
// Based on TimeDelta in:
|
||||
// https://code.google.com/p/chromium/codesearch#chromium/src/base/time/time.h
|
||||
namespace rtc {
|
||||
|
||||
class TimeDelta {
|
||||
public:
|
||||
TimeDelta() : delta_(0) {}
|
||||
|
||||
// Converts units of time to TimeDeltas.
|
||||
static constexpr TimeDelta FromSeconds(int64_t secs) {
|
||||
return TimeDelta(secs * kNumNanosecsPerSec);
|
||||
}
|
||||
static constexpr TimeDelta FromMilliseconds(int64_t ms) {
|
||||
return TimeDelta(ms * kNumNanosecsPerMillisec);
|
||||
}
|
||||
static constexpr TimeDelta FromMicroseconds(int64_t us) {
|
||||
return TimeDelta(us * kNumNanosecsPerMicrosec);
|
||||
}
|
||||
static constexpr TimeDelta FromNanoseconds(int64_t ns) {
|
||||
return TimeDelta(ns);
|
||||
}
|
||||
|
||||
// Returns true if the time delta is zero.
|
||||
bool is_zero() const { return delta_ == 0; }
|
||||
|
||||
// Converts TimeDelta to units of time.
|
||||
int64_t ToSeconds() const { return delta_ / kNumNanosecsPerSec; }
|
||||
int64_t ToMilliseconds() const { return delta_ / kNumNanosecsPerMillisec; }
|
||||
int64_t ToMicroseconds() const { return delta_ / kNumNanosecsPerMicrosec; }
|
||||
int64_t ToNanoseconds() const { return delta_; }
|
||||
|
||||
TimeDelta& operator=(TimeDelta other) {
|
||||
delta_ = other.delta_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Computations with other deltas.
|
||||
TimeDelta operator+(TimeDelta other) const {
|
||||
return TimeDelta(delta_ + other.delta_);
|
||||
}
|
||||
TimeDelta operator-(TimeDelta other) const {
|
||||
return TimeDelta(delta_ + other.delta_);
|
||||
}
|
||||
|
||||
TimeDelta& operator+=(TimeDelta other) { return *this = (*this + other); }
|
||||
TimeDelta& operator-=(TimeDelta other) { return *this = (*this - other); }
|
||||
TimeDelta operator-() const { return TimeDelta(-delta_); }
|
||||
|
||||
// Computations with numeric types.
|
||||
template <typename T>
|
||||
TimeDelta operator*(T a) const {
|
||||
return TimeDelta(delta_ * a);
|
||||
}
|
||||
template <typename T>
|
||||
TimeDelta operator/(T a) const {
|
||||
return TimeDelta(delta_ / a);
|
||||
}
|
||||
template <typename T>
|
||||
TimeDelta& operator*=(T a) {
|
||||
return *this = (*this * a);
|
||||
}
|
||||
template <typename T>
|
||||
TimeDelta& operator/=(T a) {
|
||||
return *this = (*this / a);
|
||||
}
|
||||
|
||||
TimeDelta operator%(TimeDelta a) const {
|
||||
return TimeDelta(delta_ % a.delta_);
|
||||
}
|
||||
|
||||
// Comparison operators.
|
||||
constexpr bool operator==(TimeDelta other) const {
|
||||
return delta_ == other.delta_;
|
||||
}
|
||||
constexpr bool operator!=(TimeDelta other) const {
|
||||
return delta_ != other.delta_;
|
||||
}
|
||||
constexpr bool operator<(TimeDelta other) const {
|
||||
return delta_ < other.delta_;
|
||||
}
|
||||
constexpr bool operator<=(TimeDelta other) const {
|
||||
return delta_ <= other.delta_;
|
||||
}
|
||||
constexpr bool operator>(TimeDelta other) const {
|
||||
return delta_ > other.delta_;
|
||||
}
|
||||
constexpr bool operator>=(TimeDelta other) const {
|
||||
return delta_ >= other.delta_;
|
||||
}
|
||||
|
||||
private:
|
||||
// Constructs a delta given the duration in nanoseconds. This is private
|
||||
// to avoid confusion by callers with an integer constructor. Use
|
||||
// FromSeconds, FromMilliseconds, etc. instead.
|
||||
constexpr explicit TimeDelta(int64_t delta_ns) : delta_(delta_ns) {}
|
||||
|
||||
// Delta in nanoseconds.
|
||||
int64_t delta_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline TimeDelta operator*(T a, TimeDelta td) {
|
||||
return td * a;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // WEBRTC_BASE_TIMEDELTA_H_
|
||||
@ -30,8 +30,17 @@
|
||||
|
||||
namespace rtc {
|
||||
|
||||
ClockInterface* g_clock = nullptr;
|
||||
|
||||
void SetClock(ClockInterface* clock) {
|
||||
g_clock = clock;
|
||||
}
|
||||
|
||||
uint64_t TimeNanos() {
|
||||
int64_t ticks = 0;
|
||||
if (g_clock) {
|
||||
return g_clock->TimeNanos();
|
||||
}
|
||||
int64_t ticks;
|
||||
#if defined(WEBRTC_MAC)
|
||||
static mach_timebase_info_data_t timebase;
|
||||
if (timebase.denom == 0) {
|
||||
@ -45,8 +54,8 @@ uint64_t TimeNanos() {
|
||||
ticks = mach_absolute_time() * timebase.numer / timebase.denom;
|
||||
#elif defined(WEBRTC_POSIX)
|
||||
struct timespec ts;
|
||||
// TODO: Do we need to handle the case when CLOCK_MONOTONIC
|
||||
// is not supported?
|
||||
// TODO(deadbeef): Do we need to handle the case when CLOCK_MONOTONIC is not
|
||||
// supported?
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) +
|
||||
static_cast<int64_t>(ts.tv_nsec);
|
||||
@ -58,8 +67,7 @@ uint64_t TimeNanos() {
|
||||
// Atomically update the last gotten time
|
||||
DWORD old = InterlockedExchange(last_timegettime_ptr, now);
|
||||
if (now < old) {
|
||||
// If now is earlier than old, there may have been a race between
|
||||
// threads.
|
||||
// If now is earlier than old, there may have been a race between threads.
|
||||
// 0x0fffffff ~3.1 days, the code will not take that long to execute
|
||||
// so it must have been a wrap around.
|
||||
if (old > 0xf0000000 && now < 0x0fffffff) {
|
||||
@ -67,8 +75,8 @@ uint64_t TimeNanos() {
|
||||
}
|
||||
}
|
||||
ticks = now + (num_wrap_timegettime << 32);
|
||||
// TODO: Calculate with nanosecond precision. Otherwise, we're just
|
||||
// wasting a multiply and divide when doing Time() on Windows.
|
||||
// TODO(deadbeef): Calculate with nanosecond precision. Otherwise, we're
|
||||
// just wasting a multiply and divide when doing Time() on Windows.
|
||||
ticks = ticks * kNumNanosecsPerMillisec;
|
||||
#else
|
||||
#error Unsupported platform.
|
||||
|
||||
@ -31,6 +31,26 @@ static const int64_t kNumNanosecsPerMicrosec =
|
||||
|
||||
// TODO(honghaiz): Define a type for the time value specifically.
|
||||
|
||||
class ClockInterface {
|
||||
public:
|
||||
virtual ~ClockInterface() {}
|
||||
virtual uint64_t TimeNanos() const = 0;
|
||||
};
|
||||
|
||||
// Sets the global source of time. This is useful mainly for unit tests.
|
||||
//
|
||||
// Does not transfer ownership of the clock.
|
||||
// SetClock(nullptr) should be called before the ClockInterface is deleted.
|
||||
//
|
||||
// This method is not thread-safe; it should only be used when no other thread
|
||||
// is running (for example, at the start/end of a unit test, or start/end of
|
||||
// main()).
|
||||
//
|
||||
// TODO(deadbeef): Instead of having functions that access this global
|
||||
// ClockInterface, we may want to pass the ClockInterface into everything
|
||||
// that uses it, eliminating the need for a global variable and this function.
|
||||
void SetClock(ClockInterface* clock);
|
||||
|
||||
// Returns the current time in milliseconds in 32 bits.
|
||||
uint32_t Time32();
|
||||
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
*/
|
||||
|
||||
#include "webrtc/base/common.h"
|
||||
#include "webrtc/base/event.h"
|
||||
#include "webrtc/base/fakeclock.h"
|
||||
#include "webrtc/base/gunit.h"
|
||||
#include "webrtc/base/helpers.h"
|
||||
#include "webrtc/base/thread.h"
|
||||
@ -205,4 +207,176 @@ TEST_F(TmToSeconds, TestTmToSeconds) {
|
||||
TestTmToSeconds(100000);
|
||||
}
|
||||
|
||||
TEST(TimeDelta, FromAndTo) {
|
||||
EXPECT_TRUE(TimeDelta::FromSeconds(2) == TimeDelta::FromMilliseconds(2000));
|
||||
EXPECT_TRUE(TimeDelta::FromMilliseconds(3) ==
|
||||
TimeDelta::FromMicroseconds(3000));
|
||||
EXPECT_TRUE(TimeDelta::FromMicroseconds(4) ==
|
||||
TimeDelta::FromNanoseconds(4000));
|
||||
EXPECT_EQ(13, TimeDelta::FromSeconds(13).ToSeconds());
|
||||
EXPECT_EQ(13, TimeDelta::FromMilliseconds(13).ToMilliseconds());
|
||||
EXPECT_EQ(13, TimeDelta::FromMicroseconds(13).ToMicroseconds());
|
||||
EXPECT_EQ(13, TimeDelta::FromNanoseconds(13).ToNanoseconds());
|
||||
}
|
||||
|
||||
TEST(TimeDelta, ComparisonOperators) {
|
||||
EXPECT_LT(TimeDelta::FromSeconds(1), TimeDelta::FromSeconds(2));
|
||||
EXPECT_EQ(TimeDelta::FromSeconds(3), TimeDelta::FromSeconds(3));
|
||||
EXPECT_GT(TimeDelta::FromSeconds(5), TimeDelta::FromSeconds(4));
|
||||
}
|
||||
|
||||
TEST(TimeDelta, NumericOperators) {
|
||||
double d = 0.5;
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
TimeDelta::FromMilliseconds(1000) * d);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
TimeDelta::FromMilliseconds(1000) / d);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
TimeDelta::FromMilliseconds(1000) *= d);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
TimeDelta::FromMilliseconds(1000) /= d);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
d * TimeDelta::FromMilliseconds(1000));
|
||||
|
||||
float f = 0.5;
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
TimeDelta::FromMilliseconds(1000) * f);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
TimeDelta::FromMilliseconds(1000) / f);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
TimeDelta::FromMilliseconds(1000) *= f);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
TimeDelta::FromMilliseconds(1000) /= f);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
f * TimeDelta::FromMilliseconds(1000));
|
||||
|
||||
int i = 2;
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
TimeDelta::FromMilliseconds(1000) * i);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
TimeDelta::FromMilliseconds(1000) / i);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
TimeDelta::FromMilliseconds(1000) *= i);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
TimeDelta::FromMilliseconds(1000) /= i);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
i * TimeDelta::FromMilliseconds(1000));
|
||||
|
||||
int64_t i64 = 2;
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
TimeDelta::FromMilliseconds(1000) * i64);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
TimeDelta::FromMilliseconds(1000) / i64);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
TimeDelta::FromMilliseconds(1000) *= i64);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
TimeDelta::FromMilliseconds(1000) /= i64);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
i64 * TimeDelta::FromMilliseconds(1000));
|
||||
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
TimeDelta::FromMilliseconds(1000) * 0.5);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
TimeDelta::FromMilliseconds(1000) / 0.5);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
TimeDelta::FromMilliseconds(1000) *= 0.5);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
TimeDelta::FromMilliseconds(1000) /= 0.5);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
0.5 * TimeDelta::FromMilliseconds(1000));
|
||||
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
TimeDelta::FromMilliseconds(1000) * 2);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
TimeDelta::FromMilliseconds(1000) / 2);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
TimeDelta::FromMilliseconds(1000) *= 2);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(500),
|
||||
TimeDelta::FromMilliseconds(1000) /= 2);
|
||||
EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
|
||||
2 * TimeDelta::FromMilliseconds(1000));
|
||||
}
|
||||
|
||||
// Test that all the time functions exposed by TimeUtils get time from the
|
||||
// fake clock when it's set.
|
||||
TEST(FakeClock, TimeFunctionsUseFakeClock) {
|
||||
FakeClock clock;
|
||||
SetClock(&clock);
|
||||
|
||||
clock.SetTimeNanos(987654321u);
|
||||
EXPECT_EQ(987u, Time32());
|
||||
EXPECT_EQ(987, TimeMillis());
|
||||
EXPECT_EQ(987654u, TimeMicros());
|
||||
EXPECT_EQ(987654321u, TimeNanos());
|
||||
EXPECT_EQ(1000u, TimeAfter(13));
|
||||
|
||||
SetClock(nullptr);
|
||||
// After it's unset, we should get a normal time.
|
||||
EXPECT_NE(987, TimeMillis());
|
||||
}
|
||||
|
||||
TEST(FakeClock, InitialTime) {
|
||||
FakeClock clock;
|
||||
EXPECT_EQ(0u, clock.TimeNanos());
|
||||
}
|
||||
|
||||
TEST(FakeClock, SetTimeNanos) {
|
||||
FakeClock clock;
|
||||
clock.SetTimeNanos(123u);
|
||||
EXPECT_EQ(123u, clock.TimeNanos());
|
||||
clock.SetTimeNanos(456u);
|
||||
EXPECT_EQ(456u, clock.TimeNanos());
|
||||
}
|
||||
|
||||
TEST(FakeClock, AdvanceTime) {
|
||||
FakeClock clock;
|
||||
clock.AdvanceTime(TimeDelta::FromNanoseconds(1111u));
|
||||
EXPECT_EQ(1111u, clock.TimeNanos());
|
||||
clock.AdvanceTime(TimeDelta::FromMicroseconds(2222u));
|
||||
EXPECT_EQ(2223111u, clock.TimeNanos());
|
||||
clock.AdvanceTime(TimeDelta::FromMilliseconds(3333u));
|
||||
EXPECT_EQ(3335223111u, clock.TimeNanos());
|
||||
clock.AdvanceTime(TimeDelta::FromSeconds(4444u));
|
||||
EXPECT_EQ(4447335223111u, clock.TimeNanos());
|
||||
}
|
||||
|
||||
// When the clock is advanced, threads that are waiting in a socket select
|
||||
// should wake up and look at the new time. This allows tests using the
|
||||
// fake clock to run much faster, if the test is bound by time constraints
|
||||
// (such as a test for a STUN ping timeout).
|
||||
TEST(FakeClock, SettingTimeWakesThreads) {
|
||||
int64_t real_start_time_ms = TimeMillis();
|
||||
|
||||
FakeClock clock;
|
||||
SetClock(&clock);
|
||||
|
||||
Thread worker;
|
||||
worker.Start();
|
||||
|
||||
// Post an event that won't be executed for 10 seconds.
|
||||
Event message_handler_dispatched(false, false);
|
||||
auto functor = [&message_handler_dispatched] {
|
||||
message_handler_dispatched.Set();
|
||||
};
|
||||
FunctorMessageHandler<void, decltype(functor)> handler(functor);
|
||||
worker.PostDelayed(10000, &handler);
|
||||
|
||||
// Wait for a bit for the worker thread to be started and enter its socket
|
||||
// select().
|
||||
Thread::Current()->SleepMs(1000);
|
||||
|
||||
// Advance the fake clock, expecting the worker thread to wake up
|
||||
// and dispatch the message quickly.
|
||||
clock.AdvanceTime(TimeDelta::FromSeconds(10u));
|
||||
message_handler_dispatched.Wait(Event::kForever);
|
||||
worker.Stop();
|
||||
|
||||
SetClock(nullptr);
|
||||
|
||||
// The message should have been dispatched long before the 10 seconds fully
|
||||
// elapsed.
|
||||
int64_t real_end_time_ms = TimeMillis();
|
||||
EXPECT_LT(real_end_time_ms - real_start_time_ms, 2000);
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
namespace rtc {
|
||||
|
||||
// TODO(deadbeef): Remove this and use ClockInterface instead.
|
||||
class Timing {
|
||||
public:
|
||||
Timing();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user