1 /*
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
11 #include "test/time_controller/simulated_time_controller.h"
12
13 #include <atomic>
14 #include <memory>
15
16 #include "rtc_base/task_queue.h"
17 #include "rtc_base/task_utils/repeating_task.h"
18 #include "test/gmock.h"
19 #include "test/gtest.h"
20
21 #include "rtc_base/event.h"
22
23 // NOTE: Since these tests rely on real time behavior, they will be flaky
24 // if run on heavily loaded systems.
25 namespace webrtc {
26 namespace {
27 using ::testing::AtLeast;
28 using ::testing::Invoke;
29 using ::testing::MockFunction;
30 using ::testing::NiceMock;
31 using ::testing::Return;
32 constexpr Timestamp kStartTime = Timestamp::Seconds(1000);
33 } // namespace
34
TEST(SimulatedTimeControllerTest,TaskIsStoppedOnStop)35 TEST(SimulatedTimeControllerTest, TaskIsStoppedOnStop) {
36 const TimeDelta kShortInterval = TimeDelta::Millis(5);
37 const TimeDelta kLongInterval = TimeDelta::Millis(20);
38 const int kShortIntervalCount = 4;
39 const int kMargin = 1;
40 GlobalSimulatedTimeController time_simulation(kStartTime);
41 rtc::TaskQueue task_queue(
42 time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
43 "TestQueue", TaskQueueFactory::Priority::NORMAL));
44 std::atomic_int counter(0);
45 auto handle = RepeatingTaskHandle::Start(task_queue.Get(), [&] {
46 if (++counter >= kShortIntervalCount)
47 return kLongInterval;
48 return kShortInterval;
49 });
50 // Sleep long enough to go through the initial phase.
51 time_simulation.AdvanceTime(kShortInterval * (kShortIntervalCount + kMargin));
52 EXPECT_EQ(counter.load(), kShortIntervalCount);
53
54 task_queue.PostTask(
55 [handle = std::move(handle)]() mutable { handle.Stop(); });
56
57 // Sleep long enough that the task would run at least once more if not
58 // stopped.
59 time_simulation.AdvanceTime(kLongInterval * 2);
60 EXPECT_EQ(counter.load(), kShortIntervalCount);
61 }
62
TEST(SimulatedTimeControllerTest,TaskCanStopItself)63 TEST(SimulatedTimeControllerTest, TaskCanStopItself) {
64 std::atomic_int counter(0);
65 GlobalSimulatedTimeController time_simulation(kStartTime);
66 rtc::TaskQueue task_queue(
67 time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
68 "TestQueue", TaskQueueFactory::Priority::NORMAL));
69
70 RepeatingTaskHandle handle;
71 task_queue.PostTask([&] {
72 handle = RepeatingTaskHandle::Start(task_queue.Get(), [&] {
73 ++counter;
74 handle.Stop();
75 return TimeDelta::Millis(2);
76 });
77 });
78 time_simulation.AdvanceTime(TimeDelta::Millis(10));
79 EXPECT_EQ(counter.load(), 1);
80 }
81
TEST(SimulatedTimeControllerTest,Example)82 TEST(SimulatedTimeControllerTest, Example) {
83 class ObjectOnTaskQueue {
84 public:
85 void DoPeriodicTask() {}
86 TimeDelta TimeUntilNextRun() { return TimeDelta::Millis(100); }
87 void StartPeriodicTask(RepeatingTaskHandle* handle,
88 rtc::TaskQueue* task_queue) {
89 *handle = RepeatingTaskHandle::Start(task_queue->Get(), [this] {
90 DoPeriodicTask();
91 return TimeUntilNextRun();
92 });
93 }
94 };
95 GlobalSimulatedTimeController time_simulation(kStartTime);
96 rtc::TaskQueue task_queue(
97 time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
98 "TestQueue", TaskQueueFactory::Priority::NORMAL));
99 auto object = std::make_unique<ObjectOnTaskQueue>();
100 // Create and start the periodic task.
101 RepeatingTaskHandle handle;
102 object->StartPeriodicTask(&handle, &task_queue);
103 // Restart the task
104 task_queue.PostTask(
105 [handle = std::move(handle)]() mutable { handle.Stop(); });
106 object->StartPeriodicTask(&handle, &task_queue);
107 task_queue.PostTask(
108 [handle = std::move(handle)]() mutable { handle.Stop(); });
109
110 struct Destructor {
111 void operator()() { object.reset(); }
112 std::unique_ptr<ObjectOnTaskQueue> object;
113 };
114 task_queue.PostTask(Destructor{std::move(object)});
115 }
116
TEST(SimulatedTimeControllerTest,DelayTaskRunOnTime)117 TEST(SimulatedTimeControllerTest, DelayTaskRunOnTime) {
118 GlobalSimulatedTimeController time_simulation(kStartTime);
119 rtc::TaskQueue task_queue(
120 time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
121 "TestQueue", TaskQueueFactory::Priority::NORMAL));
122
123 bool delay_task_executed = false;
124 task_queue.PostDelayedTask([&] { delay_task_executed = true; }, 10);
125
126 time_simulation.AdvanceTime(TimeDelta::Millis(10));
127 EXPECT_TRUE(delay_task_executed);
128 }
129
TEST(SimulatedTimeControllerTest,ThreadYeildsOnInvoke)130 TEST(SimulatedTimeControllerTest, ThreadYeildsOnInvoke) {
131 GlobalSimulatedTimeController sim(kStartTime);
132 auto main_thread = sim.GetMainThread();
133 auto t2 = sim.CreateThread("thread", nullptr);
134 bool task_has_run = false;
135 // Posting a task to the main thread, this should not run until AdvanceTime is
136 // called.
137 main_thread->PostTask(RTC_FROM_HERE, [&] { task_has_run = true; });
138 t2->Invoke<void>(RTC_FROM_HERE, [] {
139 rtc::Event yield_event;
140 // Wait() triggers YieldExecution() which will runs message processing on
141 // all threads that are not in the yielded set.
142
143 yield_event.Wait(0);
144 });
145 // Since we are doing an invoke from the main thread, we don't expect the main
146 // thread message loop to be processed.
147 EXPECT_FALSE(task_has_run);
148 sim.AdvanceTime(TimeDelta::Seconds(1));
149 ASSERT_TRUE(task_has_run);
150 }
151
152 } // namespace webrtc
153