Loading core/tests/BroadcastRadioTests/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -48,7 +48,7 @@ android_test { ], // mockito-target-inline dependency jni_libs: [ "libcarservicejni", "libdexmakerjvmtiagent", "libstaticjvmtiagent", ], } core/tests/BroadcastRadioTests/AndroidTest.xml 0 → 100644 +32 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 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. --> <configuration description="Runs Broadcast Radio Tests."> <option name="test-suite-tag" value="apct" /> <option name="test-suite-tag" value="apct-instrumentation" /> <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="BroadcastRadioTests.apk" /> </target_preparer> <option name="test-tag" value="BroadcastRadioTests" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="android.hardware.radio.tests" /> <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> <option name="hidden-api-checks" value="false"/> </test> </configuration> core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/ExtendedRadioMockitoTestCase.java 0 → 100644 +78 −0 Original line number Diff line number Diff line /* * Copyright (C) 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.server.broadcastradio; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import android.util.Log; import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; import org.junit.After; import org.junit.Before; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; /** * Base class to make it easier to write tests that uses {@code ExtendedMockito} for radio. * */ public abstract class ExtendedRadioMockitoTestCase { private static final String TAG = "RadioMockitoTestCase"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private MockitoSession mSession; @Before public void startSession() { StaticMockitoSessionBuilder builder = mockitoSession() .initMocks(this) .strictness(Strictness.LENIENT); initializeSession(builder); mSession = builder.startMocking(); } /** * Initializes the mockito session for radio test. * * <p>Typically used to define which classes should have static methods mocked or spied. */ protected void initializeSession(StaticMockitoSessionBuilder builder) { if (DEBUG) { Log.d(TAG, "initializeSession()"); } } @After public final void finishSession() { if (mSession == null) { Log.w(TAG, "finishSession(): no session"); return; } try { if (DEBUG) { Log.d(TAG, "finishSession()"); } } finally { // mSession.finishMocking() must ALWAYS be called (hence the over-protective try/finally // statements), otherwise it would cause failures on future tests as mockito // cannot start a session when a previous one is not finished mSession.finishMocking(); } } } core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/IRadioServiceAidlImplTest.java +31 −9 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.broadcastradio; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.anyBoolean; Loading @@ -31,30 +33,36 @@ import android.hardware.radio.ICloseHandle; import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.RadioManager; import android.os.IBinder; import android.os.ServiceManager; import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; import com.android.server.broadcastradio.aidl.BroadcastRadioServiceImpl; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import java.util.Arrays; import java.util.List; /** * Tests for {@link android.hardware.radio.IRadioService} with AIDL HAL implementation */ @RunWith(MockitoJUnitRunner.class) public final class IRadioServiceAidlImplTest { public final class IRadioServiceAidlImplTest extends ExtendedRadioMockitoTestCase { private static final int[] ENABLE_TYPES = new int[]{Announcement.TYPE_TRAFFIC}; private static final String AM_FM_SERVICE_NAME = "android.hardware.broadcastradio.IBroadcastRadio/amfm"; private static final String DAB_SERVICE_NAME = "android.hardware.broadcastradio.IBroadcastRadio/dab"; private IRadioServiceAidlImpl mAidlImpl; @Mock private BroadcastRadioService mServiceMock; @Mock private IBinder mServiceBinderMock; @Mock private BroadcastRadioServiceImpl mHalMock; @Mock private RadioManager.ModuleProperties mModuleMock; Loading @@ -73,7 +81,7 @@ public final class IRadioServiceAidlImplTest { public void setUp() throws Exception { doNothing().when(mServiceMock).enforcePolicyAccess(); when(mHalMock.listModules()).thenReturn(Arrays.asList(mModuleMock)); when(mHalMock.listModules()).thenReturn(List.of(mModuleMock)); when(mHalMock.openSession(anyInt(), any(), anyBoolean(), any())) .thenReturn(mTunerMock); when(mHalMock.addAnnouncementListener(any(), any())).thenReturn(mICloseHandle); Loading @@ -81,11 +89,26 @@ public final class IRadioServiceAidlImplTest { mAidlImpl = new IRadioServiceAidlImpl(mServiceMock, mHalMock); } @Override protected void initializeSession(StaticMockitoSessionBuilder builder) { builder.spyStatic(ServiceManager.class); } @Test public void getServicesNames_forAidlImpl() { doReturn(null).when(() -> ServiceManager.waitForDeclaredService( AM_FM_SERVICE_NAME)); doReturn(mServiceBinderMock).when(() -> ServiceManager.waitForDeclaredService( DAB_SERVICE_NAME)); assertWithMessage("Names of services available") .that(IRadioServiceAidlImpl.getServicesNames()).containsExactly(DAB_SERVICE_NAME); } @Test public void loadModules_forAidlImpl() { assertWithMessage("Modules loaded in AIDL HAL") .that(mAidlImpl.listModules()) .containsExactly(mModuleMock); .that(mAidlImpl.listModules()).containsExactly(mModuleMock); } @Test Loading @@ -105,5 +128,4 @@ public final class IRadioServiceAidlImplTest { assertWithMessage("Close handle of announcement listener for HAL 2") .that(closeHandle).isEqualTo(mICloseHandle); } } core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java 0 → 100644 +189 −0 Original line number Diff line number Diff line /* * Copyright (C) 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.server.broadcastradio.aidl; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.hardware.broadcastradio.IBroadcastRadio; import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioTuner; import android.os.IBinder; import android.os.IServiceCallback; import android.os.RemoteException; import android.os.ServiceManager; import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase; import org.junit.Test; import org.mockito.Mock; import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.Arrays; public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTestCase { private static final int FM_RADIO_MODULE_ID = 0; private static final int DAB_RADIO_MODULE_ID = 1; private static final ArrayList<String> SERVICE_LIST = new ArrayList<>(Arrays.asList("FmService", "DabService")); private BroadcastRadioServiceImpl mBroadcastRadioService; private IBinder.DeathRecipient mFmDeathRecipient; @Mock private RadioManager.ModuleProperties mFmModuleMock; @Mock private RadioManager.ModuleProperties mDabModuleMock; @Mock private RadioModule mFmRadioModuleMock; @Mock private RadioModule mDabRadioModuleMock; @Mock private IBroadcastRadio mFmHalServiceMock; @Mock private IBroadcastRadio mDabHalServiceMock; @Mock private IBinder mFmBinderMock; @Mock private IBinder mDabBinderMock; @Mock private TunerSession mFmTunerSessionMock; @Mock private ITunerCallback mTunerCallbackMock; @Override protected void initializeSession(StaticMockitoSessionBuilder builder) { builder.spyStatic(ServiceManager.class) .spyStatic(RadioModule.class); } @Test public void listModules_withMultipleServiceNames() throws Exception { createBroadcastRadioService(); assertWithMessage("Radio modules in AIDL broadcast radio HAL client") .that(mBroadcastRadioService.listModules()) .containsExactly(mFmModuleMock, mDabModuleMock); } @Test public void hasModules_withIdFoundInModules() throws Exception { createBroadcastRadioService(); assertWithMessage("DAB radio module in AIDL broadcast radio HAL client") .that(mBroadcastRadioService.hasModule(DAB_RADIO_MODULE_ID)).isTrue(); } @Test public void hasModules_withIdNotFoundInModules() throws Exception { createBroadcastRadioService(); assertWithMessage("Radio module of id not found in AIDL broadcast radio HAL client") .that(mBroadcastRadioService.hasModule(DAB_RADIO_MODULE_ID + 1)).isFalse(); } @Test public void hasAnyModules_withModulesExist() throws Exception { createBroadcastRadioService(); assertWithMessage("Any radio module in AIDL broadcast radio HAL client") .that(mBroadcastRadioService.hasAnyModules()).isTrue(); } @Test public void openSession_withIdFound() throws Exception { createBroadcastRadioService(); ITuner session = mBroadcastRadioService.openSession(FM_RADIO_MODULE_ID, /*legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock); assertWithMessage("Session opened in FM radio module") .that(session).isEqualTo(mFmTunerSessionMock); } @Test public void openSession_withIdNotFound() throws Exception { createBroadcastRadioService(); ITuner session = mBroadcastRadioService.openSession(DAB_RADIO_MODULE_ID + 1, /*legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock); assertWithMessage("Session opened with id not found").that(session).isNull(); } @Test public void binderDied_forDeathRecipient() throws Exception { createBroadcastRadioService(); mFmDeathRecipient.binderDied(); verify(mFmRadioModuleMock).closeSessions(eq(RadioTuner.ERROR_HARDWARE_FAILURE)); assertWithMessage("FM radio module after FM broadcast radio HAL service died") .that(mBroadcastRadioService.hasModule(FM_RADIO_MODULE_ID)).isFalse(); } private void createBroadcastRadioService() throws RemoteException { mockServiceManager(); mBroadcastRadioService = new BroadcastRadioServiceImpl(SERVICE_LIST); } private void mockServiceManager() throws RemoteException { doAnswer((Answer<Void>) invocation -> { String serviceName = (String) invocation.getArguments()[0]; IServiceCallback serviceCallback = (IServiceCallback) invocation.getArguments()[1]; IBinder mockBinder = serviceName.equals("FmService") ? mFmBinderMock : mDabBinderMock; serviceCallback.onRegistration(serviceName, mockBinder); return null; }).when(() -> ServiceManager.registerForNotifications(anyString(), any(IServiceCallback.class))); doReturn(mFmRadioModuleMock).when(() -> RadioModule.tryLoadingModule( eq(FM_RADIO_MODULE_ID), anyString(), any(IBinder.class), any(Object.class))); doReturn(mDabRadioModuleMock).when(() -> RadioModule.tryLoadingModule( eq(DAB_RADIO_MODULE_ID), anyString(), any(IBinder.class), any(Object.class))); when(mFmRadioModuleMock.getProperties()).thenReturn(mFmModuleMock); when(mDabRadioModuleMock.getProperties()).thenReturn(mDabModuleMock); when(mFmRadioModuleMock.getService()).thenReturn(mFmHalServiceMock); when(mDabRadioModuleMock.getService()).thenReturn(mDabHalServiceMock); when(mFmHalServiceMock.asBinder()).thenReturn(mFmBinderMock); when(mDabHalServiceMock.asBinder()).thenReturn(mDabBinderMock); doAnswer(invocation -> { mFmDeathRecipient = (IBinder.DeathRecipient) invocation.getArguments()[0]; return null; }).when(mFmBinderMock).linkToDeath(any(), anyInt()); when(mFmRadioModuleMock.openSession(eq(mTunerCallbackMock))) .thenReturn(mFmTunerSessionMock); } } Loading
core/tests/BroadcastRadioTests/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -48,7 +48,7 @@ android_test { ], // mockito-target-inline dependency jni_libs: [ "libcarservicejni", "libdexmakerjvmtiagent", "libstaticjvmtiagent", ], }
core/tests/BroadcastRadioTests/AndroidTest.xml 0 → 100644 +32 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 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. --> <configuration description="Runs Broadcast Radio Tests."> <option name="test-suite-tag" value="apct" /> <option name="test-suite-tag" value="apct-instrumentation" /> <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> <option name="cleanup-apks" value="true" /> <option name="test-file-name" value="BroadcastRadioTests.apk" /> </target_preparer> <option name="test-tag" value="BroadcastRadioTests" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="android.hardware.radio.tests" /> <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> <option name="hidden-api-checks" value="false"/> </test> </configuration>
core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/ExtendedRadioMockitoTestCase.java 0 → 100644 +78 −0 Original line number Diff line number Diff line /* * Copyright (C) 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.server.broadcastradio; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import android.util.Log; import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; import org.junit.After; import org.junit.Before; import org.mockito.MockitoSession; import org.mockito.quality.Strictness; /** * Base class to make it easier to write tests that uses {@code ExtendedMockito} for radio. * */ public abstract class ExtendedRadioMockitoTestCase { private static final String TAG = "RadioMockitoTestCase"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private MockitoSession mSession; @Before public void startSession() { StaticMockitoSessionBuilder builder = mockitoSession() .initMocks(this) .strictness(Strictness.LENIENT); initializeSession(builder); mSession = builder.startMocking(); } /** * Initializes the mockito session for radio test. * * <p>Typically used to define which classes should have static methods mocked or spied. */ protected void initializeSession(StaticMockitoSessionBuilder builder) { if (DEBUG) { Log.d(TAG, "initializeSession()"); } } @After public final void finishSession() { if (mSession == null) { Log.w(TAG, "finishSession(): no session"); return; } try { if (DEBUG) { Log.d(TAG, "finishSession()"); } } finally { // mSession.finishMocking() must ALWAYS be called (hence the over-protective try/finally // statements), otherwise it would cause failures on future tests as mockito // cannot start a session when a previous one is not finished mSession.finishMocking(); } } }
core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/IRadioServiceAidlImplTest.java +31 −9 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.broadcastradio; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.anyBoolean; Loading @@ -31,30 +33,36 @@ import android.hardware.radio.ICloseHandle; import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.RadioManager; import android.os.IBinder; import android.os.ServiceManager; import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; import com.android.server.broadcastradio.aidl.BroadcastRadioServiceImpl; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import java.util.Arrays; import java.util.List; /** * Tests for {@link android.hardware.radio.IRadioService} with AIDL HAL implementation */ @RunWith(MockitoJUnitRunner.class) public final class IRadioServiceAidlImplTest { public final class IRadioServiceAidlImplTest extends ExtendedRadioMockitoTestCase { private static final int[] ENABLE_TYPES = new int[]{Announcement.TYPE_TRAFFIC}; private static final String AM_FM_SERVICE_NAME = "android.hardware.broadcastradio.IBroadcastRadio/amfm"; private static final String DAB_SERVICE_NAME = "android.hardware.broadcastradio.IBroadcastRadio/dab"; private IRadioServiceAidlImpl mAidlImpl; @Mock private BroadcastRadioService mServiceMock; @Mock private IBinder mServiceBinderMock; @Mock private BroadcastRadioServiceImpl mHalMock; @Mock private RadioManager.ModuleProperties mModuleMock; Loading @@ -73,7 +81,7 @@ public final class IRadioServiceAidlImplTest { public void setUp() throws Exception { doNothing().when(mServiceMock).enforcePolicyAccess(); when(mHalMock.listModules()).thenReturn(Arrays.asList(mModuleMock)); when(mHalMock.listModules()).thenReturn(List.of(mModuleMock)); when(mHalMock.openSession(anyInt(), any(), anyBoolean(), any())) .thenReturn(mTunerMock); when(mHalMock.addAnnouncementListener(any(), any())).thenReturn(mICloseHandle); Loading @@ -81,11 +89,26 @@ public final class IRadioServiceAidlImplTest { mAidlImpl = new IRadioServiceAidlImpl(mServiceMock, mHalMock); } @Override protected void initializeSession(StaticMockitoSessionBuilder builder) { builder.spyStatic(ServiceManager.class); } @Test public void getServicesNames_forAidlImpl() { doReturn(null).when(() -> ServiceManager.waitForDeclaredService( AM_FM_SERVICE_NAME)); doReturn(mServiceBinderMock).when(() -> ServiceManager.waitForDeclaredService( DAB_SERVICE_NAME)); assertWithMessage("Names of services available") .that(IRadioServiceAidlImpl.getServicesNames()).containsExactly(DAB_SERVICE_NAME); } @Test public void loadModules_forAidlImpl() { assertWithMessage("Modules loaded in AIDL HAL") .that(mAidlImpl.listModules()) .containsExactly(mModuleMock); .that(mAidlImpl.listModules()).containsExactly(mModuleMock); } @Test Loading @@ -105,5 +128,4 @@ public final class IRadioServiceAidlImplTest { assertWithMessage("Close handle of announcement listener for HAL 2") .that(closeHandle).isEqualTo(mICloseHandle); } }
core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java 0 → 100644 +189 −0 Original line number Diff line number Diff line /* * Copyright (C) 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.server.broadcastradio.aidl; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.hardware.broadcastradio.IBroadcastRadio; import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioTuner; import android.os.IBinder; import android.os.IServiceCallback; import android.os.RemoteException; import android.os.ServiceManager; import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase; import org.junit.Test; import org.mockito.Mock; import org.mockito.stubbing.Answer; import java.util.ArrayList; import java.util.Arrays; public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTestCase { private static final int FM_RADIO_MODULE_ID = 0; private static final int DAB_RADIO_MODULE_ID = 1; private static final ArrayList<String> SERVICE_LIST = new ArrayList<>(Arrays.asList("FmService", "DabService")); private BroadcastRadioServiceImpl mBroadcastRadioService; private IBinder.DeathRecipient mFmDeathRecipient; @Mock private RadioManager.ModuleProperties mFmModuleMock; @Mock private RadioManager.ModuleProperties mDabModuleMock; @Mock private RadioModule mFmRadioModuleMock; @Mock private RadioModule mDabRadioModuleMock; @Mock private IBroadcastRadio mFmHalServiceMock; @Mock private IBroadcastRadio mDabHalServiceMock; @Mock private IBinder mFmBinderMock; @Mock private IBinder mDabBinderMock; @Mock private TunerSession mFmTunerSessionMock; @Mock private ITunerCallback mTunerCallbackMock; @Override protected void initializeSession(StaticMockitoSessionBuilder builder) { builder.spyStatic(ServiceManager.class) .spyStatic(RadioModule.class); } @Test public void listModules_withMultipleServiceNames() throws Exception { createBroadcastRadioService(); assertWithMessage("Radio modules in AIDL broadcast radio HAL client") .that(mBroadcastRadioService.listModules()) .containsExactly(mFmModuleMock, mDabModuleMock); } @Test public void hasModules_withIdFoundInModules() throws Exception { createBroadcastRadioService(); assertWithMessage("DAB radio module in AIDL broadcast radio HAL client") .that(mBroadcastRadioService.hasModule(DAB_RADIO_MODULE_ID)).isTrue(); } @Test public void hasModules_withIdNotFoundInModules() throws Exception { createBroadcastRadioService(); assertWithMessage("Radio module of id not found in AIDL broadcast radio HAL client") .that(mBroadcastRadioService.hasModule(DAB_RADIO_MODULE_ID + 1)).isFalse(); } @Test public void hasAnyModules_withModulesExist() throws Exception { createBroadcastRadioService(); assertWithMessage("Any radio module in AIDL broadcast radio HAL client") .that(mBroadcastRadioService.hasAnyModules()).isTrue(); } @Test public void openSession_withIdFound() throws Exception { createBroadcastRadioService(); ITuner session = mBroadcastRadioService.openSession(FM_RADIO_MODULE_ID, /*legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock); assertWithMessage("Session opened in FM radio module") .that(session).isEqualTo(mFmTunerSessionMock); } @Test public void openSession_withIdNotFound() throws Exception { createBroadcastRadioService(); ITuner session = mBroadcastRadioService.openSession(DAB_RADIO_MODULE_ID + 1, /*legacyConfig= */ null, /* withAudio= */ true, mTunerCallbackMock); assertWithMessage("Session opened with id not found").that(session).isNull(); } @Test public void binderDied_forDeathRecipient() throws Exception { createBroadcastRadioService(); mFmDeathRecipient.binderDied(); verify(mFmRadioModuleMock).closeSessions(eq(RadioTuner.ERROR_HARDWARE_FAILURE)); assertWithMessage("FM radio module after FM broadcast radio HAL service died") .that(mBroadcastRadioService.hasModule(FM_RADIO_MODULE_ID)).isFalse(); } private void createBroadcastRadioService() throws RemoteException { mockServiceManager(); mBroadcastRadioService = new BroadcastRadioServiceImpl(SERVICE_LIST); } private void mockServiceManager() throws RemoteException { doAnswer((Answer<Void>) invocation -> { String serviceName = (String) invocation.getArguments()[0]; IServiceCallback serviceCallback = (IServiceCallback) invocation.getArguments()[1]; IBinder mockBinder = serviceName.equals("FmService") ? mFmBinderMock : mDabBinderMock; serviceCallback.onRegistration(serviceName, mockBinder); return null; }).when(() -> ServiceManager.registerForNotifications(anyString(), any(IServiceCallback.class))); doReturn(mFmRadioModuleMock).when(() -> RadioModule.tryLoadingModule( eq(FM_RADIO_MODULE_ID), anyString(), any(IBinder.class), any(Object.class))); doReturn(mDabRadioModuleMock).when(() -> RadioModule.tryLoadingModule( eq(DAB_RADIO_MODULE_ID), anyString(), any(IBinder.class), any(Object.class))); when(mFmRadioModuleMock.getProperties()).thenReturn(mFmModuleMock); when(mDabRadioModuleMock.getProperties()).thenReturn(mDabModuleMock); when(mFmRadioModuleMock.getService()).thenReturn(mFmHalServiceMock); when(mDabRadioModuleMock.getService()).thenReturn(mDabHalServiceMock); when(mFmHalServiceMock.asBinder()).thenReturn(mFmBinderMock); when(mDabHalServiceMock.asBinder()).thenReturn(mDabBinderMock); doAnswer(invocation -> { mFmDeathRecipient = (IBinder.DeathRecipient) invocation.getArguments()[0]; return null; }).when(mFmBinderMock).linkToDeath(any(), anyInt()); when(mFmRadioModuleMock.openSession(eq(mTunerCallbackMock))) .thenReturn(mFmTunerSessionMock); } }