blob: d0fa238803c08dc3fdd55478a69f93c341f34c1d [file] [log] [blame]
Jakub Pawlowski5cf03042018-12-03 16:50:40 +01001/*
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 "once_timer.h"
25
26using bluetooth::common::MessageLoopThread;
27using bluetooth::common::OnceTimer;
28
29// Allowed error between the expected and actual delay for DoInThreadDelayed().
30constexpr uint32_t delay_error_ms = 3;
31
32/**
33 * Unit tests to verify Task Scheduler.
34 */
35class OnceTimerTest : public ::testing::Test {
36 public:
37 void ShouldNotHappen() { FAIL() << "Should not happen"; }
38
39 void IncreaseTaskCounter(int scheduled_tasks, std::promise<void>* promise) {
40 counter_++;
41 if (counter_ == scheduled_tasks) {
42 promise->set_value();
43 }
44 }
45
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
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
59 void CancelTimerAndWait() { timer_->CancelAndWait(); }
60
61 protected:
62 void SetUp() override {
63 ::testing::Test::SetUp();
64 counter_ = 0;
65 timer_ = new OnceTimer();
66 promise_ = new std::promise<void>();
67 }
68
69 void TearDown() override {
70 if (promise_ != nullptr) {
71 delete promise_;
72 promise_ = nullptr;
73 }
74 if (timer_ != nullptr) {
75 delete timer_;
76 timer_ = nullptr;
77 }
78 }
79
80 int counter_;
81 OnceTimer* timer_;
82 std::promise<void>* promise_;
83};
84
85TEST_F(OnceTimerTest, initial_is_not_scheduled) {
86 ASSERT_FALSE(timer_->IsScheduled());
87}
88
89TEST_F(OnceTimerTest, schedule_task) {
90 std::string name = "test_thread";
91 MessageLoopThread message_loop_thread(name);
92 message_loop_thread.StartUp();
93 auto future = promise_->get_future();
94 std::string my_name;
95 uint32_t delay_ms = 5;
96
97 timer_->Schedule(message_loop_thread.GetWeakPtr(), FROM_HERE,
98 base::BindOnce(&OnceTimerTest::GetName,
99 base::Unretained(this), &my_name, promise_),
100 base::TimeDelta::FromMilliseconds(delay_ms));
101 EXPECT_TRUE(timer_->IsScheduled());
102 future.get();
103 ASSERT_EQ(name, my_name);
104 std::this_thread::sleep_for(std::chrono::milliseconds(delay_error_ms));
105 EXPECT_FALSE(timer_->IsScheduled());
106}
107
108TEST_F(OnceTimerTest, cancel_without_scheduling) {
109 std::string name = "test_thread";
110 MessageLoopThread message_loop_thread(name);
111 message_loop_thread.StartUp();
112
113 EXPECT_FALSE(timer_->IsScheduled());
114 timer_->CancelAndWait();
115 EXPECT_FALSE(timer_->IsScheduled());
116}
117
118TEST_F(OnceTimerTest, cancel_in_callback_no_deadlock) {
119 std::string name = "test_thread";
120 MessageLoopThread message_loop_thread(name);
121 message_loop_thread.StartUp();
122 uint32_t delay_ms = 5;
123
124 timer_->Schedule(message_loop_thread.GetWeakPtr(), FROM_HERE,
125 base::BindOnce(&OnceTimerTest::CancelTimerAndWait,
126 base::Unretained(this)),
127 base::TimeDelta::FromMilliseconds(delay_ms));
128}
129
130TEST_F(OnceTimerTest, cancel_single_task) {
131 std::string name = "test_thread";
132 MessageLoopThread message_loop_thread(name);
133 message_loop_thread.StartUp();
134 uint32_t delay_ms = 100000000;
135 timer_->Schedule(
136 message_loop_thread.GetWeakPtr(), FROM_HERE,
137 base::BindOnce(&OnceTimerTest::ShouldNotHappen, base::Unretained(this)),
138 base::TimeDelta::FromMilliseconds(delay_ms));
139 std::this_thread::sleep_for(std::chrono::milliseconds(delay_error_ms));
140 timer_->CancelAndWait();
141}
142
143TEST_F(OnceTimerTest, message_loop_thread_down_cancel_task) {
144 std::string name = "test_thread";
145 {
146 MessageLoopThread message_loop_thread(name);
147 message_loop_thread.StartUp();
148 uint32_t delay_ms = 100000000;
149 timer_->Schedule(
150 message_loop_thread.GetWeakPtr(), FROM_HERE,
151 base::BindOnce(&OnceTimerTest::ShouldNotHappen, base::Unretained(this)),
152 base::TimeDelta::FromMilliseconds(delay_ms));
153 std::this_thread::sleep_for(std::chrono::milliseconds(delay_error_ms));
154 }
155}
156
157// Verify that if a task is being executed, then cancelling it is no-op
158TEST_F(OnceTimerTest, cancel_current_task_no_effect) {
159 std::string name = "test_thread";
160 MessageLoopThread message_loop_thread(name);
161 message_loop_thread.StartUp();
162 auto future = promise_->get_future();
163 uint32_t delay_ms = 5;
164
165 timer_->Schedule(message_loop_thread.GetWeakPtr(), FROM_HERE,
166 base::BindOnce(&OnceTimerTest::SleepAndIncreaseCounter,
167 base::Unretained(this), promise_, delay_ms),
168 base::TimeDelta::FromMilliseconds(delay_ms));
169 EXPECT_TRUE(timer_->IsScheduled());
170 future.get();
171 timer_->CancelAndWait();
172 ASSERT_EQ(counter_, 1);
173 EXPECT_FALSE(timer_->IsScheduled());
174}
175
176TEST_F(OnceTimerTest, reschedule_task_dont_invoke_new_task_early) {
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_->Schedule(message_loop_thread.GetWeakPtr(), FROM_HERE,
182 base::DoNothing(),
183 base::TimeDelta::FromMilliseconds(delay_ms));
184 std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms - 2));
185 timer_->Schedule(
186 message_loop_thread.GetWeakPtr(), FROM_HERE,
187 base::BindOnce(&OnceTimerTest::ShouldNotHappen, base::Unretained(this)),
188 base::TimeDelta::FromMilliseconds(delay_ms + 1000));
189 std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
190}
191
192TEST_F(OnceTimerTest, reschedule_task_when_firing_dont_invoke_new_task_early) {
193 std::string name = "test_thread";
194 MessageLoopThread message_loop_thread(name);
195 message_loop_thread.StartUp();
196 uint32_t delay_ms = 5;
197 timer_->Schedule(message_loop_thread.GetWeakPtr(), FROM_HERE,
198 base::DoNothing(),
199 base::TimeDelta::FromMilliseconds(delay_ms));
200 std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
201 timer_->Schedule(
202 message_loop_thread.GetWeakPtr(), FROM_HERE,
203 base::BindOnce(&OnceTimerTest::ShouldNotHappen, base::Unretained(this)),
204 base::TimeDelta::FromMilliseconds(delay_ms + 1000));
205 std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
206}
207
208TEST_F(OnceTimerTest, reschedule_task_when_firing_must_schedule_new_task) {
209 std::string name = "test_thread";
210 MessageLoopThread message_loop_thread(name);
211 message_loop_thread.StartUp();
212 uint32_t delay_ms = 5;
213 std::string my_name;
214 auto future = promise_->get_future();
215 timer_->Schedule(message_loop_thread.GetWeakPtr(), FROM_HERE,
216 base::DoNothing(),
217 base::TimeDelta::FromMilliseconds(delay_ms));
218 std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
219 timer_->Schedule(message_loop_thread.GetWeakPtr(), FROM_HERE,
220 base::BindOnce(&OnceTimerTest::GetName,
221 base::Unretained(this), &my_name, promise_),
222 base::TimeDelta::FromMilliseconds(delay_ms));
223 future.get();
224 ASSERT_EQ(name, my_name);
225}