/****************************************************************************** * * Copyright 2020 Google, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #include #include #include #include #include "common/metric_id_allocator.h" namespace testing { using bluetooth::common::MetricIdAllocator; RawAddress kthAddress(uint32_t k) { uint8_t array[6] = {0, 0, 0, 0, 0, 0}; for (int i = 5; i >= 2; i--) { array[i] = k % 256; k = k / 256; } RawAddress addr(array); return addr; } std::unordered_map generateAddresses(const uint32_t num) { // generate first num of mac address -> id pairs // input may is always valid 256^6 = 2^48 > 2^32 std::unordered_map device_map; for (size_t key = 0; key < num; key++) { device_map[kthAddress(key)] = key + MetricIdAllocator::kMinId; } return device_map; } TEST(BluetoothMetricIdAllocatorTest, MetricIdAllocatorInitCloseTest) { auto& allocator = MetricIdAllocator::GetInstance(); std::unordered_map paired_device_map; MetricIdAllocator::Callback callback = [](const RawAddress&, const int) { return true; }; EXPECT_TRUE(allocator.Init(paired_device_map, callback, callback)); EXPECT_FALSE(allocator.Init(paired_device_map, callback, callback)); EXPECT_TRUE(allocator.Close()); } TEST(BluetoothMetricIdAllocatorTest, MetricIdAllocatorNotCloseTest) { auto& allocator = MetricIdAllocator::GetInstance(); std::unordered_map paired_device_map; MetricIdAllocator::Callback callback = [](const RawAddress&, const int) { return true; }; EXPECT_TRUE(allocator.Init(paired_device_map, callback, callback)); // should fail because it isn't closed EXPECT_FALSE(allocator.Init(paired_device_map, callback, callback)); EXPECT_TRUE(allocator.Close()); } TEST(BluetoothMetricIdAllocatorTest, MetricIdAllocatorScanDeviceFromEmptyTest) { auto& allocator = MetricIdAllocator::GetInstance(); std::unordered_map paired_device_map; MetricIdAllocator::Callback callback = [](const RawAddress&, const int) { return true; }; // test empty map, next id should be kMinId EXPECT_TRUE(allocator.Init(paired_device_map, callback, callback)); EXPECT_EQ(allocator.AllocateId(kthAddress(0)), MetricIdAllocator::kMinId); EXPECT_EQ(allocator.AllocateId(kthAddress(1)), MetricIdAllocator::kMinId + 1); EXPECT_EQ(allocator.AllocateId(kthAddress(0)), MetricIdAllocator::kMinId); EXPECT_EQ(allocator.AllocateId(kthAddress(2)), MetricIdAllocator::kMinId + 2); EXPECT_TRUE(allocator.Close()); } TEST(BluetoothMetricIdAllocatorTest, MetricIdAllocatorScanDeviceFromFilledTest) { auto& allocator = MetricIdAllocator::GetInstance(); std::unordered_map paired_device_map; MetricIdAllocator::Callback callback = [](const RawAddress&, const int) { return true; }; int id = static_cast(MetricIdAllocator::kMaxNumPairedDevicesInMemory) + MetricIdAllocator::kMinId; // next id should be MetricIdAllocator::kMaxNumPairedDevicesInMemory paired_device_map = generateAddresses(MetricIdAllocator::kMaxNumPairedDevicesInMemory); EXPECT_TRUE(allocator.Init(paired_device_map, callback, callback)); // try new values not in the map, should get new id. EXPECT_EQ(allocator.AllocateId(kthAddress(INT_MAX)), id); EXPECT_EQ(allocator.AllocateId(kthAddress(INT_MAX - 1)), id + 1); EXPECT_EQ(allocator.AllocateId(kthAddress(INT_MAX)), id); EXPECT_EQ(allocator.AllocateId(kthAddress(INT_MAX - 2)), id + 2); EXPECT_TRUE(allocator.Close()); } TEST(BluetoothMetricIdAllocatorTest, MetricIdAllocatorAllocateExistingTest) { auto& allocator = MetricIdAllocator::GetInstance(); std::unordered_map paired_device_map = generateAddresses(MetricIdAllocator::kMaxNumPairedDevicesInMemory); MetricIdAllocator::Callback callback = [](const RawAddress&, const int) { return true; }; int id = MetricIdAllocator::kMinId; // next id should be MetricIdAllocator::kMaxNumPairedDevicesInMemory EXPECT_TRUE(allocator.Init(paired_device_map, callback, callback)); // try values already in the map, should get new id. EXPECT_EQ(allocator.AllocateId(RawAddress({0, 0, 0, 0, 0, 0})), id); EXPECT_EQ(allocator.AllocateId(RawAddress({0, 0, 0, 0, 0, 1})), id + 1); EXPECT_EQ(allocator.AllocateId(RawAddress({0, 0, 0, 0, 0, 0})), id); EXPECT_EQ(allocator.AllocateId(RawAddress({0, 0, 0, 0, 0, 2})), id + 2); EXPECT_TRUE(allocator.Close()); } TEST(BluetoothMetricIdAllocatorTest, MetricIdAllocatorMainTest1) { auto& allocator = MetricIdAllocator::GetInstance(); std::unordered_map paired_device_map; int dummy = 22; int* pointer = &dummy; MetricIdAllocator::Callback save_callback = [pointer](const RawAddress&, const int) { *pointer = *pointer * 2; return true; }; MetricIdAllocator::Callback forget_callback = [pointer](const RawAddress&, const int) { *pointer = *pointer / 2; return true; }; EXPECT_TRUE( allocator.Init(paired_device_map, save_callback, forget_callback)); EXPECT_EQ(allocator.AllocateId(RawAddress({0, 0, 0, 0, 0, 0})), MetricIdAllocator::kMinId); // save it and make sure the callback is called EXPECT_TRUE(allocator.SaveDevice(RawAddress({0, 0, 0, 0, 0, 0}))); EXPECT_EQ(dummy, 44); // should fail, since id of device is not allocated EXPECT_FALSE(allocator.SaveDevice(RawAddress({0, 0, 0, 0, 0, 1}))); EXPECT_EQ(dummy, 44); // save it and make sure the callback is called EXPECT_EQ(allocator.AllocateId(RawAddress({0, 0, 0, 0, 0, 2})), MetricIdAllocator::kMinId + 1); EXPECT_EQ(allocator.AllocateId(RawAddress({0, 0, 0, 0, 0, 3})), MetricIdAllocator::kMinId + 2); EXPECT_TRUE(allocator.SaveDevice(RawAddress({0, 0, 0, 0, 0, 2}))); EXPECT_EQ(dummy, 88); EXPECT_TRUE(allocator.SaveDevice(RawAddress({0, 0, 0, 0, 0, 3}))); EXPECT_EQ(dummy, 176); // should be true but callback won't be called, since id had been saved EXPECT_TRUE(allocator.SaveDevice(RawAddress({0, 0, 0, 0, 0, 0}))); EXPECT_EQ(dummy, 176); // forget allocator.ForgetDevice(RawAddress({0, 0, 0, 0, 0, 1})); EXPECT_EQ(dummy, 176); allocator.ForgetDevice(RawAddress({0, 0, 0, 0, 0, 2})); EXPECT_EQ(dummy, 88); EXPECT_TRUE(allocator.Close()); } TEST(BluetoothMetricIdAllocatorTest, MetricIdAllocatorFullPairedMap) { auto& allocator = MetricIdAllocator::GetInstance(); // preset a full map std::unordered_map paired_device_map = generateAddresses(MetricIdAllocator::kMaxNumPairedDevicesInMemory); int dummy = 243; int* pointer = &dummy; MetricIdAllocator::Callback save_callback = [pointer](const RawAddress&, const int) { *pointer = *pointer * 2; return true; }; MetricIdAllocator::Callback forget_callback = [pointer](const RawAddress&, const int) { *pointer = *pointer / 3; return true; }; EXPECT_TRUE( allocator.Init(paired_device_map, save_callback, forget_callback)); // check if all preset ids are there. // comments based on kMaxNumPairedDevicesInMemory = 200. It can change. int key = 0; for (key = 0; key < static_cast(MetricIdAllocator::kMaxNumPairedDevicesInMemory); key++) { EXPECT_EQ(allocator.AllocateId(kthAddress(key)), key + MetricIdAllocator::kMinId); } // paired: 0, 1, 2 ... 199, // scanned: int id = static_cast(MetricIdAllocator::kMaxNumPairedDevicesInMemory + MetricIdAllocator::kMinId); // next id should be MetricIdAllocator::kMaxNumPairedDevicesInMemory + // MetricIdAllocator::kMinId EXPECT_EQ(allocator.AllocateId(kthAddress(key)), id++); // paired: 0, 1, 2 ... 199, // scanned: 200 // save it and make sure the callback is called EXPECT_TRUE(allocator.SaveDevice(kthAddress(key))); EXPECT_EQ(dummy, 162); // one key is evicted, another key is saved so *2/3 // paired: 1, 2 ... 199, 200, // scanned: EXPECT_EQ(allocator.AllocateId(kthAddress(0)), id++); // paired: 1, 2 ... 199, 200 // scanned: 0 // key == 200 // should fail, since id of device is not allocated EXPECT_FALSE(allocator.SaveDevice(kthAddress(key + 1))); EXPECT_EQ(dummy, 162); // paired: 1, 2 ... 199, 200, // scanned: 0 EXPECT_EQ(allocator.AllocateId(kthAddress(key + 1)), id++); EXPECT_TRUE(allocator.SaveDevice(kthAddress(key + 1))); EXPECT_EQ(dummy, 108); // one key is evicted, another key is saved so *2/3, // paired: 2 ... 199, 200, 201 // scanned: 0 EXPECT_EQ(allocator.AllocateId(kthAddress(1)), id++); // paired: 2 ... 199, 200, 201, // scanned: 0, 1 // save it and make sure the callback is called EXPECT_EQ(allocator.AllocateId(kthAddress(key + 2)), id++); EXPECT_EQ(allocator.AllocateId(kthAddress(key + 3)), id++); // paired: 2 ... 199, 200, 201, // scanned: 0, 1, 202, 203 dummy = 9; EXPECT_TRUE(allocator.SaveDevice(kthAddress(key + 2))); EXPECT_EQ(dummy, 6); // one key is evicted, another key is saved so *2/3, EXPECT_TRUE(allocator.SaveDevice(kthAddress(key + 3))); EXPECT_EQ(dummy, 4); // one key is evicted, another key is saved so *2/3, // paired: 4 ... 199, 200, 201, 202, 203 // scanned: 0, 1 // should be true but callback won't be called, since id had been saved EXPECT_TRUE(allocator.SaveDevice(kthAddress(key + 2))); EXPECT_EQ(dummy, 4); dummy = 27; // forget allocator.ForgetDevice(kthAddress(key + 200)); EXPECT_EQ(dummy, 27); // should fail, no such a key allocator.ForgetDevice(kthAddress(key + 2)); EXPECT_EQ(dummy, 9); // paired: 4 ... 199, 200, 201, 203 // scanned: 0, 1 // save it and make sure the callback is called EXPECT_EQ(allocator.AllocateId(kthAddress(key + 2)), id++); EXPECT_EQ(allocator.AllocateId(kthAddress(key + 4)), id++); EXPECT_EQ(allocator.AllocateId(kthAddress(key + 5)), id++); // paired: 4 ... 199, 200, 201, 203 // scanned: 0, 1, 202, 204, 205 EXPECT_TRUE(allocator.SaveDevice(kthAddress(key + 2))); EXPECT_EQ(dummy, 18); // no key is evicted, a key is saved so *2, // should be true but callback won't be called, since id had been saved EXPECT_TRUE(allocator.SaveDevice(kthAddress(key + 3))); EXPECT_EQ(dummy, 18); // no such a key in scanned EXPECT_TRUE(allocator.SaveDevice(kthAddress(key + 4))); EXPECT_EQ(dummy, 12); // one key is evicted, another key is saved so *2/3, // paired: 5 6 ... 199, 200, 201, 203, 202, 204 // scanned: 0, 1, 205 // verify paired: for (key = 5; key <= 199; key++) { dummy = 3; allocator.ForgetDevice(kthAddress(key)); EXPECT_EQ(dummy, 1); } for (size_t k = MetricIdAllocator::kMaxNumPairedDevicesInMemory; k <= MetricIdAllocator::kMaxNumPairedDevicesInMemory + 4; k++) { dummy = 3; allocator.ForgetDevice(kthAddress(k)); EXPECT_EQ(dummy, 1); } // verify scanned dummy = 4; EXPECT_TRUE(allocator.SaveDevice(kthAddress(0))); EXPECT_TRUE(allocator.SaveDevice(kthAddress(1))); EXPECT_TRUE(allocator.SaveDevice( kthAddress(MetricIdAllocator::kMaxNumPairedDevicesInMemory + 5))); EXPECT_EQ(dummy, 32); EXPECT_TRUE(allocator.Close()); } TEST(BluetoothMetricIdAllocatorTest, MetricIdAllocatorFullScannedMap) { auto& allocator = MetricIdAllocator::GetInstance(); std::unordered_map paired_device_map; int dummy = 22; int* pointer = &dummy; MetricIdAllocator::Callback save_callback = [pointer](const RawAddress&, const int) { *pointer = *pointer * 2; return true; }; MetricIdAllocator::Callback forget_callback = [pointer](const RawAddress&, const int) { *pointer = *pointer / 2; return true; }; EXPECT_TRUE( allocator.Init(paired_device_map, save_callback, forget_callback)); // allocate kMaxNumUnpairedDevicesInMemory ids // comments based on kMaxNumUnpairedDevicesInMemory = 200 for (int key = 0; key < static_cast(MetricIdAllocator::kMaxNumUnpairedDevicesInMemory); key++) { EXPECT_EQ(allocator.AllocateId(kthAddress(key)), key + MetricIdAllocator::kMinId); } // scanned: 0, 1, 2 ... 199, // paired: int id = MetricIdAllocator::kMaxNumUnpairedDevicesInMemory + MetricIdAllocator::kMinId; RawAddress addr = kthAddress(MetricIdAllocator::kMaxNumUnpairedDevicesInMemory); EXPECT_EQ(allocator.AllocateId(addr), id); // scanned: 1, 2 ... 199, 200 // save it and make sure the callback is called EXPECT_TRUE(allocator.SaveDevice(addr)); EXPECT_EQ(allocator.AllocateId(addr), id); EXPECT_EQ(dummy, 44); // paired: 200, // scanned: 1, 2 ... 199, id++; addr = kthAddress(MetricIdAllocator::kMaxNumUnpairedDevicesInMemory + 1); EXPECT_EQ(allocator.AllocateId(addr), id++); // paired: 200, // scanned: 1, 2 ... 199, 201 // try to allocate for device 0, 1, 2, 3, 4....199 // we should have a new id every time, // since the scanned map is full at this point for (int key = 0; key < static_cast(MetricIdAllocator::kMaxNumUnpairedDevicesInMemory); key++) { EXPECT_EQ(allocator.AllocateId(kthAddress(key)), id++); } EXPECT_TRUE(allocator.Close()); } TEST(BluetoothMetricIdAllocatorTest, MetricIdAllocatorMultiThreadPressureTest) { std::unordered_map paired_device_map; auto& allocator = MetricIdAllocator::GetInstance(); int dummy = 22; int* pointer = &dummy; MetricIdAllocator::Callback save_callback = [pointer](const RawAddress&, const int) { *pointer = *pointer + 1; return true; }; MetricIdAllocator::Callback forget_callback = [pointer](const RawAddress&, const int) { *pointer = *pointer - 1; return true; }; EXPECT_TRUE( allocator.Init(paired_device_map, save_callback, forget_callback)); // make sure no deadlock std::vector workers; for (int key = 0; key < static_cast(MetricIdAllocator::kMaxNumUnpairedDevicesInMemory); key++) { workers.push_back(std::thread([key]() { auto& allocator = MetricIdAllocator::GetInstance(); RawAddress fake_mac_address = kthAddress(key); allocator.AllocateId(fake_mac_address); EXPECT_TRUE(allocator.SaveDevice(fake_mac_address)); allocator.ForgetDevice(fake_mac_address); })); } for (auto& worker : workers) { worker.join(); } EXPECT_TRUE(allocator.IsEmpty()); EXPECT_TRUE(allocator.Close()); } TEST(BluetoothMetricIdAllocatorTest, MetricIdAllocatorWrapAroundTest1) { std::unordered_map paired_device_map; auto& allocator = MetricIdAllocator::GetInstance(); MetricIdAllocator::Callback callback = [](const RawAddress&, const int) { return true; }; // make a sparse paired_device_map int min_id = MetricIdAllocator::kMinId; paired_device_map[kthAddress(min_id)] = min_id; paired_device_map[kthAddress(min_id + 1)] = min_id + 1; paired_device_map[kthAddress(min_id + 3)] = min_id + 3; paired_device_map[kthAddress(min_id + 4)] = min_id + 4; int max_id = MetricIdAllocator::kMaxId; paired_device_map[kthAddress(max_id - 3)] = max_id - 3; paired_device_map[kthAddress(max_id - 4)] = max_id - 4; EXPECT_TRUE(allocator.Init(paired_device_map, callback, callback)); // next id should be max_id - 2, max_id - 1, max_id, min_id + 2, min_id + 5 EXPECT_EQ(allocator.AllocateId(kthAddress(max_id - 2)), max_id - 2); EXPECT_EQ(allocator.AllocateId(kthAddress(max_id - 1)), max_id - 1); EXPECT_EQ(allocator.AllocateId(kthAddress(max_id)), max_id); EXPECT_EQ(allocator.AllocateId(kthAddress(min_id + 2)), min_id + 2); EXPECT_EQ(allocator.AllocateId(kthAddress(min_id + 5)), min_id + 5); EXPECT_TRUE(allocator.Close()); } TEST(BluetoothMetricIdAllocatorTest, MetricIdAllocatorWrapAroundTest2) { std::unordered_map paired_device_map; auto& allocator = MetricIdAllocator::GetInstance(); MetricIdAllocator::Callback callback = [](const RawAddress&, const int) { return true; }; // make a sparse paired_device_map int min_id = MetricIdAllocator::kMinId; int max_id = MetricIdAllocator::kMaxId; paired_device_map[kthAddress(max_id)] = max_id; EXPECT_TRUE(allocator.Init(paired_device_map, callback, callback)); // next id should be min_id, min_id + 1 EXPECT_EQ(allocator.AllocateId(kthAddress(min_id)), min_id); EXPECT_EQ(allocator.AllocateId(kthAddress(min_id + 1)), min_id + 1); EXPECT_TRUE(allocator.Close()); } } // namespace testing