blob: becdb3a4e8c4c1303a906da84f4c5d337b823318 [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.
*/
package com.android.bluetooth.btservice.storage;
import static org.mockito.Mockito.*;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import androidx.room.Room;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.List;
@MediumTest
@RunWith(AndroidJUnit4.class)
public final class DatabaseManagerTest {
@Mock private AdapterService mAdapterService;
private MetadataDatabase mDatabase;
private DatabaseManager mDatabaseManager;
private BluetoothDevice mTestDevice;
private static final String LOCAL_STORAGE = "LocalStorage";
private static final String TEST_BT_ADDR = "11:22:33:44:55:66";
private static final String OTHER_BT_ADDR = "11:11:11:11:11:11";
private static final int A2DP_SUPPORT_OP_CODEC_TEST = 0;
private static final int A2DP_ENALBED_OP_CODEC_TEST = 1;
private static final int MAX_META_ID = 16;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
TestUtils.setAdapterService(mAdapterService);
mTestDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(TEST_BT_ADDR);
// Create a memory database for DatabaseManager instead of use a real database.
mDatabase = Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getTargetContext(),
MetadataDatabase.class).build();
when(mAdapterService.getPackageManager()).thenReturn(
InstrumentationRegistry.getTargetContext().getPackageManager());
mDatabaseManager = new DatabaseManager(mAdapterService);
BluetoothDevice[] bondedDevices = {mTestDevice};
doReturn(bondedDevices).when(mAdapterService).getBondedDevices();
doNothing().when(mAdapterService).metadataChanged(anyString(), anyInt(), anyString());
restartDatabaseManagerHelper();
}
@After
public void tearDown() throws Exception {
TestUtils.clearAdapterService(mAdapterService);
mDatabase.deleteAll();
mDatabaseManager.cleanup();
}
@Test
public void testMetadataDefault() {
Metadata data = new Metadata(TEST_BT_ADDR);
mDatabase.insert(data);
restartDatabaseManagerHelper();
for (int id = 0; id < BluetoothProfile.MAX_PROFILE_ID; id++) {
Assert.assertEquals(BluetoothProfile.PRIORITY_UNDEFINED,
mDatabaseManager.getProfilePriority(mTestDevice, id));
}
Assert.assertEquals(BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED,
mDatabaseManager.getA2dpSupportsOptionalCodecs(mTestDevice));
Assert.assertEquals(BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED,
mDatabaseManager.getA2dpOptionalCodecsEnabled(mTestDevice));
for (int id = 0; id < MAX_META_ID; id++) {
Assert.assertNull(mDatabaseManager.getCustomMeta(mTestDevice, id));
}
}
@Test
public void testSetGetProfilePriority() {
int badPriority = -100;
// Cases of device not in database
testSetGetProfilePriorityCase(false, BluetoothProfile.PRIORITY_UNDEFINED,
BluetoothProfile.PRIORITY_UNDEFINED, true);
testSetGetProfilePriorityCase(false, BluetoothProfile.PRIORITY_OFF,
BluetoothProfile.PRIORITY_OFF, true);
testSetGetProfilePriorityCase(false, BluetoothProfile.PRIORITY_ON,
BluetoothProfile.PRIORITY_ON, true);
testSetGetProfilePriorityCase(false, BluetoothProfile.PRIORITY_AUTO_CONNECT,
BluetoothProfile.PRIORITY_AUTO_CONNECT, true);
testSetGetProfilePriorityCase(false, badPriority,
BluetoothProfile.PRIORITY_UNDEFINED, false);
// Cases of device already in database
testSetGetProfilePriorityCase(true, BluetoothProfile.PRIORITY_UNDEFINED,
BluetoothProfile.PRIORITY_UNDEFINED, true);
testSetGetProfilePriorityCase(true, BluetoothProfile.PRIORITY_OFF,
BluetoothProfile.PRIORITY_OFF, true);
testSetGetProfilePriorityCase(true, BluetoothProfile.PRIORITY_ON,
BluetoothProfile.PRIORITY_ON, true);
testSetGetProfilePriorityCase(true, BluetoothProfile.PRIORITY_AUTO_CONNECT,
BluetoothProfile.PRIORITY_AUTO_CONNECT, true);
testSetGetProfilePriorityCase(true, badPriority,
BluetoothProfile.PRIORITY_UNDEFINED, false);
}
@Test
public void testSetGetA2dpSupportsOptionalCodecs() {
int badValue = -100;
// Cases of device not in database
testSetGetA2dpOptionalCodecsCase(A2DP_SUPPORT_OP_CODEC_TEST, false,
BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN,
BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
testSetGetA2dpOptionalCodecsCase(A2DP_SUPPORT_OP_CODEC_TEST, false,
BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED,
BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
testSetGetA2dpOptionalCodecsCase(A2DP_SUPPORT_OP_CODEC_TEST, false,
BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED,
BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
testSetGetA2dpOptionalCodecsCase(A2DP_SUPPORT_OP_CODEC_TEST, false,
badValue, BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
// Cases of device already in database
testSetGetA2dpOptionalCodecsCase(A2DP_SUPPORT_OP_CODEC_TEST, true,
BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN,
BluetoothA2dp.OPTIONAL_CODECS_SUPPORT_UNKNOWN);
testSetGetA2dpOptionalCodecsCase(A2DP_SUPPORT_OP_CODEC_TEST, true,
BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED,
BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
testSetGetA2dpOptionalCodecsCase(A2DP_SUPPORT_OP_CODEC_TEST, true,
BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED,
BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED);
testSetGetA2dpOptionalCodecsCase(A2DP_SUPPORT_OP_CODEC_TEST, true,
badValue, BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED);
}
@Test
public void testSetGetA2dpOptionalCodecsEnabled() {
int badValue = -100;
// Cases of device not in database
testSetGetA2dpOptionalCodecsCase(A2DP_ENALBED_OP_CODEC_TEST, false,
BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN,
BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED);
testSetGetA2dpOptionalCodecsCase(A2DP_ENALBED_OP_CODEC_TEST, false,
BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED,
BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED);
testSetGetA2dpOptionalCodecsCase(A2DP_ENALBED_OP_CODEC_TEST, false,
BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED,
BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED);
testSetGetA2dpOptionalCodecsCase(A2DP_ENALBED_OP_CODEC_TEST, false,
badValue, BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED);
// Cases of device already in database
testSetGetA2dpOptionalCodecsCase(A2DP_ENALBED_OP_CODEC_TEST, true,
BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN,
BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN);
testSetGetA2dpOptionalCodecsCase(A2DP_ENALBED_OP_CODEC_TEST, true,
BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED,
BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED);
testSetGetA2dpOptionalCodecsCase(A2DP_ENALBED_OP_CODEC_TEST, true,
BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED,
BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED);
testSetGetA2dpOptionalCodecsCase(A2DP_ENALBED_OP_CODEC_TEST, true,
badValue, BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED);
}
@Test
public void testRemoveUnusedMetadata() {
// Insert three devices to database and cache, only mTestDevice is
// in the bonded list
BluetoothDevice otherDevice = BluetoothAdapter.getDefaultAdapter()
.getRemoteDevice(OTHER_BT_ADDR);
Metadata otherData = new Metadata(OTHER_BT_ADDR);
// Add metadata for otherDevice
otherData.setCustomizedMeta(0, "value");
mDatabaseManager.mMetadataCache.put(OTHER_BT_ADDR, otherData);
mDatabase.insert(otherData);
Metadata data = new Metadata(TEST_BT_ADDR);
mDatabaseManager.mMetadataCache.put(TEST_BT_ADDR, data);
mDatabase.insert(data);
mDatabaseManager.removeUnusedMetadata();
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
// Check removed device report metadata changed to null
verify(mAdapterService).metadataChanged(OTHER_BT_ADDR, 0, null);
List<Metadata> list = mDatabase.load();
// Check number of metadata in the database
Assert.assertEquals(1, list.size());
// Check whether the device is in database
Metadata checkData = list.get(0);
Assert.assertEquals(TEST_BT_ADDR, checkData.getAddress());
mDatabase.deleteAll();
// Wait for clear database
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
mDatabaseManager.mMetadataCache.clear();
}
@Test
public void testSetGetCustomMeta() {
int badKey = 100;
String value = "input value";
// Device is not in database
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_MANUFACTURER_NAME,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_MODEL_NAME,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_SOFTWARE_VERSION,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_HARDWARE_VERSION,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_COMPANION_APP,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_MAIN_ICON,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_RIGHT_ICON,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_CASE_ICON,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_LEFT_CHARGING,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_RIGHT_CHARGING,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_UNTHETHERED_CASE_CHARGING,
value, true);
testSetGetCustomMetaCase(false, BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI,
value, true);
testSetGetCustomMetaCase(false, badKey, value, false);
// Device is in database
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_MANUFACTURER_NAME,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_MODEL_NAME,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_SOFTWARE_VERSION,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_HARDWARE_VERSION,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_COMPANION_APP,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_MAIN_ICON,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_LEFT_ICON,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_RIGHT_ICON,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_CASE_ICON,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_CASE_BATTERY,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_LEFT_CHARGING,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_RIGHT_CHARGING,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_UNTHETHERED_CASE_CHARGING,
value, true);
testSetGetCustomMetaCase(true, BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI,
value, true);
}
void restartDatabaseManagerHelper() {
Metadata data = new Metadata(LOCAL_STORAGE);
data.migrated = true;
mDatabase.insert(data);
mDatabaseManager.cleanup();
mDatabaseManager.start(mDatabase);
// Wait for handler thread finish its task.
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
// Remove local storage
mDatabaseManager.mMetadataCache.remove(LOCAL_STORAGE);
mDatabase.delete(LOCAL_STORAGE);
}
void testSetGetProfilePriorityCase(boolean stored, int priority, int expectedPriority,
boolean expectedSetResult) {
if (stored) {
Metadata data = new Metadata(TEST_BT_ADDR);
mDatabaseManager.mMetadataCache.put(TEST_BT_ADDR, data);
mDatabase.insert(data);
}
Assert.assertEquals(expectedSetResult,
mDatabaseManager.setProfilePriority(mTestDevice,
BluetoothProfile.HEADSET, priority));
Assert.assertEquals(expectedPriority,
mDatabaseManager.getProfilePriority(mTestDevice, BluetoothProfile.HEADSET));
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
List<Metadata> list = mDatabase.load();
// Check number of metadata in the database
if (!stored) {
if (priority != BluetoothProfile.PRIORITY_OFF
&& priority != BluetoothProfile.PRIORITY_ON
&& priority != BluetoothProfile.PRIORITY_AUTO_CONNECT) {
// Database won't be updated
Assert.assertEquals(0, list.size());
return;
}
}
Assert.assertEquals(1, list.size());
// Check whether the device is in database
restartDatabaseManagerHelper();
Assert.assertEquals(expectedPriority,
mDatabaseManager.getProfilePriority(mTestDevice, BluetoothProfile.HEADSET));
mDatabase.deleteAll();
// Wait for clear database
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
mDatabaseManager.mMetadataCache.clear();
}
void testSetGetA2dpOptionalCodecsCase(int test, boolean stored, int value, int expectedValue) {
if (stored) {
Metadata data = new Metadata(TEST_BT_ADDR);
mDatabaseManager.mMetadataCache.put(TEST_BT_ADDR, data);
mDatabase.insert(data);
}
if (test == A2DP_SUPPORT_OP_CODEC_TEST) {
mDatabaseManager.setA2dpSupportsOptionalCodecs(mTestDevice, value);
Assert.assertEquals(expectedValue,
mDatabaseManager.getA2dpSupportsOptionalCodecs(mTestDevice));
} else {
mDatabaseManager.setA2dpOptionalCodecsEnabled(mTestDevice, value);
Assert.assertEquals(expectedValue,
mDatabaseManager.getA2dpOptionalCodecsEnabled(mTestDevice));
}
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
List<Metadata> list = mDatabase.load();
// Check number of metadata in the database
if (!stored) {
// Database won't be updated
Assert.assertEquals(0, list.size());
return;
}
Assert.assertEquals(1, list.size());
// Check whether the device is in database
restartDatabaseManagerHelper();
if (test == A2DP_SUPPORT_OP_CODEC_TEST) {
Assert.assertEquals(expectedValue,
mDatabaseManager.getA2dpSupportsOptionalCodecs(mTestDevice));
} else {
Assert.assertEquals(expectedValue,
mDatabaseManager.getA2dpOptionalCodecsEnabled(mTestDevice));
}
mDatabase.deleteAll();
// Wait for clear database
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
mDatabaseManager.mMetadataCache.clear();
}
void testSetGetCustomMetaCase(boolean stored, int key, String value, boolean expectedResult) {
String testValue = "test value";
int verifyTime = 1;
if (stored) {
Metadata data = new Metadata(TEST_BT_ADDR);
mDatabaseManager.mMetadataCache.put(TEST_BT_ADDR, data);
mDatabase.insert(data);
Assert.assertEquals(expectedResult,
mDatabaseManager.setCustomMeta(mTestDevice, key, testValue));
verify(mAdapterService).metadataChanged(TEST_BT_ADDR, key, testValue);
verifyTime++;
}
Assert.assertEquals(expectedResult,
mDatabaseManager.setCustomMeta(mTestDevice, key, value));
if (expectedResult) {
// Check for callback and get value
verify(mAdapterService, times(verifyTime)).metadataChanged(TEST_BT_ADDR, key, value);
Assert.assertEquals(value,
mDatabaseManager.getCustomMeta(mTestDevice, key));
} else {
Assert.assertNull(mDatabaseManager.getCustomMeta(mTestDevice, key));
return;
}
// Wait for database update
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
// Check whether the value is saved in database
restartDatabaseManagerHelper();
Assert.assertEquals(value,
mDatabaseManager.getCustomMeta(mTestDevice, key));
mDatabase.deleteAll();
// Wait for clear database
TestUtils.waitForLooperToFinishScheduledTask(mDatabaseManager.getHandlerLooper());
mDatabaseManager.mMetadataCache.clear();
}
}