blob: 4cb6816999956c1e45f080b288fc3cee3abde774 [file] [log] [blame]
Sebastian Janssonecb68972019-01-18 10:30:54 +01001/*
2 * Copyright 2019 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "rtc_base/task_utils/repeating_task.h"
12
Sebastian Janssonecb68972019-01-18 10:30:54 +010013#include <atomic>
Sebastian Janssonecb68972019-01-18 10:30:54 +010014#include <memory>
Sebastian Janssonecb68972019-01-18 10:30:54 +010015
Danil Chapovalovdde7fe42022-07-05 21:26:06 +020016#include "absl/functional/any_invocable.h"
Evan Shrubsolef0f47432021-11-15 17:24:45 +010017#include "api/task_queue/task_queue_base.h"
Danil Chapovalovdde7fe42022-07-05 21:26:06 +020018#include "api/units/time_delta.h"
Evan Shrubsolef0f47432021-11-15 17:24:45 +010019#include "api/units/timestamp.h"
Sebastian Janssonecb68972019-01-18 10:30:54 +010020#include "rtc_base/event.h"
Danil Chapovalov07122bc2019-03-26 14:37:01 +010021#include "rtc_base/task_queue_for_test.h"
Evan Shrubsolef0f47432021-11-15 17:24:45 +010022#include "system_wrappers/include/clock.h"
Sebastian Janssonecb68972019-01-18 10:30:54 +010023#include "test/gmock.h"
24#include "test/gtest.h"
25
26// NOTE: Since these tests rely on real time behavior, they will be flaky
27// if run on heavily loaded systems.
28namespace webrtc {
29namespace {
30using ::testing::AtLeast;
31using ::testing::Invoke;
32using ::testing::MockFunction;
33using ::testing::NiceMock;
34using ::testing::Return;
35
Danil Chapovalov0c626af2020-02-10 11:16:00 +010036constexpr TimeDelta kTimeout = TimeDelta::Millis(1000);
Sebastian Janssonecb68972019-01-18 10:30:54 +010037
Sebastian Janssonecb68972019-01-18 10:30:54 +010038class MockClosure {
39 public:
Danil Chapovalov42748d82020-05-14 20:42:41 +020040 MOCK_METHOD(TimeDelta, Call, ());
41 MOCK_METHOD(void, Delete, ());
Sebastian Janssonecb68972019-01-18 10:30:54 +010042};
43
Tommi532cac52020-05-18 14:53:42 +020044class MockTaskQueue : public TaskQueueBase {
45 public:
46 MockTaskQueue() : task_queue_setter_(this) {}
47
48 MOCK_METHOD(void, Delete, (), (override));
Danil Chapovalovdde7fe42022-07-05 21:26:06 +020049 MOCK_METHOD(void, PostTask, (absl::AnyInvocable<void() &&>), (override));
Tommi532cac52020-05-18 14:53:42 +020050 MOCK_METHOD(void,
51 PostDelayedTask,
Danil Chapovalovdde7fe42022-07-05 21:26:06 +020052 (absl::AnyInvocable<void() &&>, TimeDelta),
53 (override));
54 MOCK_METHOD(void,
55 PostDelayedHighPrecisionTask,
56 (absl::AnyInvocable<void() &&>, TimeDelta),
Tommi532cac52020-05-18 14:53:42 +020057 (override));
58
59 private:
60 CurrentTaskQueueSetter task_queue_setter_;
61};
62
Evan Shrubsolef0f47432021-11-15 17:24:45 +010063class FakeTaskQueue : public TaskQueueBase {
64 public:
65 explicit FakeTaskQueue(SimulatedClock* clock)
66 : task_queue_setter_(this), clock_(clock) {}
67
68 void Delete() override {}
69
Danil Chapovalovdde7fe42022-07-05 21:26:06 +020070 void PostTask(absl::AnyInvocable<void() &&> task) override {
Henrik Boström27e8a092022-01-24 17:12:35 +010071 last_task_ = std::move(task);
72 last_precision_ = absl::nullopt;
Danil Chapovalovdde7fe42022-07-05 21:26:06 +020073 last_delay_ = TimeDelta::Zero();
Evan Shrubsolef0f47432021-11-15 17:24:45 +010074 }
75
Danil Chapovalovdde7fe42022-07-05 21:26:06 +020076 void PostDelayedTask(absl::AnyInvocable<void() &&> task,
77 TimeDelta delay) override {
Evan Shrubsolef0f47432021-11-15 17:24:45 +010078 last_task_ = std::move(task);
Henrik Boström27e8a092022-01-24 17:12:35 +010079 last_precision_ = TaskQueueBase::DelayPrecision::kLow;
Danil Chapovalovdde7fe42022-07-05 21:26:06 +020080 last_delay_ = delay;
Henrik Boström27e8a092022-01-24 17:12:35 +010081 }
82
Danil Chapovalovdde7fe42022-07-05 21:26:06 +020083 void PostDelayedHighPrecisionTask(absl::AnyInvocable<void() &&> task,
84 TimeDelta delay) override {
Henrik Boström27e8a092022-01-24 17:12:35 +010085 last_task_ = std::move(task);
86 last_precision_ = TaskQueueBase::DelayPrecision::kHigh;
Danil Chapovalovdde7fe42022-07-05 21:26:06 +020087 last_delay_ = delay;
Evan Shrubsolef0f47432021-11-15 17:24:45 +010088 }
89
90 bool AdvanceTimeAndRunLastTask() {
91 EXPECT_TRUE(last_task_);
Danil Chapovalovdde7fe42022-07-05 21:26:06 +020092 EXPECT_TRUE(last_delay_.IsFinite());
93 clock_->AdvanceTime(last_delay_);
94 last_delay_ = TimeDelta::MinusInfinity();
Evan Shrubsolef0f47432021-11-15 17:24:45 +010095 auto task = std::move(last_task_);
Danil Chapovalovdde7fe42022-07-05 21:26:06 +020096 std::move(task)();
97 return last_task_ == nullptr;
Evan Shrubsolef0f47432021-11-15 17:24:45 +010098 }
99
100 bool IsTaskQueued() { return !!last_task_; }
101
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200102 TimeDelta last_delay() const {
103 EXPECT_TRUE(last_delay_.IsFinite());
104 return last_delay_;
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100105 }
106
Henrik Boström27e8a092022-01-24 17:12:35 +0100107 absl::optional<TaskQueueBase::DelayPrecision> last_precision() const {
108 return last_precision_;
109 }
110
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100111 private:
112 CurrentTaskQueueSetter task_queue_setter_;
113 SimulatedClock* clock_;
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200114 absl::AnyInvocable<void() &&> last_task_;
115 TimeDelta last_delay_ = TimeDelta::MinusInfinity();
Henrik Boström27e8a092022-01-24 17:12:35 +0100116 absl::optional<TaskQueueBase::DelayPrecision> last_precision_;
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100117};
118
Tomas Gunnarsson87e7b3d2022-01-17 09:58:45 +0100119// NOTE: Since this utility class holds a raw pointer to a variable that likely
120// lives on the stack, it's important that any repeating tasks that use this
121// class be explicitly stopped when the test criteria have been met. If the
122// task is not stopped, an instance of this class can be deleted when the
123// pointed-to MockClosure has been deleted and we end up trying to call a
124// virtual method on a deleted object in the dtor.
Sebastian Janssonecb68972019-01-18 10:30:54 +0100125class MoveOnlyClosure {
126 public:
127 explicit MoveOnlyClosure(MockClosure* mock) : mock_(mock) {}
128 MoveOnlyClosure(const MoveOnlyClosure&) = delete;
129 MoveOnlyClosure(MoveOnlyClosure&& other) : mock_(other.mock_) {
130 other.mock_ = nullptr;
131 }
132 ~MoveOnlyClosure() {
133 if (mock_)
134 mock_->Delete();
135 }
136 TimeDelta operator()() { return mock_->Call(); }
137
138 private:
139 MockClosure* mock_;
140};
141} // namespace
142
143TEST(RepeatingTaskTest, TaskIsStoppedOnStop) {
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100144 const TimeDelta kShortInterval = TimeDelta::Millis(50);
Sebastian Janssonecb68972019-01-18 10:30:54 +0100145
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100146 SimulatedClock clock(Timestamp::Zero());
147 FakeTaskQueue task_queue(&clock);
Sebastian Janssonecb68972019-01-18 10:30:54 +0100148 std::atomic_int counter(0);
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200149 auto handle = RepeatingTaskHandle::Start(
150 &task_queue,
151 [&] {
152 counter++;
153 return kShortInterval;
154 },
155 TaskQueueBase::DelayPrecision::kLow, &clock);
156 EXPECT_EQ(task_queue.last_delay(), TimeDelta::Zero());
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100157 EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask());
158 EXPECT_EQ(counter.load(), 1);
Sebastian Janssonecb68972019-01-18 10:30:54 +0100159
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100160 // The handle reposted at the short interval.
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200161 EXPECT_EQ(task_queue.last_delay(), kShortInterval);
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100162
163 // Stop the handle. This prevernts the counter from incrementing.
164 handle.Stop();
165 EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask());
166 EXPECT_EQ(counter.load(), 1);
Sebastian Janssonecb68972019-01-18 10:30:54 +0100167}
168
169TEST(RepeatingTaskTest, CompensatesForLongRunTime) {
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100170 const TimeDelta kRepeatInterval = TimeDelta::Millis(2);
Sebastian Janssonecb68972019-01-18 10:30:54 +0100171 // Sleeping inside the task for longer than the repeat interval once, should
172 // be compensated for by repeating the task faster to catch up.
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100173 const TimeDelta kSleepDuration = TimeDelta::Millis(20);
Sebastian Janssonecb68972019-01-18 10:30:54 +0100174
175 std::atomic_int counter(0);
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100176 SimulatedClock clock(Timestamp::Zero());
177 FakeTaskQueue task_queue(&clock);
178 RepeatingTaskHandle::Start(
179 &task_queue,
180 [&] {
181 ++counter;
182 // Task takes longer than the repeat duration.
183 clock.AdvanceTime(kSleepDuration);
184 return kRepeatInterval;
185 },
Henrik Boström27e8a092022-01-24 17:12:35 +0100186 TaskQueueBase::DelayPrecision::kLow, &clock);
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100187
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200188 EXPECT_EQ(task_queue.last_delay(), TimeDelta::Zero());
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100189 EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask());
190
191 // Task is posted right away since it took longer to run then the repeat
192 // interval.
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200193 EXPECT_EQ(task_queue.last_delay(), TimeDelta::Zero());
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100194 EXPECT_EQ(counter.load(), 1);
Sebastian Janssonecb68972019-01-18 10:30:54 +0100195}
196
197TEST(RepeatingTaskTest, CompensatesForShortRunTime) {
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100198 SimulatedClock clock(Timestamp::Millis(0));
199 FakeTaskQueue task_queue(&clock);
Sebastian Janssonecb68972019-01-18 10:30:54 +0100200 std::atomic_int counter(0);
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100201 RepeatingTaskHandle::Start(
202 &task_queue,
203 [&] {
204 // Simulate the task taking 100ms, which should be compensated for.
205 counter++;
206 clock.AdvanceTime(TimeDelta::Millis(100));
207 return TimeDelta::Millis(300);
208 },
Henrik Boström27e8a092022-01-24 17:12:35 +0100209 TaskQueueBase::DelayPrecision::kLow, &clock);
Sebastian Janssona497d122019-02-04 16:39:28 +0100210
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100211 // Expect instant post task.
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200212 EXPECT_EQ(task_queue.last_delay(), TimeDelta::Zero());
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100213 // Task should be retained by the handler since it is not cancelled.
214 EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask());
215 // New delay should be 200ms since repeat delay was 300ms but task took 100ms.
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200216 EXPECT_EQ(task_queue.last_delay(), TimeDelta::Millis(200));
Sebastian Janssonecb68972019-01-18 10:30:54 +0100217}
218
219TEST(RepeatingTaskTest, CancelDelayedTaskBeforeItRuns) {
220 rtc::Event done;
221 MockClosure mock;
222 EXPECT_CALL(mock, Call).Times(0);
223 EXPECT_CALL(mock, Delete).WillOnce(Invoke([&done] { done.Set(); }));
Danil Chapovalov07122bc2019-03-26 14:37:01 +0100224 TaskQueueForTest task_queue("queue");
Sebastian Janssonecb68972019-01-18 10:30:54 +0100225 auto handle = RepeatingTaskHandle::DelayedStart(
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100226 task_queue.Get(), TimeDelta::Millis(100), MoveOnlyClosure(&mock));
Sebastian Jansson86314cf2019-09-17 20:29:59 +0200227 task_queue.PostTask(
228 [handle = std::move(handle)]() mutable { handle.Stop(); });
Sebastian Janssonecb68972019-01-18 10:30:54 +0100229 EXPECT_TRUE(done.Wait(kTimeout.ms()));
230}
231
232TEST(RepeatingTaskTest, CancelTaskAfterItRuns) {
233 rtc::Event done;
234 MockClosure mock;
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100235 EXPECT_CALL(mock, Call).WillOnce(Return(TimeDelta::Millis(100)));
Sebastian Janssonecb68972019-01-18 10:30:54 +0100236 EXPECT_CALL(mock, Delete).WillOnce(Invoke([&done] { done.Set(); }));
Danil Chapovalov07122bc2019-03-26 14:37:01 +0100237 TaskQueueForTest task_queue("queue");
Danil Chapovalov4423c362019-03-06 18:41:39 +0100238 auto handle =
239 RepeatingTaskHandle::Start(task_queue.Get(), MoveOnlyClosure(&mock));
Sebastian Jansson86314cf2019-09-17 20:29:59 +0200240 task_queue.PostTask(
241 [handle = std::move(handle)]() mutable { handle.Stop(); });
Sebastian Janssonecb68972019-01-18 10:30:54 +0100242 EXPECT_TRUE(done.Wait(kTimeout.ms()));
243}
244
245TEST(RepeatingTaskTest, TaskCanStopItself) {
246 std::atomic_int counter(0);
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100247 SimulatedClock clock(Timestamp::Zero());
248 FakeTaskQueue task_queue(&clock);
249 RepeatingTaskHandle handle = RepeatingTaskHandle::Start(&task_queue, [&] {
250 ++counter;
251 handle.Stop();
252 return TimeDelta::Millis(2);
Sebastian Janssonecb68972019-01-18 10:30:54 +0100253 });
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200254 EXPECT_EQ(task_queue.last_delay(), TimeDelta::Zero());
Evan Shrubsolef0f47432021-11-15 17:24:45 +0100255 // Task cancelled itself so wants to be released.
256 EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask());
Sebastian Janssonecb68972019-01-18 10:30:54 +0100257 EXPECT_EQ(counter.load(), 1);
258}
259
Niels Möller902b5542022-01-17 15:20:24 +0100260TEST(RepeatingTaskTest, TaskCanStopItselfByReturningInfinity) {
261 std::atomic_int counter(0);
262 SimulatedClock clock(Timestamp::Zero());
263 FakeTaskQueue task_queue(&clock);
264 RepeatingTaskHandle handle = RepeatingTaskHandle::Start(&task_queue, [&] {
265 ++counter;
266 return TimeDelta::PlusInfinity();
267 });
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200268 EXPECT_EQ(task_queue.last_delay(), TimeDelta::Zero());
Niels Möller902b5542022-01-17 15:20:24 +0100269 // Task cancelled itself so wants to be released.
270 EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask());
271 EXPECT_EQ(counter.load(), 1);
272}
273
Sebastian Janssonecb68972019-01-18 10:30:54 +0100274TEST(RepeatingTaskTest, ZeroReturnValueRepostsTheTask) {
275 NiceMock<MockClosure> closure;
276 rtc::Event done;
277 EXPECT_CALL(closure, Call())
278 .WillOnce(Return(TimeDelta::Zero()))
Tomas Gunnarsson87e7b3d2022-01-17 09:58:45 +0100279 .WillOnce(Invoke([&] {
Sebastian Janssonecb68972019-01-18 10:30:54 +0100280 done.Set();
Niels Möller902b5542022-01-17 15:20:24 +0100281 return TimeDelta::PlusInfinity();
Sebastian Janssonecb68972019-01-18 10:30:54 +0100282 }));
Danil Chapovalov07122bc2019-03-26 14:37:01 +0100283 TaskQueueForTest task_queue("queue");
Niels Möller902b5542022-01-17 15:20:24 +0100284 RepeatingTaskHandle::Start(task_queue.Get(), MoveOnlyClosure(&closure));
Sebastian Janssonecb68972019-01-18 10:30:54 +0100285 EXPECT_TRUE(done.Wait(kTimeout.ms()));
286}
287
288TEST(RepeatingTaskTest, StartPeriodicTask) {
289 MockFunction<TimeDelta()> closure;
290 rtc::Event done;
291 EXPECT_CALL(closure, Call())
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100292 .WillOnce(Return(TimeDelta::Millis(20)))
293 .WillOnce(Return(TimeDelta::Millis(20)))
Tomas Gunnarsson87e7b3d2022-01-17 09:58:45 +0100294 .WillOnce(Invoke([&] {
Sebastian Janssonecb68972019-01-18 10:30:54 +0100295 done.Set();
Niels Möller902b5542022-01-17 15:20:24 +0100296 return TimeDelta::PlusInfinity();
Sebastian Janssonecb68972019-01-18 10:30:54 +0100297 }));
Danil Chapovalov07122bc2019-03-26 14:37:01 +0100298 TaskQueueForTest task_queue("queue");
Danil Chapovalov4423c362019-03-06 18:41:39 +0100299 RepeatingTaskHandle::Start(task_queue.Get(), closure.AsStdFunction());
Sebastian Janssonecb68972019-01-18 10:30:54 +0100300 EXPECT_TRUE(done.Wait(kTimeout.ms()));
301}
302
303TEST(RepeatingTaskTest, Example) {
304 class ObjectOnTaskQueue {
305 public:
306 void DoPeriodicTask() {}
Danil Chapovalov0c626af2020-02-10 11:16:00 +0100307 TimeDelta TimeUntilNextRun() { return TimeDelta::Millis(100); }
Sebastian Janssonecb68972019-01-18 10:30:54 +0100308 void StartPeriodicTask(RepeatingTaskHandle* handle,
Danil Chapovalov4423c362019-03-06 18:41:39 +0100309 TaskQueueBase* task_queue) {
Sebastian Janssonecb68972019-01-18 10:30:54 +0100310 *handle = RepeatingTaskHandle::Start(task_queue, [this] {
311 DoPeriodicTask();
312 return TimeUntilNextRun();
313 });
314 }
315 };
Danil Chapovalov07122bc2019-03-26 14:37:01 +0100316 TaskQueueForTest task_queue("queue");
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200317 auto object = std::make_unique<ObjectOnTaskQueue>();
Sebastian Janssonecb68972019-01-18 10:30:54 +0100318 // Create and start the periodic task.
319 RepeatingTaskHandle handle;
Danil Chapovalov4423c362019-03-06 18:41:39 +0100320 object->StartPeriodicTask(&handle, task_queue.Get());
Sebastian Janssonecb68972019-01-18 10:30:54 +0100321 // Restart the task
Sebastian Jansson86314cf2019-09-17 20:29:59 +0200322 task_queue.PostTask(
323 [handle = std::move(handle)]() mutable { handle.Stop(); });
Danil Chapovalov4423c362019-03-06 18:41:39 +0100324 object->StartPeriodicTask(&handle, task_queue.Get());
Sebastian Jansson86314cf2019-09-17 20:29:59 +0200325 task_queue.PostTask(
326 [handle = std::move(handle)]() mutable { handle.Stop(); });
Sebastian Janssonecb68972019-01-18 10:30:54 +0100327 struct Destructor {
328 void operator()() { object.reset(); }
329 std::unique_ptr<ObjectOnTaskQueue> object;
330 };
331 task_queue.PostTask(Destructor{std::move(object)});
332 // Do not wait for the destructor closure in order to create a race between
333 // task queue destruction and running the desctructor closure.
334}
335
Tommi532cac52020-05-18 14:53:42 +0200336TEST(RepeatingTaskTest, ClockIntegration) {
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200337 absl::AnyInvocable<void() &&> delayed_task;
338 TimeDelta expected_delay = TimeDelta::Zero();
Tommi532cac52020-05-18 14:53:42 +0200339 SimulatedClock clock(Timestamp::Millis(0));
340
341 NiceMock<MockTaskQueue> task_queue;
342 ON_CALL(task_queue, PostDelayedTask)
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200343 .WillByDefault([&](absl::AnyInvocable<void() &&> task, TimeDelta delay) {
344 EXPECT_EQ(delay, expected_delay);
345 delayed_task = std::move(task);
346 });
Tommi532cac52020-05-18 14:53:42 +0200347
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200348 expected_delay = TimeDelta::Millis(100);
Tommi532cac52020-05-18 14:53:42 +0200349 RepeatingTaskHandle handle = RepeatingTaskHandle::DelayedStart(
350 &task_queue, TimeDelta::Millis(100),
351 [&clock]() {
352 EXPECT_EQ(Timestamp::Millis(100), clock.CurrentTime());
353 // Simulate work happening for 10ms.
354 clock.AdvanceTimeMilliseconds(10);
355 return TimeDelta::Millis(100);
356 },
Henrik Boström27e8a092022-01-24 17:12:35 +0100357 TaskQueueBase::DelayPrecision::kLow, &clock);
Tommi532cac52020-05-18 14:53:42 +0200358
359 clock.AdvanceTimeMilliseconds(100);
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200360 absl::AnyInvocable<void()&&> task_to_run = std::move(delayed_task);
361 expected_delay = TimeDelta::Millis(90);
362 std::move(task_to_run)();
363 EXPECT_NE(delayed_task, nullptr);
Tommi532cac52020-05-18 14:53:42 +0200364 handle.Stop();
365}
366
Danil Chapovalov0f9a8e32021-06-11 18:39:17 +0200367TEST(RepeatingTaskTest, CanBeStoppedAfterTaskQueueDeletedTheRepeatingTask) {
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200368 absl::AnyInvocable<void() &&> repeating_task;
Danil Chapovalov0f9a8e32021-06-11 18:39:17 +0200369
370 MockTaskQueue task_queue;
371 EXPECT_CALL(task_queue, PostDelayedTask)
Danil Chapovalovdde7fe42022-07-05 21:26:06 +0200372 .WillOnce([&](absl::AnyInvocable<void() &&> task, TimeDelta delay) {
Danil Chapovalov0f9a8e32021-06-11 18:39:17 +0200373 repeating_task = std::move(task);
374 });
375
376 RepeatingTaskHandle handle =
377 RepeatingTaskHandle::DelayedStart(&task_queue, TimeDelta::Millis(100),
378 [] { return TimeDelta::Millis(100); });
379
380 // shutdown task queue: delete all pending tasks and run 'regular' task.
381 repeating_task = nullptr;
382 handle.Stop();
383}
384
Henrik Boström27e8a092022-01-24 17:12:35 +0100385TEST(RepeatingTaskTest, DefaultPrecisionIsLow) {
386 SimulatedClock clock(Timestamp::Zero());
387 FakeTaskQueue task_queue(&clock);
388 // Closure that repeats twice.
389 MockFunction<TimeDelta()> closure;
390 EXPECT_CALL(closure, Call())
391 .WillOnce(Return(TimeDelta::Millis(1)))
392 .WillOnce(Return(TimeDelta::PlusInfinity()));
393 RepeatingTaskHandle::Start(&task_queue, closure.AsStdFunction());
394 // Initial task is a PostTask().
395 EXPECT_FALSE(task_queue.last_precision().has_value());
396 EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask());
397 // Repeated task is a delayed task with the default precision: low.
398 EXPECT_TRUE(task_queue.last_precision().has_value());
399 EXPECT_EQ(task_queue.last_precision().value(),
400 TaskQueueBase::DelayPrecision::kLow);
401 // No more tasks.
402 EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask());
403}
404
405TEST(RepeatingTaskTest, CanSpecifyToPostTasksWithLowPrecision) {
406 SimulatedClock clock(Timestamp::Zero());
407 FakeTaskQueue task_queue(&clock);
408 // Closure that repeats twice.
409 MockFunction<TimeDelta()> closure;
410 EXPECT_CALL(closure, Call())
411 .WillOnce(Return(TimeDelta::Millis(1)))
412 .WillOnce(Return(TimeDelta::PlusInfinity()));
413 RepeatingTaskHandle::Start(&task_queue, closure.AsStdFunction(),
414 TaskQueueBase::DelayPrecision::kLow);
415 // Initial task is a PostTask().
416 EXPECT_FALSE(task_queue.last_precision().has_value());
417 EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask());
418 // Repeated task is a delayed task with the specified precision.
419 EXPECT_TRUE(task_queue.last_precision().has_value());
420 EXPECT_EQ(task_queue.last_precision().value(),
421 TaskQueueBase::DelayPrecision::kLow);
422 // No more tasks.
423 EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask());
424}
425
426TEST(RepeatingTaskTest, CanSpecifyToPostTasksWithHighPrecision) {
427 SimulatedClock clock(Timestamp::Zero());
428 FakeTaskQueue task_queue(&clock);
429 // Closure that repeats twice.
430 MockFunction<TimeDelta()> closure;
431 EXPECT_CALL(closure, Call())
432 .WillOnce(Return(TimeDelta::Millis(1)))
433 .WillOnce(Return(TimeDelta::PlusInfinity()));
434 RepeatingTaskHandle::Start(&task_queue, closure.AsStdFunction(),
435 TaskQueueBase::DelayPrecision::kHigh);
436 // Initial task is a PostTask().
437 EXPECT_FALSE(task_queue.last_precision().has_value());
438 EXPECT_FALSE(task_queue.AdvanceTimeAndRunLastTask());
439 // Repeated task is a delayed task with the specified precision.
440 EXPECT_TRUE(task_queue.last_precision().has_value());
441 EXPECT_EQ(task_queue.last_precision().value(),
442 TaskQueueBase::DelayPrecision::kHigh);
443 // No more tasks.
444 EXPECT_TRUE(task_queue.AdvanceTimeAndRunLastTask());
445}
446
Sebastian Janssonecb68972019-01-18 10:30:54 +0100447} // namespace webrtc