Actually make monotonic time functions mockable.

This is different from making the functions mockable, since
monotime_t is opaque and so providing mocks for the functions is
really hard.
This commit is contained in:
Nick Mathewson 2016-07-21 11:04:22 +02:00
parent 72a1f0180d
commit 2d26b1a549
2 changed files with 112 additions and 5 deletions

View File

@ -118,6 +118,74 @@ tor_gettimeofday(struct timeval *timeval)
/** True iff monotime_init has been called. */
static int monotime_initialized = 0;
static monotime_t initialized_at;
#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT
static monotime_coarse_t initialized_at_coarse;
#endif
#ifdef TOR_UNIT_TESTS
/** True if we are running unit tests and overriding the current monotonic
* time. Note that mocked monotonic time might not be monotonic.
*/
static int monotime_mocking_enabled = 0;
static monotime_t initialized_at_saved;
static int64_t mock_time_nsec = 0;
#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT
static int64_t mock_time_nsec_coarse = 0;
static monotime_coarse_t initialized_at_coarse_saved;
#endif
void
monotime_enable_test_mocking(void)
{
if (BUG(monotime_initialized == 0)) {
monotime_init();
}
tor_assert_nonfatal(monotime_mocking_enabled == 0);
monotime_mocking_enabled = 1;
memcpy(&initialized_at_saved,
&initialized_at, sizeof(monotime_t));
memset(&initialized_at, 0, sizeof(monotime_t));
#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT
memcpy(&initialized_at_coarse_saved,
&initialized_at_coarse, sizeof(monotime_coarse_t));
memset(&initialized_at_coarse, 0, sizeof(monotime_coarse_t));
#endif
}
void
monotime_disable_test_mocking(void)
{
tor_assert_nonfatal(monotime_mocking_enabled == 1);
monotime_mocking_enabled = 0;
memcpy(&initialized_at,
&initialized_at_saved, sizeof(monotime_t));
#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT
memcpy(&initialized_at_coarse,
&initialized_at_coarse_saved, sizeof(monotime_coarse_t));
#endif
}
void
monotime_set_mock_time_nsec(int64_t nsec)
{
tor_assert_nonfatal(monotime_mocking_enabled == 1);
mock_time_nsec = nsec;
}
#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT
void
monotime_coarse_set_mock_time_nsec(int64_t nsec)
{
tor_assert_nonfatal(monotime_mocking_enabled == 1);
mock_time_nsec_coarse = nsec;
}
#endif
#endif
/* "ratchet" functions for monotonic time. */
#if defined(_WIN32) || defined(TOR_UNIT_TESTS)
@ -223,6 +291,13 @@ monotime_init_internal(void)
void
monotime_get(monotime_t *out)
{
#ifdef TOR_UNIT_TESTS
if (monotime_mocking_enabled) {
out->abstime_ = (mock_time_nsec * mach_time_info.denom)
/ mach_time_info.numer;
return;
}
#endif
out->abstime_ = mach_absolute_time();
}
@ -254,6 +329,13 @@ monotime_init_internal(void)
void
monotime_get(monotime_t *out)
{
#ifdef TOR_UNIT_TESTS
if (monotime_mocking_enabled) {
out->ts_.tv_sec = mock_time_nsec / ONE_BILLION;
out->ts_.tv_nsec = mock_time_nsec % ONE_BILLION;
return;
}
#endif
int r = clock_gettime(CLOCK_MONOTONIC, &out->ts_);
tor_assert(r == 0);
}
@ -262,6 +344,13 @@ monotime_get(monotime_t *out)
void
monotime_coarse_get(monotime_coarse_t *out)
{
#ifdef TOR_UNIT_TESTS
if (monotime_mocking_enabled) {
out->ts_.tv_sec = mock_time_nsec_coarse / ONE_BILLION;
out->ts_.tv_nsec = mock_time_nsec_coarse % ONE_BILLION;
return;
}
#endif
int r = clock_gettime(CLOCK_MONOTONIC_COARSE, &out->ts_);
tor_assert(r == 0);
}
@ -323,6 +412,13 @@ monotime_get(monotime_t *out)
monotime_init();
}
#ifdef TOR_UNIT_TESTS
if (monotime_mocking_enabled) {
out->pcount_ = (mock_time_nsec * ticks_per_second) / ONE_BILLION;
return;
}
#endif
/* Alas, QueryPerformanceCounter is not always monotonic: see bug list at
https://www.python.org/dev/peps/pep-0418/#windows-queryperformancecounter
@ -340,6 +436,13 @@ monotime_get(monotime_t *out)
void
monotime_coarse_get(monotime_coarse_t *out)
{
#ifdef TOR_UNIT_TESTS
if (monotime_mocking_enabled) {
out->tick_count_ = mock_time_nsec_coarse / ONE_MILLION;
return;
}
#endif
if (GetTickCount64_fn) {
out->tick_count_ = (int64_t)GetTickCount64_fn();
} else {
@ -424,11 +527,6 @@ monotime_diff_nsec(const monotime_t *start,
#error "No way to implement monotonic timers."
#endif
static monotime_t initialized_at;
#ifdef MONOTIME_COARSE_FN_IS_DIFFERENT
static monotime_coarse_t initialized_at_coarse;
#endif
/**
* Initialize the monotonic timer subsystem. Must be called before any
* monotonic timer functions. This function is idempotent.

View File

@ -130,6 +130,15 @@ void tor_gettimeofday(struct timeval *timeval);
#ifdef TOR_UNIT_TESTS
void tor_sleep_msec(int msec);
void monotime_enable_test_mocking(void);
void monotime_disable_test_mocking(void);
void monotime_set_mock_time_nsec(int64_t);
#if defined(MONOTIME_COARSE_FN_IS_DIFFERENT)
void monotime_coarse_set_mock_time_nsec(int64_t);
#else
#define monotime_coarse_set_mock_time_nsec monotime_set_mock_time_nsec
#endif
#endif
#ifdef COMPAT_TIME_PRIVATE