blob: 094afc9c42a36a55d7b3207328db55136bc66900 [file] [log] [blame]
Yuri Wiitalaec353612019-06-18 17:32:39 -07001// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Jordan Baylesa26582d2019-07-10 14:44:58 -07005#include "util/alarm.h"
Yuri Wiitalaec353612019-06-18 17:32:39 -07006
7#include <algorithm>
Jordan Baylesc9201dd2020-06-02 15:51:31 -07008#include <chrono>
Yuri Wiitalaec353612019-06-18 17:32:39 -07009
10#include "gtest/gtest.h"
11#include "platform/test/fake_clock.h"
12#include "platform/test/fake_task_runner.h"
Jordan Baylesc9201dd2020-06-02 15:51:31 -070013#include "util/chrono_helpers.h"
Yuri Wiitalaec353612019-06-18 17:32:39 -070014
15namespace openscreen {
16namespace {
17
18class AlarmTest : public testing::Test {
19 public:
Yuri Wiitala2b02e322019-12-03 16:59:40 -080020 FakeClock* clock() { return &clock_; }
Yuri Wiitalac681b472020-02-20 13:41:54 -080021 FakeTaskRunner* task_runner() { return &task_runner_; }
Yuri Wiitalaec353612019-06-18 17:32:39 -070022 Alarm* alarm() { return &alarm_; }
23
24 private:
Yuri Wiitala2b02e322019-12-03 16:59:40 -080025 FakeClock clock_{Clock::now()};
26 FakeTaskRunner task_runner_{&clock_};
27 Alarm alarm_{&FakeClock::now, &task_runner_};
Yuri Wiitalaec353612019-06-18 17:32:39 -070028};
29
30TEST_F(AlarmTest, RunsTaskAsClockAdvances) {
Jordan Baylesc9201dd2020-06-02 15:51:31 -070031 constexpr Clock::duration kDelay = milliseconds(20);
Yuri Wiitalaec353612019-06-18 17:32:39 -070032
Yuri Wiitala2b02e322019-12-03 16:59:40 -080033 const Clock::time_point alarm_time = FakeClock::now() + kDelay;
34 Clock::time_point actual_run_time{};
35 alarm()->Schedule([&]() { actual_run_time = FakeClock::now(); }, alarm_time);
Yuri Wiitalaec353612019-06-18 17:32:39 -070036 // Confirm the lambda did not run immediately.
Yuri Wiitala2b02e322019-12-03 16:59:40 -080037 ASSERT_EQ(Clock::time_point{}, actual_run_time);
Yuri Wiitalaec353612019-06-18 17:32:39 -070038
39 // Confirm the lambda does not run until the necessary delay has elapsed.
40 clock()->Advance(kDelay / 2);
Yuri Wiitala2b02e322019-12-03 16:59:40 -080041 ASSERT_EQ(Clock::time_point{}, actual_run_time);
Yuri Wiitalaec353612019-06-18 17:32:39 -070042
43 // Confirm the lambda is called when the necessary delay has elapsed.
44 clock()->Advance(kDelay / 2);
45 ASSERT_EQ(alarm_time, actual_run_time);
46
47 // Confirm the lambda is only run once.
48 clock()->Advance(kDelay * 100);
49 ASSERT_EQ(alarm_time, actual_run_time);
50}
51
Yuri Wiitalac681b472020-02-20 13:41:54 -080052TEST_F(AlarmTest, RunsTaskImmediately) {
53 const Clock::time_point expected_run_time = FakeClock::now();
54 Clock::time_point actual_run_time{};
55 alarm()->Schedule([&]() { actual_run_time = FakeClock::now(); },
56 Alarm::kImmediately);
57 // Confirm the lambda did not run yet, since it should run asynchronously, in
58 // a separate TaskRunner task.
59 ASSERT_EQ(Clock::time_point{}, actual_run_time);
60
61 // Confirm the lambda runs without the clock having to tick forward.
62 task_runner()->RunTasksUntilIdle();
63 ASSERT_EQ(expected_run_time, actual_run_time);
64
65 // Confirm the lambda is only run once.
Jordan Baylesc9201dd2020-06-02 15:51:31 -070066 clock()->Advance(seconds(2));
Yuri Wiitalac681b472020-02-20 13:41:54 -080067 ASSERT_EQ(expected_run_time, actual_run_time);
68}
69
Yuri Wiitalaec353612019-06-18 17:32:39 -070070TEST_F(AlarmTest, CancelsTaskWhenGoingOutOfScope) {
Jordan Baylesc9201dd2020-06-02 15:51:31 -070071 constexpr Clock::duration kDelay = milliseconds(20);
Yuri Wiitala2b02e322019-12-03 16:59:40 -080072 constexpr Clock::time_point kNever{};
Yuri Wiitalaec353612019-06-18 17:32:39 -070073
Yuri Wiitala2b02e322019-12-03 16:59:40 -080074 Clock::time_point actual_run_time{};
Yuri Wiitalaec353612019-06-18 17:32:39 -070075 {
Yuri Wiitala2b02e322019-12-03 16:59:40 -080076 Alarm scoped_alarm(&FakeClock::now, task_runner());
77 const Clock::time_point alarm_time = FakeClock::now() + kDelay;
78 scoped_alarm.Schedule([&]() { actual_run_time = FakeClock::now(); },
79 alarm_time);
Yuri Wiitalaec353612019-06-18 17:32:39 -070080 // |scoped_alarm| is destroyed.
81 }
82
83 // Confirm the lambda has never and will never run.
84 ASSERT_EQ(kNever, actual_run_time);
85 clock()->Advance(kDelay * 100);
86 ASSERT_EQ(kNever, actual_run_time);
87}
88
89TEST_F(AlarmTest, Cancels) {
Jordan Baylesc9201dd2020-06-02 15:51:31 -070090 constexpr Clock::duration kDelay = milliseconds(20);
Yuri Wiitalaec353612019-06-18 17:32:39 -070091
Yuri Wiitala2b02e322019-12-03 16:59:40 -080092 const Clock::time_point alarm_time = FakeClock::now() + kDelay;
93 Clock::time_point actual_run_time{};
94 alarm()->Schedule([&]() { actual_run_time = FakeClock::now(); }, alarm_time);
Yuri Wiitalaec353612019-06-18 17:32:39 -070095
96 // Advance the clock for half the delay, and confirm the lambda has not run
97 // yet.
98 clock()->Advance(kDelay / 2);
Yuri Wiitala2b02e322019-12-03 16:59:40 -080099 ASSERT_EQ(Clock::time_point{}, actual_run_time);
Yuri Wiitalaec353612019-06-18 17:32:39 -0700100
101 // Cancel and then advance the clock well past the delay, and confirm the
102 // lambda has never run.
103 alarm()->Cancel();
104 clock()->Advance(kDelay * 100);
Yuri Wiitala2b02e322019-12-03 16:59:40 -0800105 ASSERT_EQ(Clock::time_point{}, actual_run_time);
Yuri Wiitalaec353612019-06-18 17:32:39 -0700106}
107
108TEST_F(AlarmTest, CancelsAndRearms) {
Jordan Baylesc9201dd2020-06-02 15:51:31 -0700109 constexpr Clock::duration kShorterDelay = milliseconds(10);
110 constexpr Clock::duration kLongerDelay = milliseconds(100);
Yuri Wiitalaec353612019-06-18 17:32:39 -0700111
112 // Run the test twice: Once when scheduling first with a long delay, then a
113 // shorter delay; and once when scheduling first with a short delay, then a
114 // longer delay. This is to test Alarm's internal scheduling/firing logic.
115 for (int do_longer_then_shorter = 0; do_longer_then_shorter <= 1;
116 ++do_longer_then_shorter) {
117 const auto delay1 = do_longer_then_shorter ? kLongerDelay : kShorterDelay;
118 const auto delay2 = do_longer_then_shorter ? kShorterDelay : kLongerDelay;
119
120 int count1 = 0;
Yuri Wiitala2b02e322019-12-03 16:59:40 -0800121 alarm()->Schedule([&]() { ++count1; }, FakeClock::now() + delay1);
Yuri Wiitalaec353612019-06-18 17:32:39 -0700122
123 // Advance the clock for half of |delay1|, and confirm the lambda that
124 // increments the variable does not run.
125 ASSERT_EQ(0, count1);
126 clock()->Advance(delay1 / 2);
127 ASSERT_EQ(0, count1);
128
129 // Schedule a different lambda, that increments a different variable, to run
130 // after |delay2|.
131 int count2 = 0;
Yuri Wiitala2b02e322019-12-03 16:59:40 -0800132 alarm()->Schedule([&]() { ++count2; }, FakeClock::now() + delay2);
Yuri Wiitalaec353612019-06-18 17:32:39 -0700133
134 // Confirm the second scheduling will fire at the right moment.
135 clock()->Advance(delay2 / 2);
136 ASSERT_EQ(0, count2);
137 clock()->Advance(delay2 / 2);
138 ASSERT_EQ(1, count2);
139
140 // Confirm the second scheduling never fires a second time, and also that
141 // the first one doesn't fire.
142 clock()->Advance(std::max(delay1, delay2) * 100);
143 ASSERT_EQ(0, count1);
144 ASSERT_EQ(1, count2);
145 }
146}
147
148} // namespace
149} // namespace openscreen