1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.bluetooth.btservice; 18 19 import static org.mockito.ArgumentMatchers.eq; 20 import static org.mockito.Mockito.*; 21 22 import android.bluetooth.BluetoothAdapter; 23 import android.content.Intent; 24 import android.os.Looper; 25 import android.support.test.InstrumentationRegistry; 26 import android.support.test.filters.MediumTest; 27 import android.support.test.rule.ServiceTestRule; 28 import android.support.test.runner.AndroidJUnit4; 29 30 import com.android.bluetooth.TestUtils; 31 32 import org.junit.After; 33 import org.junit.Assert; 34 import org.junit.Before; 35 import org.junit.Rule; 36 import org.junit.Test; 37 import org.junit.runner.RunWith; 38 import org.mockito.ArgumentCaptor; 39 import org.mockito.Mock; 40 import org.mockito.MockitoAnnotations; 41 42 import java.lang.reflect.InvocationTargetException; 43 import java.util.List; 44 import java.util.concurrent.TimeoutException; 45 46 @MediumTest 47 @RunWith(AndroidJUnit4.class) 48 public class ProfileServiceTest { 49 private static final int PROFILE_START_MILLIS = 1250; 50 private static final int NUM_REPEATS = 5; 51 52 @Rule public final ServiceTestRule mServiceTestRule = new ServiceTestRule(); 53 setProfileState(Class profile, int state)54 private void setProfileState(Class profile, int state) throws TimeoutException { 55 Intent startIntent = new Intent(InstrumentationRegistry.getTargetContext(), profile); 56 startIntent.putExtra(AdapterService.EXTRA_ACTION, 57 AdapterService.ACTION_SERVICE_STATE_CHANGED); 58 startIntent.putExtra(BluetoothAdapter.EXTRA_STATE, state); 59 mServiceTestRule.startService(startIntent); 60 } 61 setAllProfilesState(int state, int invocationNumber)62 private void setAllProfilesState(int state, int invocationNumber) throws TimeoutException { 63 for (Class profile : mProfiles) { 64 setProfileState(profile, state); 65 } 66 ArgumentCaptor<ProfileService> argument = ArgumentCaptor.forClass(ProfileService.class); 67 verify(mMockAdapterService, timeout(PROFILE_START_MILLIS).times( 68 mProfiles.length * invocationNumber)).onProfileServiceStateChanged( 69 argument.capture(), eq(state)); 70 List<ProfileService> argumentProfiles = argument.getAllValues(); 71 for (Class profile : mProfiles) { 72 int matches = 0; 73 for (ProfileService arg : argumentProfiles) { 74 if (arg.getClass().getName().equals(profile.getName())) { 75 matches += 1; 76 } 77 } 78 Assert.assertEquals(invocationNumber, matches); 79 } 80 } 81 82 private @Mock AdapterService mMockAdapterService; 83 84 private Class[] mProfiles; 85 86 @Before setUp()87 public void setUp() 88 throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { 89 if (Looper.myLooper() == null) { 90 Looper.prepare(); 91 } 92 Assert.assertNotNull(Looper.myLooper()); 93 94 MockitoAnnotations.initMocks(this); 95 96 mProfiles = Config.getSupportedProfiles(); 97 98 mMockAdapterService.initNative(); 99 100 TestUtils.setAdapterService(mMockAdapterService); 101 102 Assert.assertNotNull(AdapterService.getAdapterService()); 103 } 104 105 @After tearDown()106 public void tearDown() 107 throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { 108 mMockAdapterService.cleanupNative(); 109 TestUtils.clearAdapterService(mMockAdapterService); 110 mMockAdapterService = null; 111 mProfiles = null; 112 } 113 114 /** 115 * Test: Start the Bluetooth services that are configured. 116 * Verify that the same services start. 117 */ 118 @Test testEnableDisable()119 public void testEnableDisable() throws TimeoutException { 120 setAllProfilesState(BluetoothAdapter.STATE_ON, 1); 121 setAllProfilesState(BluetoothAdapter.STATE_OFF, 1); 122 } 123 124 /** 125 * Test: Start the Bluetooth services that are configured twice. 126 * Verify that the services start. 127 */ 128 @Test testEnableDisableTwice()129 public void testEnableDisableTwice() throws TimeoutException { 130 setAllProfilesState(BluetoothAdapter.STATE_ON, 1); 131 setAllProfilesState(BluetoothAdapter.STATE_OFF, 1); 132 setAllProfilesState(BluetoothAdapter.STATE_ON, 2); 133 setAllProfilesState(BluetoothAdapter.STATE_OFF, 2); 134 } 135 136 /** 137 * Test: Start the Bluetooth services that are configured. 138 * Verify that each profile starts and stops. 139 */ 140 @Test testEnableDisableInterleaved()141 public void testEnableDisableInterleaved() throws TimeoutException { 142 for (Class profile : mProfiles) { 143 setProfileState(profile, BluetoothAdapter.STATE_ON); 144 setProfileState(profile, BluetoothAdapter.STATE_OFF); 145 } 146 ArgumentCaptor<ProfileService> starts = ArgumentCaptor.forClass(ProfileService.class); 147 ArgumentCaptor<ProfileService> stops = ArgumentCaptor.forClass(ProfileService.class); 148 int invocationNumber = mProfiles.length; 149 verify(mMockAdapterService, 150 timeout(PROFILE_START_MILLIS).times(invocationNumber)).onProfileServiceStateChanged( 151 starts.capture(), eq(BluetoothAdapter.STATE_ON)); 152 verify(mMockAdapterService, 153 timeout(PROFILE_START_MILLIS).times(invocationNumber)).onProfileServiceStateChanged( 154 stops.capture(), eq(BluetoothAdapter.STATE_OFF)); 155 156 List<ProfileService> startedArguments = starts.getAllValues(); 157 List<ProfileService> stoppedArguments = stops.getAllValues(); 158 Assert.assertEquals(startedArguments.size(), stoppedArguments.size()); 159 for (ProfileService service : startedArguments) { 160 Assert.assertTrue(stoppedArguments.contains(service)); 161 stoppedArguments.remove(service); 162 Assert.assertFalse(stoppedArguments.contains(service)); 163 } 164 } 165 166 /** 167 * Test: Start and stop a single profile repeatedly. 168 * Verify that the profiles start and stop. 169 */ 170 @Test testRepeatedEnableDisableSingly()171 public void testRepeatedEnableDisableSingly() throws TimeoutException { 172 int profileNumber = 0; 173 for (Class profile : mProfiles) { 174 for (int i = 0; i < NUM_REPEATS; i++) { 175 setProfileState(profile, BluetoothAdapter.STATE_ON); 176 ArgumentCaptor<ProfileService> start = 177 ArgumentCaptor.forClass(ProfileService.class); 178 verify(mMockAdapterService, timeout(PROFILE_START_MILLIS).times( 179 NUM_REPEATS * profileNumber + i + 1)).onProfileServiceStateChanged( 180 start.capture(), eq(BluetoothAdapter.STATE_ON)); 181 setProfileState(profile, BluetoothAdapter.STATE_OFF); 182 ArgumentCaptor<ProfileService> stop = ArgumentCaptor.forClass(ProfileService.class); 183 verify(mMockAdapterService, timeout(PROFILE_START_MILLIS).times( 184 NUM_REPEATS * profileNumber + i + 1)).onProfileServiceStateChanged( 185 stop.capture(), eq(BluetoothAdapter.STATE_OFF)); 186 Assert.assertEquals(start.getValue(), stop.getValue()); 187 } 188 profileNumber += 1; 189 } 190 } 191 192 /** 193 * Test: Start and stop a single profile repeatedly and verify that the profile services are 194 * registered and unregistered accordingly. 195 */ 196 @Test testProfileServiceRegisterUnregister()197 public void testProfileServiceRegisterUnregister() throws TimeoutException { 198 int profileNumber = 0; 199 for (Class profile : mProfiles) { 200 for (int i = 0; i < NUM_REPEATS; i++) { 201 setProfileState(profile, BluetoothAdapter.STATE_ON); 202 ArgumentCaptor<ProfileService> start = 203 ArgumentCaptor.forClass(ProfileService.class); 204 verify(mMockAdapterService, timeout(PROFILE_START_MILLIS).times( 205 NUM_REPEATS * profileNumber + i + 1)).addProfile( 206 start.capture()); 207 setProfileState(profile, BluetoothAdapter.STATE_OFF); 208 ArgumentCaptor<ProfileService> stop = ArgumentCaptor.forClass(ProfileService.class); 209 verify(mMockAdapterService, timeout(PROFILE_START_MILLIS).times( 210 NUM_REPEATS * profileNumber + i + 1)).removeProfile( 211 stop.capture()); 212 Assert.assertEquals(start.getValue(), stop.getValue()); 213 } 214 profileNumber += 1; 215 } 216 } 217 } 218