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