• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <base/bind.h>
18 #include <base/bind_helpers.h>
19 #include <base/logging.h>
20 #include <gtest/gtest.h>
21 #include <future>
22 
23 #include "message_loop_thread.h"
24 #include "repeating_timer.h"
25 
26 using bluetooth::common::MessageLoopThread;
27 using bluetooth::common::RepeatingTimer;
28 
29 // Allowed error between the expected and actual delay for DoInThreadDelayed().
30 constexpr uint32_t delay_error_ms = 100;
31 
32 /**
33  * Unit tests to verify Task Scheduler.
34  */
35 class RepeatingTimerTest : public ::testing::Test {
36  public:
ShouldNotHappen()37   void ShouldNotHappen() { FAIL() << "Should not happen"; }
38 
IncreaseTaskCounter(int scheduled_tasks,std::promise<void> * promise)39   void IncreaseTaskCounter(int scheduled_tasks, std::promise<void>* promise) {
40     counter_++;
41     if (counter_ == scheduled_tasks) {
42       promise->set_value();
43     }
44   }
45 
GetName(std::string * name,std::promise<void> * promise)46   void GetName(std::string* name, std::promise<void>* promise) {
47     char my_name[256];
48     pthread_getname_np(pthread_self(), my_name, sizeof(my_name));
49     name->append(my_name);
50     promise->set_value();
51   }
52 
SleepAndIncreaseCounter(std::promise<void> * promise,int sleep_ms)53   void SleepAndIncreaseCounter(std::promise<void>* promise, int sleep_ms) {
54     promise->set_value();
55     std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms));
56     counter_++;
57   }
58 
VerifyDelayTimeAndSleep(std::chrono::steady_clock::time_point start_time,int interval_ms,int scheduled_tasks,int task_length_ms,std::promise<void> * promise)59   void VerifyDelayTimeAndSleep(std::chrono::steady_clock::time_point start_time,
60                                int interval_ms, int scheduled_tasks,
61                                int task_length_ms,
62                                std::promise<void>* promise) {
63     auto end_time = std::chrono::steady_clock::now();
64     auto actual_delay = std::chrono::duration_cast<std::chrono::milliseconds>(
65         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,
87                             interval_between_tasks_ms, scheduled_tasks,
88                             task_length_ms, promise_),
89         base::TimeDelta::FromMilliseconds(interval_between_tasks_ms));
90     future.get();
91     timer_->CancelAndWait();
92   }
93 
CancelRepeatingTimerAndWait()94   void CancelRepeatingTimerAndWait() { timer_->CancelAndWait(); }
95 
96  protected:
SetUp()97   void SetUp() override {
98     ::testing::Test::SetUp();
99     counter_ = 0;
100     timer_ = new RepeatingTimer();
101     promise_ = new std::promise<void>();
102   }
103 
TearDown()104   void TearDown() override {
105     if (promise_ != nullptr) {
106       delete promise_;
107       promise_ = nullptr;
108     }
109     if (timer_ != nullptr) {
110       delete timer_;
111       timer_ = nullptr;
112     }
113   }
114 
115   int counter_;
116   RepeatingTimer* timer_;
117   std::promise<void>* promise_;
118 };
119 
TEST_F(RepeatingTimerTest,initial_is_not_scheduled)120 TEST_F(RepeatingTimerTest, initial_is_not_scheduled) {
121   ASSERT_FALSE(timer_->IsScheduled());
122 }
123 
TEST_F(RepeatingTimerTest,cancel_without_scheduling)124 TEST_F(RepeatingTimerTest, cancel_without_scheduling) {
125   std::string name = "test_thread";
126   MessageLoopThread message_loop_thread(name);
127   message_loop_thread.StartUp();
128 
129   EXPECT_FALSE(timer_->IsScheduled());
130   timer_->CancelAndWait();
131   EXPECT_FALSE(timer_->IsScheduled());
132 }
133 
TEST_F(RepeatingTimerTest,periodic_run)134 TEST_F(RepeatingTimerTest, periodic_run) {
135   std::string name = "test_thread";
136   MessageLoopThread message_loop_thread(name);
137   message_loop_thread.StartUp();
138   auto future = promise_->get_future();
139   uint32_t delay_ms = 5;
140   int num_tasks = 200;
141 
142   timer_->SchedulePeriodic(
143       message_loop_thread.GetWeakPtr(), FROM_HERE,
144       base::BindRepeating(&RepeatingTimerTest::IncreaseTaskCounter,
145                           base::Unretained(this), num_tasks, promise_),
146       base::TimeDelta::FromMilliseconds(delay_ms));
147   future.get();
148   ASSERT_GE(counter_, num_tasks);
149   timer_->CancelAndWait();
150 }
151 
TEST_F(RepeatingTimerTest,schedule_periodic_task_zero_interval)152 TEST_F(RepeatingTimerTest, schedule_periodic_task_zero_interval) {
153   std::string name = "test_thread";
154   MessageLoopThread message_loop_thread(name);
155   message_loop_thread.StartUp();
156   uint32_t interval_ms = 0;
157 
158   ASSERT_FALSE(timer_->SchedulePeriodic(
159       message_loop_thread.GetWeakPtr(), FROM_HERE,
160       base::BindRepeating(&RepeatingTimerTest::ShouldNotHappen,
161                           base::Unretained(this)),
162       base::TimeDelta::FromMilliseconds(interval_ms)));
163   std::this_thread::sleep_for(std::chrono::milliseconds(delay_error_ms));
164 }
165 
166 // Verify that deleting the timer without cancelling it will cancel the task
TEST_F(RepeatingTimerTest,periodic_delete_without_cancel)167 TEST_F(RepeatingTimerTest, periodic_delete_without_cancel) {
168   std::string name = "test_thread";
169   MessageLoopThread message_loop_thread(name);
170   message_loop_thread.StartUp();
171   uint32_t delay_ms = 5;
172   timer_->SchedulePeriodic(
173       message_loop_thread.GetWeakPtr(), FROM_HERE,
174       base::BindRepeating(&RepeatingTimerTest::ShouldNotHappen,
175                           base::Unretained(this)),
176       base::TimeDelta::FromMilliseconds(delay_ms));
177   delete timer_;
178   timer_ = nullptr;
179   std::this_thread::sleep_for(std::chrono::milliseconds(delay_error_ms));
180 }
181 
TEST_F(RepeatingTimerTest,cancel_single_task_near_fire_no_race_condition)182 TEST_F(RepeatingTimerTest, cancel_single_task_near_fire_no_race_condition) {
183   std::string name = "test_thread";
184   MessageLoopThread message_loop_thread(name);
185   message_loop_thread.StartUp();
186   uint32_t delay_ms = 5;
187   timer_->SchedulePeriodic(message_loop_thread.GetWeakPtr(), FROM_HERE,
188                            base::DoNothing(),
189                            base::TimeDelta::FromMilliseconds(delay_ms));
190   std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
191   timer_->CancelAndWait();
192 }
193 
TEST_F(RepeatingTimerTest,cancel_periodic_task)194 TEST_F(RepeatingTimerTest, cancel_periodic_task) {
195   std::string name = "test_thread";
196   MessageLoopThread message_loop_thread(name);
197   message_loop_thread.StartUp();
198   uint32_t delay_ms = 5;
199   int num_tasks = 5;
200   auto future = promise_->get_future();
201 
202   timer_->SchedulePeriodic(
203       message_loop_thread.GetWeakPtr(), FROM_HERE,
204       base::BindRepeating(&RepeatingTimerTest::IncreaseTaskCounter,
205                           base::Unretained(this), num_tasks, promise_),
206       base::TimeDelta::FromMilliseconds(delay_ms));
207   future.wait();
208   timer_->CancelAndWait();
209   std::this_thread::sleep_for(
210       std::chrono::milliseconds(delay_ms + delay_error_ms));
211   int counter = counter_;
212   std::this_thread::sleep_for(
213       std::chrono::milliseconds(delay_ms + delay_error_ms));
214   ASSERT_EQ(counter, counter_);
215 }
216 
217 // Schedule 10 short periodic tasks with interval 1 ms between each; verify the
218 // functionality
TEST_F(RepeatingTimerTest,schedule_multiple_delayed_tasks)219 TEST_F(RepeatingTimerTest, schedule_multiple_delayed_tasks) {
220   VerifyMultipleDelayedTasks(10, 0, 1);
221 }
222 
223 // Schedule 10 periodic tasks with interval 2 ms between each and each takes 1
224 // ms; verify the functionality
TEST_F(RepeatingTimerTest,schedule_multiple_delayed_slow_tasks)225 TEST_F(RepeatingTimerTest, schedule_multiple_delayed_slow_tasks) {
226   VerifyMultipleDelayedTasks(10, 1, 2);
227 }
228 
TEST_F(RepeatingTimerTest,message_loop_thread_down_cancel_scheduled_periodic_task)229 TEST_F(RepeatingTimerTest,
230        message_loop_thread_down_cancel_scheduled_periodic_task) {
231   std::string name = "test_thread";
232   MessageLoopThread message_loop_thread(name);
233   message_loop_thread.StartUp();
234   std::string my_name;
235   auto future = promise_->get_future();
236   uint32_t delay_ms = 5;
237   int num_tasks = 5;
238 
239   timer_->SchedulePeriodic(
240       message_loop_thread.GetWeakPtr(), FROM_HERE,
241       base::BindRepeating(&RepeatingTimerTest::IncreaseTaskCounter,
242                           base::Unretained(this), num_tasks, promise_),
243       base::TimeDelta::FromMilliseconds(delay_ms));
244   future.wait();
245   message_loop_thread.ShutDown();
246   std::this_thread::sleep_for(
247       std::chrono::milliseconds(delay_ms + delay_error_ms));
248   int counter = counter_;
249   std::this_thread::sleep_for(
250       std::chrono::milliseconds(delay_ms + delay_error_ms));
251   ASSERT_EQ(counter, counter_);
252 }
253