1 /*
2 * Copyright 2019 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 "os/repeating_alarm.h"
18
19 #include <future>
20
21 #include "common/bind.h"
22 #include "gtest/gtest.h"
23
24 namespace bluetooth {
25 namespace os {
26 namespace {
27
28 constexpr int error_ms = 20;
29
30 class RepeatingAlarmTest : public ::testing::Test {
31 protected:
SetUp()32 void SetUp() override {
33 thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
34 handler_ = new Handler(thread_);
35 alarm_ = new RepeatingAlarm(handler_);
36 }
37
TearDown()38 void TearDown() override {
39 delete alarm_;
40 handler_->Clear();
41 delete handler_;
42 delete thread_;
43 }
44
VerifyMultipleDelayedTasks(int scheduled_tasks,int task_length_ms,int interval_between_tasks_ms)45 void VerifyMultipleDelayedTasks(int scheduled_tasks, int task_length_ms, int interval_between_tasks_ms) {
46 std::promise<void> promise;
47 auto future = promise.get_future();
48 auto start_time = std::chrono::steady_clock::now();
49 int counter = 0;
50 alarm_->Schedule(
51 common::Bind(
52 &RepeatingAlarmTest::verify_delayed_tasks,
53 common::Unretained(this),
54 common::Unretained(&counter),
55 start_time,
56 scheduled_tasks,
57 common::Unretained(&promise),
58 task_length_ms,
59 interval_between_tasks_ms),
60 std::chrono::milliseconds(interval_between_tasks_ms));
61 future.get();
62 alarm_->Cancel();
63 }
64
verify_delayed_tasks(int * counter,std::chrono::steady_clock::time_point start_time,int scheduled_tasks,std::promise<void> * promise,int task_length_ms,int interval_between_tasks_ms)65 void verify_delayed_tasks(
66 int* counter,
67 std::chrono::steady_clock::time_point start_time,
68 int scheduled_tasks,
69 std::promise<void>* promise,
70 int task_length_ms,
71 int interval_between_tasks_ms) {
72 *counter = *counter + 1;
73 auto time_now = std::chrono::steady_clock::now();
74 auto time_delta = time_now - start_time;
75 if (*counter == scheduled_tasks) {
76 promise->set_value();
77 }
78 ASSERT_NEAR(time_delta.count(), interval_between_tasks_ms * 1000000 * *counter, error_ms * 1000000);
79 std::this_thread::sleep_for(std::chrono::milliseconds(task_length_ms));
80 }
81
82 RepeatingAlarm* alarm_;
83
__anon69a28b9c0202null84 common::Closure should_not_happen_ = common::Bind([] { ASSERT_TRUE(false); });
85
86 private:
87 Thread* thread_;
88 Handler* handler_;
89 };
90
TEST_F(RepeatingAlarmTest,cancel_while_not_armed)91 TEST_F(RepeatingAlarmTest, cancel_while_not_armed) {
92 alarm_->Cancel();
93 }
94
TEST_F(RepeatingAlarmTest,schedule)95 TEST_F(RepeatingAlarmTest, schedule) {
96 std::promise<void> promise;
97 auto future = promise.get_future();
98 auto before = std::chrono::steady_clock::now();
99 int period_ms = 10;
100 alarm_->Schedule(
101 common::Bind(&std::promise<void>::set_value, common::Unretained(&promise)), std::chrono::milliseconds(period_ms));
102 future.get();
103 alarm_->Cancel();
104 auto after = std::chrono::steady_clock::now();
105 auto duration = after - before;
106 ASSERT_NEAR(duration.count(), period_ms * 1000000, error_ms * 1000000);
107 }
108
TEST_F(RepeatingAlarmTest,cancel_alarm)109 TEST_F(RepeatingAlarmTest, cancel_alarm) {
110 alarm_->Schedule(should_not_happen_, std::chrono::milliseconds(10));
111 alarm_->Cancel();
112 std::this_thread::sleep_for(std::chrono::milliseconds(50));
113 }
114
TEST_F(RepeatingAlarmTest,cancel_alarm_from_callback)115 TEST_F(RepeatingAlarmTest, cancel_alarm_from_callback) {
116 alarm_->Schedule(
117 common::Bind(&RepeatingAlarm::Cancel, common::Unretained(this->alarm_)), std::chrono::milliseconds(1));
118 std::this_thread::sleep_for(std::chrono::milliseconds(5));
119 }
120
TEST_F(RepeatingAlarmTest,schedule_while_alarm_armed)121 TEST_F(RepeatingAlarmTest, schedule_while_alarm_armed) {
122 alarm_->Schedule(should_not_happen_, std::chrono::milliseconds(1));
123 std::promise<void> promise;
124 auto future = promise.get_future();
125 alarm_->Schedule(
126 common::Bind(&std::promise<void>::set_value, common::Unretained(&promise)), std::chrono::milliseconds(10));
127 future.get();
128 alarm_->Cancel();
129 }
130
TEST_F(RepeatingAlarmTest,delete_while_alarm_armed)131 TEST_F(RepeatingAlarmTest, delete_while_alarm_armed) {
132 alarm_->Schedule(should_not_happen_, std::chrono::milliseconds(1));
133 delete alarm_;
134 alarm_ = nullptr;
135 std::this_thread::sleep_for(std::chrono::milliseconds(1));
136 }
137
TEST_F(RepeatingAlarmTest,verify_small)138 TEST_F(RepeatingAlarmTest, verify_small) {
139 VerifyMultipleDelayedTasks(100, 1, 10);
140 }
141
TEST_F(RepeatingAlarmTest,verify_large)142 TEST_F(RepeatingAlarmTest, verify_large) {
143 VerifyMultipleDelayedTasks(100, 3, 10);
144 }
145
146 } // namespace
147 } // namespace os
148 } // namespace bluetooth
149