From f8881fee3d08cb50896b22adc0841223694d51d2 Mon Sep 17 00:00:00 2001 From: Arman Uguray Date: Tue, 4 Aug 2015 12:56:56 -0700 Subject: [PATCH] service: Add Mock support for Daemon and CoreStack This patch turns the Daemon and CoreStack classes into abstract interfaces. Mock and real implementations are implemented in special subclasses and obtained via a factory method. Other test implementations (e.g. stub) can be provided in the future. Bug: 22532180 Change-Id: Ic3000518e5cef1c867dd803cd0bba6aab49dc596 --- service/core_stack.cpp | 41 +++++++++++--- service/core_stack.h | 30 +++++------ service/daemon.cpp | 113 +++++++++++++++++++++++---------------- service/daemon.h | 29 +++++----- service/ipc/ipc_handler_unix.cpp | 4 +- service/test/mock_core_stack.h | 41 ++++++++++++++ service/test/mock_daemon.h | 41 ++++++++++++++ 7 files changed, 212 insertions(+), 87 deletions(-) create mode 100644 service/test/mock_core_stack.h create mode 100644 service/test/mock_daemon.h diff --git a/service/core_stack.cpp b/service/core_stack.cpp index f5f94f393..21081dec6 100644 --- a/service/core_stack.cpp +++ b/service/core_stack.cpp @@ -181,13 +181,35 @@ bt_os_callouts_t callouts = { namespace bluetooth { -CoreStack::CoreStack() : adapter_(nullptr), hal_(nullptr) { +// The real CoreStack implementation to be used in production code. +class CoreStackImpl : public CoreStack { + public: + CoreStackImpl(); + ~CoreStackImpl() override; + + // CoreStack overrides. + bool Initialize() override; + bool SetAdapterName(const std::string& name) override; + bool SetClassicDiscoverable() override; + const void* GetInterface(const char* profile) override; + + private: + // Our libhardware handle. + bluetooth_device_t *adapter_; + + // Common Bluetooth interface handle. + const bt_interface_t *hal_; + + DISALLOW_COPY_AND_ASSIGN(CoreStackImpl); +}; + +CoreStackImpl::CoreStackImpl() : adapter_(nullptr), hal_(nullptr) { std::lock_guard lock(mutex); // TODO(icoolidge): DCHECK(!instantiated); instantiated = true; } -bool CoreStack::Initialize() { +bool CoreStackImpl::Initialize() { std::unique_lock lock(mutex); // Load the bluetooth module. @@ -230,11 +252,11 @@ bool CoreStack::Initialize() { } synchronize.wait(lock); - LOG_INFO(LOG_TAG, "%s", "CoreStack::Initialize success"); + LOG_INFO(LOG_TAG, "%s", "CoreStackImpl::Initialize success"); return true; } -bool CoreStack::SetAdapterName(const std::string &name) { +bool CoreStackImpl::SetAdapterName(const std::string &name) { bt_bdname_t n; snprintf(reinterpret_cast(n.name), sizeof(n.name), "%s", name.c_str()); @@ -255,7 +277,7 @@ bool CoreStack::SetAdapterName(const std::string &name) { return true; } -bool CoreStack::SetClassicDiscoverable() { +bool CoreStackImpl::SetClassicDiscoverable() { bt_scan_mode_t mode = BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE; bt_property_t disc; disc.len = sizeof(mode); @@ -274,7 +296,7 @@ bool CoreStack::SetClassicDiscoverable() { return true; } -const void *CoreStack::GetInterface(const char *profile) { +const void* CoreStackImpl::GetInterface(const char *profile) { std::unique_lock lock(mutex); // Get the interface to the GATT profile. const void *interface = hal_->get_profile_interface(profile); @@ -285,10 +307,15 @@ const void *CoreStack::GetInterface(const char *profile) { return interface; } -CoreStack::~CoreStack() { +CoreStackImpl::~CoreStackImpl() { // TODO(icoolidge): Disable bluetooth hardware, clean up library state. std::lock_guard lock(mutex); instantiated = false; } +// static +std::unique_ptr CoreStack::Create() { + return std::unique_ptr(new CoreStackImpl()); +} + } // namespace bluetooth diff --git a/service/core_stack.h b/service/core_stack.h index 8b5671af6..a77a49cdd 100644 --- a/service/core_stack.h +++ b/service/core_stack.h @@ -13,11 +13,13 @@ // See the License for the specific language governing permissions and // limitations under the License. // + #pragma once +#include #include -#include "hardware/bluetooth.h" +#include namespace bluetooth { @@ -26,32 +28,30 @@ namespace bluetooth { // It is also used to access profile interfaces. class CoreStack { public: - CoreStack(); - ~CoreStack(); + virtual ~CoreStack() = default; // Initialize the bluetooth stack and device. - bool Initialize(); + virtual bool Initialize() = 0; // Set the device name. // This can be referenced in BLE GAP advertisements. - bool SetAdapterName(const std::string& name); + virtual bool SetAdapterName(const std::string& name) = 0; // Allow activated classic profiles to be discovered. - bool SetClassicDiscoverable(); + virtual bool SetClassicDiscoverable() = 0; // Get an interface for a profile (BLE GATT, A2DP, etc). - const void *GetInterface(const char* profile); + virtual const void* GetInterface(const char* profile) = 0; - private: - // Prevent copy and assignment. - CoreStack& operator=(const CoreStack& rhs) = delete; - CoreStack(const CoreStack& rhs) = delete; + // Factory method that creates a real CoreStack instance. This should be used + // in production code. + static std::unique_ptr Create(); - // Our libhardware handle. - bluetooth_device_t *adapter_; + protected: + CoreStack() = default; - // Common bluetooth interface handle. - const bt_interface_t *hal_; + private: + DISALLOW_COPY_AND_ASSIGN(CoreStack); }; } // namespace bluetooth diff --git a/service/daemon.cpp b/service/daemon.cpp index 2f353565f..661bebdf1 100644 --- a/service/daemon.cpp +++ b/service/daemon.cpp @@ -16,6 +16,8 @@ #include "service/daemon.h" +#include + #include #include "service/core_stack.h" @@ -29,13 +31,67 @@ namespace { // The global Daemon instance. Daemon* g_daemon = nullptr; +class DaemonImpl : public Daemon { + public: + DaemonImpl() = default; + ~DaemonImpl() override = default; + + void StartMainLoop() override { + message_loop_->Run(); + } + + Settings* GetSettings() const override { + return settings_.get(); + } + + base::MessageLoop* GetMessageLoop() const override { + return message_loop_.get(); + } + + private: + bool Init() override { + message_loop_.reset(new base::MessageLoop()); + + settings_.reset(new Settings()); + if (!settings_->Init()) { + LOG(ERROR) << "Failed to set up Settings"; + return false; + } + + core_stack_ = CoreStack::Create(); + if (!core_stack_->Initialize()) { + LOG(ERROR) << "Failed to set up CoreStack"; + return false; + } + + ipc_manager_.reset(new ipc::IPCManager(core_stack_.get())); + + // If an IPC socket path was given, initialize IPC with it. + if ((!settings_->create_ipc_socket_path().empty() || + !settings_->android_ipc_socket_suffix().empty()) && + !ipc_manager_->Start(ipc::IPCManager::TYPE_UNIX)) { + LOG(ERROR) << "Failed to set up UNIX domain-socket IPCManager"; + return false; + } + + return true; + } + + std::unique_ptr message_loop_; + std::unique_ptr settings_; + std::unique_ptr core_stack_; + std::unique_ptr ipc_manager_; + + DISALLOW_COPY_AND_ASSIGN(DaemonImpl); +}; + } // namespace // static bool Daemon::Initialize() { CHECK(!g_daemon); - g_daemon = new Daemon(); + g_daemon = new DaemonImpl(); if (g_daemon->Init()) return true; @@ -50,59 +106,22 @@ bool Daemon::Initialize() { // static void Daemon::ShutDown() { CHECK(g_daemon); - CHECK(g_daemon->initialized_); - delete g_daemon; - g_daemon = NULL; + g_daemon = nullptr; } // static -Daemon* Daemon::Get() { - CHECK(g_daemon); - return g_daemon; -} - -Daemon::Daemon() : initialized_(false) { -} - -Daemon::~Daemon() { -} +void Daemon::InitializeForTesting(Daemon* test_daemon) { + CHECK(test_daemon); + CHECK(!g_daemon); -void Daemon::StartMainLoop() { - CHECK(initialized_); - message_loop_->Run(); + g_daemon = test_daemon; } -bool Daemon::Init() { - CHECK(!initialized_); - - message_loop_.reset(new base::MessageLoop()); - - settings_.reset(new Settings()); - if (!settings_->Init()) { - LOG(ERROR) << "Failed to set up Settings"; - return false; - } - - core_stack_.reset(new CoreStack()); - if (!core_stack_->Initialize()) { - LOG(ERROR) << "Failed to set up CoreStack"; - return false; - } - - ipc_manager_.reset(new ipc::IPCManager(core_stack_.get())); - - // If an IPC socket path was given, initialize IPC with it. - if ((!settings_->create_ipc_socket_path().empty() || - !settings_->android_ipc_socket_suffix().empty()) && - !ipc_manager_->Start(ipc::IPCManager::TYPE_UNIX)) { - LOG(ERROR) << "Failed to set up UNIX domain-socket IPCManager"; - return false; - } - - initialized_ = true; - - return true; +// static +Daemon* Daemon::Get() { + CHECK(g_daemon); + return g_daemon; } } // namespace bluetooth diff --git a/service/daemon.h b/service/daemon.h index ab0225f0c..c792dfc79 100644 --- a/service/daemon.h +++ b/service/daemon.h @@ -16,8 +16,6 @@ #pragma once -#include - #include #include @@ -43,33 +41,32 @@ class Daemon { // Cleans up all the resources associated with the global Daemon object. static void ShutDown(); + // Assigns the global Daemon instance for testing. Should only be called from + // test code. + static void InitializeForTesting(Daemon* test_daemon); + // Returns the singleton Daemon instance. All classes can interact with the // Daemon, obtain its resources etc using this getter. static Daemon* Get(); // The global Settings object. All classes have direct access to this through // the Daemon object. - Settings* settings() const { return settings_.get(); } + virtual Settings* GetSettings() const = 0; // The main event loop. This should be used for any events and delayed tasks // that should be executed on the daemon's main thread. - base::MessageLoop* message_loop() const { return message_loop_.get(); } + virtual base::MessageLoop* GetMessageLoop() const = 0; // Starts the daemon's main loop. - void StartMainLoop(); + virtual void StartMainLoop() = 0; - private: - Daemon(); - ~Daemon(); + protected: + Daemon() = default; + virtual ~Daemon() = default; - // Private instance helper for Initialize(). - bool Init(); - - bool initialized_; - std::unique_ptr message_loop_; - std::unique_ptr settings_; - std::unique_ptr core_stack_; - std::unique_ptr ipc_manager_; + private: + // Internal instance helper called by Initialize(). + virtual bool Init() = 0; DISALLOW_COPY_AND_ASSIGN(Daemon); }; diff --git a/service/ipc/ipc_handler_unix.cpp b/service/ipc/ipc_handler_unix.cpp index a051c964e..7d57ec5a4 100644 --- a/service/ipc/ipc_handler_unix.cpp +++ b/service/ipc/ipc_handler_unix.cpp @@ -41,9 +41,9 @@ bool IPCHandlerUnix::Run() { CHECK(!running_); const std::string& android_suffix = - bluetooth::Daemon::Get()->settings()->android_ipc_socket_suffix(); + bluetooth::Daemon::Get()->GetSettings()->android_ipc_socket_suffix(); const base::FilePath& path = - bluetooth::Daemon::Get()->settings()->create_ipc_socket_path(); + bluetooth::Daemon::Get()->GetSettings()->create_ipc_socket_path(); // Both flags cannot be set at the same time. CHECK(android_suffix.empty() || path.empty()); diff --git a/service/test/mock_core_stack.h b/service/test/mock_core_stack.h new file mode 100644 index 000000000..334dcbe4a --- /dev/null +++ b/service/test/mock_core_stack.h @@ -0,0 +1,41 @@ +// +// Copyright (C) 2015 Google, Inc. +// +// 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. +// + +#pragma once + +#include + +#include "service/core_stack.h" + +namespace bluetooth { +namespace testing { + +class MockCoreStack : public CoreStack { + public: + MockCoreStack() = default; + ~MockCoreStack() override = default; + + MOCK_METHOD0(Initialize, bool()); + MOCK_METHOD1(SetAdapterName, bool(const std::string&)); + MOCK_METHOD0(SetClassicDiscoverable, bool()); + MOCK_METHOD1(GetInterface, const void*(const char*)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockCoreStack); +}; + +} // namespace testing +} // namespace bluetooth diff --git a/service/test/mock_daemon.h b/service/test/mock_daemon.h new file mode 100644 index 000000000..a5dd974fd --- /dev/null +++ b/service/test/mock_daemon.h @@ -0,0 +1,41 @@ +// +// Copyright (C) 2015 Google, Inc. +// +// 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. +// + +#pragma once + +#include + +#include "service/daemon.h" + +namespace bluetooth { +namespace testing { + +class MockDaemon : public Daemon { + public: + MockDaemon() = default; + ~MockDaemon() override = default; + + MOCK_CONST_METHOD0(GetSettings, Settings*()); + MOCK_CONST_METHOD0(GetMessageLoop, base::MessageLoop*()); + MOCK_METHOD0(StartMainLoop, void()); + MOCK_METHOD0(Init, bool()); + + private: + DISALLOW_COPY_AND_ASSIGN(MockDaemon); +}; + +} // namespace testing +} // namespace bluetooth -- 2.11.0