普通文本  |  530行  |  19.75 KB

/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <base/bind.h>
#include <base/logging.h>
#include <base/message_loop/message_loop.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "avrcp_internal.h"
#include "avrcp_test_helper.h"
#include "connection_handler.h"

using ::testing::_;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SaveArgPointee;
using ::testing::SetArgPointee;
using ::testing::MockFunction;
using ::testing::NiceMock;
using ::testing::StrictMock;

namespace bluetooth {
namespace avrcp {

using device_ptr = std::shared_ptr<Device>;

class AvrcpConnectionHandlerTest : public testing::Test {
 public:
  void SetUp() override {
    ON_CALL(mock_avrcp_, Close(_)).WillByDefault(Return(0));
  }

  void SetUpSdp(tAVRC_FIND_CBACK* sdp_cb, bool browsing, bool absolute_volume) {
    EXPECT_CALL(mock_avrcp_, FindService(_, _, _, _))
        .Times(1)
        .WillOnce(DoAll(SaveArg<3>(sdp_cb), Return(0)));

    static tSDP_DISC_ATTR fake_features;

    fake_features = {
        .p_next_attr = nullptr,
        .attr_id = 0,
        .attr_len_type = 0,
        .attr_value.v.u16 = 0,
    };

    if (browsing) fake_features.attr_value.v.u16 |= AVRC_SUPF_CT_BROWSE;
    if (absolute_volume) fake_features.attr_value.v.u16 |= AVRC_SUPF_CT_CAT2;

    EXPECT_CALL(mock_sdp_, FindAttributeInRec(_, _))
        .Times(4)
        .WillRepeatedly(Return(&fake_features));

    EXPECT_CALL(mock_sdp_, FindServiceInDb(_, _, _))
        .Times(2)
        .WillOnce(Return((tSDP_DISC_REC*)0x01))   // Return any non null pointer
        .WillOnce(Return((tSDP_DISC_REC*)0x01));  // Return any non null pointer

    EXPECT_CALL(mock_sdp_, FindProfileVersionInRec(_, _, _))
        .Times(2)
        .WillRepeatedly(DoAll(SetArgPointee<2>(AVRC_REV_1_6), Return(true)));
  }

 protected:
  ConnectionHandler* connection_handler_ = nullptr;

  // We use NiceMock's here because each function of this code does quite a few
  // operations. This way it is much easier to write a higher number of smaller
  // tests without having a large amount of warnings.
  NiceMock<MockFunction<void(device_ptr)>> device_cb;
  NiceMock<MockAvrcpInterface> mock_avrcp_;
  NiceMock<MockSdpInterface> mock_sdp_;
  NiceMock<MockVolumeInterface> mock_volume_;
};

TEST_F(AvrcpConnectionHandlerTest, initializeTest) {
  // Set an Expectation that Open will be called as an acceptor and save the
  // connection callback once it is called
  tAVRC_CONN_CB conn_cb;
  EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kAny))
      .Times(1)
      .WillOnce(
          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)));

  auto bound_callback = base::Bind(&MockFunction<void(device_ptr)>::Call,
                                   base::Unretained(&device_cb));
  ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_,
                                            &mock_sdp_, &mock_volume_));
  connection_handler_ = ConnectionHandler::Get();

  // Check that the callback was sent with us as the acceptor
  ASSERT_EQ(conn_cb.conn, 1);

  connection_handler_ = nullptr;
  ConnectionHandler::CleanUp();
}

// Check that disconnecting without an active connection
TEST_F(AvrcpConnectionHandlerTest, notConnectedDisconnectTest) {
  // Set an Expectation that Open will be called twice as an acceptor and save
  // the connection callback once it is called.
  tAVRC_CONN_CB conn_cb;
  EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kAny))
      .Times(1)
      .WillOnce(
          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)));

  // Initialize the interface
  auto bound_callback = base::Bind(&MockFunction<void(device_ptr)>::Call,
                                   base::Unretained(&device_cb));
  ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_,
                                            &mock_sdp_, &mock_volume_));
  connection_handler_ = ConnectionHandler::Get();

  // Call the callback with a message saying the connection has closed
  conn_cb.ctrl_cback.Run(1, AVRC_CLOSE_IND_EVT, 0, &RawAddress::kAny);

  connection_handler_ = nullptr;
  ConnectionHandler::CleanUp();
};

// Test calling the connection callback after the handler is cleaned up
TEST_F(AvrcpConnectionHandlerTest, disconnectAfterCleanupTest) {
  // Set an Expectation that Open will be called twice as an acceptor and save
  // the connection callback once it is called.
  tAVRC_CONN_CB conn_cb;
  EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kAny))
      .Times(1)
      .WillOnce(
          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)));

  // Initialize the interface
  auto bound_callback = base::Bind(&MockFunction<void(device_ptr)>::Call,
                                   base::Unretained(&device_cb));
  ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_,
                                            &mock_sdp_, &mock_volume_));
  connection_handler_ = ConnectionHandler::Get();

  connection_handler_ = nullptr;
  ConnectionHandler::CleanUp();

  // Call the callback with a message saying the connection has closed
  conn_cb.ctrl_cback.Run(1, AVRC_CLOSE_IND_EVT, 0, &RawAddress::kAny);
};

// Check that we can handle having a remote device connect to us, start SDP, and
// open another acceptor connection
TEST_F(AvrcpConnectionHandlerTest, remoteDeviceConnectionTest) {
  // Set an Expectation that Open will be called twice as an acceptor and save
  // the connection callback once it is called.
  tAVRC_CONN_CB conn_cb;
  EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kAny))
      .Times(2)
      .WillOnce(
          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)))
      .WillOnce(
          DoAll(SetArgPointee<0>(2), SaveArgPointee<1>(&conn_cb), Return(0)));

  // Initialize the interface
  auto bound_callback = base::Bind(&MockFunction<void(device_ptr)>::Call,
                                   base::Unretained(&device_cb));
  ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_,
                                            &mock_sdp_, &mock_volume_));
  connection_handler_ = ConnectionHandler::Get();

  // Check that the callback was sent with us as the acceptor
  ASSERT_EQ(conn_cb.conn, 1);

  // Set an Expectations that SDP will be performed
  tAVRC_FIND_CBACK sdp_cb;
  SetUpSdp(&sdp_cb, false, false);

  // Set an expectation that a device will be created
  EXPECT_CALL(device_cb, Call(_)).Times(1);

  // Set an Expectation that OpenBrowse will be called in acceptor mode when the
  // device connects.
  EXPECT_CALL(mock_avrcp_, OpenBrowse(1, AVCT_ACP)).Times(1);

  // Call the callback with a message saying that a remote device has connected
  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);

  // Run the SDP callback with status success
  sdp_cb.Run(0);

  connection_handler_ = nullptr;
  ConnectionHandler::CleanUp();
}

// Check that when a device does not support absolute volume, that the
// handler reports that via the volume interface.
TEST_F(AvrcpConnectionHandlerTest, noAbsoluteVolumeTest) {
  // Set an Expectation that Open will be called twice as an acceptor and save
  // the connection callback once it is called.
  tAVRC_CONN_CB conn_cb;
  EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kAny))
      .Times(2)
      .WillOnce(
          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)))
      .WillOnce(
          DoAll(SetArgPointee<0>(2), SaveArgPointee<1>(&conn_cb), Return(0)));

  // Initialize the interface
  auto bound_callback = base::Bind(&MockFunction<void(device_ptr)>::Call,
                                   base::Unretained(&device_cb));
  ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_,
                                            &mock_sdp_, &mock_volume_));
  connection_handler_ = ConnectionHandler::Get();

  // Set an Expectations that SDP will be performed
  tAVRC_FIND_CBACK sdp_cb;
  SetUpSdp(&sdp_cb, false, false);

  EXPECT_CALL(mock_volume_, DeviceConnected(RawAddress::kAny)).Times(1);

  // Call the callback with a message saying that a remote device has connected
  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);

  // Run the SDP callback with status success
  sdp_cb.Run(0);

  connection_handler_ = nullptr;
  ConnectionHandler::CleanUp();
}

// Check that when a device does support absolute volume, that the handler
// doesn't report it. Instead that will be left up to the device.
TEST_F(AvrcpConnectionHandlerTest, absoluteVolumeTest) {
  // Set an Expectation that Open will be called twice as an acceptor and save
  // the connection callback once it is called.
  tAVRC_CONN_CB conn_cb;
  EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kAny))
      .Times(2)
      .WillOnce(
          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)))
      .WillOnce(
          DoAll(SetArgPointee<0>(2), SaveArgPointee<1>(&conn_cb), Return(0)));

  // Initialize the interface
  auto bound_callback = base::Bind(&MockFunction<void(device_ptr)>::Call,
                                   base::Unretained(&device_cb));

  StrictMock<MockVolumeInterface> strict_volume;
  ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_,
                                            &mock_sdp_, &strict_volume));
  connection_handler_ = ConnectionHandler::Get();

  // Set an Expectations that SDP will be performed with absolute volume
  // supported
  tAVRC_FIND_CBACK sdp_cb;
  SetUpSdp(&sdp_cb, false, true);

  // Call the callback with a message saying that a remote device has connected
  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);

  // Run the SDP callback with status success
  sdp_cb.Run(0);

  connection_handler_ = nullptr;
  ConnectionHandler::CleanUp();
}

TEST_F(AvrcpConnectionHandlerTest, disconnectTest) {
  // Set an Expectation that Open will be called twice as an acceptor and save
  // the connection callback once it is called.
  tAVRC_CONN_CB conn_cb;
  EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kAny))
      .Times(2)
      .WillOnce(
          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)))
      .WillOnce(DoAll(SetArgPointee<0>(2), Return(0)));

  // Initialize the interface
  auto bound_callback = base::Bind(&MockFunction<void(device_ptr)>::Call,
                                   base::Unretained(&device_cb));
  ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_,
                                            &mock_sdp_, &mock_volume_));
  connection_handler_ = ConnectionHandler::Get();

  // Call the callback with a message saying that a remote device has connected
  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);

  // Set up the expectation that Close will be called
  EXPECT_CALL(mock_avrcp_, Close(1)).Times(1);

  // Call the callback with a message saying that a remote device has
  // disconnected
  conn_cb.ctrl_cback.Run(1, AVRC_CLOSE_IND_EVT, 0, &RawAddress::kAny);

  connection_handler_ = nullptr;
  ConnectionHandler::CleanUp();
}

// Check that we can handle having a remote device connect to us, start SDP, and
// open another acceptor connection
TEST_F(AvrcpConnectionHandlerTest, multipleRemoteDeviceConnectionTest) {
  // Set an Expectation that Open will be called three times as an acceptor and
  // save the connection callback once it is called.
  tAVRC_CONN_CB conn_cb;
  EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kAny))
      .Times(3)
      .WillOnce(
          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)))
      .WillOnce(
          DoAll(SetArgPointee<0>(2), SaveArgPointee<1>(&conn_cb), Return(0)))
      .WillOnce(
          DoAll(SetArgPointee<0>(3), SaveArgPointee<1>(&conn_cb), Return(0)));

  // Initialize the interface
  auto bound_callback = base::Bind(&MockFunction<void(device_ptr)>::Call,
                                   base::Unretained(&device_cb));
  ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_,
                                            &mock_sdp_, &mock_volume_));
  connection_handler_ = ConnectionHandler::Get();

  // Check that the callback was sent with us as the acceptor
  ASSERT_EQ(conn_cb.conn, 1);

  // Set an Expectations that SDP will be performed
  tAVRC_FIND_CBACK sdp_cb;
  SetUpSdp(&sdp_cb, false, false);

  // Set an expectation that a device will be created
  EXPECT_CALL(device_cb, Call(_)).Times(1);

  // Set an Expectation that OpenBrowse will be called in acceptor mode when the
  // device connects on handle 1
  EXPECT_CALL(mock_avrcp_, OpenBrowse(1, AVCT_ACP)).Times(1);

  // Call the callback with a message saying that a remote device has connected
  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);

  // Run the SDP callback with status success
  sdp_cb.Run(0);

  // Set an Expectations that SDP will be performed again
  SetUpSdp(&sdp_cb, false, false);

  // Set an expectation that a device will be created again
  EXPECT_CALL(device_cb, Call(_)).Times(1);

  // Set an Expectation that OpenBrowse will be called in acceptor mode when the
  // device connects on handle 2
  EXPECT_CALL(mock_avrcp_, OpenBrowse(2, AVCT_ACP)).Times(1);

  // Call the callback with a message saying that a remote device has connected
  // with a different address
  conn_cb.ctrl_cback.Run(2, AVRC_OPEN_IND_EVT, 0, &RawAddress::kEmpty);

  // Run the SDP callback with status success
  sdp_cb.Run(0);

  connection_handler_ = nullptr;
  ConnectionHandler::CleanUp();
}

TEST_F(AvrcpConnectionHandlerTest, cleanupTest) {
  // Set Up Expectations for Initialize
  tAVRC_CONN_CB conn_cb;
  EXPECT_CALL(mock_avrcp_, Open(_, _, _))
      .WillOnce(
          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)))
      .WillOnce(
          DoAll(SetArgPointee<0>(2), SaveArgPointee<1>(&conn_cb), Return(0)))
      .WillOnce(
          DoAll(SetArgPointee<0>(3), SaveArgPointee<1>(&conn_cb), Return(0)));

  // Initialize the interface
  auto bound_callback = base::Bind(&MockFunction<void(device_ptr)>::Call,
                                   base::Unretained(&device_cb));
  ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_,
                                            &mock_sdp_, &mock_volume_));
  connection_handler_ = ConnectionHandler::Get();

  // Call the callback twice with a message saying that a remote device has
  // connected
  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);
  conn_cb.ctrl_cback.Run(2, AVRC_OPEN_IND_EVT, 0, &RawAddress::kEmpty);

  // Set an Expectation that Close will be called twice with handles 1 and 2
  EXPECT_CALL(mock_avrcp_, Close(1));
  EXPECT_CALL(mock_avrcp_, Close(2));

  // Cleanup the object causing all open connections to be closed
  connection_handler_ = nullptr;
  ConnectionHandler::CleanUp();
}

TEST_F(AvrcpConnectionHandlerTest, connectToRemoteDeviceTest) {
  // Initialize the interface
  auto bound_callback = base::Bind(&MockFunction<void(device_ptr)>::Call,
                                   base::Unretained(&device_cb));
  ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_,
                                            &mock_sdp_, &mock_volume_));
  connection_handler_ = ConnectionHandler::Get();

  // Set an Expectation that SDP will be performed
  tAVRC_FIND_CBACK sdp_cb;
  SetUpSdp(&sdp_cb, false, false);

  // Connect to the device which starts SDP
  connection_handler_->ConnectDevice(RawAddress::kEmpty);

  // Set an expectation that the handler will try to open an AVRCP connection
  // after doing SDP
  tAVRC_CONN_CB conn_cb;
  EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kEmpty))
      .Times(1)
      .WillOnce(
          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)));

  // Complete SDP
  sdp_cb.Run(0);

  // Check that the callback was sent with us as the initiator
  ASSERT_EQ(conn_cb.conn, 0);

  // Set an expectation that a device will be created
  EXPECT_CALL(device_cb, Call(_)).Times(1);

  // Set an Expectation that OpenBrowse will NOT be called since the SDP entry
  // didn't list browsing as a feature
  EXPECT_CALL(mock_avrcp_, OpenBrowse(_, _)).Times(0);

  // Call the callback with a message saying that a remote device has connected
  // with a different address
  conn_cb.ctrl_cback.Run(2, AVRC_OPEN_IND_EVT, 0, &RawAddress::kEmpty);

  // Cleanup the object causing all open connections to be closed
  connection_handler_ = nullptr;
  ConnectionHandler::CleanUp();
}

TEST_F(AvrcpConnectionHandlerTest, connectToBrowsableRemoteDeviceTest) {
  // Initialize the interface
  auto bound_callback = base::Bind(&MockFunction<void(device_ptr)>::Call,
                                   base::Unretained(&device_cb));
  ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_,
                                            &mock_sdp_, &mock_volume_));
  connection_handler_ = ConnectionHandler::Get();

  // Set an Expectation that SDP will be performed
  tAVRC_FIND_CBACK sdp_cb;
  SetUpSdp(&sdp_cb, true, false);

  // Connect to the device which starts SDP
  connection_handler_->ConnectDevice(RawAddress::kEmpty);

  // Set an expectation that the handler will try to open an AVRCP connection
  // after doing SDP
  tAVRC_CONN_CB conn_cb;
  EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kEmpty))
      .Times(1)
      .WillOnce(
          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)));

  // Complete SDP
  sdp_cb.Run(0);

  // Check that the callback was sent with us as the initiator
  ASSERT_EQ(conn_cb.conn, 0);

  // Set an expectation that a device will be created
  EXPECT_CALL(device_cb, Call(_)).Times(1);

  // Set an Expectation that OpenBrowse will be called since browsing is listed
  // as supported in SDP
  EXPECT_CALL(mock_avrcp_, OpenBrowse(1, AVCT_INT)).Times(1);

  // Call the callback with a message saying that a remote device has connected
  // with a different address
  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kEmpty);

  // Cleanup the object causing all open connections to be closed
  connection_handler_ = nullptr;
  ConnectionHandler::CleanUp();
}

TEST_F(AvrcpConnectionHandlerTest, disconnectWhileDoingSdpTest) {
  // Set an Expectation that Open will be called twice as an acceptor and save
  // the connection callback once it is called.
  tAVRC_CONN_CB conn_cb;
  EXPECT_CALL(mock_avrcp_, Open(_, _, RawAddress::kAny))
      .Times(2)
      .WillOnce(
          DoAll(SetArgPointee<0>(1), SaveArgPointee<1>(&conn_cb), Return(0)))
      .WillOnce(DoAll(SetArgPointee<0>(2), Return(0)));

  // Initialize the interface
  auto bound_callback = base::Bind(&MockFunction<void(device_ptr)>::Call,
                                   base::Unretained(&device_cb));
  ASSERT_TRUE(ConnectionHandler::Initialize(bound_callback, &mock_avrcp_,
                                            &mock_sdp_, &mock_volume_));
  connection_handler_ = ConnectionHandler::Get();

  // Set an Expectation that SDP will be performed
  tAVRC_FIND_CBACK sdp_cb;
  SetUpSdp(&sdp_cb, true, false);

  // Call the callback with a message saying that a remote device has connected
  conn_cb.ctrl_cback.Run(1, AVRC_OPEN_IND_EVT, 0, &RawAddress::kAny);

  // Call the callback with a message saying that a remote device has
  // disconnected
  conn_cb.ctrl_cback.Run(1, AVRC_CLOSE_IND_EVT, 0, &RawAddress::kAny);

  // Signal that SDP has completed
  sdp_cb.Run(0);

  connection_handler_ = nullptr;
  ConnectionHandler::CleanUp();
}

}  // namespace avrcp
}  // namespace bluetooth