1761 lines
81 KiB
C++
1761 lines
81 KiB
C++
/*
|
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
|
* You may not use this file except in compliance with the License.
|
|
* A copy of the License is located at
|
|
*
|
|
* http://aws.amazon.com/apache2.0/
|
|
*
|
|
* or in the "license" file accompanying this file. This file 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 <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <fstream>
|
|
#include <sstream>
|
|
|
|
#include <acsdkApplicationAudioPipelineFactoryInterfaces/MockApplicationAudioPipelineFactory.h>
|
|
#include <acsdkBluetoothInterfaces/MockBluetoothDeviceObserver.h>
|
|
#include <acsdkShutdownManagerInterfaces/MockShutdownNotifier.h>
|
|
#include <AVSCommon/AVS/Attachment/MockAttachmentManager.h>
|
|
#include <AVSCommon/SDKInterfaces/Bluetooth/BluetoothDeviceInterface.h>
|
|
#include <AVSCommon/SDKInterfaces/Bluetooth/MockBluetoothDevice.h>
|
|
#include <AVSCommon/SDKInterfaces/Bluetooth/MockBluetoothDeviceConnectionRule.h>
|
|
#include <AVSCommon/SDKInterfaces/Bluetooth/MockBluetoothDeviceManager.h>
|
|
#include <AVSCommon/SDKInterfaces/Bluetooth/MockBluetoothHostController.h>
|
|
#include <AVSCommon/SDKInterfaces/MockDirectiveHandlerResult.h>
|
|
#include <AVSCommon/SDKInterfaces/Bluetooth/Services/A2DPSinkInterface.h>
|
|
#include <AVSCommon/SDKInterfaces/Bluetooth/Services/A2DPSourceInterface.h>
|
|
#include <AVSCommon/SDKInterfaces/Bluetooth/Services/AVRCPControllerInterface.h>
|
|
#include <AVSCommon/SDKInterfaces/Bluetooth/Services/AVRCPTargetInterface.h>
|
|
#include <AVSCommon/SDKInterfaces/Bluetooth/Services/HIDInterface.h>
|
|
#include <AVSCommon/SDKInterfaces/Bluetooth/Services/MockBluetoothService.h>
|
|
#include <AVSCommon/SDKInterfaces/Bluetooth/Services/SPPInterface.h>
|
|
#include <AVSCommon/SDKInterfaces/MockChannelVolumeInterface.h>
|
|
#include <AVSCommon/SDKInterfaces/MockExceptionEncounteredSender.h>
|
|
#include <AVSCommon/SDKInterfaces/MockExceptionEncounteredSender.h>
|
|
#include <AVSCommon/SDKInterfaces/MockContextManager.h>
|
|
#include <AVSCommon/SDKInterfaces/MockFocusManager.h>
|
|
#include <AVSCommon/SDKInterfaces/MockMessageSender.h>
|
|
#include <AVSCommon/SDKInterfaces/Endpoints/MockEndpointCapabilitiesRegistrar.h>
|
|
#include <AVSCommon/Utils/Bluetooth/BluetoothEventBus.h>
|
|
#include <AVSCommon/Utils/Bluetooth/DeviceCategory.h>
|
|
#include <AVSCommon/Utils/Bluetooth/SDPRecords.h>
|
|
#include <AVSCommon/Utils/Configuration/ConfigurationNode.h>
|
|
#include <AVSCommon/Utils/JSON/JSONUtils.h>
|
|
#include <AVSCommon/Utils/MediaPlayer/MockMediaPlayer.h>
|
|
#include <AVSCommon/Utils/Memory/Memory.h>
|
|
#include <AVSCommon/Utils/Optional.h>
|
|
#include <RegistrationManager/MockCustomerDataManager.h>
|
|
|
|
#include "acsdkBluetooth/BasicDeviceConnectionRule.h"
|
|
#include "acsdkBluetooth/Bluetooth.h"
|
|
#include "acsdkBluetooth/BluetoothNotifier.h"
|
|
#include "acsdkBluetooth/DeviceConnectionRulesAdapter.h"
|
|
#include "acsdkBluetooth/SQLiteBluetoothStorage.h"
|
|
|
|
namespace alexaClientSDK {
|
|
namespace acsdkBluetooth {
|
|
namespace test {
|
|
|
|
using namespace avsCommon::avs;
|
|
using namespace avsCommon::avs::attachment;
|
|
using namespace avsCommon::avs::attachment::test;
|
|
using namespace avsCommon::sdkInterfaces;
|
|
using namespace avsCommon::sdkInterfaces::bluetooth;
|
|
using namespace avsCommon::sdkInterfaces::bluetooth::services;
|
|
using namespace avsCommon::sdkInterfaces::bluetooth::test;
|
|
using namespace avsCommon::sdkInterfaces::bluetooth::services::test;
|
|
using namespace avsCommon::sdkInterfaces::test;
|
|
using namespace avsCommon::utils;
|
|
using namespace avsCommon::utils::bluetooth;
|
|
using namespace avsCommon::utils::configuration;
|
|
using namespace avsCommon::utils::json;
|
|
using namespace avsCommon::utils::mediaPlayer::test;
|
|
using namespace ::testing;
|
|
using namespace rapidjson;
|
|
|
|
/// String to identify log entries originating from this file.
|
|
static const std::string TAG{"BluetoothTest"};
|
|
|
|
/**
|
|
* Create a LogEntry using this file's TAG and the specified event string.
|
|
*
|
|
* @param The event string for this @c LogEntry.
|
|
*/
|
|
#define LX(event) alexaClientSDK::avsCommon::utils::logger::LogEntry(TAG, event)
|
|
|
|
/// Test Bluetooth device mac address 1.
|
|
static const std::string TEST_BLUETOOTH_DEVICE_MAC = "01:23:45:67:89:ab";
|
|
|
|
/// Test Bluetooth device friendly name 1.
|
|
static const std::string TEST_BLUETOOTH_FRIENDLY_NAME = "test_friendly_name_1";
|
|
|
|
/// Test Bluetooth device uuid 1.
|
|
static const std::string TEST_BLUETOOTH_UUID = "650f973b-c2ab-4c6e-bff4-3788cd521340";
|
|
|
|
/// Test Bluetooth device mac address 2.
|
|
static const std::string TEST_BLUETOOTH_DEVICE_MAC_2 = "11:23:45:67:89:ab";
|
|
|
|
/// Test Bluetooth device friendly name 2.
|
|
static const std::string TEST_BLUETOOTH_FRIENDLY_NAME_2 = "test_friendly_name_2";
|
|
|
|
/// Test Bluetooth device uuid 2.
|
|
static const std::string TEST_BLUETOOTH_UUID_2 = "650f973b-c2ab-4c6e-bff4-3788cd521341";
|
|
|
|
/// Test Bluetooth device mac address 3.
|
|
static const std::string TEST_BLUETOOTH_DEVICE_MAC_3 = "21:23:45:67:89:ab";
|
|
|
|
/// Test Bluetooth device friendly name 3.
|
|
static const std::string TEST_BLUETOOTH_FRIENDLY_NAME_3 = "test_friendly_name_3";
|
|
|
|
/// Test Bluetooth device uuid 3.
|
|
static const std::string TEST_BLUETOOTH_UUID_3 = "650f973b-c2ab-4c6e-bff4-3788cd521342";
|
|
|
|
/// Test Database file name. Can be changed if there are conflicts.
|
|
static const std::string TEST_DATABASE = "BluetoothCATest.db";
|
|
|
|
// clang-format off
|
|
static const std::string BLUETOOTH_JSON = R"(
|
|
{
|
|
"bluetooth" : {
|
|
"databaseFilePath":")" + TEST_DATABASE + R"("
|
|
}
|
|
}
|
|
)";
|
|
// clang-format on
|
|
|
|
/// Error message for when the file already exists.
|
|
static const std::string FILE_EXISTS_ERROR = "Database File " + TEST_DATABASE + " already exists.";
|
|
|
|
/// Namespace of Bluetooth.
|
|
static const std::string NAMESPACE_BLUETOOTH = "Bluetooth";
|
|
|
|
/// THe Bluetooth state portion of the Context.
|
|
static const NamespaceAndName BLUETOOTH_STATE{NAMESPACE_BLUETOOTH, "BluetoothState"};
|
|
|
|
/// JSON key for the event section of a message.
|
|
static const std::string MESSAGE_EVENT_KEY = "event";
|
|
|
|
/// JSON key for the header section of a message.
|
|
static const std::string MESSAGE_HEADER_KEY = "header";
|
|
|
|
/// JSON key for the name section of a message.
|
|
static const std::string MESSAGE_NAME_KEY = "name";
|
|
|
|
/// JSON key for the payload section of a message.
|
|
static const std::string PAYLOAD_KEY = "payload";
|
|
|
|
/// JSON key for the requester section of a message.
|
|
static const std::string REQUESTER_KEY = "requester";
|
|
|
|
/// JSON value for the cloud requester.
|
|
static const std::string CLOUD_REQUESTER_VALUE = "CLOUD";
|
|
|
|
/// JSON value for the device requester.
|
|
static const std::string DEVICE_REQUESTER_VALUE = "DEVICE";
|
|
|
|
/// ConnectByDevice directive.
|
|
static const std::string CONNECT_BY_DEVICE_IDS_DIRECTIVE = "ConnectByDeviceIds";
|
|
|
|
/// ConnectByProfile directive.
|
|
static const std::string CONNECT_BY_PROFILE_DIRECTIVE = "ConnectByProfile";
|
|
|
|
/// PairDevice directive
|
|
static const std::string PAIR_DEVICES_DIRECTIVE = "PairDevices";
|
|
|
|
/// UnpairDevice directive
|
|
static const std::string UNPAIR_DEVICES_DIRECTIVE = "UnpairDevices";
|
|
|
|
/// DisconnectDevice directive
|
|
static const std::string DISCONNECT_DEVICES_DIRECTIVE = "DisconnectDevices";
|
|
|
|
/// SetDeviceCategories directive
|
|
static const std::string SET_DEVICE_CATEGORIES = "SetDeviceCategories";
|
|
|
|
/// Test message id.
|
|
static const std::string TEST_MESSAGE_ID = "MessageId_Test";
|
|
|
|
/// Test message id.
|
|
static const std::string TEST_MESSAGE_ID_2 = "MessageId_Test_2";
|
|
|
|
// clang-format off
|
|
/// ConnectByDeviceIds payload.
|
|
static const std::string TEST_CONNECT_BY_DEVICE_IDS_PAYLOAD = R"(
|
|
{
|
|
"devices" : [{
|
|
"uniqueDeviceId":")" + TEST_BLUETOOTH_UUID + R"(",
|
|
"friendlyName" :")" + TEST_BLUETOOTH_FRIENDLY_NAME + R"("
|
|
}, {"uniqueDeviceId":")" + TEST_BLUETOOTH_UUID_2 + R"(",
|
|
"friendlyName" :")" + TEST_BLUETOOTH_FRIENDLY_NAME_2 + R"("
|
|
}]
|
|
}
|
|
)";
|
|
// clang-format on
|
|
|
|
/// The @c ConnectByDeviceIdSucceeded event name.
|
|
static const std::string CONNECT_BY_DEVICE_IDS_SUCCEEDED = "ConnectByDeviceIdsSucceeded";
|
|
|
|
/// The @c ConnectByProfileSucceeded event name.
|
|
static const std::string CONNECT_BY_PROFILE_SUCCEEDED = "ConnectByProfileSucceeded";
|
|
|
|
/// The @c ConnectByProfileFailed event name.
|
|
static const std::string CONNECT_BY_PROFILE_FAILED = "ConnectByProfileFailed";
|
|
|
|
/// The @c PairDeviceSucceeded event name.
|
|
static const std::string PAIR_DEVICES_SUCCEEDED = "PairDevicesSucceeded";
|
|
|
|
/// The @c UnpairDeviceSucceeded event name.
|
|
static const std::string UNPAIR_DEVICES_SUCCEEDED = "UnpairDevicesSucceeded";
|
|
|
|
/// The @c SetDeviceCategoriesSucceeded event name.
|
|
static const std::string SET_DEVICE_CATEGORIES_SUCCEEDED = "SetDeviceCategoriesSucceeded";
|
|
|
|
/// The @c DisconnectDeviceSucceeded event name.
|
|
static const std::string DISCONNECT_DEVICES_SUCCEEDED = "DisconnectDevicesSucceeded";
|
|
|
|
/// The @c ScanDevicesUpdated event name.
|
|
static const std::string SCAN_DEVICES_REPORT = "ScanDevicesReport";
|
|
|
|
/// The @c StreamingStarted event name.
|
|
static const std::string STREAMING_STARTED = "StreamingStarted";
|
|
|
|
/// The @c StreamingEnded event name.
|
|
static const std::string STREAMING_ENDED = "StreamingEnded";
|
|
|
|
/// Test unmatched profile name.
|
|
static const std::string TEST_UNMATCHED_PROFILE_NAME = "HFP";
|
|
|
|
/// Test matched profile name.
|
|
static const std::string TEST_MATCHED_PROFILE_NAME = "AVRCP";
|
|
|
|
/// Test profile version.
|
|
static const std::string TEST_PROFILE_VERSION = "1";
|
|
|
|
// clang-format off
|
|
/// ConnectByDeviceProfile payload 1.
|
|
static const std::string TEST_CONNECT_BY_PROFILE_PAYLOAD_1 = R"(
|
|
{
|
|
"profile" : {
|
|
"name":")" + TEST_UNMATCHED_PROFILE_NAME + R"(",
|
|
"version" :")" + TEST_PROFILE_VERSION + R"("
|
|
}
|
|
}
|
|
)";
|
|
// clang-format on
|
|
|
|
// clang-format off
|
|
/// ConnectByDeviceProfile payload 2
|
|
static const std::string TEST_CONNECT_BY_PROFILE_PAYLOAD_2 = R"(
|
|
{
|
|
"profile" : {
|
|
"name":")" + TEST_MATCHED_PROFILE_NAME + R"(",
|
|
"version" :")" + TEST_PROFILE_VERSION + R"("
|
|
}
|
|
}
|
|
)";
|
|
// clang-format on
|
|
|
|
// clang-format off
|
|
/// PairDevices payload
|
|
static const std::string TEST_PAIR_DEVICES_PAYLOAD = R"(
|
|
{
|
|
"devices" : [{
|
|
"uniqueDeviceId":")" + TEST_BLUETOOTH_UUID + R"("
|
|
}, {
|
|
"uniqueDeviceId":")" + TEST_BLUETOOTH_UUID_2 + R"("
|
|
}]
|
|
}
|
|
)";
|
|
|
|
// clang-format on
|
|
|
|
// clang-format off
|
|
/// UnpairDevices payload
|
|
static const std::string TEST_UNPAIR_DEVICES_PAYLOAD = R"(
|
|
{
|
|
"devices" : [{
|
|
"uniqueDeviceId":")" + TEST_BLUETOOTH_UUID + R"("
|
|
}, {
|
|
"uniqueDeviceId":")" + TEST_BLUETOOTH_UUID_2 + R"("
|
|
}]
|
|
}
|
|
)";
|
|
// clang-format on
|
|
|
|
// clang-format off
|
|
/// DisconnectDevices payload
|
|
static const std::string TEST_DISCONNECT_DEVICES_PAYLOAD = R"(
|
|
{
|
|
"devices" : [{
|
|
"uniqueDeviceId":")" + TEST_BLUETOOTH_UUID + R"("
|
|
}, {
|
|
"uniqueDeviceId":")" + TEST_BLUETOOTH_UUID_2 + R"("
|
|
}]
|
|
}
|
|
)";
|
|
// clang-format on
|
|
|
|
// clang-format off
|
|
/// SetDeviceCategories payload
|
|
static const std::string TEST_SET_DEVICE_CATEGORIES_PAYLOAD = R"(
|
|
{
|
|
"devices" : [{
|
|
"uniqueDeviceId":")" + TEST_BLUETOOTH_UUID + R"(",
|
|
"deviceCategory": "PHONE"
|
|
}, {
|
|
"uniqueDeviceId":")" + TEST_BLUETOOTH_UUID_2 + R"(",
|
|
"deviceCategory": "GADGET"
|
|
}]
|
|
}
|
|
)";
|
|
// clang-format on
|
|
|
|
// clang-format off
|
|
/// Mock Context
|
|
static const std::string MOCK_CONTEXT = R"(
|
|
{
|
|
"context": [{
|
|
"header": {
|
|
"namespace": "Bluetooth",
|
|
"name": "BluetoothState"
|
|
},
|
|
"payload": {
|
|
"alexaDevice": {
|
|
"friendlyName": "{{STRING}}"
|
|
},
|
|
"pairedDevices": [{
|
|
"uniqueDeviceId": "{{STRING}}",
|
|
"friendlyName": "{{STRING}}",
|
|
"supportedProfiles": [{
|
|
"name": "{{STRING}}",
|
|
"version": "{{STRING}}"
|
|
}]
|
|
}],
|
|
"activeDevice": {
|
|
"uniqueDeviceId": "{{STRING}}",
|
|
"friendlyName": "{{STRING}}",
|
|
"supportedProfiles": [{
|
|
"name": "{{STRING}}",
|
|
"version": "{{STRING}}"
|
|
}],
|
|
"streaming": "{{STRING}}"
|
|
}
|
|
}
|
|
}]
|
|
}
|
|
)";
|
|
|
|
/// Wait timeout.
|
|
static std::chrono::milliseconds WAIT_TIMEOUT_MS(1000);
|
|
// Delay to let events happen / threads catch up
|
|
static std::chrono::milliseconds EVENT_PROCESS_DELAY_MS(500);
|
|
|
|
/**
|
|
* Checks whether a file exists in the file system.
|
|
*
|
|
* @param file The file name.
|
|
* @return Whether the file exists.
|
|
*/
|
|
static bool fileExists(const std::string& file) {
|
|
std::ifstream dbFile(file);
|
|
return dbFile.good();
|
|
}
|
|
|
|
class BluetoothTest: public ::testing::Test {
|
|
public:
|
|
void SetUp() override;
|
|
void TearDown() override;
|
|
|
|
/// @c Bluetooth to test
|
|
std::shared_ptr<Bluetooth> m_Bluetooth;
|
|
|
|
/// @c ContextManager to provide state and update state.
|
|
std::shared_ptr<MockContextManager> m_mockContextManager;
|
|
|
|
/// @c FocusManager to request focus to the CONTENT channel.
|
|
acsdkManufactory::Annotated<
|
|
avsCommon::sdkInterfaces::AudioFocusAnnotation,
|
|
avsCommon::sdkInterfaces::FocusManagerInterface> m_annotatedFocusManager;
|
|
|
|
/// The mock focus manager, wrapped by m_annotatedFocusManager. Keeping a reference to this mock is
|
|
/// required in order to set expectations on it.
|
|
std::shared_ptr<MockFocusManager> m_mockFocusManager;
|
|
|
|
/// A message sender used to send events to AVS.
|
|
std::shared_ptr<MockMessageSender> m_mockMessageSender;
|
|
|
|
/// An exception sender used to send exception encountered events to AVS.
|
|
std::shared_ptr<MockExceptionEncounteredSender> m_mockExceptionSender;
|
|
|
|
/// The storage component for @c Bluetooth.
|
|
std::shared_ptr<SQLiteBluetoothStorage> m_bluetoothStorage;
|
|
|
|
/// Player to send the audio to.
|
|
std::shared_ptr<MockMediaPlayer> m_mockBluetoothMediaPlayer;
|
|
|
|
/// A bus to abstract Bluetooth stack specific messages.
|
|
std::shared_ptr<avsCommon::utils::bluetooth::BluetoothEventBus> m_eventBus;
|
|
|
|
/// Object that will track the CustomerDataHandler.
|
|
std::shared_ptr<NiceMock<registrationManager::MockCustomerDataManager>> m_customerDataManager;
|
|
|
|
/// @c BluetoothHostController to create @c MockBluetoothDeviceManager
|
|
std::shared_ptr<MockBluetoothHostController> m_mockBluetoothHostController;
|
|
|
|
/// The list of discovered devices to create @c MockBluetoothDeviceManager
|
|
std::list<std::shared_ptr<avsCommon::sdkInterfaces::bluetooth::BluetoothDeviceInterface>>
|
|
m_mockDiscoveredBluetoothDevices;
|
|
|
|
/// The mock @c ApplicationAudioPipelineFactoryInterface.
|
|
std::shared_ptr<acsdkApplicationAudioPipelineFactoryInterfaces::test::MockApplicationAudioPipelineFactory>
|
|
m_mockAudioPipelineFactory;
|
|
|
|
/// An endpoint capabilities registrar with which to register the Bluetooth CA.
|
|
acsdkManufactory::Annotated<
|
|
avsCommon::sdkInterfaces::endpoints::DefaultEndpointAnnotation,
|
|
avsCommon::sdkInterfaces::endpoints::EndpointCapabilitiesRegistrarInterface>
|
|
m_mockEndpointCapabilitiesRegistrar;
|
|
|
|
/// An object that provides the Bluetooth device connection rules.
|
|
std::shared_ptr<acsdkBluetoothInterfaces::BluetoothDeviceConnectionRulesProviderInterface> m_connectionRulesProvider;
|
|
|
|
/// Object to notify the Bluetooth CA when to shut down.
|
|
std::shared_ptr<acsdkShutdownManagerInterfaces::ShutdownNotifierInterface> m_shutdownNotifier;
|
|
|
|
/// Bluetooth devices used to test the Bluetooth CA connection logic.
|
|
std::shared_ptr<MockBluetoothDevice> m_mockBluetoothDevice1;
|
|
std::shared_ptr<MockBluetoothDevice> m_mockBluetoothDevice2;
|
|
std::shared_ptr<MockBluetoothDevice> m_mockBluetoothDevice3;
|
|
|
|
/// Bluetooth device connection rules.
|
|
/// Bluetooth device connection rule for DeviceCategory::REMOTE_CONTROL.
|
|
std::shared_ptr<MockBluetoothDeviceConnectionRule> m_remoteControlConnectionRule;
|
|
/// Bluetooth device connection rule for DeviceCategory::GADGET.
|
|
std::shared_ptr<MockBluetoothDeviceConnectionRule> m_gadgetConnectionRule;
|
|
|
|
/// A manager to take care of Bluetooth devices.
|
|
std::unique_ptr<MockBluetoothDeviceManager> m_mockDeviceManager;
|
|
|
|
/// A directive handler result to send the result to.
|
|
std::unique_ptr<MockDirectiveHandlerResult> m_mockDirectiveHandlerResult;
|
|
|
|
/// An observer to be notified of the Bluetooth connection change.
|
|
std::shared_ptr<acsdkBluetoothInterfaces::test::MockBluetoothDeviceObserver> m_mockBluetoothDeviceObserver;
|
|
|
|
/// A @c ChannelVolumeInterface object to control volume
|
|
std::shared_ptr<MockChannelVolumeInterface> m_mockChannelVolumeInterface;
|
|
|
|
/// A @c BluetoothNotifierInterface to notify observers.
|
|
std::shared_ptr<acsdkBluetoothInterfaces::BluetoothNotifierInterface> m_bluetoothNotifier;
|
|
|
|
/// Condition variable to wake on a message being sent.
|
|
std::condition_variable m_messageSentTrigger;
|
|
|
|
/// Expected messages.
|
|
std::map<std::string, int> m_messages;
|
|
|
|
/// Function to wait for @c m_wakeSetCompleteFuture to be set.
|
|
void wakeOnSetCompleted();
|
|
|
|
/**
|
|
* Get the request event name.
|
|
*
|
|
* @param request The @c MessageRequest to verify.
|
|
* @return The event name.
|
|
*/
|
|
std::string getRequestName(std::shared_ptr<avsCommon::avs::MessageRequest> request);
|
|
|
|
/**
|
|
* Verify that the message name matches the expected name.
|
|
*
|
|
* @param request The @c MessageRequest to verify.
|
|
* @param expectedName The expected name to find in the json header.
|
|
* @return true if the message name matched the expect name.
|
|
*/
|
|
bool verifyMessage(std::shared_ptr<avsCommon::avs::MessageRequest> request, std::string expectedName);
|
|
|
|
/**
|
|
* Verify that the messages sent matches the ordered list of events.
|
|
*
|
|
* @param request The @c MessageRequest to verify.
|
|
* @param trigger The function to trigger sending the messages.
|
|
* @return true if the messages sent matches the ordered list of events.
|
|
*/
|
|
bool verifyMessagesSentInOrder(std::vector<std::string> orderedEvents, std::function<void()> trigger);
|
|
|
|
/**
|
|
* Verify that the messages sent matches the count.
|
|
*
|
|
* @param request The @c MessageRequest to verify.
|
|
* @param messages The Map<RequestName, Count> expected messages.
|
|
*/
|
|
void verifyMessagesCount(std::shared_ptr<avsCommon::avs::MessageRequest> request,
|
|
std::map<std::string, int>* messages);
|
|
|
|
/// A Constructor which initializes the promises and futures needed for the test class.
|
|
BluetoothTest() : m_wakeSetCompletedPromise{}, m_wakeSetCompletedFuture{m_wakeSetCompletedPromise.get_future()} {
|
|
}
|
|
|
|
protected:
|
|
/// Promise to synchronize directive handling through SetCompleted.
|
|
std::promise<void> m_wakeSetCompletedPromise;
|
|
|
|
/// Future to synchronize directive handling through SetCompleted.
|
|
std::future<void> m_wakeSetCompletedFuture;
|
|
};
|
|
|
|
void BluetoothTest::SetUp() {
|
|
m_mockContextManager = std::make_shared<NiceMock<MockContextManager>>();
|
|
m_mockMessageSender = std::make_shared<NiceMock<MockMessageSender>>();
|
|
m_mockExceptionSender = std::make_shared<NiceMock<MockExceptionEncounteredSender>>();
|
|
m_bluetoothNotifier = std::make_shared<acsdkBluetooth::BluetoothNotifier>();
|
|
m_shutdownNotifier = std::make_shared<NiceMock<acsdkShutdownManagerInterfaces::test::MockShutdownNotifier>>();
|
|
m_mockAudioPipelineFactory =
|
|
std::make_shared<acsdkApplicationAudioPipelineFactoryInterfaces::test::MockApplicationAudioPipelineFactory>();
|
|
|
|
auto registrar =
|
|
std::make_shared<NiceMock<avsCommon::sdkInterfaces::endpoints::test::MockEndpointCapabilitiesRegistrar>>();
|
|
m_mockEndpointCapabilitiesRegistrar = acsdkManufactory::Annotated<
|
|
avsCommon::sdkInterfaces::endpoints::DefaultEndpointAnnotation,
|
|
avsCommon::sdkInterfaces::endpoints::EndpointCapabilitiesRegistrarInterface>(
|
|
registrar);
|
|
m_mockFocusManager = std::make_shared<NiceMock<MockFocusManager>>();
|
|
m_annotatedFocusManager = acsdkManufactory::
|
|
Annotated<avsCommon::sdkInterfaces::AudioFocusAnnotation, avsCommon::sdkInterfaces::FocusManagerInterface>(
|
|
m_mockFocusManager);
|
|
|
|
m_eventBus = std::make_shared<avsCommon::utils::bluetooth::BluetoothEventBus>();
|
|
m_mockBluetoothHostController = std::make_shared<NiceMock<MockBluetoothHostController>>();
|
|
m_mockDirectiveHandlerResult = std::unique_ptr<MockDirectiveHandlerResult>(new MockDirectiveHandlerResult);
|
|
m_mockBluetoothDeviceObserver = std::make_shared<NiceMock<acsdkBluetoothInterfaces::test::MockBluetoothDeviceObserver>>();
|
|
m_mockBluetoothMediaPlayer = MockMediaPlayer::create();
|
|
m_customerDataManager = std::make_shared<NiceMock<registrationManager::MockCustomerDataManager>>();
|
|
|
|
m_bluetoothNotifier->addObserver(m_mockBluetoothDeviceObserver);
|
|
|
|
/*
|
|
* Create Mock Devices.
|
|
*/
|
|
auto metaData =MockBluetoothDevice::MetaData(Optional<int>(), Optional<int>(),
|
|
MockBluetoothDevice::MetaData::UNDEFINED_CLASS_VALUE, Optional<int>(), Optional<std::string>());
|
|
auto a2dpSink = std::make_shared<NiceMock<MockBluetoothService>>(std::make_shared<A2DPSinkRecord>(""));
|
|
auto avrcpTarget = std::make_shared<NiceMock<MockBluetoothService>>(std::make_shared<AVRCPTargetRecord>(""));
|
|
std::vector<std::shared_ptr<BluetoothServiceInterface>> services = {a2dpSink, avrcpTarget};
|
|
m_mockBluetoothDevice1 = std::make_shared<NiceMock<MockBluetoothDevice>>(
|
|
TEST_BLUETOOTH_DEVICE_MAC, TEST_BLUETOOTH_FRIENDLY_NAME, metaData, services);
|
|
m_mockDiscoveredBluetoothDevices.push_back(m_mockBluetoothDevice1);
|
|
|
|
auto metaData2 =MockBluetoothDevice::MetaData(Optional<int>(), Optional<int>(),
|
|
MockBluetoothDevice::MetaData::UNDEFINED_CLASS_VALUE, Optional<int>(), Optional<std::string>());
|
|
auto hid = std::make_shared<NiceMock<MockBluetoothService>>(std::make_shared<HIDRecord>(""));
|
|
auto spp = std::make_shared<NiceMock<MockBluetoothService>>(std::make_shared<SPPRecord>(""));
|
|
auto a2dpSource = std::make_shared<NiceMock<MockBluetoothService>>(std::make_shared<A2DPSourceRecord>(""));
|
|
std::vector<std::shared_ptr<BluetoothServiceInterface>> services2 = {spp, hid, a2dpSource};
|
|
m_mockBluetoothDevice2 = std::make_shared<NiceMock<MockBluetoothDevice>>(
|
|
TEST_BLUETOOTH_DEVICE_MAC_2, TEST_BLUETOOTH_FRIENDLY_NAME_2, metaData2, services2);
|
|
m_mockDiscoveredBluetoothDevices.push_back(m_mockBluetoothDevice2);
|
|
|
|
auto metaData3 =MockBluetoothDevice::MetaData(Optional<int>(), Optional<int>(),
|
|
MockBluetoothDevice::MetaData::UNDEFINED_CLASS_VALUE, Optional<int>(), Optional<std::string>());
|
|
std::vector<std::shared_ptr<BluetoothServiceInterface>> services3 = {a2dpSink};
|
|
m_mockBluetoothDevice3 = std::make_shared<NiceMock<MockBluetoothDevice>>(
|
|
TEST_BLUETOOTH_DEVICE_MAC_3, TEST_BLUETOOTH_FRIENDLY_NAME_3, metaData3, services3);
|
|
m_mockDiscoveredBluetoothDevices.push_back(m_mockBluetoothDevice3);
|
|
|
|
/*
|
|
* Create mock device connection rules.
|
|
*/
|
|
std::set<DeviceCategory> remoteCategory{DeviceCategory::REMOTE_CONTROL};
|
|
std::set<std::string> remoteDependentProfiles{HIDInterface::UUID, SPPInterface::UUID};
|
|
m_remoteControlConnectionRule =
|
|
std::make_shared<NiceMock<MockBluetoothDeviceConnectionRule>>(remoteCategory, remoteDependentProfiles);
|
|
std::set<DeviceCategory> gadgetCategory{DeviceCategory::GADGET};
|
|
std::set<std::string> gadgetDependentProfiles{HIDInterface::UUID, SPPInterface::UUID};
|
|
m_gadgetConnectionRule =
|
|
std::make_shared<NiceMock<MockBluetoothDeviceConnectionRule>>(gadgetCategory, gadgetDependentProfiles);
|
|
/*
|
|
* GadgetConnectionRule:
|
|
* 1) No need to explicitly disconnect/connect device.
|
|
* 2) No devices needed to disconnect when a new device with DeviceCategory::GADGET connects.
|
|
*/
|
|
m_gadgetConnectionRule->setExplicitlyConnect(false);
|
|
m_gadgetConnectionRule->setExplicitlyDisconnect(true);
|
|
|
|
/*
|
|
* RemoteControlConnectionRule:
|
|
* 1) No need to explicitly disconnect/connect device.
|
|
* 2) Devices with DeviceCategory::REMOTE_CONTROL needed to disconnect when a new device with
|
|
* DeviceCategory::REMOTE_CONTROL connects.
|
|
*/
|
|
m_remoteControlConnectionRule->setExplicitlyConnect(false);
|
|
m_remoteControlConnectionRule->setExplicitlyDisconnect(false);
|
|
|
|
std::unordered_set<std::shared_ptr<BluetoothDeviceConnectionRuleInterface>> mockConnectionRules =
|
|
{m_remoteControlConnectionRule, m_gadgetConnectionRule, BasicDeviceConnectionRule::create()};
|
|
m_connectionRulesProvider = std::make_shared<acsdkBluetooth::DeviceConnectionRulesAdapter>(mockConnectionRules);
|
|
|
|
/**
|
|
* create MockChannelVolumeInterface for ducking.
|
|
*/
|
|
m_mockChannelVolumeInterface = std::make_shared<MockChannelVolumeInterface>();
|
|
m_mockChannelVolumeInterface->DelegateToReal();
|
|
|
|
/**
|
|
* Set up expected calls to injected objects.
|
|
*/
|
|
EXPECT_CALL(
|
|
*(m_mockAudioPipelineFactory.get()),
|
|
createApplicationMediaInterfaces(acsdkBluetooth::BLUETOOTH_MEDIA_PLAYER_NAME, _, _, _, _, _))
|
|
.WillRepeatedly(Return(std::make_shared<avsCommon::sdkInterfaces::ApplicationMediaInterfaces>(
|
|
m_mockBluetoothMediaPlayer, nullptr, nullptr, nullptr, m_mockChannelVolumeInterface)));
|
|
EXPECT_CALL(
|
|
*(registrar.get()),
|
|
withCapability(A<const std::shared_ptr<avsCommon::sdkInterfaces::CapabilityConfigurationInterface>&>(), _))
|
|
.WillRepeatedly(ReturnRef(
|
|
*(std::make_shared<avsCommon::sdkInterfaces::endpoints::test::MockEndpointCapabilitiesRegistrar>()).get()));
|
|
|
|
/*
|
|
* Generate a Bluetooth database for testing.
|
|
* Ensure the db file does not exist already. We don't want to overwrite anything.
|
|
*/
|
|
if (fileExists(TEST_DATABASE)) {
|
|
ADD_FAILURE() << FILE_EXISTS_ERROR;
|
|
exit(1);
|
|
}
|
|
auto json = std::shared_ptr<std::stringstream>(new std::stringstream());
|
|
*json << BLUETOOTH_JSON;
|
|
std::vector<std::shared_ptr<std::istream>> jsonStream;
|
|
jsonStream.push_back(json);
|
|
ConfigurationNode::initialize(jsonStream);
|
|
m_bluetoothStorage = SQLiteBluetoothStorage::create(ConfigurationNode::getRoot());
|
|
ASSERT_TRUE(m_bluetoothStorage->createDatabase());
|
|
// Insert the test device data into the test database
|
|
m_bluetoothStorage->insertByMac(TEST_BLUETOOTH_DEVICE_MAC, TEST_BLUETOOTH_UUID, true);
|
|
m_bluetoothStorage->insertByMac(TEST_BLUETOOTH_DEVICE_MAC_2, TEST_BLUETOOTH_UUID_2, true);
|
|
m_bluetoothStorage->insertByMac(TEST_BLUETOOTH_DEVICE_MAC_3, TEST_BLUETOOTH_UUID_3, true);
|
|
m_bluetoothStorage->close();
|
|
|
|
m_Bluetooth = Bluetooth::createBluetoothCapabilityAgent(
|
|
m_mockContextManager,
|
|
m_mockMessageSender,
|
|
m_mockExceptionSender,
|
|
m_bluetoothStorage,
|
|
avsCommon::utils::memory::make_unique<NiceMock<MockBluetoothDeviceManager>>(
|
|
m_mockBluetoothHostController, m_mockDiscoveredBluetoothDevices, m_eventBus),
|
|
m_eventBus,
|
|
m_customerDataManager,
|
|
m_mockAudioPipelineFactory,
|
|
m_annotatedFocusManager,
|
|
m_shutdownNotifier,
|
|
m_mockEndpointCapabilitiesRegistrar,
|
|
m_connectionRulesProvider,
|
|
nullptr,
|
|
m_bluetoothNotifier);
|
|
ASSERT_THAT(m_Bluetooth, NotNull());
|
|
}
|
|
|
|
void BluetoothTest::TearDown() {
|
|
m_bluetoothNotifier->removeObserver(m_mockBluetoothDeviceObserver);
|
|
if (m_Bluetooth) {
|
|
m_Bluetooth->shutdown();
|
|
}
|
|
m_mockBluetoothMediaPlayer->shutdown();
|
|
if (fileExists(TEST_DATABASE)) {
|
|
remove(TEST_DATABASE.c_str());
|
|
}
|
|
|
|
m_bluetoothStorage->updateByCategory(TEST_BLUETOOTH_UUID, deviceCategoryToString(DeviceCategory::UNKNOWN));
|
|
m_bluetoothStorage->updateByCategory(TEST_BLUETOOTH_UUID_2, deviceCategoryToString(DeviceCategory::UNKNOWN));
|
|
m_bluetoothStorage->updateByCategory(TEST_BLUETOOTH_UUID_3, deviceCategoryToString(DeviceCategory::UNKNOWN));
|
|
}
|
|
|
|
void BluetoothTest::wakeOnSetCompleted() {
|
|
m_wakeSetCompletedPromise.set_value();
|
|
}
|
|
|
|
std::string BluetoothTest::getRequestName(std::shared_ptr<alexaClientSDK::avsCommon::avs::MessageRequest> request) {
|
|
rapidjson::Document document;
|
|
document.Parse(request->getJsonContent().c_str());
|
|
EXPECT_FALSE(document.HasParseError());
|
|
|
|
auto event = document.FindMember(MESSAGE_EVENT_KEY);
|
|
EXPECT_NE(event, document.MemberEnd());
|
|
|
|
auto header = event->value.FindMember(MESSAGE_HEADER_KEY);
|
|
EXPECT_NE(header, event->value.MemberEnd());
|
|
|
|
auto payload = event->value.FindMember(PAYLOAD_KEY);
|
|
EXPECT_NE(payload, event->value.MemberEnd());
|
|
|
|
std::string requestName;
|
|
jsonUtils::retrieveValue(header->value, MESSAGE_NAME_KEY, &requestName);
|
|
return requestName;
|
|
}
|
|
|
|
bool BluetoothTest::verifyMessage(std::shared_ptr<alexaClientSDK::avsCommon::avs::MessageRequest> request,
|
|
std::string expectedName) {
|
|
return getRequestName(request) == expectedName;
|
|
}
|
|
|
|
bool BluetoothTest::verifyMessagesSentInOrder(std::vector<std::string> orderedEvents, std::function<void()> trigger) {
|
|
size_t curIndex = 0;
|
|
std::mutex waitMutex;
|
|
|
|
EXPECT_CALL(*m_mockMessageSender, sendMessage(_))
|
|
.Times(AtLeast(1))
|
|
.WillRepeatedly(
|
|
Invoke([this, orderedEvents, &curIndex](std::shared_ptr<avsCommon::avs::MessageRequest> request) {
|
|
if (curIndex < orderedEvents.size()) {
|
|
if (verifyMessage(request, orderedEvents.at(curIndex))) {
|
|
if (curIndex < orderedEvents.size()) {
|
|
curIndex++;
|
|
}
|
|
}
|
|
}
|
|
m_messageSentTrigger.notify_one();
|
|
}));
|
|
|
|
trigger();
|
|
|
|
bool result;
|
|
{
|
|
std::unique_lock<std::mutex> lock(waitMutex);
|
|
result = m_messageSentTrigger.wait_for(lock, WAIT_TIMEOUT_MS, [orderedEvents, &curIndex] {
|
|
if (curIndex == orderedEvents.size()) {
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void BluetoothTest::verifyMessagesCount(std::shared_ptr<alexaClientSDK::avsCommon::avs::MessageRequest> request,
|
|
std::map<std::string, int>* messages) {
|
|
std::string requestName = getRequestName(request);
|
|
|
|
if (messages->find(requestName) != messages->end()) {
|
|
messages->at(requestName) += 1;
|
|
}
|
|
}
|
|
|
|
/// Test that create() returns a nullptr if called with invalid arguments.
|
|
TEST_F(BluetoothTest, test_createBTWithNullParams) {
|
|
// Create Bluetooth CapabilityAgent with null @c ContextManager.
|
|
auto bluetooth1 = Bluetooth::createBluetoothCapabilityAgent(
|
|
nullptr,
|
|
m_mockMessageSender,
|
|
m_mockExceptionSender,
|
|
m_bluetoothStorage,
|
|
avsCommon::utils::memory::make_unique<NiceMock<MockBluetoothDeviceManager>>(
|
|
m_mockBluetoothHostController, m_mockDiscoveredBluetoothDevices, m_eventBus),
|
|
m_eventBus,
|
|
m_customerDataManager,
|
|
m_mockAudioPipelineFactory,
|
|
m_annotatedFocusManager,
|
|
m_shutdownNotifier,
|
|
m_mockEndpointCapabilitiesRegistrar,
|
|
m_connectionRulesProvider,
|
|
nullptr,
|
|
m_bluetoothNotifier);
|
|
EXPECT_THAT(bluetooth1, IsNull());
|
|
|
|
// Create Bluetooth CapabilityAgent with null @c FocusManager
|
|
auto bluetooth2 = Bluetooth::createBluetoothCapabilityAgent(
|
|
m_mockContextManager,
|
|
m_mockMessageSender,
|
|
m_mockExceptionSender,
|
|
m_bluetoothStorage,
|
|
avsCommon::utils::memory::make_unique<NiceMock<MockBluetoothDeviceManager>>(
|
|
m_mockBluetoothHostController, m_mockDiscoveredBluetoothDevices, m_eventBus),
|
|
m_eventBus,
|
|
m_customerDataManager,
|
|
m_mockAudioPipelineFactory,
|
|
nullptr,
|
|
m_shutdownNotifier,
|
|
m_mockEndpointCapabilitiesRegistrar,
|
|
m_connectionRulesProvider,
|
|
nullptr,
|
|
m_bluetoothNotifier);
|
|
EXPECT_THAT(bluetooth2, IsNull());
|
|
|
|
// Create Bluetooth CapabilityAgent with null @c MessageSender
|
|
auto bluetooth3 = Bluetooth::createBluetoothCapabilityAgent(
|
|
m_mockContextManager,
|
|
nullptr,
|
|
m_mockExceptionSender,
|
|
m_bluetoothStorage,
|
|
avsCommon::utils::memory::make_unique<NiceMock<MockBluetoothDeviceManager>>(
|
|
m_mockBluetoothHostController, m_mockDiscoveredBluetoothDevices, m_eventBus),
|
|
m_eventBus,
|
|
m_customerDataManager,
|
|
m_mockAudioPipelineFactory,
|
|
m_annotatedFocusManager,
|
|
m_shutdownNotifier,
|
|
m_mockEndpointCapabilitiesRegistrar,
|
|
m_connectionRulesProvider,
|
|
nullptr,
|
|
m_bluetoothNotifier);
|
|
EXPECT_THAT(bluetooth3, IsNull());
|
|
|
|
// Create Bluetooth CapabilityAgent with null @c ExceptionEncounterSender
|
|
auto bluetooth4 = Bluetooth::createBluetoothCapabilityAgent(
|
|
m_mockContextManager,
|
|
m_mockMessageSender,
|
|
nullptr,
|
|
m_bluetoothStorage,
|
|
avsCommon::utils::memory::make_unique<NiceMock<MockBluetoothDeviceManager>>(
|
|
m_mockBluetoothHostController, m_mockDiscoveredBluetoothDevices, m_eventBus),
|
|
m_eventBus,
|
|
m_customerDataManager,
|
|
m_mockAudioPipelineFactory,
|
|
m_annotatedFocusManager,
|
|
m_shutdownNotifier,
|
|
m_mockEndpointCapabilitiesRegistrar,
|
|
m_connectionRulesProvider,
|
|
nullptr,
|
|
m_bluetoothNotifier);
|
|
EXPECT_THAT(bluetooth4, IsNull());
|
|
|
|
// Create Bluetooth CapabilityAgent with null @c BluetoothStorage
|
|
auto bluetooth5 = Bluetooth::createBluetoothCapabilityAgent(
|
|
m_mockContextManager,
|
|
m_mockMessageSender,
|
|
m_mockExceptionSender,
|
|
nullptr,
|
|
avsCommon::utils::memory::make_unique<NiceMock<MockBluetoothDeviceManager>>(
|
|
m_mockBluetoothHostController, m_mockDiscoveredBluetoothDevices, m_eventBus),
|
|
m_eventBus,
|
|
m_customerDataManager,
|
|
m_mockAudioPipelineFactory,
|
|
m_annotatedFocusManager,
|
|
m_shutdownNotifier,
|
|
m_mockEndpointCapabilitiesRegistrar,
|
|
m_connectionRulesProvider,
|
|
nullptr,
|
|
m_bluetoothNotifier);
|
|
EXPECT_THAT(bluetooth5, IsNull());
|
|
|
|
// Create Bluetooth CapabilityAgent with null @c DeviceManager
|
|
auto bluetooth6 = Bluetooth::createBluetoothCapabilityAgent(
|
|
m_mockContextManager,
|
|
m_mockMessageSender,
|
|
m_mockExceptionSender,
|
|
m_bluetoothStorage,
|
|
nullptr,
|
|
m_eventBus,
|
|
m_customerDataManager,
|
|
m_mockAudioPipelineFactory,
|
|
m_annotatedFocusManager,
|
|
m_shutdownNotifier,
|
|
m_mockEndpointCapabilitiesRegistrar,
|
|
m_connectionRulesProvider,
|
|
nullptr,
|
|
m_bluetoothNotifier);
|
|
EXPECT_THAT(bluetooth6, IsNull());
|
|
|
|
// Create Bluetooth CapabilityAgent with null @c BluetoothEventBus
|
|
auto bluetooth7 = Bluetooth::createBluetoothCapabilityAgent(
|
|
m_mockContextManager,
|
|
m_mockMessageSender,
|
|
m_mockExceptionSender,
|
|
m_bluetoothStorage,
|
|
avsCommon::utils::memory::make_unique<NiceMock<MockBluetoothDeviceManager>>(
|
|
m_mockBluetoothHostController, m_mockDiscoveredBluetoothDevices, m_eventBus),
|
|
nullptr,
|
|
m_customerDataManager,
|
|
m_mockAudioPipelineFactory,
|
|
m_annotatedFocusManager,
|
|
m_shutdownNotifier,
|
|
m_mockEndpointCapabilitiesRegistrar,
|
|
m_connectionRulesProvider,
|
|
nullptr,
|
|
m_bluetoothNotifier);
|
|
EXPECT_THAT(bluetooth7, IsNull());
|
|
|
|
// Create Bluetooth CapabilityAgent with null @c ApplicationAudioPipelineFactoryInterface
|
|
auto bluetooth8 = Bluetooth::createBluetoothCapabilityAgent(
|
|
m_mockContextManager,
|
|
m_mockMessageSender,
|
|
m_mockExceptionSender,
|
|
m_bluetoothStorage,
|
|
avsCommon::utils::memory::make_unique<NiceMock<MockBluetoothDeviceManager>>(
|
|
m_mockBluetoothHostController, m_mockDiscoveredBluetoothDevices, m_eventBus),
|
|
m_eventBus,
|
|
m_customerDataManager,
|
|
nullptr,
|
|
m_annotatedFocusManager,
|
|
m_shutdownNotifier,
|
|
m_mockEndpointCapabilitiesRegistrar,
|
|
m_connectionRulesProvider,
|
|
nullptr,
|
|
m_bluetoothNotifier);
|
|
EXPECT_THAT(bluetooth8, IsNull());
|
|
|
|
// Create Bluetooth CapabilityAgent with null @c EndpointCapabilitiesRegistrar.
|
|
auto bluetooth9 = Bluetooth::createBluetoothCapabilityAgent(
|
|
m_mockContextManager,
|
|
m_mockMessageSender,
|
|
m_mockExceptionSender,
|
|
m_bluetoothStorage,
|
|
avsCommon::utils::memory::make_unique<NiceMock<MockBluetoothDeviceManager>>(
|
|
m_mockBluetoothHostController, m_mockDiscoveredBluetoothDevices, m_eventBus),
|
|
m_eventBus,
|
|
m_customerDataManager,
|
|
m_mockAudioPipelineFactory,
|
|
m_annotatedFocusManager,
|
|
m_shutdownNotifier,
|
|
nullptr,
|
|
m_connectionRulesProvider,
|
|
nullptr,
|
|
m_bluetoothNotifier);
|
|
EXPECT_THAT(bluetooth9, IsNull());
|
|
|
|
// Create Bluetooth CapabilityAgent with null @c BluetoothNotifier.
|
|
auto bluetooth10 = Bluetooth::createBluetoothCapabilityAgent(
|
|
m_mockContextManager,
|
|
m_mockMessageSender,
|
|
m_mockExceptionSender,
|
|
m_bluetoothStorage,
|
|
avsCommon::utils::memory::make_unique<NiceMock<MockBluetoothDeviceManager>>(
|
|
m_mockBluetoothHostController, m_mockDiscoveredBluetoothDevices, m_eventBus),
|
|
m_eventBus,
|
|
m_customerDataManager,
|
|
m_mockAudioPipelineFactory,
|
|
m_annotatedFocusManager,
|
|
m_shutdownNotifier,
|
|
m_mockEndpointCapabilitiesRegistrar,
|
|
m_connectionRulesProvider,
|
|
nullptr,
|
|
nullptr);
|
|
EXPECT_THAT(bluetooth10, IsNull());
|
|
|
|
// Create Bluetooth CapabilityAgent with null @c ShutdownNotifier.
|
|
auto bluetooth11 = Bluetooth::createBluetoothCapabilityAgent(
|
|
m_mockContextManager,
|
|
m_mockMessageSender,
|
|
m_mockExceptionSender,
|
|
m_bluetoothStorage,
|
|
avsCommon::utils::memory::make_unique<NiceMock<MockBluetoothDeviceManager>>(
|
|
m_mockBluetoothHostController, m_mockDiscoveredBluetoothDevices, m_eventBus),
|
|
m_eventBus,
|
|
m_customerDataManager,
|
|
m_mockAudioPipelineFactory,
|
|
m_annotatedFocusManager,
|
|
nullptr,
|
|
m_mockEndpointCapabilitiesRegistrar,
|
|
m_connectionRulesProvider,
|
|
nullptr,
|
|
m_bluetoothNotifier);
|
|
EXPECT_THAT(bluetooth11, IsNull());
|
|
}
|
|
|
|
/**
|
|
* Test that create() returns a nullptr if called with an invalid set of device connection rules.
|
|
* Fail due to re-defined device category.
|
|
*/
|
|
TEST_F(BluetoothTest, test_createBTWithDuplicateDeviceCategoriesInConnectionRules) {
|
|
std::set<DeviceCategory> categories1{DeviceCategory::REMOTE_CONTROL};
|
|
std::set<DeviceCategory> categories2{DeviceCategory::REMOTE_CONTROL, DeviceCategory::GADGET};
|
|
std::set<std::string> dependentProfiles{HIDInterface::UUID, SPPInterface::UUID};
|
|
auto mockDeviceConnectionRule1 =
|
|
std::make_shared<MockBluetoothDeviceConnectionRule>(categories1, dependentProfiles);
|
|
auto mockDeviceConnectionRule2 =
|
|
std::make_shared<MockBluetoothDeviceConnectionRule>(categories2, dependentProfiles);
|
|
std::unordered_set<std::shared_ptr<BluetoothDeviceConnectionRuleInterface>> enabledRules =
|
|
{mockDeviceConnectionRule1, mockDeviceConnectionRule2};
|
|
|
|
auto connectionRulesProvider = std::make_shared<acsdkBluetooth::DeviceConnectionRulesAdapter>(enabledRules);
|
|
|
|
auto bluetooth = Bluetooth::createBluetoothCapabilityAgent(
|
|
m_mockContextManager,
|
|
m_mockMessageSender,
|
|
m_mockExceptionSender,
|
|
m_bluetoothStorage,
|
|
avsCommon::utils::memory::make_unique<NiceMock<MockBluetoothDeviceManager>>(
|
|
m_mockBluetoothHostController, m_mockDiscoveredBluetoothDevices, m_eventBus),
|
|
m_eventBus,
|
|
m_customerDataManager,
|
|
m_mockAudioPipelineFactory,
|
|
m_annotatedFocusManager,
|
|
m_shutdownNotifier,
|
|
m_mockEndpointCapabilitiesRegistrar,
|
|
connectionRulesProvider,
|
|
nullptr,
|
|
m_bluetoothNotifier);
|
|
ASSERT_THAT(bluetooth, IsNull());
|
|
}
|
|
|
|
/**
|
|
* Test that create() returns a nullptr if called with an invalid set of device connection rules.
|
|
* Fail due to lack of dependent profiles defined in the device connection rule.
|
|
*/
|
|
TEST_F(BluetoothTest, test_createBTWithLackOfProfilesInConnectionRules) {
|
|
std::set<DeviceCategory> categories{DeviceCategory::REMOTE_CONTROL};
|
|
std::set<std::string> dependentProfiles{HIDInterface::UUID};
|
|
auto mockDeviceConnectionRule = std::make_shared<MockBluetoothDeviceConnectionRule>(categories, dependentProfiles);
|
|
std::unordered_set<std::shared_ptr<BluetoothDeviceConnectionRuleInterface>> enabledRules =
|
|
{mockDeviceConnectionRule};
|
|
|
|
auto connectionRulesProvider = std::make_shared<acsdkBluetooth::DeviceConnectionRulesAdapter>(enabledRules);
|
|
|
|
auto bluetooth = Bluetooth::createBluetoothCapabilityAgent(
|
|
m_mockContextManager,
|
|
m_mockMessageSender,
|
|
m_mockExceptionSender,
|
|
m_bluetoothStorage,
|
|
avsCommon::utils::memory::make_unique<NiceMock<MockBluetoothDeviceManager>>(
|
|
m_mockBluetoothHostController, m_mockDiscoveredBluetoothDevices, m_eventBus),
|
|
m_eventBus,
|
|
m_customerDataManager,
|
|
m_mockAudioPipelineFactory,
|
|
m_annotatedFocusManager,
|
|
m_shutdownNotifier,
|
|
m_mockEndpointCapabilitiesRegistrar,
|
|
connectionRulesProvider,
|
|
nullptr,
|
|
m_bluetoothNotifier);
|
|
ASSERT_THAT(bluetooth, IsNull());
|
|
}
|
|
|
|
/**
|
|
* Test call to handle ConnectByDeviceIds directive with two matched A2DP device UUIDs.
|
|
*
|
|
* Assumption:
|
|
* A @c DeviceManager contains m_mockBluetoothDevice1 and m_mockBluetoothDevice2. Both of them belong to
|
|
* DeviceCategory::UNKNOWN. Both devices are in disconnected state.
|
|
* Use case:
|
|
* A ConnectByDeviceIds directive is sent down, whose payload contains the mockBluetoothDevice1 and
|
|
* mockBluetoothDevice2 UUIDs.
|
|
* Expected result:
|
|
* 1) Only one device which connects later(m_mockBluetoothDevice1) will be connected eventually even
|
|
* though both of them were connected successfully. However, The earlier connected device(m_mockBluetoothDevice2
|
|
* in this case) will be disconnected due to @c BasicDeviceConnectionRule.
|
|
* 2) The observer should be notified device connection twice and disconnection once.
|
|
* 3) Two @c ConnectByDeviceIdsSucceed events, both of which have CLOUD as @c Requester, and one
|
|
* @c DisconnectDevicesSucceed event, should be sent to cloud.
|
|
*/
|
|
TEST_F(BluetoothTest, test_handleConnectByDeviceIdsDirectiveWithTwoA2DPDevices) {
|
|
EXPECT_CALL(*m_mockBluetoothDeviceObserver, onActiveDeviceConnected(_)).Times(Exactly(2));
|
|
EXPECT_CALL(*m_mockBluetoothDeviceObserver, onActiveDeviceDisconnected(_)).Times(Exactly(1));
|
|
EXPECT_CALL(*(m_mockDirectiveHandlerResult.get()), setCompleted())
|
|
.Times(1)
|
|
.WillOnce(InvokeWithoutArgs(this, &BluetoothTest::wakeOnSetCompleted));
|
|
EXPECT_CALL(*m_mockContextManager, setState(BLUETOOTH_STATE, _, StateRefreshPolicy::NEVER, _)).Times(Exactly(3));
|
|
std::vector<std::string> events = {CONNECT_BY_DEVICE_IDS_SUCCEEDED, CONNECT_BY_DEVICE_IDS_SUCCEEDED,
|
|
DISCONNECT_DEVICES_SUCCEEDED};
|
|
ASSERT_TRUE(verifyMessagesSentInOrder(events, [this]() {
|
|
// Create ConnectedByDeviceId Directive.
|
|
auto attachmentManager = std::make_shared<StrictMock<MockAttachmentManager>>();
|
|
auto avsMessageHeader =
|
|
std::make_shared<AVSMessageHeader>(NAMESPACE_BLUETOOTH, CONNECT_BY_DEVICE_IDS_DIRECTIVE, TEST_MESSAGE_ID);
|
|
std::shared_ptr<AVSDirective> directive =
|
|
AVSDirective::create("", avsMessageHeader, TEST_CONNECT_BY_DEVICE_IDS_PAYLOAD, attachmentManager, "");
|
|
// cast to DirectiveHandlerInterface so the compiler can find the correct preHandleDirective signature
|
|
std::shared_ptr<DirectiveHandlerInterface> agentAsDirectiveHandler = m_Bluetooth;
|
|
agentAsDirectiveHandler->preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult));
|
|
agentAsDirectiveHandler->handleDirective(TEST_MESSAGE_ID);
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
|
|
/*
|
|
* Mimic the @c DeviceStateChangedEvent which should happen after device connection status changes.
|
|
* In order to guarantee that all @c DeviceStateChangedEvent happen after the corresponding device connection
|
|
* status changes, force the test to wait EVENT_PROCESS_DELAY_MS.
|
|
*
|
|
* TODO: Add send event to @c BluetoothEventBus within @c MockBluetoothDevice.
|
|
*/
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(EVENT_PROCESS_DELAY_MS));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice2, DeviceState::CONNECTED));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::CONNECTED));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice2, DeviceState::DISCONNECTED));
|
|
}));
|
|
|
|
// Verify the connection result.
|
|
ASSERT_TRUE(m_mockBluetoothDevice1->isConnected());
|
|
ASSERT_FALSE(m_mockBluetoothDevice2->isConnected());
|
|
}
|
|
|
|
/**
|
|
* Test call to handle ConnectByDeviceIds directive with two matched device UUIDs with different device categories.
|
|
*
|
|
* Assumption:
|
|
* A @c DeviceManager contains m_mockBluetoothDevice1 and m_mockBluetoothDevice2. m_mockBluetoothDevice1
|
|
* belongs to DeviceCategory::PHONE, m_mockBluetoothDevice2 belongs to DeviceCategory::GADGET. Both devices are
|
|
* in disconnect state.
|
|
* Use case:
|
|
* A ConnectByDeviceIds directive is sent down, whose payload contains the mockBluetoothDevice1 and
|
|
* mockBluetoothDevice2.
|
|
* Expected result:
|
|
* 1)Both devices should be connected successfully.
|
|
* 2)The observer should be notified deivce connection twice.
|
|
* 3)Two @c ConnectByDeviceIdsSucceed events, both of which have CLOUD as @c Requester,should be sent to cloud.
|
|
*/
|
|
TEST_F(BluetoothTest, test_handleConnectByDeviceIdsDirectiveWithOnePhoneOneGadget) {
|
|
m_mockBluetoothDevice1->disconnect();
|
|
m_mockBluetoothDevice2->disconnect();
|
|
// Initially, all devices are stored as DeviceCategory::UNKNOWN. Need to manually update device category in order
|
|
// to test.
|
|
m_bluetoothStorage->updateByCategory(TEST_BLUETOOTH_UUID, deviceCategoryToString(DeviceCategory::PHONE));
|
|
m_bluetoothStorage->updateByCategory(TEST_BLUETOOTH_UUID_2, deviceCategoryToString(DeviceCategory::GADGET));
|
|
|
|
EXPECT_CALL(*m_mockBluetoothDeviceObserver, onActiveDeviceConnected(_)).Times(Exactly(2));
|
|
EXPECT_CALL(*(m_mockDirectiveHandlerResult.get()), setCompleted())
|
|
.Times(1)
|
|
.WillOnce(InvokeWithoutArgs(this, &BluetoothTest::wakeOnSetCompleted));
|
|
EXPECT_CALL(*m_mockContextManager, setState(BLUETOOTH_STATE, _, StateRefreshPolicy::NEVER, _)).Times(Exactly(2));
|
|
// Verify the @c ConnectByDeviceIdsSucceed event.
|
|
std::vector<std::string> events = {CONNECT_BY_DEVICE_IDS_SUCCEEDED, CONNECT_BY_DEVICE_IDS_SUCCEEDED};
|
|
ASSERT_TRUE(verifyMessagesSentInOrder(events, [this]() {
|
|
// Create ConnectedByDeviceId Directive.
|
|
auto attachmentManager = std::make_shared<StrictMock<MockAttachmentManager>>();
|
|
auto avsMessageHeader =
|
|
std::make_shared<AVSMessageHeader>(NAMESPACE_BLUETOOTH, CONNECT_BY_DEVICE_IDS_DIRECTIVE, TEST_MESSAGE_ID);
|
|
std::shared_ptr<AVSDirective> directive =
|
|
AVSDirective::create("", avsMessageHeader, TEST_CONNECT_BY_DEVICE_IDS_PAYLOAD, attachmentManager, "");
|
|
// cast to DirectiveHandlerInterface so the compiler can find the correct preHandleDirective signature
|
|
std::shared_ptr<DirectiveHandlerInterface> agentAsDirectiveHandler = m_Bluetooth;
|
|
agentAsDirectiveHandler->preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult));
|
|
agentAsDirectiveHandler->handleDirective(TEST_MESSAGE_ID);
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(EVENT_PROCESS_DELAY_MS));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice2, DeviceState::CONNECTED));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::CONNECTED));
|
|
}));
|
|
|
|
// Verify the connection result.
|
|
ASSERT_TRUE(m_mockBluetoothDevice1->isConnected());
|
|
ASSERT_TRUE(m_mockBluetoothDevice2->isConnected());
|
|
}
|
|
|
|
/**
|
|
* Test call to handle ConnectByDeviceProfile directive with an unmatched profile name.
|
|
*
|
|
* Assumption:
|
|
* A @c DeviceManager contains m_mockBluetoothDevice1 and m_mockBluetoothDevice2.
|
|
* m_mockBluetoothDevice1 has @c A2DPSinkInterface and @c AVRCPTargetInterface services.
|
|
* m_mockBluetoothDevice2 has @c HIDInterface and @c SPPInterface services.
|
|
* Use case:
|
|
* A @c ConnectByProfile directive is sent down, which contains @c HFPInterface as a profile.
|
|
* Expected result:
|
|
* 1) m_mockBluetoothDevice1 and m_mockBluetoothDevice2 should not be connected successfully.
|
|
* 2) Because no device is connected, the observer should not be notified.
|
|
* 3) One @c ConnectByDeviceProfileFailed event should be sent to cloud.
|
|
*/
|
|
TEST_F(BluetoothTest, test_handleConnectByProfileWithUnmatchedProfileName) {
|
|
/*
|
|
* Because We're only connecting devices that have been previously connected and currently paired.
|
|
* Therefore, assume m_mockBluetoothDevice1 and m_mockBluetoothDevice2 are currently paired.
|
|
*/
|
|
m_mockBluetoothDevice1->pair();
|
|
m_mockBluetoothDevice2->pair();
|
|
|
|
EXPECT_CALL(*m_mockBluetoothDeviceObserver, onActiveDeviceConnected(_)).Times(Exactly(0));
|
|
EXPECT_CALL(*(m_mockDirectiveHandlerResult.get()), setCompleted())
|
|
.Times(1)
|
|
.WillOnce(InvokeWithoutArgs(this, &BluetoothTest::wakeOnSetCompleted));
|
|
EXPECT_CALL(*m_mockContextManager, setState(BLUETOOTH_STATE, _, StateRefreshPolicy::NEVER, _)).Times(Exactly(1));
|
|
std::vector<std::string> events = {CONNECT_BY_PROFILE_FAILED};
|
|
ASSERT_TRUE(verifyMessagesSentInOrder(events, [this]() {
|
|
// Create ConnectedByDeviceId Directive.
|
|
auto attachmentManager = std::make_shared<StrictMock<MockAttachmentManager>>();
|
|
auto avsMessageHeader =
|
|
std::make_shared<AVSMessageHeader>(NAMESPACE_BLUETOOTH, CONNECT_BY_PROFILE_DIRECTIVE, TEST_MESSAGE_ID);
|
|
std::shared_ptr<AVSDirective> directive =
|
|
AVSDirective::create("", avsMessageHeader, TEST_CONNECT_BY_PROFILE_PAYLOAD_1, attachmentManager, "");
|
|
// cast to DirectiveHandlerInterface so the compiler can find the correct preHandleDirective signature
|
|
std::shared_ptr<DirectiveHandlerInterface> agentAsDirectiveHandler = m_Bluetooth;
|
|
agentAsDirectiveHandler->preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult));
|
|
agentAsDirectiveHandler->handleDirective(TEST_MESSAGE_ID);
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
}));
|
|
|
|
ASSERT_FALSE(m_mockBluetoothDevice1->isConnected());
|
|
ASSERT_FALSE(m_mockBluetoothDevice2->isConnected());
|
|
}
|
|
|
|
/**
|
|
* Test call to handle ConnectByDeviceProfile directive with a matched profile.
|
|
*
|
|
* Assumption:
|
|
* A @c DeviceManager contains m_mockBluetoothDevice1 and m_mockBluetoothDevice2.
|
|
* m_mockBluetoothDevice1 has @c A2DPSinkInterface and @c AVRCPTargetInterface services.
|
|
* m_mockBluetoothDevice2 has @c HIDInterface and @c SPPInterface services.
|
|
* Use case:
|
|
* A @c ConnectByProfile directive is sent down, which contains @c AVRCPTargetInterface as a profile.
|
|
* Expected result:
|
|
* 1) m_mockBluetoothDevice1 should be connected successfully.
|
|
* 2) m_mockBluetoothDevice2 should not be connected.
|
|
* 3) Because m_mockBluetoothDevice is connected, the observer should be notificed once.
|
|
* 4) One @c ConnectByDeviceProfileSucceeded event should be sent to cloud.
|
|
*/
|
|
TEST_F(BluetoothTest, test_handleConnectByProfileWithMatchedProfileName) {
|
|
std::mutex waitMutex;
|
|
std::unique_lock<std::mutex> waitLock(waitMutex);
|
|
|
|
// Assume devices are paired previously.
|
|
m_mockBluetoothDevice1->pair();
|
|
m_mockBluetoothDevice2->pair();
|
|
|
|
EXPECT_CALL(*m_mockBluetoothDeviceObserver, onActiveDeviceConnected(_)).Times(Exactly(1));
|
|
EXPECT_CALL(*(m_mockDirectiveHandlerResult.get()), setCompleted())
|
|
.Times(1)
|
|
.WillOnce(InvokeWithoutArgs(this, &BluetoothTest::wakeOnSetCompleted));
|
|
std::vector<std::string> events = {CONNECT_BY_PROFILE_SUCCEEDED};
|
|
ASSERT_TRUE(verifyMessagesSentInOrder(events, [this]() {
|
|
// Create ConnectedByDeviceId Directive.
|
|
auto attachmentManager = std::make_shared<StrictMock<MockAttachmentManager>>();
|
|
auto avsMessageHeader =
|
|
std::make_shared<AVSMessageHeader>(NAMESPACE_BLUETOOTH, CONNECT_BY_PROFILE_DIRECTIVE, TEST_MESSAGE_ID);
|
|
std::shared_ptr<AVSDirective> directive =
|
|
AVSDirective::create("", avsMessageHeader, TEST_CONNECT_BY_PROFILE_PAYLOAD_2, attachmentManager, "");
|
|
// cast to DirectiveHandlerInterface so the compiler can find the correct preHandleDirective signature
|
|
std::shared_ptr<DirectiveHandlerInterface> agentAsDirectiveHandler = m_Bluetooth;
|
|
agentAsDirectiveHandler->preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult));
|
|
agentAsDirectiveHandler->handleDirective(TEST_MESSAGE_ID);
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(EVENT_PROCESS_DELAY_MS));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::CONNECTED));
|
|
}));
|
|
|
|
ASSERT_TRUE(m_mockBluetoothDevice1->isConnected());
|
|
ASSERT_FALSE(m_mockBluetoothDevice2->isConnected());
|
|
}
|
|
|
|
/**
|
|
* Test call to handle the local connect() method.
|
|
*
|
|
* Assumption:
|
|
* A @c DeviceManager contains m_mockBluetoothDevice1. The device belongs to
|
|
* DeviceCategory::UNKNOWN. The device is in disconnected state.
|
|
* Use case:
|
|
* A local connect() call is made with the MAC address of m_mockBluetoothDevice1.
|
|
* Expected result:
|
|
* 1) m_mockBluetoothDevice1 connects.
|
|
* 2) The observer should be notified of device connection once.
|
|
* 3) One @c ConnectByDeviceIdsSucceed event.
|
|
*/
|
|
TEST_F(BluetoothTest, test_handleConnectLocal) {
|
|
EXPECT_CALL(*m_mockBluetoothDeviceObserver, onActiveDeviceConnected(_)).Times(Exactly(1));
|
|
EXPECT_CALL(*m_mockContextManager, setState(BLUETOOTH_STATE, _, StateRefreshPolicy::NEVER, _)).Times(Exactly(1));
|
|
std::vector<std::string> events = {CONNECT_BY_DEVICE_IDS_SUCCEEDED};
|
|
ASSERT_TRUE(verifyMessagesSentInOrder(events, [this]() {
|
|
// Call connect()
|
|
m_Bluetooth->connect(TEST_BLUETOOTH_DEVICE_MAC);
|
|
|
|
/*
|
|
* Mimic the @c DeviceStateChangedEvent which should happen after device connection status changes.
|
|
* In order to guarantee that all @c DeviceStateChangedEvent happen after the corresponding device connection
|
|
* status changes, force the test to wait EVENT_PROCESS_DELAY_MS.
|
|
*/
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(EVENT_PROCESS_DELAY_MS));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::CONNECTED));
|
|
}));
|
|
|
|
// Verify the connection result.
|
|
ASSERT_TRUE(m_mockBluetoothDevice1->isConnected());
|
|
}
|
|
|
|
/**
|
|
* Test call to handle PairDevices directive with matched device UUIDs.
|
|
* Assumption:
|
|
* A @c DeviceManager contains m_mockBluetoothDevice1 and m_mockBluetoothDevice2.
|
|
* m_mockBluetoothDevice1 belongs to DeviceCategory::PHONE, which follows @c BasicDeviceConnectionRule.
|
|
* m_mockBluetoothDevice2 belongs to DeviceCategory::GADGET, which follows @c GadgetConnectionRule.
|
|
* Use case:
|
|
* A @c PairDevices directive is sent down, whose payload contains m_mockBluetoothDevice1 and m_mockBluetoothDevice2.
|
|
* Expected result:
|
|
* 1) Both devices should be paired successfully.
|
|
* 2) Based on the connection rule (m_mockBluetoothDevice1 follows @c BasicDeviceConnectionRule,
|
|
* m_mockBluetoothDevice2 follows @c GadgetConnectionRule), m_mockBluetoothDevice1 should be connected successfully.
|
|
* 3) A sequence of {PAIR_DEVICES_SUCCEEDED, CONNECT_BY_DEVICE_IDS_SUCCEEDED, PAIR_DEVICES_SUCCEEDED)
|
|
* should be sent to cloud.
|
|
* a. {PAIR_DEVICES_SUCCEEDED, CONNECT_BY_DEVICE_IDS_SUCCEEDED} are sent when Bluetooth CapabilityAgent tries to pair
|
|
* m_mockBluetoothDevice1.
|
|
* b. {PAIR_DEVICES_SUCCEEDED} is sent when Bluetooth CapabilityAgent tries to pair m_mockBluetoothDevice2.
|
|
*/
|
|
TEST_F(BluetoothTest, DISABLED_test_handlePairDevices) {
|
|
// Initially, all devices are stored as DeviceCategory::UNKNOWN. Need to manually update device category in order
|
|
// to test.
|
|
m_bluetoothStorage->updateByCategory(TEST_BLUETOOTH_UUID, deviceCategoryToString(DeviceCategory::PHONE));
|
|
m_bluetoothStorage->updateByCategory(TEST_BLUETOOTH_UUID_2, deviceCategoryToString(DeviceCategory::GADGET));
|
|
|
|
m_messages.insert({PAIR_DEVICES_SUCCEEDED, 0});
|
|
m_messages.insert({CONNECT_BY_DEVICE_IDS_SUCCEEDED, 0});
|
|
std::mutex waitMutex;
|
|
|
|
EXPECT_CALL(*(m_mockDirectiveHandlerResult.get()), setCompleted())
|
|
.Times(1)
|
|
.WillOnce(InvokeWithoutArgs(this, &BluetoothTest::wakeOnSetCompleted));
|
|
|
|
EXPECT_CALL(*m_mockMessageSender, sendMessage(_))
|
|
.Times(AtLeast(1))
|
|
.WillRepeatedly(Invoke([this](std::shared_ptr<avsCommon::avs::MessageRequest> request) {
|
|
verifyMessagesCount(request, &m_messages);
|
|
m_messageSentTrigger.notify_one();
|
|
}));
|
|
|
|
// Create PairDevices Directive.
|
|
auto attachmentManager = std::make_shared<StrictMock<MockAttachmentManager>>();
|
|
auto avsMessageHeader =
|
|
std::make_shared<AVSMessageHeader>(NAMESPACE_BLUETOOTH, PAIR_DEVICES_DIRECTIVE, TEST_MESSAGE_ID);
|
|
std::shared_ptr<AVSDirective> directive =
|
|
AVSDirective::create("", avsMessageHeader, TEST_PAIR_DEVICES_PAYLOAD, attachmentManager, "");
|
|
// cast to DirectiveHandlerInterface so the compiler can find the correct preHandleDirective signature
|
|
std::shared_ptr<DirectiveHandlerInterface> agentAsDirectiveHandler = m_Bluetooth;
|
|
agentAsDirectiveHandler->preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult));
|
|
agentAsDirectiveHandler->handleDirective(TEST_MESSAGE_ID);
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(EVENT_PROCESS_DELAY_MS));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::PAIRED));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::CONNECTED));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice2, DeviceState::PAIRED));
|
|
|
|
std::unique_lock<std::mutex> lock(waitMutex);
|
|
bool result;
|
|
result = m_messageSentTrigger.wait_for(lock, WAIT_TIMEOUT_MS, [this] {
|
|
for(auto message : m_messages) {
|
|
if (message.first == PAIR_DEVICES_SUCCEEDED) {
|
|
if (message.second != 2) {
|
|
return false;
|
|
}
|
|
} else if (message.first == CONNECT_BY_DEVICE_IDS_SUCCEEDED) {
|
|
if (message.second != 1) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
ASSERT_TRUE(result);
|
|
|
|
// Verify the pair result.
|
|
ASSERT_TRUE(m_mockBluetoothDevice1->isPaired());
|
|
ASSERT_TRUE(m_mockBluetoothDevice1->isConnected());
|
|
ASSERT_TRUE(m_mockBluetoothDevice2->isPaired());
|
|
ASSERT_FALSE(m_mockBluetoothDevice2->isConnected());
|
|
}
|
|
|
|
/**
|
|
* Test call to handle the local pair() method.
|
|
* Assumption:
|
|
* A @c DeviceManager contains m_mockBluetoothDevice1.
|
|
* m_mockBluetoothDevice1 belongs to DeviceCategory::PHONE, which follows @c BasicDeviceConnectionRule.
|
|
* Use case:
|
|
* A local pair() call is made with the MAC address of m_mockBluetoothDevice1.
|
|
* Expected result:
|
|
* 1) m_mockBluetoothDevice1 pairs and connects.
|
|
* 2) The observer should be notified of device connection once.
|
|
* 3) One @c PairDevicesSucceeded and one @c ConnectByDeviceIdsSucceed event.
|
|
*/
|
|
TEST_F(BluetoothTest, test_handlePairLocal) {
|
|
// Initially, all devices are stored as DeviceCategory::UNKNOWN. Need to manually update device category in order
|
|
// to test.
|
|
m_bluetoothStorage->updateByCategory(TEST_BLUETOOTH_UUID, deviceCategoryToString(DeviceCategory::PHONE));
|
|
|
|
std::vector<std::string> events = {PAIR_DEVICES_SUCCEEDED, CONNECT_BY_DEVICE_IDS_SUCCEEDED};
|
|
ASSERT_TRUE(verifyMessagesSentInOrder(events, [this]() {
|
|
// Call pair()
|
|
m_Bluetooth->pair(TEST_BLUETOOTH_DEVICE_MAC);
|
|
|
|
/*
|
|
* Mimic the @c DeviceStateChangedEvent which should happen after device connection status changes.
|
|
* In order to guarantee that all @c DeviceStateChangedEvent happen after the corresponding device connection
|
|
* status changes, force the test to wait EVENT_PROCESS_DELAY_MS.
|
|
*/
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(EVENT_PROCESS_DELAY_MS * 5));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::PAIRED));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::CONNECTED));
|
|
}));
|
|
|
|
// Verify the pair result.
|
|
ASSERT_TRUE(m_mockBluetoothDevice1->isPaired());
|
|
ASSERT_TRUE(m_mockBluetoothDevice1->isConnected());
|
|
}
|
|
|
|
/**
|
|
* Test call to handle UnpairDevices directive with matched device UUIDs.
|
|
*
|
|
* Assumption:
|
|
* A @c DeviceManager contains m_mockBluetoothDevice1 and m_mockBluetoothDevice2.
|
|
* m_mockBluetoothDevice1 belongs to DeviceCategory::PHONE, whcih follows @c BasicDeviceConnectionRule.
|
|
* m_mockBluetoothDevice2 belongs to DeviceCategory::GADGET, which follows @c GadgetConnectionRule.
|
|
* Both devices are in paired and connected state.
|
|
* Use case:
|
|
* First a @c PairDevices directive is sent down, whose payload contains m_mockBluetoothDevice1
|
|
* and m_mockBluetoothDevice2.
|
|
* Then a @c UnpairDevices directive is sent down, whose payload contains m_mockBluetoothDevice1
|
|
* and m_mockBluetoothDevice2.
|
|
* Expected result:
|
|
* 1) Both m_mockBluetoothDevice1 and m_mockBluetoothDevice2 should be unpaired successfully.
|
|
* 2) Based on the connection rule, both m_mockBluetoothDevice1 and m_mockBluetoothDevice2 should be diconnected
|
|
* successfully.
|
|
* 3) Events:
|
|
* A sequence of {DISCONNECT_DEVICES_SUCCEEDED, UNPAIR_DEVICES_SUCCEEDED, DISCONNECT_DEVICES_SUCCEEDED,
|
|
* UNPAIR_DEVICES_SUCCEEDED} should be sent to cloud:
|
|
* a. {DISCONNECT_DEVICES_SUCCEEDED, UNPAIR_DEVICES_SUCCEEDED} are sent when Bluetooth CapabilityAgents tries to unpair
|
|
* m_mockBluetoothDevice1.
|
|
* b. {DISCONNECT_DEVICES_SUCCEEDED, UNPAIR_DEVICES_SUCCEEDED} are sent when Bluetooth CapabilityAgents tries to unpair
|
|
* m_mockBluetoothDevice2.
|
|
*/
|
|
TEST_F(BluetoothTest, test_handleUnpairDevices) {
|
|
// Initially, all devices are stored as DeviceCategory::UNKNOWN. Need to manually update device category in order
|
|
// to test.
|
|
m_bluetoothStorage->updateByCategory(TEST_BLUETOOTH_UUID, deviceCategoryToString(DeviceCategory::PHONE));
|
|
m_bluetoothStorage->updateByCategory(TEST_BLUETOOTH_UUID_2, deviceCategoryToString(DeviceCategory::GADGET));
|
|
|
|
// Assume all devices are paired and connected before.
|
|
m_mockBluetoothDevice1->pair();
|
|
m_mockBluetoothDevice1->connect();
|
|
m_mockBluetoothDevice2->pair();
|
|
m_mockBluetoothDevice2->connect();
|
|
ASSERT_TRUE(m_mockBluetoothDevice1->isConnected());
|
|
ASSERT_TRUE(m_mockBluetoothDevice2->isConnected());
|
|
|
|
EXPECT_CALL(*m_mockBluetoothDeviceObserver, onActiveDeviceDisconnected(_)).Times(Exactly(2));
|
|
EXPECT_CALL(*(m_mockDirectiveHandlerResult.get()), setCompleted())
|
|
.Times(1)
|
|
.WillOnce(InvokeWithoutArgs(this, &BluetoothTest::wakeOnSetCompleted));
|
|
std::vector<std::string> events = {DISCONNECT_DEVICES_SUCCEEDED, UNPAIR_DEVICES_SUCCEEDED,
|
|
DISCONNECT_DEVICES_SUCCEEDED, UNPAIR_DEVICES_SUCCEEDED};
|
|
|
|
ASSERT_TRUE(verifyMessagesSentInOrder(events, [this]() {
|
|
auto attachmentManager = std::make_shared<StrictMock<MockAttachmentManager>>();
|
|
auto avsMessageHeader =
|
|
std::make_shared<AVSMessageHeader>(NAMESPACE_BLUETOOTH, UNPAIR_DEVICES_DIRECTIVE, TEST_MESSAGE_ID);
|
|
std::shared_ptr<AVSDirective> directive =
|
|
AVSDirective::create("", avsMessageHeader, TEST_UNPAIR_DEVICES_PAYLOAD, attachmentManager, "");
|
|
// cast to DirectiveHandlerInterface so the compiler can find the correct preHandleDirective signature
|
|
std::shared_ptr<DirectiveHandlerInterface> agentAsDirectiveHandler = m_Bluetooth;
|
|
|
|
agentAsDirectiveHandler->preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult));
|
|
agentAsDirectiveHandler->handleDirective(TEST_MESSAGE_ID);
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(EVENT_PROCESS_DELAY_MS));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::DISCONNECTED));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::UNPAIRED));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice2, DeviceState::DISCONNECTED));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice2, DeviceState::UNPAIRED));
|
|
}));
|
|
|
|
// Verify the Unpair result.
|
|
ASSERT_FALSE(m_mockBluetoothDevice1->isPaired());
|
|
ASSERT_FALSE(m_mockBluetoothDevice1->isConnected());
|
|
ASSERT_FALSE(m_mockBluetoothDevice2->isPaired());
|
|
ASSERT_FALSE(m_mockBluetoothDevice2->isConnected());
|
|
}
|
|
|
|
/**
|
|
* Test call to handle the local unpair() method.
|
|
* Assumption:
|
|
* A @c DeviceManager contains m_mockBluetoothDevice1.
|
|
* m_mockBluetoothDevice1 belongs to DeviceCategory::PHONE, which follows @c BasicDeviceConnectionRule.
|
|
* Use case:
|
|
* A local unpair() call is made with the MAC address of m_mockBluetoothDevice1.
|
|
* Expected result:
|
|
* 1) m_mockBluetoothDevice1 disconnects and unpairs.
|
|
* 2) The observer should be notified of device disconnection once.
|
|
* 3) One @c DisconnectDevicesSucceeded and one @c UnpairDevicesSucceeded event.
|
|
*/
|
|
TEST_F(BluetoothTest, test_handleUnpairLocal) {
|
|
// Initially, all devices are stored as DeviceCategory::UNKNOWN. Need to manually update device category in order
|
|
// to test.
|
|
m_bluetoothStorage->updateByCategory(TEST_BLUETOOTH_UUID, deviceCategoryToString(DeviceCategory::PHONE));
|
|
|
|
// Assume all devices are paired and connected before.
|
|
m_mockBluetoothDevice1->pair();
|
|
m_mockBluetoothDevice1->connect();
|
|
ASSERT_TRUE(m_mockBluetoothDevice1->isConnected());
|
|
|
|
std::vector<std::string> events = {DISCONNECT_DEVICES_SUCCEEDED, UNPAIR_DEVICES_SUCCEEDED};
|
|
ASSERT_TRUE(verifyMessagesSentInOrder(events, [this]() {
|
|
// Call unpair()
|
|
m_Bluetooth->unpair(TEST_BLUETOOTH_DEVICE_MAC);
|
|
|
|
/*
|
|
* Mimic the @c DeviceStateChangedEvent which should happen after device connection status changes.
|
|
* In order to guarantee that all @c DeviceStateChangedEvent happen after the corresponding device connection
|
|
* status changes, force the test to wait EVENT_PROCESS_DELAY_MS.
|
|
*/
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(EVENT_PROCESS_DELAY_MS));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::DISCONNECTED));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::UNPAIRED));
|
|
}));
|
|
|
|
// Verify the unpair result.
|
|
ASSERT_FALSE(m_mockBluetoothDevice1->isPaired());
|
|
ASSERT_FALSE(m_mockBluetoothDevice1->isConnected());
|
|
}
|
|
|
|
/**
|
|
* Test call to handle DisconnectDevices directive with matched device UUIDs.
|
|
*
|
|
* Assumption:
|
|
* A @c DeviceManager contains m_mockBluetoothDevice1 and m_mockBluetoothDevice2.
|
|
* Both devices are in paired and connected state.
|
|
* Use case:
|
|
* A @c DisconnectDevices directive is sent down, whose payload contains m_mockBluetoothDevice1
|
|
* and m_mockBluetoothDevice2.
|
|
* Expected result:
|
|
* 1) Both m_mockBluetoothDevice1 and m_mockBluetoothDevice2 should be disconnected successfully.
|
|
* 2) The observer should be notified the device disconnection once.
|
|
* 3) Events:
|
|
* A sequnce of {DISCONNECT_DEVICES_SUCCEEDED, DISCONNECT_DEVICES_SUCCEEDED} should be sent to cloud. One for
|
|
* m_mockBluetoothDevice1, one for m_mockBluetoothDevice2.
|
|
*/
|
|
TEST_F(BluetoothTest, test_handleDisconnectDevices) {
|
|
// Assume all devices are paired and connected before.
|
|
m_mockBluetoothDevice1->pair();
|
|
m_mockBluetoothDevice1->connect();
|
|
m_mockBluetoothDevice2->pair();
|
|
m_mockBluetoothDevice2->connect();
|
|
ASSERT_TRUE(m_mockBluetoothDevice1->isConnected());
|
|
ASSERT_TRUE(m_mockBluetoothDevice2->isConnected());
|
|
|
|
EXPECT_CALL(*m_mockBluetoothDeviceObserver, onActiveDeviceDisconnected(_)).Times(Exactly(2));
|
|
std::vector<std::string> events = {DISCONNECT_DEVICES_SUCCEEDED, DISCONNECT_DEVICES_SUCCEEDED};
|
|
ASSERT_TRUE(verifyMessagesSentInOrder(events, [this]() {
|
|
auto attachmentManager = std::make_shared<StrictMock<MockAttachmentManager>>();
|
|
auto avsMessageHeader=
|
|
std::make_shared<AVSMessageHeader>(NAMESPACE_BLUETOOTH, DISCONNECT_DEVICES_DIRECTIVE, TEST_MESSAGE_ID);
|
|
std::shared_ptr<AVSDirective> directive =
|
|
AVSDirective::create("", avsMessageHeader, TEST_DISCONNECT_DEVICES_PAYLOAD, attachmentManager, "");
|
|
// cast to DirectiveHandlerInterface so the compiler can find the correct preHandleDirective signature
|
|
std::shared_ptr<DirectiveHandlerInterface> agentAsDirectiveHandler = m_Bluetooth;
|
|
agentAsDirectiveHandler->preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult));
|
|
agentAsDirectiveHandler->handleDirective(TEST_MESSAGE_ID);
|
|
m_wakeSetCompletedPromise = std::promise<void>();
|
|
m_wakeSetCompletedFuture = m_wakeSetCompletedPromise.get_future();
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(EVENT_PROCESS_DELAY_MS));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::DISCONNECTED));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice2, DeviceState::DISCONNECTED));
|
|
}));
|
|
|
|
ASSERT_FALSE(m_mockBluetoothDevice1->isConnected());
|
|
ASSERT_FALSE(m_mockBluetoothDevice2->isConnected());
|
|
}
|
|
|
|
/**
|
|
* Test call to handle the local disconnect() method.
|
|
*
|
|
* Assumption:
|
|
* A @c DeviceManager contains m_mockBluetoothDevice1. The device belongs to
|
|
* DeviceCategory::UNKNOWN. The device is in connected state.
|
|
* Use case:
|
|
* A local disconnect() call is made with the MAC address of m_mockBluetoothDevice1.
|
|
* Expected result:
|
|
* 1) m_mockBluetoothDevice1 disconnects.
|
|
* 2) The observer should be notified of device disconnection once.
|
|
* 3) One @c DisconnectDevicesSucceeded event.
|
|
*/
|
|
TEST_F(BluetoothTest, test_handleDisconnectLocal) {
|
|
// Assume all devices are paired and connected before.
|
|
m_mockBluetoothDevice1->pair();
|
|
m_mockBluetoothDevice1->connect();
|
|
ASSERT_TRUE(m_mockBluetoothDevice1->isConnected());
|
|
|
|
EXPECT_CALL(*m_mockBluetoothDeviceObserver, onActiveDeviceDisconnected(_)).Times(Exactly(1));
|
|
EXPECT_CALL(*m_mockContextManager, setState(BLUETOOTH_STATE, _, StateRefreshPolicy::NEVER, _)).Times(Exactly(1));
|
|
std::vector<std::string> events = {DISCONNECT_DEVICES_SUCCEEDED};
|
|
ASSERT_TRUE(verifyMessagesSentInOrder(events, [this]() {
|
|
// Call disconnect()
|
|
m_Bluetooth->disconnect(TEST_BLUETOOTH_DEVICE_MAC);
|
|
|
|
/*
|
|
* Mimic the @c DeviceStateChangedEvent which should happen after device connection status changes.
|
|
* In order to guarantee that all @c DeviceStateChangedEvent happen after the corresponding device connection
|
|
* status changes, force the test to wait EVENT_PROCESS_DELAY_MS.
|
|
*/
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(EVENT_PROCESS_DELAY_MS));
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::DISCONNECTED));
|
|
}));
|
|
|
|
// Verify the disconnection result.
|
|
ASSERT_FALSE(m_mockBluetoothDevice1->isConnected());
|
|
}
|
|
|
|
/**
|
|
* Test call to handle SetDeviceCategories directive with matched device UUID.
|
|
*
|
|
* Assumption:
|
|
* A @c DeviceManager contains m_mockBluetoothDevice1 and m_mockBluetoothDevice2. Both of them belong to
|
|
* DeviceCategory::UNKNOWN
|
|
* Use case:
|
|
* A @c SetDeviceCategories directive is sent down, whose payload contains m_mockBluetoothDevice1 (need to be set
|
|
* to DeviceCategory::PHONE) and m_mockBluetoothDevice2 (need to be set to DeviceCategory::GADGET).
|
|
* Expected result:
|
|
* 1) Both devices are set the assigned device category successfully.
|
|
* 2) Events:
|
|
* A sequnce of {SET_DEVICE_CATEGORIES_SUCCEEDED, SET_DEVICE_CATEGORIES_SUCCEEDED} should be sent to cloud. One for
|
|
* m_mockBluetoothDevice1, one for m_mockBluetoothDevice2.
|
|
*/
|
|
TEST_F(BluetoothTest, test_handleSetDeviceCategories) {
|
|
std::vector<std::string> events = {SET_DEVICE_CATEGORIES_SUCCEEDED};
|
|
ASSERT_TRUE(verifyMessagesSentInOrder(events, [this]() {
|
|
auto attachmentManager = std::make_shared<StrictMock<MockAttachmentManager>>();
|
|
auto avsMessageHeader=
|
|
std::make_shared<AVSMessageHeader>(NAMESPACE_BLUETOOTH, SET_DEVICE_CATEGORIES, TEST_MESSAGE_ID);
|
|
std::shared_ptr<AVSDirective> directive =
|
|
AVSDirective::create("", avsMessageHeader, TEST_SET_DEVICE_CATEGORIES_PAYLOAD, attachmentManager, "");
|
|
// cast to DirectiveHandlerInterface so the compiler can find the correct preHandleDirective signature
|
|
std::shared_ptr<DirectiveHandlerInterface> agentAsDirectiveHandler = m_Bluetooth;
|
|
agentAsDirectiveHandler->preHandleDirective(directive, std::move(m_mockDirectiveHandlerResult));
|
|
agentAsDirectiveHandler->handleDirective(TEST_MESSAGE_ID);
|
|
m_wakeSetCompletedPromise = std::promise<void>();
|
|
m_wakeSetCompletedFuture = m_wakeSetCompletedPromise.get_future();
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
|
|
m_Bluetooth->onContextAvailable(MOCK_CONTEXT);
|
|
}));
|
|
|
|
std::string category1;
|
|
std::string category2;
|
|
m_bluetoothStorage->getCategory(TEST_BLUETOOTH_UUID, &category1);
|
|
m_bluetoothStorage->getCategory(TEST_BLUETOOTH_UUID_2, &category2);
|
|
ASSERT_EQ(deviceCategoryToString(DeviceCategory::PHONE), category1);
|
|
ASSERT_EQ(deviceCategoryToString(DeviceCategory::GADGET), category2);
|
|
}
|
|
|
|
TEST_F(BluetoothTest, test_contentDucksUponReceivingBackgroundFocus) {
|
|
// Assume all devices are paired and connected before.
|
|
m_mockBluetoothDevice1->pair();
|
|
m_mockBluetoothDevice1->connect();
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::CONNECTED));
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
ASSERT_TRUE(m_mockBluetoothDevice1->isConnected());
|
|
|
|
// change streaming state to ACTIVE
|
|
m_eventBus->sendEvent(MediaStreamingStateChangedEvent(avsCommon::utils::bluetooth::MediaStreamingState::ACTIVE, avsCommon::utils::bluetooth::A2DPRole::SOURCE, m_mockBluetoothDevice1));
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
|
|
// ensure that music is not stopped when ducking.
|
|
EXPECT_CALL(*m_mockBluetoothMediaPlayer, stop(_)).Times(0);
|
|
EXPECT_CALL(*m_mockChannelVolumeInterface, startDucking()).Times(1);
|
|
m_Bluetooth->onFocusChanged(avsCommon::avs::FocusState::BACKGROUND, avsCommon::avs::MixingBehavior::MAY_DUCK);
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
}
|
|
|
|
TEST_F(BluetoothTest, test_contentUnducksUponReceivingForegroundOrNoneFocus) {
|
|
// Assume all devices are paired and connected before.
|
|
m_mockBluetoothDevice1->pair();
|
|
m_mockBluetoothDevice1->connect();
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::CONNECTED));
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
ASSERT_TRUE(m_mockBluetoothDevice1->isConnected());
|
|
|
|
// change streaming state to ACTIVE.
|
|
m_eventBus->sendEvent(MediaStreamingStateChangedEvent(avsCommon::utils::bluetooth::MediaStreamingState::ACTIVE, avsCommon::utils::bluetooth::A2DPRole::SOURCE, m_mockBluetoothDevice1));
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
|
|
// ensure that music is not stopped when ducking upon receiving background focus.
|
|
EXPECT_CALL(*m_mockBluetoothMediaPlayer, stop(_)).Times(0);
|
|
EXPECT_CALL(*m_mockChannelVolumeInterface, startDucking()).Times(1);
|
|
m_Bluetooth->onFocusChanged(avsCommon::avs::FocusState::BACKGROUND, avsCommon::avs::MixingBehavior::MAY_DUCK);
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
|
|
// upon receiving foreground focus , content must be unducked.
|
|
EXPECT_CALL(*m_mockChannelVolumeInterface, stopDucking()).Times(1);
|
|
m_Bluetooth->onFocusChanged(avsCommon::avs::FocusState::FOREGROUND, avsCommon::avs::MixingBehavior::PRIMARY);
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
|
|
// upon receiving foreground focus , content must be unducked.
|
|
EXPECT_CALL(*m_mockChannelVolumeInterface, stopDucking()).Times(1);
|
|
m_Bluetooth->onFocusChanged(avsCommon::avs::FocusState::NONE, avsCommon::avs::MixingBehavior::MUST_STOP);
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
}
|
|
|
|
/**
|
|
* Test streaming state change of multiple device connections.
|
|
*
|
|
* Assumption:
|
|
* A @c DeviceManager contains m_mockBluetoothDevice1 and m_mockBluetoothDevice2. m_mockBluetoothDevice1 belongs to
|
|
* DeviceCategory::AUDIO_VIDEO. m_mockBluetoothDevice2 belongs to DeviceCategory::PHONE.
|
|
* Use case:
|
|
* m_mockBluetoothDevice1 initiates connection and starts streaming audio.
|
|
* Then m_mockBluetoothDevice2 initiates connection.
|
|
* Expected Result:
|
|
* 1) m_mockBluetoothDevice1 should connect. A @c StreamingStarted event should be sent.
|
|
* 2) When m_mockBluetoothDevice2 connects, m_mockBluetoothDevice1 should be disconnected. A @c StreamingEnded event
|
|
* should be sent.
|
|
*/
|
|
TEST_F(BluetoothTest, test_streamingStateChange) {
|
|
// Initially, all devices are stored as DeviceCategory::UNKNOWN. Need to manually update device category in order
|
|
// to test.
|
|
m_bluetoothStorage->updateByCategory(TEST_BLUETOOTH_UUID, deviceCategoryToString(DeviceCategory::AUDIO_VIDEO));
|
|
m_bluetoothStorage->updateByCategory(TEST_BLUETOOTH_UUID_2, deviceCategoryToString(DeviceCategory::PHONE));
|
|
|
|
EXPECT_CALL(*m_mockMessageSender, sendMessage(_))
|
|
.Times(AtLeast(1))
|
|
.WillOnce(Invoke([this](std::shared_ptr<avsCommon::avs::MessageRequest> request) {
|
|
verifyMessage(request, STREAMING_STARTED);
|
|
}))
|
|
.WillOnce(Invoke([this](std::shared_ptr<avsCommon::avs::MessageRequest> request) {
|
|
verifyMessage(request, STREAMING_ENDED);
|
|
}));
|
|
|
|
// m_mockBluetoothDevice1 initiates connection and starts streaming media.
|
|
m_mockBluetoothDevice1->connect();
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice1, DeviceState::CONNECTED));
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(EVENT_PROCESS_DELAY_MS));
|
|
m_eventBus->sendEvent(MediaStreamingStateChangedEvent(
|
|
MediaStreamingState::ACTIVE, A2DPRole::SOURCE, m_mockBluetoothDevice1));
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(EVENT_PROCESS_DELAY_MS));
|
|
|
|
// m_mockBluetoothDevice2 initiates connection.
|
|
m_mockBluetoothDevice2->connect();
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice2, DeviceState::CONNECTED));
|
|
}
|
|
|
|
/**
|
|
* Test focus state change of barge-in scenario.
|
|
*
|
|
* Assumption:
|
|
* A @c DeviceManager contains m_mockBluetoothDevice3, which belongs to DeviceCategory::PHONE.
|
|
* Use case:
|
|
* 1. m_mockBluetoothDevice3 initiates connection. Stream audio from m_mockBluetoothDevice3.
|
|
* 2. A job(e.g, TTS) barge-in, which moves Bluetooth to background.
|
|
* Exepected Result:
|
|
* 1. m_mockBluetoothDevice3 should connect and start streaming audio. It should acquire focus.
|
|
* 2. m_mockBluetoothDevice3 should pause streaming audio. However, it should NOT release focus.
|
|
*/
|
|
TEST_F(BluetoothTest, test_focusStateChange) {
|
|
m_bluetoothStorage->updateByCategory(TEST_BLUETOOTH_UUID_3, deviceCategoryToString(DeviceCategory::PHONE));
|
|
|
|
EXPECT_CALL(*m_mockFocusManager, acquireChannel(_, _)).Times(1).WillOnce(Return(true));
|
|
EXPECT_CALL(*m_mockBluetoothMediaPlayer, play(_)).Times(1).WillOnce(Return(true));
|
|
EXPECT_CALL(*m_mockFocusManager, releaseChannel(_, _)).Times(0);
|
|
EXPECT_CALL(*m_mockBluetoothMediaPlayer, stop(_)).Times(1).WillOnce(Return(true));
|
|
|
|
m_mockBluetoothDevice3->connect();
|
|
m_eventBus->sendEvent(DeviceStateChangedEvent(m_mockBluetoothDevice3, DeviceState::CONNECTED));
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
m_eventBus->sendEvent(MediaStreamingStateChangedEvent(
|
|
MediaStreamingState::ACTIVE, A2DPRole::SINK, m_mockBluetoothDevice3));
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
m_Bluetooth->onFocusChanged(avsCommon::avs::FocusState::FOREGROUND, avsCommon::avs::MixingBehavior::PRIMARY);
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
m_Bluetooth->onPlaybackStarted(m_mockBluetoothMediaPlayer->getCurrentSourceId(), {std::chrono::milliseconds(0)});
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
|
|
// The other job barges in, which moves Bluetooth to background.
|
|
m_Bluetooth->onFocusChanged(avsCommon::avs::FocusState::BACKGROUND, avsCommon::avs::MixingBehavior::MUST_STOP);
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
m_eventBus->sendEvent(MediaStreamingStateChangedEvent(
|
|
MediaStreamingState::IDLE, A2DPRole::SINK, m_mockBluetoothDevice3));
|
|
m_wakeSetCompletedFuture.wait_for(WAIT_TIMEOUT_MS);
|
|
}
|
|
} // namespace test
|
|
} // namespace acsdkBluetooth
|
|
} // namespace alexaClientSDK
|