1 /*
2  * Copyright 2024 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 <cctype>
18 #include <chrono>
19 #include <future>
20 #include <memory>
21 
22 #include "common/bind.h"
23 #include "gtest/gtest.h"
24 #include "os/alarm.h"
25 
26 // TODO(b/369381361) Enfore -Wmissing-prototypes
27 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
28 
29 namespace bluetooth::common {
30 
31 struct IsSpace {
operator ()bluetooth::common::IsSpace32   bool operator()(std::string::value_type v) { return isspace(static_cast<int>(v)); }
33 };
34 
StringTrim(std::string str)35 std::string StringTrim(std::string str) {
36   str.erase(str.begin(), std::find_if_not(str.begin(), str.end(), IsSpace{}));
37   str.erase(std::find_if_not(str.rbegin(), str.rend(), IsSpace{}).base(), str.end());
38   return str;
39 }
40 }  // namespace bluetooth::common
41 
42 namespace bluetooth::os {
43 
44 using common::BindOnce;
45 using std::chrono::milliseconds;
46 using std::chrono::seconds;
47 
48 static constexpr seconds kForever = seconds(1);
49 static constexpr milliseconds kShortWait = milliseconds(10);
50 
51 class AlarmOnTimerFdTest : public ::testing::TestWithParam<bool> {
52 protected:
SetUp()53   void SetUp() override {
54     bool isWakeAlarm = GetParam();
55     thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
56     handler_ = new Handler(thread_);
57     alarm_ = std::make_shared<Alarm>(handler_, isWakeAlarm);
58   }
59 
TearDown()60   void TearDown() override {
61     alarm_.reset();
62     handler_->Clear();
63     delete handler_;
64     delete thread_;
65   }
66 
get_new_alarm()67   std::shared_ptr<Alarm> get_new_alarm() { return std::make_shared<Alarm>(handler_, GetParam()); }
68 
69   std::shared_ptr<Alarm> alarm_;
70 
71 private:
72   Handler* handler_;
73   Thread* thread_;
74 };
75 
TEST_P(AlarmOnTimerFdTest,cancel_while_not_armed)76 TEST_P(AlarmOnTimerFdTest, cancel_while_not_armed) { alarm_->Cancel(); }
77 
TEST_P(AlarmOnTimerFdTest,schedule)78 TEST_P(AlarmOnTimerFdTest, schedule) {
79   auto promise = std::make_unique<std::promise<void>>();
80   auto future = promise->get_future();
81   alarm_->Schedule(BindOnce(&std::promise<void>::set_value, std::move(promise)), kShortWait);
82   ASSERT_EQ(std::future_status::ready, future.wait_for(kForever));
83 }
84 
TEST_P(AlarmOnTimerFdTest,cancel_alarm)85 TEST_P(AlarmOnTimerFdTest, cancel_alarm) {
86   auto promise = std::make_unique<std::promise<void>>();
87   auto future = promise->get_future();
88   alarm_->Schedule(BindOnce([]() { FAIL(); }), kForever);
89   alarm_->Cancel();
90   ASSERT_NE(std::future_status::ready, future.wait_for(kShortWait));
91 }
92 
TEST_P(AlarmOnTimerFdTest,cancel_alarm_from_callback)93 TEST_P(AlarmOnTimerFdTest, cancel_alarm_from_callback) {
94   auto promise = std::promise<void>();
95   auto future = promise.get_future();
96   alarm_->Schedule(BindOnce(
97                            [](std::shared_ptr<Alarm> alarm, std::promise<void> promise) {
98                              alarm->Cancel();
99                              alarm.reset();  // Allow alarm to be freed by Teardown
100                              promise.set_value();
101                            },
102                            alarm_, std::move(promise)),
103                    kShortWait);
104   ASSERT_EQ(std::future_status::ready, future.wait_for(kForever));
105 }
106 
TEST_P(AlarmOnTimerFdTest,schedule_while_alarm_armed)107 TEST_P(AlarmOnTimerFdTest, schedule_while_alarm_armed) {
108   auto promise = std::make_unique<std::promise<void>>();
109   auto future = promise->get_future();
110   alarm_->Schedule(BindOnce([]() { FAIL(); }), kForever);
111   alarm_->Schedule(BindOnce(&std::promise<void>::set_value, std::move(promise)), kShortWait);
112   ASSERT_EQ(std::future_status::ready, future.wait_for(kForever));
113 }
114 
TEST_P(AlarmOnTimerFdTest,delete_while_alarm_armed)115 TEST_P(AlarmOnTimerFdTest, delete_while_alarm_armed) {
116   auto promise = std::make_unique<std::promise<void>>();
117   auto future = promise->get_future();
118   alarm_->Schedule(BindOnce([]() { FAIL(); }), kForever);
119   alarm_.reset();
120   ASSERT_NE(std::future_status::ready, future.wait_for(kShortWait));
121 }
122 
123 class TwoAlarmOnTimerFdTest : public AlarmOnTimerFdTest {
124 protected:
SetUp()125   void SetUp() override {
126     AlarmOnTimerFdTest::SetUp();
127     alarm2 = get_new_alarm();
128   }
129 
TearDown()130   void TearDown() override {
131     alarm2.reset();
132     AlarmOnTimerFdTest::TearDown();
133   }
134 
135   std::shared_ptr<Alarm> alarm2;
136 };
137 
TEST_P(TwoAlarmOnTimerFdTest,schedule_from_alarm)138 TEST_P(TwoAlarmOnTimerFdTest, schedule_from_alarm) {
139   auto promise = std::make_unique<std::promise<void>>();
140   auto future = promise->get_future();
141   alarm_->Schedule(
142           BindOnce(
143                   [](std::shared_ptr<Alarm> alarm2, std::unique_ptr<std::promise<void>> promise) {
144                     alarm2->Schedule(BindOnce(&std::promise<void>::set_value, std::move(promise)),
145                                      kShortWait);
146                   },
147                   alarm2, std::move(promise)),
148           kShortWait);
149   EXPECT_EQ(std::future_status::ready, future.wait_for(kForever));
150 }
151 
152 INSTANTIATE_TEST_SUITE_P(
153         /* no label */, AlarmOnTimerFdTest, ::testing::Bool());
154 
155 INSTANTIATE_TEST_SUITE_P(
156         /* no label */, TwoAlarmOnTimerFdTest, ::testing::Bool());
157 
158 }  // namespace bluetooth::os
159