-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Adds a fake clock utility. A fake clock allows a unit test to be in perfect control of how time is advancing, without using any sleep or usleep statements. * fix whitespace
- Loading branch information
1 parent
d70607e
commit f3609a0
Showing
6 changed files
with
258 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/** \copyright | ||
* Copyright (c) 2020, Balazs Racz | ||
* All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are met: | ||
* | ||
* - Redistributions of source code must retain the above copyright notice, | ||
* this list of conditions and the following disclaimer. | ||
* | ||
* - Redistributions in binary form must reproduce the above copyright notice, | ||
* this list of conditions and the following disclaimer in the documentation | ||
* and/or other materials provided with the distribution. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
* POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
* \file FakeClock.cxx | ||
* | ||
* Helper class for unit tests that want to control the advancement of time by | ||
* hand. | ||
* | ||
* @author Balazs Racz | ||
* @date 28 Nov 2020 | ||
*/ | ||
|
||
#include "os/FakeClock.hxx" | ||
|
||
#ifdef GTEST | ||
|
||
extern "C" | ||
{ | ||
|
||
long long os_get_fake_time(void) | ||
{ | ||
if (FakeClock::exists()) | ||
{ | ||
return FakeClock::instance()->get_time_nsec(); | ||
} | ||
else | ||
{ | ||
return -1; | ||
} | ||
} | ||
|
||
} // extern C | ||
|
||
#endif // GTEST |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
#include "os/FakeClock.hxx" | ||
|
||
#include "utils/test_main.hxx" | ||
|
||
TEST(FakeClockTest, advance) | ||
{ | ||
long long t1 = os_get_time_monotonic(); | ||
usleep(20000); | ||
long long t2 = os_get_time_monotonic(); | ||
EXPECT_LT(t1 + MSEC_TO_NSEC(20), t2); | ||
|
||
FakeClock clk; | ||
long long tfreeze = os_get_time_monotonic(); | ||
// Upon startup the time should be pretty close. | ||
EXPECT_GT(t2 + MSEC_TO_NSEC(1), tfreeze); | ||
|
||
// Time will not advance too much when frozen. | ||
for (unsigned i = 0; i < 100; ++i) | ||
{ | ||
EXPECT_GT(tfreeze + 500, os_get_time_monotonic()); | ||
} | ||
|
||
// But still be monotonic. | ||
t1 = os_get_time_monotonic(); | ||
t2 = os_get_time_monotonic(); | ||
EXPECT_EQ(1, t2 - t1); | ||
} | ||
|
||
TEST(FakeClockTest, independent_test) | ||
{ | ||
// There should be no freezing left over for the next test. | ||
long long t1 = os_get_time_monotonic(); | ||
usleep(20000); | ||
long long t2 = os_get_time_monotonic(); | ||
EXPECT_LT(t1 + MSEC_TO_NSEC(20), t2); | ||
} | ||
|
||
class CountingTimer : public Timer | ||
{ | ||
public: | ||
CountingTimer() | ||
: Timer(g_executor.active_timers()) | ||
{ | ||
start(MSEC_TO_NSEC(20)); | ||
} | ||
|
||
long long timeout() override | ||
{ | ||
++count_; | ||
if (needStop_) | ||
{ | ||
return DELETE; | ||
} | ||
return RESTART; | ||
} | ||
|
||
bool needStop_ = false; | ||
int count_ = 0; | ||
}; | ||
|
||
TEST(FakeClockTest, executor_timer) | ||
{ | ||
FakeClock clk; | ||
CountingTimer *tim = new CountingTimer; | ||
|
||
EXPECT_EQ(0, tim->count_); | ||
usleep(50000); | ||
wait_for_main_executor(); | ||
EXPECT_EQ(0, tim->count_); | ||
clk.advance(MSEC_TO_NSEC(20) - 100); | ||
wait_for_main_executor(); | ||
EXPECT_EQ(0, tim->count_); | ||
clk.advance(100); | ||
wait_for_main_executor(); | ||
EXPECT_EQ(1, tim->count_); | ||
|
||
clk.advance(MSEC_TO_NSEC(200)); | ||
wait_for_main_executor(); | ||
EXPECT_EQ(11, tim->count_); | ||
clk.advance(MSEC_TO_NSEC(20)); | ||
wait_for_main_executor(); | ||
EXPECT_EQ(12, tim->count_); | ||
tim->needStop_ = true; | ||
clk.advance(MSEC_TO_NSEC(20)); | ||
wait_for_main_executor(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/** \copyright | ||
* Copyright (c) 2020, Balazs Racz | ||
* All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are met: | ||
* | ||
* - Redistributions of source code must retain the above copyright notice, | ||
* this list of conditions and the following disclaimer. | ||
* | ||
* - Redistributions in binary form must reproduce the above copyright notice, | ||
* this list of conditions and the following disclaimer in the documentation | ||
* and/or other materials provided with the distribution. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
* POSSIBILITY OF SUCH DAMAGE. | ||
* | ||
* \file FakeClock.hxx | ||
* | ||
* Helper class for unit tests that want to control the advancement of time by | ||
* hand. | ||
* | ||
* @author Balazs Racz | ||
* @date 28 Nov 2020 | ||
*/ | ||
|
||
#ifndef _OS_FAKECLOCK_HXX_ | ||
#define _OS_FAKECLOCK_HXX_ | ||
|
||
#include "executor/Executor.hxx" | ||
#include "os/os.h" | ||
#include "utils/Singleton.hxx" | ||
|
||
/// Stores the private variables of a fake clock. | ||
struct FakeClockContent | ||
{ | ||
protected: | ||
/// @param t the starting timestamp for the fake clock. | ||
FakeClockContent(long long t) | ||
: lastTime_(t) | ||
{ | ||
} | ||
|
||
long long lastTime_; | ||
}; | ||
|
||
/// Class that injects a fake progression of time for unit tests. When this | ||
/// class is created, the time as returned by os_get_time_monotonic() | ||
/// freezes. From that point on time only moves forward when advance() is | ||
/// called. | ||
/// | ||
/// There can be at most one instance of this class at any time. | ||
class FakeClock : private FakeClockContent, public Singleton<FakeClock> | ||
{ | ||
public: | ||
FakeClock() | ||
: FakeClockContent(os_get_time_monotonic()) | ||
{ | ||
} | ||
|
||
/// Advances the time returned by os_get_time_monotonic(). | ||
/// @param nsec how much the time should jump forward (relative to now). | ||
void advance(long long nsec) | ||
{ | ||
lastTime_ += nsec; | ||
// Wakes up all executors. This will cause them to evaluate if their | ||
// timers have something expired. | ||
ExecutorBase *current = ExecutorBase::link_head(); | ||
while (current) | ||
{ | ||
current->add(new CallbackExecutable([]() {})); | ||
current = current->link_next(); | ||
} | ||
} | ||
|
||
/// @return the currently set time. | ||
long long get_time_nsec() | ||
{ | ||
return lastTime_++; | ||
} | ||
|
||
private: | ||
}; | ||
|
||
#endif // _OS_FAKECLOCK_HXX_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters