blob: 9ec13b943c92b7ca882407c3609ef7b827f65a1f [file] [log] [blame]
/*
* 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.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Intent;
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.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 {
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 {
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_withActionAclDisconnectedNoTransport_whenConnected_doesNotCallDisconnect() {
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, never()).disconnect();
}
@Test
public void
broadcastReceiver_withActionAclDisconnectedLeTransport_whenConnected_doesNotCallDisconnect() {
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);
intent.putExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_LE);
mService.mMapReceiver.onReceive(mService, intent);
verify(sm, never()).disconnect();
}
@Test
public void
broadcastReceiver_withActionAclDisconnectedBrEdrTransport_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);
intent.putExtra(BluetoothDevice.EXTRA_TRANSPORT, BluetoothDevice.TRANSPORT_BREDR);
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(BluetoothDevice.ACTION_SDP_RECORD);
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);
}
}