1 /*
2 * Copyright 2020 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 <memory>
12 #include <vector>
13
14 #include "api/test/time_controller.h"
15 #include "api/units/time_delta.h"
16 #include "rtc_base/event.h"
17 #include "rtc_base/synchronization/mutex.h"
18 #include "rtc_base/thread.h"
19 #include "rtc_base/thread_annotations.h"
20 #include "test/gmock.h"
21 #include "test/gtest.h"
22 #include "test/time_controller/real_time_controller.h"
23 #include "test/time_controller/simulated_time_controller.h"
24
25 namespace webrtc {
26 namespace {
27
28 using ::testing::ElementsAreArray;
29 using ::testing::TestParamInfo;
30 using ::testing::TestWithParam;
31 using ::testing::Values;
32
33 enum class TimeMode { kRealTime, kSimulated };
34
CreateTimeController(TimeMode mode)35 std::unique_ptr<TimeController> CreateTimeController(TimeMode mode) {
36 switch (mode) {
37 case TimeMode::kRealTime:
38 return std::make_unique<RealTimeController>();
39 case TimeMode::kSimulated:
40 // Using an offset of 100000 to get nice fixed width and readable
41 // timestamps in typical test scenarios.
42 constexpr Timestamp kSimulatedStartTime = Timestamp::Seconds(100000);
43 return std::make_unique<GlobalSimulatedTimeController>(
44 kSimulatedStartTime);
45 }
46 }
47
ParamsToString(const TestParamInfo<webrtc::TimeMode> & param)48 std::string ParamsToString(const TestParamInfo<webrtc::TimeMode>& param) {
49 switch (param.param) {
50 case webrtc::TimeMode::kRealTime:
51 return "RealTime";
52 case webrtc::TimeMode::kSimulated:
53 return "SimulatedTime";
54 default:
55 RTC_DCHECK_NOTREACHED() << "Time mode not supported";
56 }
57 }
58
59 // Keeps order of executions. May be called from different threads.
60 class ExecutionOrderKeeper {
61 public:
Executed(int execution_id)62 void Executed(int execution_id) {
63 MutexLock lock(&mutex_);
64 order_.push_back(execution_id);
65 }
66
order() const67 std::vector<int> order() const {
68 MutexLock lock(&mutex_);
69 return order_;
70 }
71
72 private:
73 mutable Mutex mutex_;
74 std::vector<int> order_ RTC_GUARDED_BY(mutex_);
75 };
76
77 // Tests conformance between real time and simulated time time controller.
78 class SimulatedRealTimeControllerConformanceTest
79 : public TestWithParam<webrtc::TimeMode> {};
80
TEST_P(SimulatedRealTimeControllerConformanceTest,ThreadPostOrderTest)81 TEST_P(SimulatedRealTimeControllerConformanceTest, ThreadPostOrderTest) {
82 std::unique_ptr<TimeController> time_controller =
83 CreateTimeController(GetParam());
84 std::unique_ptr<rtc::Thread> thread = time_controller->CreateThread("thread");
85
86 // Tasks on thread have to be executed in order in which they were
87 // posted.
88 ExecutionOrderKeeper execution_order;
89 thread->PostTask([&]() { execution_order.Executed(1); });
90 thread->PostTask([&]() { execution_order.Executed(2); });
91 time_controller->AdvanceTime(TimeDelta::Millis(100));
92 EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2}));
93 // Destroy `thread` before `execution_order` to be sure `execution_order`
94 // is not accessed on the posted task after it is destroyed.
95 thread = nullptr;
96 }
97
TEST_P(SimulatedRealTimeControllerConformanceTest,ThreadPostDelayedOrderTest)98 TEST_P(SimulatedRealTimeControllerConformanceTest, ThreadPostDelayedOrderTest) {
99 std::unique_ptr<TimeController> time_controller =
100 CreateTimeController(GetParam());
101 std::unique_ptr<rtc::Thread> thread = time_controller->CreateThread("thread");
102
103 ExecutionOrderKeeper execution_order;
104 thread->PostDelayedTask([&]() { execution_order.Executed(2); },
105 TimeDelta::Millis(500));
106 thread->PostTask([&]() { execution_order.Executed(1); });
107 time_controller->AdvanceTime(TimeDelta::Millis(600));
108 EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2}));
109 // Destroy `thread` before `execution_order` to be sure `execution_order`
110 // is not accessed on the posted task after it is destroyed.
111 thread = nullptr;
112 }
113
TEST_P(SimulatedRealTimeControllerConformanceTest,ThreadPostInvokeOrderTest)114 TEST_P(SimulatedRealTimeControllerConformanceTest, ThreadPostInvokeOrderTest) {
115 std::unique_ptr<TimeController> time_controller =
116 CreateTimeController(GetParam());
117 std::unique_ptr<rtc::Thread> thread = time_controller->CreateThread("thread");
118
119 // Tasks on thread have to be executed in order in which they were
120 // posted/invoked.
121 ExecutionOrderKeeper execution_order;
122 thread->PostTask([&]() { execution_order.Executed(1); });
123 thread->BlockingCall([&]() { execution_order.Executed(2); });
124 time_controller->AdvanceTime(TimeDelta::Millis(100));
125 EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2}));
126 // Destroy `thread` before `execution_order` to be sure `execution_order`
127 // is not accessed on the posted task after it is destroyed.
128 thread = nullptr;
129 }
130
TEST_P(SimulatedRealTimeControllerConformanceTest,ThreadPostInvokeFromThreadOrderTest)131 TEST_P(SimulatedRealTimeControllerConformanceTest,
132 ThreadPostInvokeFromThreadOrderTest) {
133 std::unique_ptr<TimeController> time_controller =
134 CreateTimeController(GetParam());
135 std::unique_ptr<rtc::Thread> thread = time_controller->CreateThread("thread");
136
137 // If task is invoked from thread X on thread X it has to be executed
138 // immediately.
139 ExecutionOrderKeeper execution_order;
140 thread->PostTask([&]() {
141 thread->PostTask([&]() { execution_order.Executed(2); });
142 thread->BlockingCall([&]() { execution_order.Executed(1); });
143 });
144 time_controller->AdvanceTime(TimeDelta::Millis(100));
145 EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2}));
146 // Destroy `thread` before `execution_order` to be sure `execution_order`
147 // is not accessed on the posted task after it is destroyed.
148 thread = nullptr;
149 }
150
TEST_P(SimulatedRealTimeControllerConformanceTest,TaskQueuePostEventWaitOrderTest)151 TEST_P(SimulatedRealTimeControllerConformanceTest,
152 TaskQueuePostEventWaitOrderTest) {
153 std::unique_ptr<TimeController> time_controller =
154 CreateTimeController(GetParam());
155 auto task_queue = time_controller->GetTaskQueueFactory()->CreateTaskQueue(
156 "task_queue", webrtc::TaskQueueFactory::Priority::NORMAL);
157
158 // Tasks on thread have to be executed in order in which they were
159 // posted/invoked.
160 ExecutionOrderKeeper execution_order;
161 rtc::Event event;
162 task_queue->PostTask([&]() { execution_order.Executed(1); });
163 task_queue->PostTask([&]() {
164 execution_order.Executed(2);
165 event.Set();
166 });
167 EXPECT_TRUE(event.Wait(/*give_up_after=*/TimeDelta::Millis(100)));
168 time_controller->AdvanceTime(TimeDelta::Millis(100));
169 EXPECT_THAT(execution_order.order(), ElementsAreArray({1, 2}));
170 // Destroy `task_queue` before `execution_order` to be sure `execution_order`
171 // is not accessed on the posted task after it is destroyed.
172 task_queue = nullptr;
173 }
174
175 INSTANTIATE_TEST_SUITE_P(ConformanceTest,
176 SimulatedRealTimeControllerConformanceTest,
177 Values(TimeMode::kRealTime, TimeMode::kSimulated),
178 ParamsToString);
179
180 } // namespace
181 } // namespace webrtc
182