| /****************************************************************************** | |
| * | |
| * 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")); | |
| } |