/* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "os/alarm.h" #include #include #include "common/bind.h" #include "gtest/gtest.h" #include "os/fake_timer/fake_timerfd.h" namespace bluetooth { namespace os { namespace { using common::BindOnce; using fake_timer::fake_timerfd_advance; using fake_timer::fake_timerfd_reset; class AlarmTest : public ::testing::Test { protected: void SetUp() override { thread_ = new Thread("test_thread", Thread::Priority::NORMAL); handler_ = new Handler(thread_); alarm_ = std::make_shared(handler_); } void TearDown() override { alarm_.reset(); handler_->Clear(); delete handler_; delete thread_; fake_timerfd_reset(); } void fake_timer_advance(uint64_t ms) { handler_->Post(common::BindOnce(fake_timerfd_advance, ms)); } std::shared_ptr get_new_alarm() { return std::make_shared(handler_); } std::shared_ptr alarm_; private: Handler* handler_; Thread* thread_; }; TEST_F(AlarmTest, cancel_while_not_armed) { alarm_->Cancel(); } TEST_F(AlarmTest, schedule) { std::promise promise; auto future = promise.get_future(); int delay_ms = 10; alarm_->Schedule( BindOnce(&std::promise::set_value, common::Unretained(&promise)), std::chrono::milliseconds(delay_ms)); fake_timer_advance(10); future.get(); ASSERT_FALSE(future.valid()); } TEST_F(AlarmTest, cancel_alarm) { alarm_->Schedule(BindOnce([]() { ASSERT_TRUE(false) << "Should not happen"; }), std::chrono::milliseconds(3)); alarm_->Cancel(); std::this_thread::sleep_for(std::chrono::milliseconds(5)); } TEST_F(AlarmTest, cancel_alarm_from_callback) { std::promise promise; auto future = promise.get_future(); alarm_->Schedule( BindOnce( [](std::shared_ptr alarm, std::promise promise) { alarm->Cancel(); alarm.reset(); // Allow alarm to be freed by Teardown promise.set_value(); }, alarm_, std::move(promise)), std::chrono::milliseconds(1)); fake_timer_advance(10); ASSERT_EQ(std::future_status::ready, future.wait_for(std::chrono::seconds(1))); ASSERT_EQ(alarm_.use_count(), 1); } TEST_F(AlarmTest, schedule_while_alarm_armed) { alarm_->Schedule(BindOnce([]() { ASSERT_TRUE(false) << "Should not happen"; }), std::chrono::milliseconds(1)); std::promise promise; auto future = promise.get_future(); alarm_->Schedule( BindOnce(&std::promise::set_value, common::Unretained(&promise)), std::chrono::milliseconds(10)); fake_timer_advance(10); future.get(); } TEST_F(AlarmTest, delete_while_alarm_armed) { alarm_->Schedule(BindOnce([]() { ASSERT_TRUE(false) << "Should not happen"; }), std::chrono::milliseconds(1)); alarm_.reset(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } class TwoAlarmTest : public AlarmTest { protected: void SetUp() override { AlarmTest::SetUp(); alarm2 = get_new_alarm(); } void TearDown() override { alarm2.reset(); AlarmTest::TearDown(); } std::shared_ptr alarm2; }; TEST_F(TwoAlarmTest, schedule_from_alarm_long) { auto promise = std::make_unique>(); auto future = promise->get_future(); auto promise2 = std::make_unique>(); auto future2 = promise2->get_future(); alarm_->Schedule( BindOnce( [](std::shared_ptr alarm2, std::unique_ptr> promise, std::unique_ptr> promise2) { promise->set_value(); alarm2->Schedule( BindOnce(&std::promise::set_value, std::move(promise2)), std::chrono::milliseconds(10)); }, alarm2, std::move(promise), std::move(promise2)), std::chrono::milliseconds(1)); fake_timer_advance(10); EXPECT_EQ(std::future_status::ready, future.wait_for(std::chrono::milliseconds(20))); fake_timer_advance(10); EXPECT_EQ(std::future_status::ready, future2.wait_for(std::chrono::milliseconds(20))); } } // namespace } // namespace os } // namespace bluetooth