xref: /aosp_15_r20/external/webrtc/test/time_controller/time_controller_conformance_test.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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