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

Commit e1d3291a authored by Hyundo Moon's avatar Hyundo Moon Committed by Cherrypicker Worker
Browse files

Add MapClientServiceTest

Bug: 237467631
Test: atest MapClientServiceTest
Change-Id: I212a7ead80ed2a289293b480862668f733828d2e
(cherry picked from commit cc75d744)
Merged-In: I212a7ead80ed2a289293b480862668f733828d2e
parent 0db97b88
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -64,7 +64,8 @@ public class MapClientService extends ProfileService {
    private AdapterService mAdapterService;
    private DatabaseManager mDatabaseManager;
    private static MapClientService sMapClientService;
    private MapBroadcastReceiver mMapReceiver;
    @VisibleForTesting
    MapBroadcastReceiver mMapReceiver;

    public static boolean isEnabled() {
        return BluetoothProperties.isProfileMapClientEnabled().orElse(false);
@@ -82,7 +83,8 @@ public class MapClientService extends ProfileService {
        return sMapClientService;
    }

    private static synchronized void setMapClientService(MapClientService instance) {
    @VisibleForTesting
    static synchronized void setMapClientService(MapClientService instance) {
        if (DBG) {
            Log.d(TAG, "setMapClientService(): set to: " + instance);
        }
@@ -362,6 +364,7 @@ public class MapClientService extends ProfileService {
            Log.d(TAG, "in Cleanup");
        }
        removeUncleanAccounts();
        mMapInstanceMap.clear();
        // TODO(b/72948646): should be moved to stop()
        setMapClientService(null);
    }
@@ -719,7 +722,8 @@ public class MapClientService extends ProfileService {
        }
    }

    private class MapBroadcastReceiver extends BroadcastReceiver {
    @VisibleForTesting
    class MapBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
+311 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 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.mapclient;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadsetClient;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Intent;

import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import androidx.test.rule.ServiceTestRule;
import androidx.test.runner.AndroidJUnit4;

import com.android.bluetooth.BluetoothMethodProxy;
import com.android.bluetooth.TestUtils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.storage.DatabaseManager;

import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@MediumTest
@RunWith(AndroidJUnit4.class)
public class MapClientServiceTest {
    private static final String REMOTE_DEVICE_ADDRESS = "00:00:00:00:00:00";

    @Rule public final ServiceTestRule mServiceRule = new ServiceTestRule();

    @Mock private AdapterService mAdapterService;
    @Mock private DatabaseManager mDatabaseManager;

    private MapClientService mService = null;
    private BluetoothAdapter mAdapter = null;
    private BluetoothDevice mRemoteDevice;

    @Before
    public void setUp() throws Exception {
        Assume.assumeTrue("Ignore test when MapClientService is not enabled",
                MapClientService.isEnabled());
        MockitoAnnotations.initMocks(this);
        TestUtils.setAdapterService(mAdapterService);
        doReturn(mDatabaseManager).when(mAdapterService).getDatabase();
        doReturn(true, false).when(mAdapterService).isStartedProfile(anyString());
        TestUtils.startService(mServiceRule, MapClientService.class);
        mService = MapClientService.getMapClientService();
        assertThat(mService).isNotNull();
        // Try getting the Bluetooth adapter
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        assertThat(mAdapter).isNotNull();
        mRemoteDevice = mAdapter.getRemoteDevice(REMOTE_DEVICE_ADDRESS);
    }

    @After
    public void tearDown() throws Exception {
        if (!MapClientService.isEnabled()) {
            return;
        }
        TestUtils.stopService(mServiceRule, MapClientService.class);
        mService = MapClientService.getMapClientService();
        assertThat(mService).isNull();
        TestUtils.clearAdapterService(mAdapterService);
        BluetoothMethodProxy.setInstanceForTesting(null);
    }

    @Test
    public void initialize() {
        assertThat(MapClientService.getMapClientService()).isNotNull();
    }

    @Test
    public void setMapClientService_withNull() {
        MapClientService.setMapClientService(null);

        assertThat(MapClientService.getMapClientService()).isNull();
    }

    @Test
    public void dump_callsStateMachineDump() {
        MceStateMachine sm = mock(MceStateMachine.class);
        mService.getInstanceMap().put(mRemoteDevice, sm);
        StringBuilder builder = new StringBuilder();

        mService.dump(builder);

        verify(sm).dump(builder);
    }

    @Test
    public void setConnectionPolicy() {
        int connectionPolicy = BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
        when(mDatabaseManager.setProfileConnectionPolicy(
                mRemoteDevice, BluetoothProfile.MAP_CLIENT, connectionPolicy)).thenReturn(true);

        assertThat(mService.setConnectionPolicy(mRemoteDevice, connectionPolicy)).isTrue();
    }

    @Test
    public void getConnectionPolicy() {
        int connectionPolicy = BluetoothProfile.CONNECTION_POLICY_ALLOWED;
        when(mDatabaseManager.getProfileConnectionPolicy(
                mRemoteDevice, BluetoothProfile.MAP_CLIENT)).thenReturn(connectionPolicy);

        assertThat(mService.getConnectionPolicy(mRemoteDevice)).isEqualTo(connectionPolicy);
    }

    @Test
    public void connect_whenPolicyIsForbidden_returnsFalse() {
        int connectionPolicy = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
        when(mDatabaseManager.getProfileConnectionPolicy(
                mRemoteDevice, BluetoothProfile.MAP_CLIENT)).thenReturn(connectionPolicy);

        assertThat(mService.connect(mRemoteDevice)).isFalse();
    }

    @Test
    public void connect_whenPolicyIsAllowed_returnsTrue() {
        int connectionPolicy = BluetoothProfile.CONNECTION_POLICY_ALLOWED;
        when(mDatabaseManager.getProfileConnectionPolicy(
                mRemoteDevice, BluetoothProfile.MAP_CLIENT)).thenReturn(connectionPolicy);

        assertThat(mService.connect(mRemoteDevice)).isTrue();
    }

    @Test
    public void disconnect_whenNotConnected_returnsFalse() {
        assertThat(mService.disconnect(mRemoteDevice)).isFalse();
    }

    @Test
    public void disconnect_whenConnected_returnsTrue() {
        int connectionState = BluetoothProfile.STATE_CONNECTED;
        MceStateMachine sm = mock(MceStateMachine.class);
        when(sm.getState()).thenReturn(connectionState);
        mService.getInstanceMap().put(mRemoteDevice, sm);

        assertThat(mService.disconnect(mRemoteDevice)).isTrue();

        verify(sm).disconnect();
    }

    @Test
    public void getConnectionState_whenNotConnected() {
        assertThat(mService.getConnectionState(mRemoteDevice))
                .isEqualTo(BluetoothProfile.STATE_DISCONNECTED);
    }

    @Test
    public void getConnectionState_whenConnected() {
        int connectionState = BluetoothProfile.STATE_CONNECTED;
        MceStateMachine sm = mock(MceStateMachine.class);
        when(sm.getState()).thenReturn(connectionState);
        mService.getInstanceMap().put(mRemoteDevice, sm);

        assertThat(mService.getConnectionState(mRemoteDevice)).isEqualTo(connectionState);
    }

    @Test
    public void getConnectedDevices() {
        int connectionState = BluetoothProfile.STATE_CONNECTED;
        MceStateMachine sm = mock(MceStateMachine.class);
        BluetoothDevice[] bondedDevices = new BluetoothDevice[] {mRemoteDevice};
        when(mAdapterService.getBondedDevices()).thenReturn(bondedDevices);
        mService.getInstanceMap().put(mRemoteDevice, sm);
        when(sm.getState()).thenReturn(connectionState);

        assertThat(mService.getConnectedDevices()).contains(mRemoteDevice);
    }

    @Test
    public void getMceStateMachineForDevice() {
        MceStateMachine sm = mock(MceStateMachine.class);
        mService.getInstanceMap().put(mRemoteDevice, sm);

        assertThat(mService.getMceStateMachineForDevice(mRemoteDevice)).isEqualTo(sm);
    }

    @Test
    public void getSupportedFeatures() {
        int supportedFeatures = 100;
        MceStateMachine sm = mock(MceStateMachine.class);
        mService.getInstanceMap().put(mRemoteDevice, sm);
        when(sm.getSupportedFeatures()).thenReturn(supportedFeatures);

        assertThat(mService.getSupportedFeatures(mRemoteDevice)).isEqualTo(supportedFeatures);
        verify(sm).getSupportedFeatures();
    }

    @Test
    public void setMessageStatus() {
        String handle = "FFAB";
        int status = 123;
        MceStateMachine sm = mock(MceStateMachine.class);
        mService.getInstanceMap().put(mRemoteDevice, sm);
        when(sm.setMessageStatus(handle, status)).thenReturn(true);

        assertThat(mService.setMessageStatus(mRemoteDevice, handle, status)).isTrue();
        verify(sm).setMessageStatus(handle, status);
    }

    @Test
    public void getUnreadMessages() {
        MceStateMachine sm = mock(MceStateMachine.class);
        mService.getInstanceMap().put(mRemoteDevice, sm);
        when(sm.getUnreadMessages()).thenReturn(true);

        assertThat(mService.getUnreadMessages(mRemoteDevice)).isTrue();
        verify(sm).getUnreadMessages();
    }

    @Test
    public void cleanUpDevice() {
        MceStateMachine sm = mock(MceStateMachine.class);
        mService.getInstanceMap().put(mRemoteDevice, sm);

        mService.cleanupDevice(mRemoteDevice);

        assertThat(mService.getInstanceMap()).doesNotContainKey(mRemoteDevice);
    }

    @Test
    public void broadcastReceiver_withRandomAction_doesNothing() {
        MceStateMachine sm = mock(MceStateMachine.class);
        mService.getInstanceMap().put(mRemoteDevice, sm);

        Intent intent = new Intent("Test_random_action");
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
        mService.mMapReceiver.onReceive(mService, intent);

        verify(sm, never()).disconnect();
    }

    @Test
    public void broadcastReceiver_withActionAclDisconnected_withoutDevice_doesNothing() {
        int connectionState = BluetoothProfile.STATE_CONNECTED;
        MceStateMachine sm = mock(MceStateMachine.class);
        mService.getInstanceMap().put(mRemoteDevice, sm);
        when(sm.getState()).thenReturn(connectionState);

        Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        // Device is not included in this intent
        mService.mMapReceiver.onReceive(mService, intent);

        verify(sm, never()).disconnect();
    }

    @Test
    public void broadcastReceiver_withActionAclDisconnected_whenNotConnected_doesNothing() {
        // No state machine exists for this device
        Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
        mService.mMapReceiver.onReceive(mService, intent);
    }

    @Test
    public void broadcastReceiver_withActionAclDisconnected_whenConnected_callsDisconnect() {
        int connectionState = BluetoothProfile.STATE_CONNECTED;
        MceStateMachine sm = mock(MceStateMachine.class);
        mService.getInstanceMap().put(mRemoteDevice, sm);
        when(sm.getState()).thenReturn(connectionState);

        Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
        mService.mMapReceiver.onReceive(mService, intent);

        verify(sm).disconnect();
    }

    @Test
    public void broadcastReceiver_withActionSdpRecord_withoutMasRecord_doesNothing() {
        MceStateMachine sm = mock(MceStateMachine.class);
        mService.getInstanceMap().put(mRemoteDevice, sm);

        Intent intent = new Intent(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mRemoteDevice);
        intent.putExtra(BluetoothProfile.EXTRA_STATE, BluetoothProfile.STATE_DISCONNECTED);
        intent.putExtra(BluetoothDevice.EXTRA_UUID, BluetoothUuid.MAS);
        // No MasRecord / searchStatus is included in this intent
        mService.mMapReceiver.onReceive(mService, intent);
    }
}