Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e19be3ce authored by Alice Kuo's avatar Alice Kuo
Browse files

Add CachedBluetoothDeviceManager test case for csip set member device logic

The patch contains two topic.
1. Add test case for csip set member device add/remove logic
2. Fix clearNonBondedDevices issue. Remove object from set as iterating, it would cause ConcurrentModificationException, make a copy as iterating to achieve the safe remove.

Bug: 205507889
Bug: 150670922
Bug: 178981521
Test: make -j50 RunSettingsLibRoboTests ROBOTEST_FILTER=CachedBluetoothDeviceManagerTest
Change-Id: I3fa3fd9a9e13e011ce2ce01a8142511c86ccbf1c
parent 4312cc92
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -230,9 +230,10 @@ public class CachedBluetoothDeviceManager {
    private void clearNonBondedSubDevices() {
        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
            CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
            final Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
            Set<CachedBluetoothDevice> memberDevices = cachedDevice.getMemberDevice();
            if (!memberDevices.isEmpty()) {
                for (CachedBluetoothDevice memberDevice : memberDevices) {
                for (Object it : memberDevices.toArray()) {
                    CachedBluetoothDevice memberDevice = (CachedBluetoothDevice) it;
                    // Member device exists and it is not bonded
                    if (memberDevice.getDevice().getBondState() == BluetoothDevice.BOND_NONE) {
                        cachedDevice.removeMemberDevice(memberDevice);
+164 −1
Original line number Diff line number Diff line
@@ -26,7 +26,9 @@ import static org.mockito.Mockito.when;

import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
import android.os.ParcelUuid;

import org.junit.Before;
import org.junit.Test;
@@ -37,6 +39,8 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

@RunWith(RobolectricTestRunner.class)
public class CachedBluetoothDeviceManagerTest {
@@ -51,6 +55,10 @@ public class CachedBluetoothDeviceManagerTest {
    private final static String DEVICE_ADDRESS_3 = "AA:BB:CC:DD:EE:33";
    private final static long HISYNCID1 = 10;
    private final static long HISYNCID2 = 11;
    private final static Map<Integer, ParcelUuid> CAP_GROUP1 =
            Map.of(1, BluetoothUuid.CAP);
    private final static Map<Integer, ParcelUuid> CAP_GROUP2 =
            Map.of(2, BluetoothUuid.CAP);
    private final BluetoothClass DEVICE_CLASS_1 =
        new BluetoothClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES);
    private final BluetoothClass DEVICE_CLASS_2 =
@@ -70,6 +78,8 @@ public class CachedBluetoothDeviceManagerTest {
    @Mock
    private HearingAidProfile mHearingAidProfile;
    @Mock
    private CsipSetCoordinatorProfile mCsipSetCoordinatorProfile;
    @Mock
    private BluetoothDevice mDevice1;
    @Mock
    private BluetoothDevice mDevice2;
@@ -105,8 +115,12 @@ public class CachedBluetoothDeviceManagerTest {
        when(mA2dpProfile.isProfileReady()).thenReturn(true);
        when(mPanProfile.isProfileReady()).thenReturn(true);
        when(mHearingAidProfile.isProfileReady()).thenReturn(true);
        when(mCsipSetCoordinatorProfile.isProfileReady())
                .thenReturn(true);
        doAnswer((invocation) -> mHearingAidProfile).
                when(mLocalProfileManager).getHearingAidProfile();
        doAnswer((invocation) -> mCsipSetCoordinatorProfile)
                .when(mLocalProfileManager).getCsipSetCoordinatorProfile();
        mCachedDeviceManager = new CachedBluetoothDeviceManager(mContext, mLocalBluetoothManager);
        mCachedDevice1 = spy(new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice1));
        mCachedDevice2 = spy(new CachedBluetoothDevice(mContext, mLocalProfileManager, mDevice2));
@@ -298,7 +312,7 @@ public class CachedBluetoothDeviceManagerTest {
     * Test to verify OnDeviceUnpaired() for main hearing Aid device unpair.
     */
    @Test
    public void onDeviceUnpaired_unpairMainDevice() {
    public void onDeviceUnpaired_unpairHearingAidMainDevice() {
        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
@@ -398,4 +412,153 @@ public class CachedBluetoothDeviceManagerTest {
        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
        assertThat(mCachedDeviceManager.onDeviceDisappeared(cachedDevice1)).isTrue();
    }

     /**
     * Test to verify getMemberDevice(), new device has the same group id.
     */
    @Test
    public void addDevice_sameGroupId_validMemberDevice() {
        doAnswer((invocation) -> CAP_GROUP1).when(mCsipSetCoordinatorProfile)
                .getGroupUuidMapByDevice(mDevice1);
        doAnswer((invocation) -> CAP_GROUP1).when(mCsipSetCoordinatorProfile)
                .getGroupUuidMapByDevice(mDevice2);
        doAnswer((invocation) -> CAP_GROUP1).when(mCsipSetCoordinatorProfile)
                .getGroupUuidMapByDevice(mDevice3);
        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
        CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3);

        assertThat(cachedDevice1.getMemberDevice()).contains(cachedDevice2);
        assertThat(cachedDevice1.getMemberDevice()).contains(cachedDevice3);
    }

    /**
     * Test to verify getMemberDevice(), new device has the different group id.
     */
    @Test
    public void addDevice_differentGroupId_validMemberDevice() {
        doAnswer((invocation) -> CAP_GROUP1).when(mCsipSetCoordinatorProfile)
                .getGroupUuidMapByDevice(mDevice1);
        doAnswer((invocation) -> CAP_GROUP2).when(mCsipSetCoordinatorProfile)
                .getGroupUuidMapByDevice(mDevice2);
        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);

        assertThat(cachedDevice1.getMemberDevice()).isEmpty();
    }

    /**
     * Test to verify addDevice(), new device has the same group id.
     */
    @Test
    public void addDevice_sameGroupId_validCachedDevices_mainDevicesAdded_memberDevicesNotAdded() {
        doAnswer((invocation) -> CAP_GROUP1).when(mCsipSetCoordinatorProfile)
                .getGroupUuidMapByDevice(mDevice1);
        doAnswer((invocation) -> CAP_GROUP1).when(mCsipSetCoordinatorProfile)
                .getGroupUuidMapByDevice(mDevice2);
        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);

        Collection<CachedBluetoothDevice> devices = mCachedDeviceManager.getCachedDevicesCopy();
        assertThat(devices).contains(cachedDevice1);
        assertThat(devices).doesNotContain(cachedDevice2);
    }

    /**
     * Test to verify addDevice(), new device has the different group id.
     */
    @Test
    public void addDevice_differentGroupId_validCachedDevices_bothAdded() {
        doAnswer((invocation) -> CAP_GROUP1).when(mCsipSetCoordinatorProfile)
                .getGroupUuidMapByDevice(mDevice1);
        doAnswer((invocation) -> CAP_GROUP2).when(mCsipSetCoordinatorProfile)
                .getGroupUuidMapByDevice(mDevice2);
        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);

        Collection<CachedBluetoothDevice> devices = mCachedDeviceManager.getCachedDevicesCopy();
        assertThat(devices).contains(cachedDevice1);
        assertThat(devices).contains(cachedDevice2);
    }

    /**
     * Test to verify clearNonBondedDevices() for csip set member device.
     */
    @Test
    public void clearNonBondedDevices_nonBondedMemberDevice() {
        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
        when(mDevice3.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
        CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3);
        cachedDevice1.setMemberDevice(cachedDevice2);
        cachedDevice1.setMemberDevice(cachedDevice3);

        assertThat(cachedDevice1.getMemberDevice()).contains(cachedDevice2);
        assertThat(cachedDevice1.getMemberDevice()).contains(cachedDevice3);
        mCachedDeviceManager.clearNonBondedDevices();

        assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice2)).isFalse();
        assertThat(cachedDevice1.getMemberDevice().contains(cachedDevice3)).isTrue();
    }

    /**
     * Test to verify OnDeviceUnpaired() for csip device unpair.
     */
    @Test
    public void onDeviceUnpaired_unpairCsipMainDevice() {
        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
        cachedDevice1.setGroupId(1);
        cachedDevice2.setGroupId(1);
        cachedDevice1.setMemberDevice(cachedDevice2);

        // Call onDeviceUnpaired for the one in mCachedDevices.
        mCachedDeviceManager.onDeviceUnpaired(cachedDevice1);
        verify(mDevice2).removeBond();
    }

    /**
     * Test to verify OnDeviceUnpaired() for csip device unpair.
     */
    @Test
    public void onDeviceUnpaired_unpairCsipSubDevice() {
        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
        CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
        cachedDevice1.setGroupId(1);
        cachedDevice2.setGroupId(1);
        cachedDevice1.setMemberDevice(cachedDevice2);

        // Call onDeviceUnpaired for the one in mCachedDevices.
        mCachedDeviceManager.onDeviceUnpaired(cachedDevice2);
        verify(mDevice1).removeBond();
    }

    /**
     * Test to verify isSubDevice_validSubDevice().
     */
    @Test
    public void isSubDevice_validMemberDevice() {
        doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice1);
        mCachedDeviceManager.addDevice(mDevice1);

        // Both device are not sub device in default value.
        assertThat(mCachedDeviceManager.isSubDevice(mDevice1)).isFalse();
        assertThat(mCachedDeviceManager.isSubDevice(mDevice2)).isFalse();

        // Add Device-2 as device with Device-1 with the same group id, and add Device-3 with
        // the different group id.
        doReturn(CAP_GROUP1).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice2);
        doReturn(CAP_GROUP2).when(mCsipSetCoordinatorProfile).getGroupUuidMapByDevice(mDevice3);
        mCachedDeviceManager.addDevice(mDevice2);
        mCachedDeviceManager.addDevice(mDevice3);

        // Verify Device-2 is sub device, but Device-1, and Device-3 is not.
        assertThat(mCachedDeviceManager.isSubDevice(mDevice1)).isFalse();
        assertThat(mCachedDeviceManager.isSubDevice(mDevice2)).isTrue();
        assertThat(mCachedDeviceManager.isSubDevice(mDevice3)).isFalse();
    }
}