1 /******************************************************************************
2 *
3 * Copyright 2020 Google, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18 #include "common/metric_id_manager.h"
19
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22
23 #include <thread>
24
25 namespace testing {
26
27 using bluetooth::common::MetricIdManager;
28
kthAddress(uint32_t k)29 static bluetooth::hci::Address kthAddress(uint32_t k) {
30 uint8_t array[6] = {0, 0, 0, 0, 0, 0};
31 for (int i = 5; i >= 2; i--) {
32 array[i] = k % 256;
33 k = k / 256;
34 }
35 bluetooth::hci::Address addr(array);
36 return addr;
37 }
38
generateAddresses(const uint32_t num)39 static std::unordered_map<bluetooth::hci::Address, int> generateAddresses(const uint32_t num) {
40 // generate first num of mac address -> id pairs
41 // input may is always valid 256^6 = 2^48 > 2^32
42 std::unordered_map<bluetooth::hci::Address, int> device_map;
43 for (size_t key = 0; key < num; key++) {
44 device_map[kthAddress(key)] = key + MetricIdManager::kMinId;
45 }
46 return device_map;
47 }
48
TEST(BluetoothMetricIdManagerTest,MetricIdManagerInitCloseTest)49 TEST(BluetoothMetricIdManagerTest, MetricIdManagerInitCloseTest) {
50 auto& manager = MetricIdManager::GetInstance();
51 std::unordered_map<bluetooth::hci::Address, int> paired_device_map;
52 MetricIdManager::Callback callback = [](const bluetooth::hci::Address&, const int) {
53 return true;
54 };
55 ASSERT_TRUE(manager.Init(paired_device_map, callback, callback));
56 ASSERT_FALSE(manager.Init(paired_device_map, callback, callback));
57 ASSERT_TRUE(manager.Close());
58 }
59
TEST(BluetoothMetricIdManagerTest,MetricIdManagerNotCloseTest)60 TEST(BluetoothMetricIdManagerTest, MetricIdManagerNotCloseTest) {
61 auto& manager = MetricIdManager::GetInstance();
62 std::unordered_map<bluetooth::hci::Address, int> paired_device_map;
63 MetricIdManager::Callback callback = [](const bluetooth::hci::Address&, const int) {
64 return true;
65 };
66 ASSERT_TRUE(manager.Init(paired_device_map, callback, callback));
67
68 // should fail because it isn't closed
69 ASSERT_FALSE(manager.Init(paired_device_map, callback, callback));
70 ASSERT_TRUE(manager.Close());
71 }
72
TEST(BluetoothMetricIdManagerTest,MetricIdManagerScanDeviceFromEmptyTest)73 TEST(BluetoothMetricIdManagerTest, MetricIdManagerScanDeviceFromEmptyTest) {
74 auto& manager = MetricIdManager::GetInstance();
75 std::unordered_map<bluetooth::hci::Address, int> paired_device_map;
76 MetricIdManager::Callback callback = [](const bluetooth::hci::Address&, const int) {
77 return true;
78 };
79 // test empty map, next id should be kMinId
80 ASSERT_TRUE(manager.Init(paired_device_map, callback, callback));
81 ASSERT_EQ(manager.AllocateId(kthAddress(0)), MetricIdManager::kMinId);
82 ASSERT_EQ(manager.AllocateId(kthAddress(1)), MetricIdManager::kMinId + 1);
83 ASSERT_EQ(manager.AllocateId(kthAddress(0)), MetricIdManager::kMinId);
84 ASSERT_EQ(manager.AllocateId(kthAddress(2)), MetricIdManager::kMinId + 2);
85 ASSERT_TRUE(manager.Close());
86 }
87
TEST(BluetoothMetricIdManagerTest,MetricIdManagerScanDeviceFromFilledTest)88 TEST(BluetoothMetricIdManagerTest, MetricIdManagerScanDeviceFromFilledTest) {
89 auto& manager = MetricIdManager::GetInstance();
90 std::unordered_map<bluetooth::hci::Address, int> paired_device_map;
91 MetricIdManager::Callback callback = [](const bluetooth::hci::Address&, const int) {
92 return true;
93 };
94 int id =
95 static_cast<int>(MetricIdManager::kMaxNumPairedDevicesInMemory) + MetricIdManager::kMinId;
96 // next id should be MetricIdManager::kMaxNumPairedDevicesInMemory
97 paired_device_map = generateAddresses(MetricIdManager::kMaxNumPairedDevicesInMemory);
98 ASSERT_TRUE(manager.Init(paired_device_map, callback, callback));
99 // try new values not in the map, should get new id.
100 ASSERT_EQ(manager.AllocateId(kthAddress(INT_MAX)), id);
101 ASSERT_EQ(manager.AllocateId(kthAddress(INT_MAX - 1)), id + 1);
102 ASSERT_EQ(manager.AllocateId(kthAddress(INT_MAX)), id);
103 ASSERT_EQ(manager.AllocateId(kthAddress(INT_MAX - 2)), id + 2);
104 ASSERT_TRUE(manager.Close());
105 }
106
TEST(BluetoothMetricIdManagerTest,MetricIdManagerAllocateExistingTest)107 TEST(BluetoothMetricIdManagerTest, MetricIdManagerAllocateExistingTest) {
108 auto& manager = MetricIdManager::GetInstance();
109 std::unordered_map<bluetooth::hci::Address, int> paired_device_map =
110 generateAddresses(MetricIdManager::kMaxNumPairedDevicesInMemory);
111
112 MetricIdManager::Callback callback = [](const bluetooth::hci::Address&, const int) {
113 return true;
114 };
115 int id = MetricIdManager::kMinId;
116 // next id should be MetricIdManager::kMaxNumPairedDevicesInMemory
117 ASSERT_TRUE(manager.Init(paired_device_map, callback, callback));
118
119 // try values already in the map, should get new id.
120 ASSERT_EQ(manager.AllocateId(bluetooth::hci::Address({0, 0, 0, 0, 0, 0})), id);
121 ASSERT_EQ(manager.AllocateId(bluetooth::hci::Address({0, 0, 0, 0, 0, 1})), id + 1);
122 ASSERT_EQ(manager.AllocateId(bluetooth::hci::Address({0, 0, 0, 0, 0, 0})), id);
123 ASSERT_EQ(manager.AllocateId(bluetooth::hci::Address({0, 0, 0, 0, 0, 2})), id + 2);
124 ASSERT_TRUE(manager.Close());
125 }
126
TEST(BluetoothMetricIdManagerTest,MetricIdManagerMainTest1)127 TEST(BluetoothMetricIdManagerTest, MetricIdManagerMainTest1) {
128 auto& manager = MetricIdManager::GetInstance();
129 std::unordered_map<bluetooth::hci::Address, int> paired_device_map;
130 int placeholder = 22;
131 int* pointer = &placeholder;
132 MetricIdManager::Callback save_callback = [pointer](const bluetooth::hci::Address&, const int) {
133 *pointer = *pointer * 2;
134 return true;
135 };
136 MetricIdManager::Callback forget_callback = [pointer](const bluetooth::hci::Address&, const int) {
137 *pointer = *pointer / 2;
138 return true;
139 };
140
141 ASSERT_TRUE(manager.Init(paired_device_map, save_callback, forget_callback));
142 ASSERT_EQ(manager.AllocateId(bluetooth::hci::Address({0, 0, 0, 0, 0, 0})),
143 MetricIdManager::kMinId);
144 // save it and make sure the callback is called
145 ASSERT_TRUE(manager.SaveDevice(bluetooth::hci::Address({0, 0, 0, 0, 0, 0})));
146 ASSERT_EQ(placeholder, 44);
147
148 // should fail, since id of device is not allocated
149 ASSERT_FALSE(manager.SaveDevice(bluetooth::hci::Address({0, 0, 0, 0, 0, 1})));
150 ASSERT_EQ(placeholder, 44);
151
152 // save it and make sure the callback is called
153 ASSERT_EQ(manager.AllocateId(bluetooth::hci::Address({0, 0, 0, 0, 0, 2})),
154 MetricIdManager::kMinId + 1);
155 ASSERT_EQ(manager.AllocateId(bluetooth::hci::Address({0, 0, 0, 0, 0, 3})),
156 MetricIdManager::kMinId + 2);
157 ASSERT_TRUE(manager.SaveDevice(bluetooth::hci::Address({0, 0, 0, 0, 0, 2})));
158 ASSERT_EQ(placeholder, 88);
159 ASSERT_TRUE(manager.SaveDevice(bluetooth::hci::Address({0, 0, 0, 0, 0, 3})));
160 ASSERT_EQ(placeholder, 176);
161
162 // should be true but callback won't be called, since id had been saved
163 ASSERT_TRUE(manager.SaveDevice(bluetooth::hci::Address({0, 0, 0, 0, 0, 0})));
164 ASSERT_EQ(placeholder, 176);
165
166 // forget
167 manager.ForgetDevice(bluetooth::hci::Address({0, 0, 0, 0, 0, 1}));
168 ASSERT_EQ(placeholder, 176);
169 manager.ForgetDevice(bluetooth::hci::Address({0, 0, 0, 0, 0, 2}));
170 ASSERT_EQ(placeholder, 88);
171
172 ASSERT_TRUE(manager.Close());
173 }
174
TEST(BluetoothMetricIdManagerTest,MetricIdManagerFullPairedMap)175 TEST(BluetoothMetricIdManagerTest, MetricIdManagerFullPairedMap) {
176 auto& manager = MetricIdManager::GetInstance();
177 // preset a full map
178 std::unordered_map<bluetooth::hci::Address, int> paired_device_map =
179 generateAddresses(MetricIdManager::kMaxNumPairedDevicesInMemory);
180 int placeholder = 243;
181 int* pointer = &placeholder;
182 MetricIdManager::Callback save_callback = [pointer](const bluetooth::hci::Address&, const int) {
183 *pointer = *pointer * 2;
184 return true;
185 };
186 MetricIdManager::Callback forget_callback = [pointer](const bluetooth::hci::Address&, const int) {
187 *pointer = *pointer / 3;
188 return true;
189 };
190
191 ASSERT_TRUE(manager.Init(paired_device_map, save_callback, forget_callback));
192
193 // check if all preset ids are there.
194 // comments based on kMaxNumPairedDevicesInMemory = 200. It can change.
195 int key = 0;
196 for (key = 0; key < static_cast<int>(MetricIdManager::kMaxNumPairedDevicesInMemory); key++) {
197 ASSERT_EQ(manager.AllocateId(kthAddress(key)), key + MetricIdManager::kMinId);
198 }
199 // paired: 0, 1, 2 ... 199,
200 // scanned:
201
202 int id =
203 static_cast<int>(MetricIdManager::kMaxNumPairedDevicesInMemory + MetricIdManager::kMinId);
204 // next id should be MetricIdManager::kMaxNumPairedDevicesInMemory +
205 // MetricIdManager::kMinId
206
207 ASSERT_EQ(manager.AllocateId(kthAddress(key)), id++);
208 // paired: 0, 1, 2 ... 199,
209 // scanned: 200
210
211 // save it and make sure the callback is called
212 ASSERT_TRUE(manager.SaveDevice(kthAddress(key)));
213 // one key is evicted, another key is saved so *2/3
214 ASSERT_EQ(placeholder, 162);
215
216 // paired: 1, 2 ... 199, 200,
217 // scanned:
218
219 ASSERT_EQ(manager.AllocateId(kthAddress(0)), id++);
220 // paired: 1, 2 ... 199, 200
221 // scanned: 0
222
223 // key == 200
224 // should fail, since id of device is not allocated
225 ASSERT_FALSE(manager.SaveDevice(kthAddress(key + 1)));
226 ASSERT_EQ(placeholder, 162);
227 // paired: 1, 2 ... 199, 200,
228 // scanned: 0
229
230 ASSERT_EQ(manager.AllocateId(kthAddress(key + 1)), id++);
231 ASSERT_TRUE(manager.SaveDevice(kthAddress(key + 1)));
232 // one key is evicted, another key is saved so *2/3,
233 ASSERT_EQ(placeholder, 108);
234 // paired: 2 ... 199, 200, 201
235 // scanned: 0
236
237 ASSERT_EQ(manager.AllocateId(kthAddress(1)), id++);
238 // paired: 2 ... 199, 200, 201,
239 // scanned: 0, 1
240
241 // save it and make sure the callback is called
242 ASSERT_EQ(manager.AllocateId(kthAddress(key + 2)), id++);
243 ASSERT_EQ(manager.AllocateId(kthAddress(key + 3)), id++);
244 // paired: 2 ... 199, 200, 201,
245 // scanned: 0, 1, 202, 203
246
247 placeholder = 9;
248 ASSERT_TRUE(manager.SaveDevice(kthAddress(key + 2)));
249 // one key is evicted, another key is saved so *2/3,
250 ASSERT_EQ(placeholder, 6);
251 ASSERT_TRUE(manager.SaveDevice(kthAddress(key + 3)));
252 // one key is evicted, another key is saved so *2/3,
253 ASSERT_EQ(placeholder, 4);
254 // paired: 4 ... 199, 200, 201, 202, 203
255 // scanned: 0, 1
256
257 // should be true but callback won't be called, since id had been saved
258 ASSERT_TRUE(manager.SaveDevice(kthAddress(key + 2)));
259 ASSERT_EQ(placeholder, 4);
260
261 placeholder = 27;
262 // forget
263 manager.ForgetDevice(kthAddress(key + 200));
264 ASSERT_EQ(placeholder, 27); // should fail, no such a key
265 manager.ForgetDevice(kthAddress(key + 2));
266 ASSERT_EQ(placeholder, 9);
267 // paired: 4 ... 199, 200, 201, 203
268 // scanned: 0, 1
269
270 // save it and make sure the callback is called
271 ASSERT_EQ(manager.AllocateId(kthAddress(key + 2)), id++);
272 ASSERT_EQ(manager.AllocateId(kthAddress(key + 4)), id++);
273 ASSERT_EQ(manager.AllocateId(kthAddress(key + 5)), id++);
274 // paired: 4 ... 199, 200, 201, 203
275 // scanned: 0, 1, 202, 204, 205
276
277 ASSERT_TRUE(manager.SaveDevice(kthAddress(key + 2)));
278 ASSERT_EQ(placeholder, 18); // no key is evicted, a key is saved so *2,
279
280 // should be true but callback won't be called, since id had been saved
281 ASSERT_TRUE(manager.SaveDevice(kthAddress(key + 3)));
282 ASSERT_EQ(placeholder, 18); // no such a key in scanned
283 ASSERT_TRUE(manager.SaveDevice(kthAddress(key + 4)));
284 // one key is evicted, another key is saved so *2/3
285 ASSERT_EQ(placeholder, 12);
286 // paired: 5 6 ... 199, 200, 201, 203, 202, 204
287 // scanned: 0, 1, 205
288
289 // verify paired:
290 for (key = 5; key <= 199; key++) {
291 placeholder = 3;
292 manager.ForgetDevice(kthAddress(key));
293 ASSERT_EQ(placeholder, 1);
294 }
295 for (size_t k = MetricIdManager::kMaxNumPairedDevicesInMemory;
296 k <= MetricIdManager::kMaxNumPairedDevicesInMemory + 4; k++) {
297 placeholder = 3;
298 manager.ForgetDevice(kthAddress(k));
299 ASSERT_EQ(placeholder, 1);
300 }
301
302 // verify scanned
303 placeholder = 4;
304 ASSERT_TRUE(manager.SaveDevice(kthAddress(0)));
305 ASSERT_TRUE(manager.SaveDevice(kthAddress(1)));
306 ASSERT_TRUE(manager.SaveDevice(kthAddress(MetricIdManager::kMaxNumPairedDevicesInMemory + 5)));
307 ASSERT_EQ(placeholder, 32);
308
309 ASSERT_TRUE(manager.Close());
310 }
311
TEST(BluetoothMetricIdManagerTest,MetricIdManagerFullScannedMap)312 TEST(BluetoothMetricIdManagerTest, MetricIdManagerFullScannedMap) {
313 auto& manager = MetricIdManager::GetInstance();
314 std::unordered_map<bluetooth::hci::Address, int> paired_device_map;
315 int placeholder = 22;
316 int* pointer = &placeholder;
317 MetricIdManager::Callback save_callback = [pointer](const bluetooth::hci::Address&, const int) {
318 *pointer = *pointer * 2;
319 return true;
320 };
321 MetricIdManager::Callback forget_callback = [pointer](const bluetooth::hci::Address&, const int) {
322 *pointer = *pointer / 2;
323 return true;
324 };
325
326 ASSERT_TRUE(manager.Init(paired_device_map, save_callback, forget_callback));
327
328 // allocate kMaxNumUnpairedDevicesInMemory ids
329 // comments based on kMaxNumUnpairedDevicesInMemory = 200
330 for (int key = 0; key < static_cast<int>(MetricIdManager::kMaxNumUnpairedDevicesInMemory);
331 key++) {
332 ASSERT_EQ(manager.AllocateId(kthAddress(key)), key + MetricIdManager::kMinId);
333 }
334 // scanned: 0, 1, 2 ... 199,
335 // paired:
336
337 int id = MetricIdManager::kMaxNumUnpairedDevicesInMemory + MetricIdManager::kMinId;
338 bluetooth::hci::Address addr = kthAddress(MetricIdManager::kMaxNumUnpairedDevicesInMemory);
339 ASSERT_EQ(manager.AllocateId(addr), id);
340 // scanned: 1, 2 ... 199, 200
341
342 // save it and make sure the callback is called
343 ASSERT_TRUE(manager.SaveDevice(addr));
344 ASSERT_EQ(manager.AllocateId(addr), id);
345 ASSERT_EQ(placeholder, 44);
346 // paired: 200,
347 // scanned: 1, 2 ... 199,
348 id++;
349
350 addr = kthAddress(MetricIdManager::kMaxNumUnpairedDevicesInMemory + 1);
351 ASSERT_EQ(manager.AllocateId(addr), id++);
352 // paired: 200,
353 // scanned: 1, 2 ... 199, 201
354
355 // try to allocate for device 0, 1, 2, 3, 4....199
356 // we should have a new id every time,
357 // since the scanned map is full at this point
358 for (int key = 0; key < static_cast<int>(MetricIdManager::kMaxNumUnpairedDevicesInMemory);
359 key++) {
360 ASSERT_EQ(manager.AllocateId(kthAddress(key)), id++);
361 }
362 ASSERT_TRUE(manager.Close());
363 }
364
TEST(BluetoothMetricIdManagerTest,MetricIdManagerMultiThreadPressureTest)365 TEST(BluetoothMetricIdManagerTest, MetricIdManagerMultiThreadPressureTest) {
366 std::unordered_map<bluetooth::hci::Address, int> paired_device_map;
367 auto& manager = MetricIdManager::GetInstance();
368 int placeholder = 22;
369 int* pointer = &placeholder;
370 MetricIdManager::Callback save_callback = [pointer](const bluetooth::hci::Address&, const int) {
371 *pointer = *pointer + 1;
372 return true;
373 };
374 MetricIdManager::Callback forget_callback = [pointer](const bluetooth::hci::Address&, const int) {
375 *pointer = *pointer - 1;
376 return true;
377 };
378 ASSERT_TRUE(manager.Init(paired_device_map, save_callback, forget_callback));
379
380 // make sure no deadlock
381 std::vector<std::thread> workers;
382 for (int key = 0; key < static_cast<int>(MetricIdManager::kMaxNumUnpairedDevicesInMemory);
383 key++) {
384 workers.push_back(std::thread([key]() {
385 auto& manager = MetricIdManager::GetInstance();
386 bluetooth::hci::Address fake_mac_address = kthAddress(key);
387 manager.AllocateId(fake_mac_address);
388 ASSERT_TRUE(manager.SaveDevice(fake_mac_address));
389 manager.ForgetDevice(fake_mac_address);
390 }));
391 }
392 for (auto& worker : workers) {
393 worker.join();
394 }
395 ASSERT_TRUE(manager.IsEmpty());
396 ASSERT_TRUE(manager.Close());
397 }
398
TEST(BluetoothMetricIdManagerTest,MetricIdManagerWrapAroundTest1)399 TEST(BluetoothMetricIdManagerTest, MetricIdManagerWrapAroundTest1) {
400 std::unordered_map<bluetooth::hci::Address, int> paired_device_map;
401 auto& manager = MetricIdManager::GetInstance();
402 MetricIdManager::Callback callback = [](const bluetooth::hci::Address&, const int) {
403 return true;
404 };
405
406 // make a sparse paired_device_map
407 int min_id = MetricIdManager::kMinId;
408 paired_device_map[kthAddress(min_id)] = min_id;
409 paired_device_map[kthAddress(min_id + 1)] = min_id + 1;
410 paired_device_map[kthAddress(min_id + 3)] = min_id + 3;
411 paired_device_map[kthAddress(min_id + 4)] = min_id + 4;
412
413 int max_id = MetricIdManager::kMaxId;
414 paired_device_map[kthAddress(max_id - 3)] = max_id - 3;
415 paired_device_map[kthAddress(max_id - 4)] = max_id - 4;
416
417 ASSERT_TRUE(manager.Init(paired_device_map, callback, callback));
418
419 // next id should be max_id - 2, max_id - 1, max_id, min_id + 2, min_id + 5
420 ASSERT_EQ(manager.AllocateId(kthAddress(max_id - 2)), max_id - 2);
421 ASSERT_EQ(manager.AllocateId(kthAddress(max_id - 1)), max_id - 1);
422 ASSERT_EQ(manager.AllocateId(kthAddress(max_id)), max_id);
423 ASSERT_EQ(manager.AllocateId(kthAddress(min_id + 2)), min_id + 2);
424 ASSERT_EQ(manager.AllocateId(kthAddress(min_id + 5)), min_id + 5);
425
426 ASSERT_TRUE(manager.Close());
427 }
428
TEST(BluetoothMetricIdManagerTest,MetricIdManagerWrapAroundTest2)429 TEST(BluetoothMetricIdManagerTest, MetricIdManagerWrapAroundTest2) {
430 std::unordered_map<bluetooth::hci::Address, int> paired_device_map;
431 auto& manager = MetricIdManager::GetInstance();
432 MetricIdManager::Callback callback = [](const bluetooth::hci::Address&, const int) {
433 return true;
434 };
435
436 // make a sparse paired_device_map
437 int min_id = MetricIdManager::kMinId;
438 int max_id = MetricIdManager::kMaxId;
439 paired_device_map[kthAddress(max_id)] = max_id;
440
441 ASSERT_TRUE(manager.Init(paired_device_map, callback, callback));
442
443 // next id should be min_id, min_id + 1
444 ASSERT_EQ(manager.AllocateId(kthAddress(min_id)), min_id);
445 ASSERT_EQ(manager.AllocateId(kthAddress(min_id + 1)), min_id + 1);
446
447 ASSERT_TRUE(manager.Close());
448 }
449
450 } // namespace testing
451