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