Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 1 | // 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 Bayles | a26582d | 2019-07-10 14:44:58 -0700 | [diff] [blame] | 5 | #include "util/alarm.h" |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 6 | |
| 7 | #include <algorithm> |
Jordan Bayles | c9201dd | 2020-06-02 15:51:31 -0700 | [diff] [blame] | 8 | #include <chrono> |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 9 | |
| 10 | #include "gtest/gtest.h" |
| 11 | #include "platform/test/fake_clock.h" |
| 12 | #include "platform/test/fake_task_runner.h" |
Jordan Bayles | c9201dd | 2020-06-02 15:51:31 -0700 | [diff] [blame] | 13 | #include "util/chrono_helpers.h" |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 14 | |
| 15 | namespace openscreen { |
| 16 | namespace { |
| 17 | |
| 18 | class AlarmTest : public testing::Test { |
| 19 | public: |
Yuri Wiitala | 2b02e32 | 2019-12-03 16:59:40 -0800 | [diff] [blame] | 20 | FakeClock* clock() { return &clock_; } |
Yuri Wiitala | c681b47 | 2020-02-20 13:41:54 -0800 | [diff] [blame] | 21 | FakeTaskRunner* task_runner() { return &task_runner_; } |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 22 | Alarm* alarm() { return &alarm_; } |
| 23 | |
| 24 | private: |
Yuri Wiitala | 2b02e32 | 2019-12-03 16:59:40 -0800 | [diff] [blame] | 25 | FakeClock clock_{Clock::now()}; |
| 26 | FakeTaskRunner task_runner_{&clock_}; |
| 27 | Alarm alarm_{&FakeClock::now, &task_runner_}; |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 28 | }; |
| 29 | |
| 30 | TEST_F(AlarmTest, RunsTaskAsClockAdvances) { |
Jordan Bayles | c9201dd | 2020-06-02 15:51:31 -0700 | [diff] [blame] | 31 | constexpr Clock::duration kDelay = milliseconds(20); |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 32 | |
Yuri Wiitala | 2b02e32 | 2019-12-03 16:59:40 -0800 | [diff] [blame] | 33 | 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 Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 36 | // Confirm the lambda did not run immediately. |
Yuri Wiitala | 2b02e32 | 2019-12-03 16:59:40 -0800 | [diff] [blame] | 37 | ASSERT_EQ(Clock::time_point{}, actual_run_time); |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 38 | |
| 39 | // Confirm the lambda does not run until the necessary delay has elapsed. |
| 40 | clock()->Advance(kDelay / 2); |
Yuri Wiitala | 2b02e32 | 2019-12-03 16:59:40 -0800 | [diff] [blame] | 41 | ASSERT_EQ(Clock::time_point{}, actual_run_time); |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 42 | |
| 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 Wiitala | c681b47 | 2020-02-20 13:41:54 -0800 | [diff] [blame] | 52 | TEST_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 Bayles | c9201dd | 2020-06-02 15:51:31 -0700 | [diff] [blame] | 66 | clock()->Advance(seconds(2)); |
Yuri Wiitala | c681b47 | 2020-02-20 13:41:54 -0800 | [diff] [blame] | 67 | ASSERT_EQ(expected_run_time, actual_run_time); |
| 68 | } |
| 69 | |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 70 | TEST_F(AlarmTest, CancelsTaskWhenGoingOutOfScope) { |
Jordan Bayles | c9201dd | 2020-06-02 15:51:31 -0700 | [diff] [blame] | 71 | constexpr Clock::duration kDelay = milliseconds(20); |
Yuri Wiitala | 2b02e32 | 2019-12-03 16:59:40 -0800 | [diff] [blame] | 72 | constexpr Clock::time_point kNever{}; |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 73 | |
Yuri Wiitala | 2b02e32 | 2019-12-03 16:59:40 -0800 | [diff] [blame] | 74 | Clock::time_point actual_run_time{}; |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 75 | { |
Yuri Wiitala | 2b02e32 | 2019-12-03 16:59:40 -0800 | [diff] [blame] | 76 | 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 Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 80 | // |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 | |
| 89 | TEST_F(AlarmTest, Cancels) { |
Jordan Bayles | c9201dd | 2020-06-02 15:51:31 -0700 | [diff] [blame] | 90 | constexpr Clock::duration kDelay = milliseconds(20); |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 91 | |
Yuri Wiitala | 2b02e32 | 2019-12-03 16:59:40 -0800 | [diff] [blame] | 92 | 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 Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 95 | |
| 96 | // Advance the clock for half the delay, and confirm the lambda has not run |
| 97 | // yet. |
| 98 | clock()->Advance(kDelay / 2); |
Yuri Wiitala | 2b02e32 | 2019-12-03 16:59:40 -0800 | [diff] [blame] | 99 | ASSERT_EQ(Clock::time_point{}, actual_run_time); |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 100 | |
| 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 Wiitala | 2b02e32 | 2019-12-03 16:59:40 -0800 | [diff] [blame] | 105 | ASSERT_EQ(Clock::time_point{}, actual_run_time); |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 106 | } |
| 107 | |
| 108 | TEST_F(AlarmTest, CancelsAndRearms) { |
Jordan Bayles | c9201dd | 2020-06-02 15:51:31 -0700 | [diff] [blame] | 109 | constexpr Clock::duration kShorterDelay = milliseconds(10); |
| 110 | constexpr Clock::duration kLongerDelay = milliseconds(100); |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 111 | |
| 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 Wiitala | 2b02e32 | 2019-12-03 16:59:40 -0800 | [diff] [blame] | 121 | alarm()->Schedule([&]() { ++count1; }, FakeClock::now() + delay1); |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 122 | |
| 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 Wiitala | 2b02e32 | 2019-12-03 16:59:40 -0800 | [diff] [blame] | 132 | alarm()->Schedule([&]() { ++count2; }, FakeClock::now() + delay2); |
Yuri Wiitala | ec35361 | 2019-06-18 17:32:39 -0700 | [diff] [blame] | 133 | |
| 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 |