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/event.h"
17 #include "rtc_base/task_queue.h"
18 #include "rtc_base/task_queue_for_test.h"
19 #include "rtc_base/task_utils/repeating_task.h"
20 #include "test/gmock.h"
21 #include "test/gtest.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 task_queue.PostTask([object = std::move(object)] {});
111 }
112
TEST(SimulatedTimeControllerTest,DelayTaskRunOnTime)113 TEST(SimulatedTimeControllerTest, DelayTaskRunOnTime) {
114 GlobalSimulatedTimeController time_simulation(kStartTime);
115 std::unique_ptr<TaskQueueBase, TaskQueueDeleter> task_queue =
116 time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
117 "TestQueue", TaskQueueFactory::Priority::NORMAL);
118
119 bool delay_task_executed = false;
120 task_queue->PostDelayedTask([&] { delay_task_executed = true; },
121 TimeDelta::Millis(10));
122
123 time_simulation.AdvanceTime(TimeDelta::Millis(10));
124 EXPECT_TRUE(delay_task_executed);
125 }
126
TEST(SimulatedTimeControllerTest,ThreadYeildsOnSynchronousCall)127 TEST(SimulatedTimeControllerTest, ThreadYeildsOnSynchronousCall) {
128 GlobalSimulatedTimeController sim(kStartTime);
129 auto main_thread = sim.GetMainThread();
130 auto t2 = sim.CreateThread("thread", nullptr);
131 bool task_has_run = false;
132 // Posting a task to the main thread, this should not run until AdvanceTime is
133 // called.
134 main_thread->PostTask([&] { task_has_run = true; });
135 SendTask(t2.get(), [] {
136 rtc::Event yield_event;
137 // Wait() triggers YieldExecution() which will runs message processing on
138 // all threads that are not in the yielded set.
139
140 yield_event.Wait(TimeDelta::Zero());
141 });
142 // Since we are doing an invoke from the main thread, we don't expect the main
143 // thread message loop to be processed.
144 EXPECT_FALSE(task_has_run);
145 sim.AdvanceTime(TimeDelta::Seconds(1));
146 ASSERT_TRUE(task_has_run);
147 }
148
149 } // namespace webrtc
150