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