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, int interval_ms,
61                                int scheduled_tasks, int task_length_ms,
62                                std::promise<void>* promise) {
63     auto end_time = std::chrono::steady_clock::now();
64     auto actual_delay =
65             std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
66     counter_++;
67     int64_t scheduled_delay_ms = interval_ms * counter_;
68     if (counter_ == scheduled_tasks) {
69       promise->set_value();
70     }
71     ASSERT_NEAR(scheduled_delay_ms, actual_delay.count(), delay_error_ms);
72     std::this_thread::sleep_for(std::chrono::milliseconds(task_length_ms));
73   }
74 
VerifyMultipleDelayedTasks(int scheduled_tasks,int task_length_ms,int interval_between_tasks_ms)75   void VerifyMultipleDelayedTasks(int scheduled_tasks, int task_length_ms,
76                                   int interval_between_tasks_ms) {
77     std::string name = "test_thread";
78     MessageLoopThread message_loop_thread(name);
79     message_loop_thread.StartUp();
80     message_loop_thread.EnableRealTimeScheduling();
81     auto future = promise_->get_future();
82     auto start_time = std::chrono::steady_clock::now();
83     timer_->SchedulePeriodic(
84             message_loop_thread.GetWeakPtr(), FROM_HERE,
85             base::BindRepeating(&RepeatingTimerTest::VerifyDelayTimeAndSleep,
86                                 base::Unretained(this), start_time, interval_between_tasks_ms,
87                                 scheduled_tasks, task_length_ms, promise_),
88             std::chrono::milliseconds(interval_between_tasks_ms));
89     future.get();
90     timer_->CancelAndWait();
91   }
92 
CancelRepeatingTimerAndWait()93   void CancelRepeatingTimerAndWait() { timer_->CancelAndWait(); }
94 
95 protected:
SetUp()96   void SetUp() override {
97     ::testing::Test::SetUp();
98     counter_ = 0;
99     timer_ = new RepeatingTimer();
100     promise_ = new std::promise<void>();
101   }
102 
TearDown()103   void TearDown() override {
104     if (promise_ != nullptr) {
105       delete promise_;
106       promise_ = nullptr;
107     }
108     if (timer_ != nullptr) {
109       delete timer_;
110       timer_ = nullptr;
111     }
112   }
113 
114   int counter_;
115   RepeatingTimer* timer_;
116   std::promise<void>* promise_;
117 };
118 
TEST_F(RepeatingTimerTest,initial_is_not_scheduled)119 TEST_F(RepeatingTimerTest, initial_is_not_scheduled) { ASSERT_FALSE(timer_->IsScheduled()); }
120 
TEST_F(RepeatingTimerTest,cancel_without_scheduling)121 TEST_F(RepeatingTimerTest, cancel_without_scheduling) {
122   std::string name = "test_thread";
123   MessageLoopThread message_loop_thread(name);
124   message_loop_thread.StartUp();
125 
126   EXPECT_FALSE(timer_->IsScheduled());
127   timer_->CancelAndWait();
128   EXPECT_FALSE(timer_->IsScheduled());
129 }
130 
TEST_F(RepeatingTimerTest,periodic_run)131 TEST_F(RepeatingTimerTest, periodic_run) {
132   std::string name = "test_thread";
133   MessageLoopThread message_loop_thread(name);
134   message_loop_thread.StartUp();
135   auto future = promise_->get_future();
136   uint32_t delay_ms = 5;
137   int num_tasks = 200;
138 
139   timer_->SchedulePeriodic(message_loop_thread.GetWeakPtr(), FROM_HERE,
140                            base::BindRepeating(&RepeatingTimerTest::IncreaseTaskCounter,
141                                                base::Unretained(this), num_tasks, promise_),
142                            std::chrono::milliseconds(delay_ms));
143   future.get();
144   ASSERT_GE(counter_, num_tasks);
145   timer_->CancelAndWait();
146 }
147 
TEST_F(RepeatingTimerTest,schedule_periodic_task_zero_interval)148 TEST_F(RepeatingTimerTest, schedule_periodic_task_zero_interval) {
149   std::string name = "test_thread";
150   MessageLoopThread message_loop_thread(name);
151   message_loop_thread.StartUp();
152   uint32_t interval_ms = 0;
153 
154   ASSERT_FALSE(timer_->SchedulePeriodic(
155           message_loop_thread.GetWeakPtr(), FROM_HERE,
156           base::BindRepeating(&RepeatingTimerTest::ShouldNotHappen, base::Unretained(this)),
157           std::chrono::milliseconds(interval_ms)));
158   std::this_thread::sleep_for(std::chrono::milliseconds(delay_error_ms));
159 }
160 
161 // Verify that deleting the timer without cancelling it will cancel the task
TEST_F(RepeatingTimerTest,periodic_delete_without_cancel)162 TEST_F(RepeatingTimerTest, periodic_delete_without_cancel) {
163   std::string name = "test_thread";
164   MessageLoopThread message_loop_thread(name);
165   message_loop_thread.StartUp();
166   uint32_t delay_ms = 5;
167   timer_->SchedulePeriodic(
168           message_loop_thread.GetWeakPtr(), FROM_HERE,
169           base::BindRepeating(&RepeatingTimerTest::ShouldNotHappen, base::Unretained(this)),
170           std::chrono::milliseconds(delay_ms));
171   delete timer_;
172   timer_ = nullptr;
173   std::this_thread::sleep_for(std::chrono::milliseconds(delay_error_ms));
174 }
175 
TEST_F(RepeatingTimerTest,cancel_single_task_near_fire_no_race_condition)176 TEST_F(RepeatingTimerTest, cancel_single_task_near_fire_no_race_condition) {
177   std::string name = "test_thread";
178   MessageLoopThread message_loop_thread(name);
179   message_loop_thread.StartUp();
180   uint32_t delay_ms = 5;
181   timer_->SchedulePeriodic(message_loop_thread.GetWeakPtr(), FROM_HERE, base::DoNothing(),
182                            std::chrono::milliseconds(delay_ms));
183   std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
184   timer_->CancelAndWait();
185 }
186 
TEST_F(RepeatingTimerTest,cancel_periodic_task)187 TEST_F(RepeatingTimerTest, cancel_periodic_task) {
188   std::string name = "test_thread";
189   MessageLoopThread message_loop_thread(name);
190   message_loop_thread.StartUp();
191   uint32_t delay_ms = 5;
192   int num_tasks = 5;
193   auto future = promise_->get_future();
194 
195   timer_->SchedulePeriodic(message_loop_thread.GetWeakPtr(), FROM_HERE,
196                            base::BindRepeating(&RepeatingTimerTest::IncreaseTaskCounter,
197                                                base::Unretained(this), num_tasks, promise_),
198                            std::chrono::milliseconds(delay_ms));
199   future.wait();
200   timer_->CancelAndWait();
201   std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms + delay_error_ms));
202   int counter = counter_;
203   std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms + delay_error_ms));
204   ASSERT_EQ(counter, counter_);
205 }
206 
207 // Schedule 10 short periodic tasks with interval 1 ms between each; verify the
208 // functionality
TEST_F(RepeatingTimerTest,schedule_multiple_delayed_tasks)209 TEST_F(RepeatingTimerTest, schedule_multiple_delayed_tasks) {
210   VerifyMultipleDelayedTasks(10, 0, 1);
211 }
212 
213 // Schedule 10 periodic tasks with interval 2 ms between each and each takes 1
214 // ms; verify the functionality
TEST_F(RepeatingTimerTest,schedule_multiple_delayed_slow_tasks)215 TEST_F(RepeatingTimerTest, schedule_multiple_delayed_slow_tasks) {
216   VerifyMultipleDelayedTasks(10, 1, 2);
217 }
218 
TEST_F(RepeatingTimerTest,message_loop_thread_down_cancel_scheduled_periodic_task)219 TEST_F(RepeatingTimerTest, message_loop_thread_down_cancel_scheduled_periodic_task) {
220   std::string name = "test_thread";
221   MessageLoopThread message_loop_thread(name);
222   message_loop_thread.StartUp();
223   std::string my_name;
224   auto future = promise_->get_future();
225   uint32_t delay_ms = 5;
226   int num_tasks = 5;
227 
228   timer_->SchedulePeriodic(message_loop_thread.GetWeakPtr(), FROM_HERE,
229                            base::BindRepeating(&RepeatingTimerTest::IncreaseTaskCounter,
230                                                base::Unretained(this), num_tasks, promise_),
231                            std::chrono::milliseconds(delay_ms));
232   future.wait();
233   message_loop_thread.ShutDown();
234   std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms + delay_error_ms));
235   int counter = counter_;
236   std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms + delay_error_ms));
237   ASSERT_EQ(counter, counter_);
238 }
239