summaryrefslogtreecommitdiffstats
path: root/test/utility/timer.cpp
diff options
context:
space:
mode:
authorWilliam A. Kennington III <wak@google.com>2018-09-20 11:35:11 -0700
committerWilliam A. Kennington III <wak@google.com>2018-09-26 12:18:50 -0700
commitba04ffb5a94fd47d8acc57c7a6be4d31624d2c23 (patch)
treeaa8629e7418795879a563ff9dc6909985b79899e /test/utility/timer.cpp
parentfa9431d52f37bf51a2aa0d3a85eaaf027db8488f (diff)
downloadsdeventplus-ba04ffb5a94fd47d8acc57c7a6be4d31624d2c23.tar.gz
sdeventplus-ba04ffb5a94fd47d8acc57c7a6be4d31624d2c23.zip
utility/timer: Implement oneshot timers
This change is meant to enable users of the old openbmc timer class to trivially use the timer if they only want single executions. It also makes setting up the timer less verbose if you do not already know the timeout interval. Tested: Run through unit tests and did a sample integration with phosphor-watchdog and phosphor-networkd. Verified that the new oneshot example works as expected. Change-Id: I2cd006d1f19fff99bce3f732a16eac9ca9553666 Signed-off-by: William A. Kennington III <wak@google.com>
Diffstat (limited to 'test/utility/timer.cpp')
-rw-r--r--test/utility/timer.cpp182
1 files changed, 166 insertions, 16 deletions
diff --git a/test/utility/timer.cpp b/test/utility/timer.cpp
index 414ad82..a329287 100644
--- a/test/utility/timer.cpp
+++ b/test/utility/timer.cpp
@@ -2,6 +2,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <memory>
+#include <optional>
#include <sdeventplus/clock.hpp>
#include <sdeventplus/event.hpp>
#include <sdeventplus/test/sdevent.hpp>
@@ -50,6 +51,7 @@ class TimerTest : public testing::Test
const milliseconds starting_time{10};
sd_event_time_handler_t handler = nullptr;
void* handler_userdata;
+ std::unique_ptr<Event> event;
std::unique_ptr<TestTimer> timer;
std::function<void()> callback;
@@ -83,14 +85,41 @@ class TimerTest : public testing::Test
DoAll(SetArgPointee<1>(static_cast<int>(enabled)), Return(0)));
}
+ void resetTimer()
+ {
+ if (timer)
+ {
+ expectSetEnabled(source::Enabled::Off);
+ timer.reset();
+ }
+ }
+
+ void expireTimer()
+ {
+ const milliseconds new_time(90);
+ expectNow(new_time);
+ expectSetTime(new_time + interval);
+ EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
+ EXPECT_TRUE(timer->hasExpired());
+ EXPECT_EQ(interval, timer->getInterval());
+ }
+
void SetUp()
{
EXPECT_CALL(mock, sd_event_ref(expected_event))
.WillRepeatedly(DoAll(EventRef(), Return(expected_event)));
EXPECT_CALL(mock, sd_event_unref(expected_event))
.WillRepeatedly(DoAll(EventUnref(), Return(nullptr)));
- Event event(expected_event, &mock);
+ event = std::make_unique<Event>(expected_event, &mock);
+ EXPECT_CALL(mock, sd_event_source_unref(expected_source))
+ .WillRepeatedly(Return(nullptr));
+ EXPECT_CALL(mock,
+ sd_event_source_set_userdata(expected_source, testing::_))
+ .WillRepeatedly(
+ DoAll(SaveArg<1>(&handler_userdata), Return(nullptr)));
+ // Having a callback proxy allows us to update the test callback
+ // dynamically, without changing it inside the timer
auto runCallback = [&](TestTimer&) {
if (callback)
{
@@ -105,24 +134,54 @@ class TimerTest : public testing::Test
1000, testing::_, nullptr))
.WillOnce(DoAll(SetArgPointee<1>(expected_source),
SaveArg<5>(&handler), Return(0)));
- EXPECT_CALL(mock,
- sd_event_source_set_userdata(expected_source, testing::_))
- .WillOnce(DoAll(SaveArg<1>(&handler_userdata), Return(nullptr)));
- // Timer always enables the source to keep ticking
expectSetEnabled(source::Enabled::On);
- timer = std::make_unique<TestTimer>(event, runCallback, interval);
+ timer = std::make_unique<TestTimer>(*event, runCallback, interval);
}
void TearDown()
{
- expectSetEnabled(source::Enabled::Off);
- EXPECT_CALL(mock, sd_event_source_unref(expected_source))
- .WillOnce(Return(nullptr));
- timer.reset();
+ resetTimer();
+ event.reset();
EXPECT_EQ(0, event_ref_times);
}
};
+TEST_F(TimerTest, NoCallback)
+{
+ resetTimer();
+ expectNow(starting_time);
+ EXPECT_CALL(
+ mock, sd_event_add_time(expected_event, testing::_,
+ static_cast<clockid_t>(testClock),
+ microseconds(starting_time + interval).count(),
+ 1000, testing::_, nullptr))
+ .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<5>(&handler),
+ Return(0)));
+ expectSetEnabled(source::Enabled::On);
+ timer = std::make_unique<TestTimer>(*event, nullptr, interval);
+
+ expectNow(starting_time);
+ expectSetTime(starting_time + interval);
+ EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
+}
+
+TEST_F(TimerTest, NoInterval)
+{
+ resetTimer();
+ expectNow(starting_time);
+ EXPECT_CALL(mock, sd_event_add_time(expected_event, testing::_,
+ static_cast<clockid_t>(testClock),
+ microseconds(starting_time).count(),
+ 1000, testing::_, nullptr))
+ .WillOnce(DoAll(SetArgPointee<1>(expected_source), SaveArg<5>(&handler),
+ Return(0)));
+ expectSetEnabled(source::Enabled::Off);
+ timer = std::make_unique<TestTimer>(*event, nullptr);
+
+ EXPECT_EQ(std::nullopt, timer->getInterval());
+ EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
+}
+
TEST_F(TimerTest, NewTimer)
{
EXPECT_FALSE(timer->hasExpired());
@@ -184,6 +243,32 @@ TEST_F(TimerTest, SetEnabled)
EXPECT_FALSE(timer->hasExpired());
}
+TEST_F(TimerTest, SetEnabledUnsetTimer)
+{
+ // Force the timer to become unset
+ expectSetEnabled(source::Enabled::Off);
+ timer->restart(std::nullopt);
+
+ // Setting an interval should not update the timer directly
+ timer->setInterval(milliseconds(90));
+
+ expectSetEnabled(source::Enabled::Off);
+ timer->setEnabled(false);
+ EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
+}
+
+TEST_F(TimerTest, SetEnabledOneshot)
+{
+ // Timer effectively becomes oneshot if it gets initialized but has
+ // the interval removed
+ timer->setInterval(std::nullopt);
+
+ expectSetEnabled(source::Enabled::Off);
+ timer->setEnabled(false);
+ expectSetEnabled(source::Enabled::On);
+ timer->setEnabled(true);
+}
+
TEST_F(TimerTest, SetRemaining)
{
const milliseconds now(90), remaining(30);
@@ -212,6 +297,48 @@ TEST_F(TimerTest, SetInterval)
EXPECT_FALSE(timer->hasExpired());
}
+TEST_F(TimerTest, SetIntervalEmpty)
+{
+ timer->setInterval(std::nullopt);
+ EXPECT_EQ(std::nullopt, timer->getInterval());
+ EXPECT_FALSE(timer->hasExpired());
+}
+
+TEST_F(TimerTest, CallbackHappensLast)
+{
+ const milliseconds new_time(90);
+ expectNow(new_time);
+ expectSetTime(new_time + interval);
+ callback = [&]() {
+ EXPECT_TRUE(timer->hasExpired());
+ expectSetEnabled(source::Enabled::On);
+ timer->setEnabled(true);
+ timer->clearExpired();
+ timer->setInterval(std::nullopt);
+ };
+ EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
+ EXPECT_FALSE(timer->hasExpired());
+ EXPECT_EQ(std::nullopt, timer->getInterval());
+ expectSetEnabled(source::Enabled::On);
+ timer->setEnabled(true);
+}
+
+TEST_F(TimerTest, CallbackOneshot)
+{
+ // Make sure we try a one shot so we can test the callback
+ // correctly
+ timer->setInterval(std::nullopt);
+
+ expectSetEnabled(source::Enabled::Off);
+ callback = [&]() {
+ EXPECT_TRUE(timer->hasExpired());
+ EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
+ timer->setInterval(interval);
+ };
+ EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
+ EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
+}
+
TEST_F(TimerTest, SetValuesExpiredTimer)
{
const milliseconds new_time(90);
@@ -242,12 +369,7 @@ TEST_F(TimerTest, SetValuesExpiredTimer)
TEST_F(TimerTest, Restart)
{
- const milliseconds new_time(90);
- expectNow(new_time);
- expectSetTime(new_time + interval);
- EXPECT_EQ(0, handler(nullptr, 0, handler_userdata));
- EXPECT_TRUE(timer->hasExpired());
- EXPECT_EQ(interval, timer->getInterval());
+ expireTimer();
const milliseconds new_interval(471);
expectNow(starting_time);
@@ -256,6 +378,34 @@ TEST_F(TimerTest, Restart)
timer->restart(new_interval);
EXPECT_FALSE(timer->hasExpired());
EXPECT_EQ(new_interval, timer->getInterval());
+ expectSetEnabled(source::Enabled::On);
+ timer->setEnabled(true);
+}
+
+TEST_F(TimerTest, RestartEmpty)
+{
+ expireTimer();
+
+ expectSetEnabled(source::Enabled::Off);
+ timer->restart(std::nullopt);
+ EXPECT_FALSE(timer->hasExpired());
+ EXPECT_EQ(std::nullopt, timer->getInterval());
+ EXPECT_THROW(timer->setEnabled(true), std::runtime_error);
+}
+
+TEST_F(TimerTest, RestartOnce)
+{
+ expireTimer();
+
+ const milliseconds remaining(471);
+ expectNow(starting_time);
+ expectSetTime(starting_time + remaining);
+ expectSetEnabled(source::Enabled::On);
+ timer->restartOnce(remaining);
+ EXPECT_FALSE(timer->hasExpired());
+ EXPECT_EQ(std::nullopt, timer->getInterval());
+ expectSetEnabled(source::Enabled::On);
+ timer->setEnabled(true);
}
} // namespace
OpenPOWER on IntegriCloud