1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "repeating_timer.h"
18 
19 #include <base/functional/bind.h>
20 #include <gtest/gtest.h>
21 
22 #include <future>
23 
24 #include "bind_helpers.h"
25 #include "message_loop_thread.h"
26 
27 using bluetooth::common::MessageLoopThread;
28 using bluetooth::common::RepeatingTimer;
29 
30 // Allowed error between the expected and actual delay for DoInThreadDelayed().
31 constexpr uint32_t delay_error_ms = 100;
32 
33 /**
34  * Unit tests to verify Task Scheduler.
35  */
36 class RepeatingTimerTest : public ::testing::Test {
37  public:
ShouldNotHappen()38   void ShouldNotHappen() { FAIL() << "Should not happen"; }
39 
IncreaseTaskCounter(int scheduled_tasks,std::promise<void> * promise)40   void IncreaseTaskCounter(int scheduled_tasks, std::promise<void>* promise) {
41     counter_++;
42     if (counter_ == scheduled_tasks) {
43       promise->set_value();
44     }
45   }
46 
GetName(std::string * name,std::promise<void> * promise)47   void GetName(std::string* name, std::promise<void>* promise) {
48     char my_name[256];
49     pthread_getname_np(pthread_self(), my_name, sizeof(my_name));
50     name->append(my_name);
51     promise->set_value();
52   }
53 
SleepAndIncreaseCounter(std::promise<void> * promise,int sleep_ms)54   void SleepAndIncreaseCounter(std::promise<void>* promise, int sleep_ms) {
55     promise->set_value();
56     std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms));
57     counter_++;
58   }
59 
VerifyDelayTimeAndSleep(std::chrono::steady_clock::time_point start_time,int interval_ms,int scheduled_tasks,int task_length_ms,std::promise<void> * promise)60   void VerifyDelayTimeAndSleep(std::chrono::steady_clock::time_point start_time,
61                                int interval_ms, int scheduled_tasks,
62                                int task_length_ms,
63                                std::promise<void>* promise) {
64     auto end_time = std::chrono::steady_clock::now();
65     auto actual_delay = std::chrono::duration_cast<std::chrono::milliseconds>(
66         end_time - start_time);
67     counter_++;
68     int64_t scheduled_delay_ms = interval_ms * counter_;
69     if (counter_ == scheduled_tasks) {
70       promise->set_value();
71     }
72     ASSERT_NEAR(scheduled_delay_ms, actual_delay.count(), delay_error_ms);
73     std::this_thread::sleep_for(std::chrono::milliseconds(task_length_ms));
74   }
75 
VerifyMultipleDelayedTasks(int scheduled_tasks,int task_length_ms,int interval_between_tasks_ms)76   void VerifyMultipleDelayedTasks(int scheduled_tasks, int task_length_ms,
77                                   int interval_between_tasks_ms) {
78     std::string name = "test_thread";
79     MessageLoopThread message_loop_thread(name);
80     message_loop_thread.StartUp();
81     message_loop_thread.EnableRealTimeScheduling();
82     auto future = promise_->get_future();
83     auto start_time = std::chrono::steady_clock::now();
84     timer_->SchedulePeriodic(
85         message_loop_thread.GetWeakPtr(), FROM_HERE,
86         base::BindRepeating(&RepeatingTimerTest::VerifyDelayTimeAndSleep,
87                             base::Unretained(this), start_time,
88                             interval_between_tasks_ms, scheduled_tasks,
89                             task_length_ms, promise_),
90         std::chrono::milliseconds(interval_between_tasks_ms));
91     future.get();
92     timer_->CancelAndWait();
93   }
94 
CancelRepeatingTimerAndWait()95   void CancelRepeatingTimerAndWait() { timer_->CancelAndWait(); }
96 
97  protected:
SetUp()98   void SetUp() override {
99     ::testing::Test::SetUp();
100     counter_ = 0;
101     timer_ = new RepeatingTimer();
102     promise_ = new std::promise<void>();
103   }
104 
TearDown()105   void TearDown() override {
106     if (promise_ != nullptr) {
107       delete promise_;
108       promise_ = nullptr;
109     }
110     if (timer_ != nullptr) {
111       delete timer_;
112       timer_ = nullptr;
113     }
114   }
115 
116   int counter_;
117   RepeatingTimer* timer_;
118   std::promise<void>* promise_;
119 };
120 
TEST_F(RepeatingTimerTest,initial_is_not_scheduled)121 TEST_F(RepeatingTimerTest, initial_is_not_scheduled) {
122   ASSERT_FALSE(timer_->IsScheduled());
123 }
124 
TEST_F(RepeatingTimerTest,cancel_without_scheduling)125 TEST_F(RepeatingTimerTest, cancel_without_scheduling) {
126   std::string name = "test_thread";
127   MessageLoopThread message_loop_thread(name);
128   message_loop_thread.StartUp();
129 
130   EXPECT_FALSE(timer_->IsScheduled());
131   timer_->CancelAndWait();
132   EXPECT_FALSE(timer_->IsScheduled());
133 }
134 
TEST_F(RepeatingTimerTest,periodic_run)135 TEST_F(RepeatingTimerTest, periodic_run) {
136   std::string name = "test_thread";
137   MessageLoopThread message_loop_thread(name);
138   message_loop_thread.StartUp();
139   auto future = promise_->get_future();
140   uint32_t delay_ms = 5;
141   int num_tasks = 200;
142 
143   timer_->SchedulePeriodic(
144       message_loop_thread.GetWeakPtr(), FROM_HERE,
145       base::BindRepeating(&RepeatingTimerTest::IncreaseTaskCounter,
146                           base::Unretained(this), num_tasks, promise_),
147       std::chrono::milliseconds(delay_ms));
148   future.get();
149   ASSERT_GE(counter_, num_tasks);
150   timer_->CancelAndWait();
151 }
152 
TEST_F(RepeatingTimerTest,schedule_periodic_task_zero_interval)153 TEST_F(RepeatingTimerTest, schedule_periodic_task_zero_interval) {
154   std::string name = "test_thread";
155   MessageLoopThread message_loop_thread(name);
156   message_loop_thread.StartUp();
157   uint32_t interval_ms = 0;
158 
159   ASSERT_FALSE(timer_->SchedulePeriodic(
160       message_loop_thread.GetWeakPtr(), FROM_HERE,
161       base::BindRepeating(&RepeatingTimerTest::ShouldNotHappen,
162                           base::Unretained(this)),
163       std::chrono::milliseconds(interval_ms)));
164   std::this_thread::sleep_for(std::chrono::milliseconds(delay_error_ms));
165 }
166 
167 // Verify that deleting the timer without cancelling it will cancel the task
TEST_F(RepeatingTimerTest,periodic_delete_without_cancel)168 TEST_F(RepeatingTimerTest, periodic_delete_without_cancel) {
169   std::string name = "test_thread";
170   MessageLoopThread message_loop_thread(name);
171   message_loop_thread.StartUp();
172   uint32_t delay_ms = 5;
173   timer_->SchedulePeriodic(
174       message_loop_thread.GetWeakPtr(), FROM_HERE,
175       base::BindRepeating(&RepeatingTimerTest::ShouldNotHappen,
176                           base::Unretained(this)),
177       std::chrono::milliseconds(delay_ms));
178   delete timer_;
179   timer_ = nullptr;
180   std::this_thread::sleep_for(std::chrono::milliseconds(delay_error_ms));
181 }
182 
TEST_F(RepeatingTimerTest,cancel_single_task_near_fire_no_race_condition)183 TEST_F(RepeatingTimerTest, cancel_single_task_near_fire_no_race_condition) {
184   std::string name = "test_thread";
185   MessageLoopThread message_loop_thread(name);
186   message_loop_thread.StartUp();
187   uint32_t delay_ms = 5;
188   timer_->SchedulePeriodic(message_loop_thread.GetWeakPtr(), FROM_HERE,
189                            base::DoNothing(),
190                            std::chrono::milliseconds(delay_ms));
191   std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
192   timer_->CancelAndWait();
193 }
194 
TEST_F(RepeatingTimerTest,cancel_periodic_task)195 TEST_F(RepeatingTimerTest, cancel_periodic_task) {
196   std::string name = "test_thread";
197   MessageLoopThread message_loop_thread(name);
198   message_loop_thread.StartUp();
199   uint32_t delay_ms = 5;
200   int num_tasks = 5;
201   auto future = promise_->get_future();
202 
203   timer_->SchedulePeriodic(
204       message_loop_thread.GetWeakPtr(), FROM_HERE,
205       base::BindRepeating(&RepeatingTimerTest::IncreaseTaskCounter,
206                           base::Unretained(this), num_tasks, promise_),
207       std::chrono::milliseconds(delay_ms));
208   future.wait();
209   timer_->CancelAndWait();
210   std::this_thread::sleep_for(
211       std::chrono::milliseconds(delay_ms + delay_error_ms));
212   int counter = counter_;
213   std::this_thread::sleep_for(
214       std::chrono::milliseconds(delay_ms + delay_error_ms));
215   ASSERT_EQ(counter, counter_);
216 }
217 
218 // Schedule 10 short periodic tasks with interval 1 ms between each; verify the
219 // functionality
TEST_F(RepeatingTimerTest,schedule_multiple_delayed_tasks)220 TEST_F(RepeatingTimerTest, schedule_multiple_delayed_tasks) {
221   VerifyMultipleDelayedTasks(10, 0, 1);
222 }
223 
224 // Schedule 10 periodic tasks with interval 2 ms between each and each takes 1
225 // ms; verify the functionality
TEST_F(RepeatingTimerTest,schedule_multiple_delayed_slow_tasks)226 TEST_F(RepeatingTimerTest, schedule_multiple_delayed_slow_tasks) {
227   VerifyMultipleDelayedTasks(10, 1, 2);
228 }
229 
TEST_F(RepeatingTimerTest,message_loop_thread_down_cancel_scheduled_periodic_task)230 TEST_F(RepeatingTimerTest,
231        message_loop_thread_down_cancel_scheduled_periodic_task) {
232   std::string name = "test_thread";
233   MessageLoopThread message_loop_thread(name);
234   message_loop_thread.StartUp();
235   std::string my_name;
236   auto future = promise_->get_future();
237   uint32_t delay_ms = 5;
238   int num_tasks = 5;
239 
240   timer_->SchedulePeriodic(
241       message_loop_thread.GetWeakPtr(), FROM_HERE,
242       base::BindRepeating(&RepeatingTimerTest::IncreaseTaskCounter,
243                           base::Unretained(this), num_tasks, promise_),
244       std::chrono::milliseconds(delay_ms));
245   future.wait();
246   message_loop_thread.ShutDown();
247   std::this_thread::sleep_for(
248       std::chrono::milliseconds(delay_ms + delay_error_ms));
249   int counter = counter_;
250   std::this_thread::sleep_for(
251       std::chrono::milliseconds(delay_ms + delay_error_ms));
252   ASSERT_EQ(counter, counter_);
253 }
254