blob: 8966284df57e8b33bb4cedc99455690c470fdf28 [file] [log] [blame]
/*
* Copyright 2021 HIMSA II K/S - www.himsa.com.
* Represented by EHIMA - www.ehima.com
*
* 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/logging.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "bta_groups.h"
#include "types/bluetooth/uuid.h"
#include "types/raw_address.h"
std::map<std::string, int> mock_function_count_map;
namespace bluetooth {
namespace groups {
using ::testing::_;
using ::testing::DoAll;
using ::testing::Invoke;
using ::testing::Mock;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
using ::testing::Test;
using bluetooth::groups::DeviceGroups;
using bluetooth::groups::DeviceGroupsCallbacks;
DeviceGroupsCallbacks* dev_callbacks;
RawAddress GetTestAddress(int index) {
CHECK_LT(index, UINT8_MAX);
RawAddress result = {
{0xC0, 0xDE, 0xC0, 0xDE, 0x00, static_cast<uint8_t>(index)}};
return result;
}
class MockGroupsCallbacks : public DeviceGroupsCallbacks {
public:
MockGroupsCallbacks() = default;
~MockGroupsCallbacks() override = default;
MOCK_METHOD((void), OnGroupAdded,
(const RawAddress& address, const bluetooth::Uuid& uuid,
int group_id),
(override));
MOCK_METHOD((void), OnGroupMemberAdded,
(const RawAddress& address, int group_id), (override));
MOCK_METHOD((void), OnGroupRemoved,
(const bluetooth::Uuid& uuid, int group_id), (override));
MOCK_METHOD((void), OnGroupMemberRemoved,
(const RawAddress& address, int group_id), (override));
MOCK_METHOD((void), OnGroupAddFromStorage,
(const RawAddress& address, const bluetooth::Uuid& uuid,
int group_id),
(override));
private:
DISALLOW_COPY_AND_ASSIGN(MockGroupsCallbacks);
};
class GroupsTest : public ::testing::Test {
protected:
void SetUp() override {
mock_function_count_map.clear();
callbacks.reset(new MockGroupsCallbacks());
}
void TearDown() override { DeviceGroups::CleanUp(callbacks.get()); }
std::unique_ptr<MockGroupsCallbacks> callbacks;
};
TEST_F(GroupsTest, test_initialize) {
DeviceGroups::Initialize(callbacks.get());
ASSERT_TRUE(DeviceGroups::Get());
DeviceGroups::CleanUp(callbacks.get());
}
TEST_F(GroupsTest, test_initialize_twice) {
DeviceGroups::Initialize(callbacks.get());
DeviceGroups* dev_groups_p = DeviceGroups::Get();
DeviceGroups::Initialize(callbacks.get());
ASSERT_EQ(dev_groups_p, DeviceGroups::Get());
DeviceGroups::CleanUp(callbacks.get());
dev_groups_p->CleanUp(callbacks.get());
}
TEST_F(GroupsTest, test_cleanup_initialized) {
DeviceGroups::Initialize(callbacks.get());
DeviceGroups::CleanUp(callbacks.get());
ASSERT_FALSE(DeviceGroups::Get());
}
TEST_F(GroupsTest, test_cleanup_uninitialized) {
DeviceGroups::CleanUp(callbacks.get());
ASSERT_FALSE(DeviceGroups::Get());
}
TEST_F(GroupsTest, test_groups_add_single_device) {
EXPECT_CALL(*callbacks, OnGroupAdded(GetTestAddress(1), Uuid::kEmpty, 7));
DeviceGroups::Initialize(callbacks.get());
DeviceGroups::Get()->AddDevice(GetTestAddress(1), Uuid::kEmpty, 7);
DeviceGroups::CleanUp(callbacks.get());
}
TEST_F(GroupsTest, test_groups_add_two_devices) {
EXPECT_CALL(*callbacks, OnGroupAdded(GetTestAddress(1), _, 7));
EXPECT_CALL(*callbacks, OnGroupMemberAdded(GetTestAddress(2), 7));
DeviceGroups::Initialize(callbacks.get());
DeviceGroups::Get()->AddDevice(GetTestAddress(1), Uuid::kEmpty, 7);
DeviceGroups::Get()->AddDevice(GetTestAddress(2), Uuid::kEmpty, 7);
DeviceGroups::CleanUp(callbacks.get());
}
TEST_F(GroupsTest, test_groups_remove_device) {
EXPECT_CALL(*callbacks, OnGroupMemberRemoved(GetTestAddress(2), 7));
DeviceGroups::Initialize(callbacks.get());
DeviceGroups::Get()->AddDevice(GetTestAddress(2), Uuid::kEmpty, 7);
DeviceGroups::Get()->RemoveDevice(GetTestAddress(2));
ASSERT_EQ(kGroupUnknown,
DeviceGroups::Get()->GetGroupId(GetTestAddress(2), Uuid::kEmpty));
ASSERT_EQ(kGroupUnknown,
DeviceGroups::Get()->GetGroupId(GetTestAddress(3), Uuid::kEmpty));
DeviceGroups::CleanUp(callbacks.get());
}
TEST_F(GroupsTest, test_add_multiple_devices) {
EXPECT_CALL(*callbacks, OnGroupAdded(GetTestAddress(2), Uuid::kEmpty, 7));
EXPECT_CALL(*callbacks, OnGroupMemberAdded(_, 7)).Times(2);
DeviceGroups::Initialize(callbacks.get());
DeviceGroups::Get()->AddDevice(GetTestAddress(2), Uuid::kEmpty, 7);
DeviceGroups::Get()->AddDevice(GetTestAddress(3), Uuid::kEmpty, 7);
DeviceGroups::Get()->AddDevice(GetTestAddress(4), Uuid::kEmpty, 7);
DeviceGroups::CleanUp(callbacks.get());
}
TEST_F(GroupsTest, test_remove_multiple_devices) {
EXPECT_CALL(*callbacks, OnGroupMemberRemoved(_, _)).Times(3);
DeviceGroups::Initialize(callbacks.get());
DeviceGroups::Get()->AddDevice(GetTestAddress(2), Uuid::kEmpty, 7);
DeviceGroups::Get()->AddDevice(GetTestAddress(3), Uuid::kEmpty, 7);
DeviceGroups::Get()->AddDevice(GetTestAddress(4), Uuid::kEmpty, 7);
DeviceGroups::Get()->RemoveDevice(GetTestAddress(2));
DeviceGroups::Get()->RemoveDevice(GetTestAddress(3));
DeviceGroups::Get()->RemoveDevice(GetTestAddress(4));
DeviceGroups::CleanUp(callbacks.get());
}
TEST_F(GroupsTest, test_add_multiple_groups) {
EXPECT_CALL(*callbacks, OnGroupAdded(_, _, _)).Times(2);
DeviceGroups::Initialize(callbacks.get());
DeviceGroups::Get()->AddDevice(GetTestAddress(1), Uuid::kEmpty, 8);
DeviceGroups::Get()->AddDevice(GetTestAddress(1), Uuid::kEmpty, 9);
DeviceGroups::CleanUp(callbacks.get());
}
TEST_F(GroupsTest, test_remove_multiple_groups) {
Uuid uuid1 = Uuid::GetRandom();
Uuid uuid2 = Uuid::GetRandom();
ASSERT_NE(uuid1, uuid2);
EXPECT_CALL(*callbacks, OnGroupAdded(_, _, _)).Times(2);
DeviceGroups::Initialize(callbacks.get());
DeviceGroups::Get()->AddDevice(GetTestAddress(1), uuid1, 8);
DeviceGroups::Get()->AddDevice(GetTestAddress(1), uuid2, 9);
DeviceGroups::Get()->AddDevice(GetTestAddress(2), uuid2, 9);
EXPECT_CALL(*callbacks, OnGroupMemberRemoved(GetTestAddress(1), 8));
EXPECT_CALL(*callbacks, OnGroupMemberRemoved(GetTestAddress(1), 9));
EXPECT_CALL(*callbacks, OnGroupRemoved(uuid1, 8));
EXPECT_CALL(*callbacks, OnGroupRemoved(uuid2, 9)).Times(0);
DeviceGroups::Get()->RemoveDevice(GetTestAddress(1));
DeviceGroups::CleanUp(callbacks.get());
}
TEST_F(GroupsTest, test_remove_device_fo_devices) {
Uuid uuid1 = Uuid::GetRandom();
Uuid uuid2 = Uuid::GetRandom();
EXPECT_CALL(*callbacks, OnGroupAdded(_, _, _)).Times(2);
DeviceGroups::Initialize(callbacks.get());
DeviceGroups::Get()->AddDevice(GetTestAddress(1), uuid1, 8);
DeviceGroups::Get()->AddDevice(GetTestAddress(1), uuid2, 9);
EXPECT_CALL(*callbacks, OnGroupRemoved(uuid1, 8));
EXPECT_CALL(*callbacks, OnGroupRemoved(uuid2, 9)).Times(0);
DeviceGroups::Get()->RemoveDevice(GetTestAddress(1), 8);
Mock::VerifyAndClearExpectations(&callbacks);
EXPECT_CALL(*callbacks, OnGroupRemoved(uuid1, 8)).Times(0);
EXPECT_CALL(*callbacks, OnGroupRemoved(uuid2, 9));
DeviceGroups::Get()->RemoveDevice(GetTestAddress(1), 9);
}
TEST_F(GroupsTest, test_add_devices_different_group_id) {
DeviceGroups::Initialize(callbacks.get());
DeviceGroups::Get()->AddDevice(GetTestAddress(2), Uuid::kEmpty, 10);
DeviceGroups::Get()->AddDevice(GetTestAddress(3), Uuid::kEmpty, 11);
auto group_id_1 =
DeviceGroups::Get()->GetGroupId(GetTestAddress(2), Uuid::kEmpty);
auto group_id_2 =
DeviceGroups::Get()->GetGroupId(GetTestAddress(3), Uuid::kEmpty);
ASSERT_TRUE(group_id_1 != group_id_2);
DeviceGroups::CleanUp(callbacks.get());
}
TEST_F(GroupsTest, test_group_id_assign) {
int captured_gid1 = kGroupUnknown;
int captured_gid2 = kGroupUnknown;
DeviceGroups::Initialize(callbacks.get());
EXPECT_CALL(*callbacks, OnGroupAdded(GetTestAddress(1), _, _))
.WillOnce(SaveArg<2>(&captured_gid1));
EXPECT_CALL(*callbacks, OnGroupAdded(GetTestAddress(2), _, _))
.WillOnce(SaveArg<2>(&captured_gid2));
int gid1 = DeviceGroups::Get()->AddDevice(GetTestAddress(1), Uuid::kEmpty,
bluetooth::groups::kGroupUnknown);
int gid2 = DeviceGroups::Get()->AddDevice(GetTestAddress(2), Uuid::kEmpty);
int gid3 = DeviceGroups::Get()->AddDevice(GetTestAddress(2), Uuid::kEmpty);
ASSERT_NE(bluetooth::groups::kGroupUnknown, gid1);
ASSERT_NE(bluetooth::groups::kGroupUnknown, gid2);
ASSERT_EQ(gid2, gid3);
ASSERT_EQ(gid1, captured_gid1);
ASSERT_EQ(gid2, captured_gid2);
DeviceGroups::CleanUp(callbacks.get());
}
TEST_F(GroupsTest, test_storage_calls) {
ASSERT_EQ(0, mock_function_count_map["btif_storage_load_bonded_groups"]);
DeviceGroups::Initialize(callbacks.get());
ASSERT_EQ(1, mock_function_count_map["btif_storage_load_bonded_groups"]);
ASSERT_EQ(0, mock_function_count_map["btif_storage_add_groups"]);
DeviceGroups::Get()->AddDevice(GetTestAddress(1), Uuid::kEmpty, 7);
DeviceGroups::Get()->AddDevice(GetTestAddress(1), Uuid::kEmpty, 8);
ASSERT_EQ(2, mock_function_count_map["btif_storage_add_groups"]);
DeviceGroups::Get()->AddDevice(GetTestAddress(2), Uuid::kEmpty, 7);
DeviceGroups::Get()->AddDevice(GetTestAddress(3), Uuid::kEmpty, 7);
ASSERT_EQ(4, mock_function_count_map["btif_storage_add_groups"]);
ASSERT_EQ(0, mock_function_count_map["btif_storage_remove_groups"]);
DeviceGroups::Get()->RemoveDevice(GetTestAddress(1));
DeviceGroups::Get()->RemoveDevice(GetTestAddress(2));
DeviceGroups::Get()->RemoveDevice(GetTestAddress(3));
ASSERT_EQ(3, mock_function_count_map["btif_storage_remove_groups"]);
DeviceGroups::CleanUp(callbacks.get());
}
TEST_F(GroupsTest, test_storage_content) {
int gid1 = bluetooth::groups::kGroupUnknown;
int gid2 = bluetooth::groups::kGroupUnknown;
Uuid uuid1 = Uuid::GetRandom();
Uuid uuid2 = Uuid::GetRandom();
ASSERT_NE(uuid1, uuid2);
DeviceGroups::Initialize(callbacks.get());
gid1 = DeviceGroups::Get()->AddDevice(GetTestAddress(1), uuid1, gid1);
DeviceGroups::Get()->AddDevice(GetTestAddress(2), uuid1, gid1);
gid2 = DeviceGroups::Get()->AddDevice(GetTestAddress(2), uuid2, gid2);
ASSERT_NE(bluetooth::groups::kGroupUnknown, gid1);
ASSERT_NE(gid1, gid2);
std::vector<uint8_t> dev1_storage;
std::vector<uint8_t> dev2_storage;
// Store to byte buffer
DeviceGroups::GetForStorage(GetTestAddress(1), dev1_storage);
DeviceGroups::GetForStorage(GetTestAddress(2), dev2_storage);
ASSERT_NE(0u, dev1_storage.size());
ASSERT_TRUE(dev2_storage.size() > dev1_storage.size());
// Clean it up
DeviceGroups::CleanUp(callbacks.get());
ASSERT_EQ(nullptr, DeviceGroups::Get());
// Restore dev1 from the byte buffer
DeviceGroups::Initialize(callbacks.get());
EXPECT_CALL(*callbacks, OnGroupAdded(GetTestAddress(1), uuid1, gid1));
DeviceGroups::AddFromStorage(GetTestAddress(1), dev1_storage);
// Restore dev2 from the byte buffer
EXPECT_CALL(*callbacks, OnGroupAdded(GetTestAddress(2), uuid2, gid2));
EXPECT_CALL(*callbacks, OnGroupMemberAdded(GetTestAddress(2), gid1)).Times(1);
DeviceGroups::AddFromStorage(GetTestAddress(2), dev2_storage);
DeviceGroups::CleanUp(callbacks.get());
}
} // namespace groups
} // namespace bluetooth