blob: bf28f3c8def1a8c5ecff20eb7e4b962802144475 [file] [log] [blame]
/*
* Copyright 2019 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 <gtest/gtest.h>
#include <cstdint>
#define LOG_TAG "bt_shim_test"
#include "osi/include/log.h"
#include "shim/l2cap.h"
#include "shim/test_stack.h"
#include "types/raw_address.h"
TestStack test_stack_;
bluetooth::shim::IStack* bluetooth::shim::GetGabeldorscheStack() {
return (bluetooth::shim::IStack*)&test_stack_;
}
namespace bluetooth {
namespace legacy {
namespace {
constexpr uint16_t kPsm = 123;
constexpr uint16_t kCid = 987;
constexpr size_t kDataBufferSize = 1024;
uint8_t bt_hdr_data[] = {
0x00, 0x00, /* event */
0x08, 0x00, /* len */
0x00, 0x00, /* offset */
0x00, 0x00, /* layer specific */
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, /* data */
0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, /* data */
};
class L2capTest;
L2capTest* l2cap_test_ = nullptr;
class L2capTest : public ::testing::Test {
public:
static shim::L2cap* l2cap_;
struct {
int L2caConnectCfmCb;
int L2caConnectPndCb;
int L2caConfigIndCb;
int L2caConfigCfmCb;
int L2caDisconnectIndCb;
int L2caDisconnectCfmCb;
int L2caQosViolationIndCb;
int L2caDataIndCb;
int L2caCongestionStatusCb;
int L2caTxCompleteCb;
int L2caCreditsReceivedCb;
} cnt_{
.L2caConnectCfmCb = 0,
.L2caConnectPndCb = 0,
.L2caConfigIndCb = 0,
.L2caConfigCfmCb = 0,
.L2caDisconnectIndCb = 0,
.L2caDisconnectCfmCb = 0,
.L2caQosViolationIndCb = 0,
.L2caDataIndCb = 0,
.L2caCongestionStatusCb = 0,
.L2caTxCompleteCb = 0,
.L2caCreditsReceivedCb = 0,
};
protected:
void SetUp() override {
l2cap_ = new shim::L2cap();
l2cap_test_ = this;
}
void TearDown() override {
delete l2cap_;
l2cap_ = nullptr;
}
uint8_t data_buffer_[kDataBufferSize];
};
shim::L2cap* L2capTest::l2cap_ = nullptr;
// Indication of remotely initiated connection response sent
void L2caConnectIndCb(const RawAddress& raw_address, uint16_t a, uint16_t b,
uint8_t c) {
LOG_INFO(LOG_TAG, "%s", __func__);
}
// Confirms locally initiated connection request completed
void L2caConnectCfmCb(uint16_t cid, uint16_t result) {
l2cap_test_->cnt_.L2caConnectCfmCb++;
LOG_INFO(LOG_TAG, "%s cid:%hd result:%hd", __func__, cid, result);
}
void L2caConnectPndCb(uint16_t cid) {
l2cap_test_->cnt_.L2caConnectPndCb++;
LOG_INFO(LOG_TAG, "%s", __func__);
}
// Indication of remotely initiated configuration response sent
void L2caConfigIndCb(uint16_t cid, tL2CAP_CFG_INFO* callbacks) {
l2cap_test_->cnt_.L2caConfigIndCb++;
LOG_INFO(LOG_TAG, "%s", __func__);
}
// Confirms locally initiated config request completed
void L2caConfigCfmCb(uint16_t cid, tL2CAP_CFG_INFO* callbacks) {
l2cap_test_->cnt_.L2caConfigCfmCb++;
LOG_INFO(LOG_TAG, "%s", __func__);
}
// Indication of remotely initiated disconnection response sent
void L2caDisconnectIndCb(uint16_t cid, bool needs_ack) {
l2cap_test_->cnt_.L2caDisconnectIndCb++;
LOG_INFO(LOG_TAG, "%s", __func__);
}
// Confirms locally initiated disconnect request completed
void L2caDisconnectCfmCb(uint16_t cid, uint16_t result) {
l2cap_test_->cnt_.L2caDisconnectCfmCb++;
LOG_INFO(LOG_TAG, "%s", __func__);
}
void L2caQosViolationIndCb(const RawAddress& raw_address) {
l2cap_test_->cnt_.L2caQosViolationIndCb++;
LOG_INFO(LOG_TAG, "%s", __func__);
}
void L2caDataIndCb(uint16_t cid, BT_HDR* bt_hdr) {
l2cap_test_->cnt_.L2caDataIndCb++;
LOG_INFO(LOG_TAG, "%s", __func__);
}
void L2caCongestionStatusCb(uint16_t cid, bool is_congested) {
l2cap_test_->cnt_.L2caCongestionStatusCb++;
LOG_INFO(LOG_TAG, "%s", __func__);
}
void L2caTxCompleteCb(uint16_t cid, uint16_t sdu_cnt) {
l2cap_test_->cnt_.L2caTxCompleteCb++;
LOG_INFO(LOG_TAG, "%s", __func__);
}
void L2caCreditsReceivedCb(uint16_t cid, uint16_t credits_received,
uint16_t credit_count) {
l2cap_test_->cnt_.L2caCreditsReceivedCb++;
LOG_INFO(LOG_TAG, "%s", __func__);
}
tL2CAP_APPL_INFO test_callbacks{
.pL2CA_ConnectInd_Cb = L2caConnectIndCb,
.pL2CA_ConnectCfm_Cb = L2caConnectCfmCb,
.pL2CA_ConnectPnd_Cb = L2caConnectPndCb,
.pL2CA_ConfigInd_Cb = L2caConfigIndCb,
.pL2CA_ConfigCfm_Cb = L2caConfigCfmCb,
.pL2CA_DisconnectInd_Cb = L2caDisconnectIndCb,
.pL2CA_DisconnectCfm_Cb = L2caDisconnectCfmCb,
.pL2CA_QoSViolationInd_Cb = L2caQosViolationIndCb,
.pL2CA_DataInd_Cb = L2caDataIndCb,
.pL2CA_CongestionStatus_Cb = L2caCongestionStatusCb,
.pL2CA_TxComplete_Cb = L2caTxCompleteCb,
.pL2CA_CreditsReceived_Cb = L2caCreditsReceivedCb,
};
TEST_F(L2capTest, RegisterService) {
l2cap_->RegisterService(kPsm, &test_callbacks, false);
CHECK(test_stack_.test_l2cap_.registered_service_.count(kPsm) == 1);
}
TEST_F(L2capTest, UnregisterService) {
l2cap_->RegisterService(kPsm, &test_callbacks, false);
CHECK(test_stack_.test_l2cap_.registered_service_.count(kPsm) == 1);
l2cap_->UnregisterService(kPsm);
CHECK(test_stack_.test_l2cap_.registered_service_.count(kPsm) == 0);
}
TEST_F(L2capTest, CreateConnection_NotRegistered) {
RawAddress raw_address;
std::string string_address("11:22:33:44:55:66");
RawAddress::FromString(string_address, raw_address);
uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
CHECK(cid == 0);
}
TEST_F(L2capTest, CreateConnection_Registered) {
test_stack_.test_l2cap_.cid_ = kCid;
l2cap_->RegisterService(kPsm, &test_callbacks, false);
RawAddress raw_address;
std::string string_address("11:22:33:44:55:66");
RawAddress::FromString(string_address, raw_address);
uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
CHECK(cid != 0);
}
TEST_F(L2capTest, CreateConnection_ConnectResponse) {
test_stack_.test_l2cap_.cid_ = kCid;
l2cap_->RegisterService(kPsm, &test_callbacks, false);
RawAddress raw_address;
std::string string_address("11:22:33:44:55:66");
RawAddress::FromString(string_address, raw_address);
uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
CHECK(cid != 0);
CHECK(l2cap_->ConnectResponse(raw_address, 0, cid, 0, 0, nullptr));
}
TEST_F(L2capTest, CreateConnection_ConfigRequest) {
test_stack_.test_l2cap_.cid_ = kCid;
l2cap_->RegisterService(kPsm, &test_callbacks, false);
RawAddress raw_address;
std::string string_address("11:22:33:44:55:66");
RawAddress::FromString(string_address, raw_address);
uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
CHECK(cid != 0);
// Simulate a successful connection response
l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
CHECK(cnt_.L2caConnectCfmCb == 1);
CHECK(l2cap_->ConfigRequest(cid, nullptr));
}
TEST_F(L2capTest, CreateConnection_ConfigResponse) {
test_stack_.test_l2cap_.cid_ = kCid;
l2cap_->RegisterService(kPsm, &test_callbacks, false);
RawAddress raw_address;
std::string string_address("11:22:33:44:55:66");
RawAddress::FromString(string_address, raw_address);
uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
CHECK(cid != 0);
// Simulate a successful connection response
l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
CHECK(cnt_.L2caConnectCfmCb == 1);
CHECK(l2cap_->ConfigResponse(cid, nullptr));
}
TEST_F(L2capTest, CreateConnection_DisconnectRequest) {
test_stack_.test_l2cap_.cid_ = kCid;
l2cap_->RegisterService(kPsm, &test_callbacks, false);
RawAddress raw_address;
std::string string_address("11:22:33:44:55:66");
RawAddress::FromString(string_address, raw_address);
uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
CHECK(cid != 0);
// Simulate a successful connection response
l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
CHECK(cnt_.L2caConnectCfmCb == 1);
CHECK(l2cap_->DisconnectRequest(cid));
}
TEST_F(L2capTest, CreateConnection_DisconnectResponse) {
test_stack_.test_l2cap_.cid_ = kCid;
l2cap_->RegisterService(kPsm, &test_callbacks, false);
RawAddress raw_address;
std::string string_address("11:22:33:44:55:66");
RawAddress::FromString(string_address, raw_address);
uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
CHECK(cid != 0);
// Simulate a successful connection response
l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
CHECK(cnt_.L2caConnectCfmCb == 1);
CHECK(l2cap_->DisconnectResponse(cid));
}
TEST_F(L2capTest, CreateConnection_WithHandshake) {
test_stack_.test_l2cap_.cid_ = kCid;
l2cap_->RegisterService(kPsm, &test_callbacks, false);
RawAddress raw_address;
std::string string_address("11:22:33:44:55:66");
RawAddress::FromString(string_address, raw_address);
uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
CHECK(cid != 0);
// Simulate a successful connection response
l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
CHECK(cnt_.L2caConnectCfmCb == 1);
CHECK(l2cap_->ConfigRequest(cid, nullptr) == true);
CHECK(cnt_.L2caConfigCfmCb == 1);
CHECK(cnt_.L2caConfigIndCb == 1);
BT_HDR* bt_hdr = (BT_HDR*)bt_hdr_data;
test_stack_.test_l2cap_.data_buffer_ = data_buffer_;
test_stack_.test_l2cap_.data_buffer_size_ = kDataBufferSize;
l2cap_->Write(cid, bt_hdr);
CHECK(data_buffer_[0] == 0x11);
CHECK(data_buffer_[1] == 0x22);
CHECK(data_buffer_[2] == 0x33);
CHECK(data_buffer_[3] == 0x44);
CHECK(data_buffer_[4] == 0x55);
CHECK(data_buffer_[5] == 0x66);
CHECK(data_buffer_[6] == 0x77);
CHECK(data_buffer_[7] == 0x88);
CHECK(data_buffer_[8] == 0x00);
}
} // namespace
} // namespace legacy
} // namespace bluetooth