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/external_time_controller.h"
12 
13 #include <atomic>
14 #include <memory>
15 #include <utility>
16 
17 #include "rtc_base/event.h"
18 #include "rtc_base/task_queue.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 
34 class FakeAlarm : public ControlledAlarmClock {
35  public:
36   explicit FakeAlarm(Timestamp start_time);
37 
38   Clock* GetClock() override;
39   bool ScheduleAlarmAt(Timestamp deadline) override;
40   void SetCallback(std::function<void()> callback) override;
41   void Sleep(TimeDelta duration) override;
42 
43  private:
44   SimulatedClock clock_;
45   Timestamp deadline_;
46   std::function<void()> callback_;
47 };
48 
FakeAlarm(Timestamp start_time)49 FakeAlarm::FakeAlarm(Timestamp start_time)
50     : clock_(start_time),
51       deadline_(Timestamp::PlusInfinity()),
52       callback_([] {}) {}
53 
GetClock()54 Clock* FakeAlarm::GetClock() {
55   return &clock_;
56 }
57 
ScheduleAlarmAt(Timestamp deadline)58 bool FakeAlarm::ScheduleAlarmAt(Timestamp deadline) {
59   if (deadline < deadline_) {
60     deadline_ = deadline;
61     return true;
62   }
63   return false;
64 }
65 
SetCallback(std::function<void ()> callback)66 void FakeAlarm::SetCallback(std::function<void()> callback) {
67   callback_ = callback;
68 }
69 
Sleep(TimeDelta duration)70 void FakeAlarm::Sleep(TimeDelta duration) {
71   Timestamp end_time = clock_.CurrentTime() + duration;
72 
73   while (deadline_ <= end_time) {
74     clock_.AdvanceTime(deadline_ - clock_.CurrentTime());
75     deadline_ = Timestamp::PlusInfinity();
76     callback_();
77   }
78 
79   clock_.AdvanceTime(end_time - clock_.CurrentTime());
80 }
81 
82 }  // namespace
83 
TEST(ExternalTimeControllerTest,TaskIsStoppedOnStop)84 TEST(ExternalTimeControllerTest, TaskIsStoppedOnStop) {
85   const TimeDelta kShortInterval = TimeDelta::Millis(5);
86   const TimeDelta kLongInterval = TimeDelta::Millis(20);
87   const int kShortIntervalCount = 4;
88   const int kMargin = 1;
89   FakeAlarm alarm(kStartTime);
90   ExternalTimeController time_simulation(&alarm);
91   rtc::TaskQueue task_queue(
92       time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
93           "TestQueue", TaskQueueFactory::Priority::NORMAL));
94   std::atomic_int counter(0);
95   auto handle = RepeatingTaskHandle::Start(task_queue.Get(), [&] {
96     if (++counter >= kShortIntervalCount)
97       return kLongInterval;
98     return kShortInterval;
99   });
100   // Sleep long enough to go through the initial phase.
101   time_simulation.AdvanceTime(kShortInterval * (kShortIntervalCount + kMargin));
102   EXPECT_EQ(counter.load(), kShortIntervalCount);
103 
104   task_queue.PostTask(
105       [handle = std::move(handle)]() mutable { handle.Stop(); });
106 
107   // Sleep long enough that the task would run at least once more if not
108   // stopped.
109   time_simulation.AdvanceTime(kLongInterval * 2);
110   EXPECT_EQ(counter.load(), kShortIntervalCount);
111 }
112 
TEST(ExternalTimeControllerTest,TaskCanStopItself)113 TEST(ExternalTimeControllerTest, TaskCanStopItself) {
114   std::atomic_int counter(0);
115   FakeAlarm alarm(kStartTime);
116   ExternalTimeController time_simulation(&alarm);
117   rtc::TaskQueue task_queue(
118       time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
119           "TestQueue", TaskQueueFactory::Priority::NORMAL));
120 
121   RepeatingTaskHandle handle;
122   task_queue.PostTask([&] {
123     handle = RepeatingTaskHandle::Start(task_queue.Get(), [&] {
124       ++counter;
125       handle.Stop();
126       return TimeDelta::Millis(2);
127     });
128   });
129   time_simulation.AdvanceTime(TimeDelta::Millis(10));
130   EXPECT_EQ(counter.load(), 1);
131 }
132 
TEST(ExternalTimeControllerTest,YieldForTask)133 TEST(ExternalTimeControllerTest, YieldForTask) {
134   FakeAlarm alarm(kStartTime);
135   ExternalTimeController time_simulation(&alarm);
136 
137   rtc::TaskQueue task_queue(
138       time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
139           "TestQueue", TaskQueueFactory::Priority::NORMAL));
140 
141   rtc::Event event;
142   task_queue.PostTask([&] { event.Set(); });
143   EXPECT_TRUE(event.Wait(200));
144 }
145 
TEST(ExternalTimeControllerTest,TasksYieldToEachOther)146 TEST(ExternalTimeControllerTest, TasksYieldToEachOther) {
147   FakeAlarm alarm(kStartTime);
148   ExternalTimeController time_simulation(&alarm);
149 
150   rtc::TaskQueue task_queue(
151       time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
152           "TestQueue", TaskQueueFactory::Priority::NORMAL));
153   rtc::TaskQueue other_queue(
154       time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
155           "OtherQueue", TaskQueueFactory::Priority::NORMAL));
156 
157   task_queue.PostTask([&] {
158     rtc::Event event;
159     other_queue.PostTask([&] { event.Set(); });
160     EXPECT_TRUE(event.Wait(200));
161   });
162 
163   time_simulation.AdvanceTime(TimeDelta::Millis(300));
164 }
165 
TEST(ExternalTimeControllerTest,CurrentTaskQueue)166 TEST(ExternalTimeControllerTest, CurrentTaskQueue) {
167   FakeAlarm alarm(kStartTime);
168   ExternalTimeController time_simulation(&alarm);
169 
170   rtc::TaskQueue task_queue(
171       time_simulation.GetTaskQueueFactory()->CreateTaskQueue(
172           "TestQueue", TaskQueueFactory::Priority::NORMAL));
173 
174   task_queue.PostTask([&] { EXPECT_TRUE(task_queue.IsCurrent()); });
175 
176   time_simulation.AdvanceTime(TimeDelta::Millis(10));
177 }
178 
179 }  // namespace webrtc
180