| /****************************************************************************** |
| * |
| * Copyright 2017 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 <base/bind.h> |
| #include <base/logging.h> |
| #include <base/threading/thread.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <semaphore.h> |
| #include <time.h> |
| #include <unistd.h> |
| |
| #include "btcore/include/module.h" |
| #include "common/message_loop_thread.h" |
| #include "osi/include/alarm.h" |
| #include "osi/include/fixed_queue.h" |
| #include "stack/include/btu.h" |
| |
| class TimeoutHelper { |
| public: |
| TimeoutHelper() { sem_init(&sem, 0, 0); } |
| |
| ~TimeoutHelper() { sem_destroy(&sem); } |
| |
| void wait(int seconds, base::Closure callback) { |
| struct timespec timeout; |
| clock_gettime(CLOCK_REALTIME, &timeout); |
| timeout.tv_sec += seconds; |
| |
| int semvalue; |
| sem_getvalue(&sem, &semvalue); |
| |
| // Call the callback if timeout occured |
| if (sem_timedwait(&sem, &timeout) == -1 && !callback.is_null()) { |
| callback.Run(); |
| } |
| } |
| |
| void notify() { sem_post(&sem); } |
| |
| private: |
| sem_t sem; |
| }; |
| |
| TimeoutHelper helper; |
| |
| // External function definitions |
| void btu_task_start_up(void* context); |
| void btu_task_shut_down(void* context); |
| |
| /* Below are methods and variables that must be implemented if we don't want to |
| * compile the whole stack. They will be removed, or changed into mocks one by |
| * one in the future, as the refactoring progresses */ |
| bt_status_t do_in_jni_thread(const base::Location& from_here, |
| base::OnceClosure task) { |
| helper.notify(); |
| return BT_STATUS_SUCCESS; |
| } |
| |
| void btu_init_core(){}; |
| void btif_init_ok(unsigned short, char*){}; |
| void BTE_InitStack(){}; |
| void bta_sys_init(){}; |
| void bta_sys_free(){}; |
| void btu_free_core(){}; |
| const module_t* get_module(const char*) { return nullptr; }; |
| bool module_init(module_t const*) { return true; }; |
| void module_clean_up(module_t const*){}; |
| |
| bluetooth::common::MessageLoopThread bt_startup_thread("test alarm thread"); |
| |
| class BtuMessageLoopTest : public testing::Test { |
| public: |
| MOCK_METHOD0(TestCallback, void(void)); |
| base::MessageLoop* message_loop; |
| |
| void SetUp() override { |
| // Initialize alarms to prevent btu_task_shut_down from crashing |
| alarm_new("test alarm"); |
| bt_startup_thread.StartUp(); |
| // btu_task_start_up calls btif_transfer_context to let the stack know |
| // start up is finished |
| btu_task_start_up(nullptr); |
| helper.wait(5, base::Bind(&BtuMessageLoopTest::Fail, base::Unretained(this), |
| "BTU startup timed out")); |
| } |
| |
| void TearDown() override { |
| btu_task_shut_down(nullptr); |
| alarm_cleanup(); |
| bt_startup_thread.ShutDown(); |
| } |
| |
| void Fail(std::string message) { FAIL() << message; } |
| }; |
| |
| TEST_F(BtuMessageLoopTest, send_message) { |
| message_loop = get_main_message_loop(); |
| EXPECT_FALSE(message_loop == nullptr); |
| |
| EXPECT_CALL(*this, TestCallback()).Times(1); |
| message_loop->task_runner()->PostTask( |
| FROM_HERE, |
| base::Bind(&BtuMessageLoopTest::TestCallback, base::Unretained(this))); |
| |
| message_loop->task_runner()->PostTask( |
| FROM_HERE, base::Bind(&TimeoutHelper::notify, base::Unretained(&helper))); |
| |
| // Prevent the test from ending before the message loop posts the function |
| helper.wait(5, base::Bind(&BtuMessageLoopTest::Fail, base::Unretained(this), |
| "Timed out waiting for callback")); |
| } |