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

Commit 7721ec26 authored by Sal Savage's avatar Sal Savage
Browse files

Initialize the player list after setting up factory injection pattern

Problem: MediaPlayerList leverages MediaSessionManager as an
implementation detail, which is marked as final. Bluetooth cannot
leverage Mockito extended to mock it, so the real version is used. This
causes the state of media on a device to leak into the tests. Some
devices, like cars, have preinstalled media applications which can be
found (radio, for example). This state was causing unexpected updates to
be sent, making many of the never or times calls to be off by 1.

Solution: Initizlize the object under test after setting up the factory
pattern. This causes the controllers and players made to all be the same
mock, which effectively ends up with one object in the map, no matter
how many players exist on the device under test. This is because there's
check to see if the controller itself exists in the map before adding a
new one.

This is far from a long term solution, but will get the tests passing
again while more structural changes can be prioritized, designed and
implemented.

Bug: 368171591
Flag: EXEMPT, test only change
Test: atest com.android.bluetooth.audio_util.MediaPlayerListTest
Change-Id: I0c728173033f18d8bd7140e753b2e28eca2f8d20
parent 7f68eb72
Loading
Loading
Loading
Loading
+10 −4
Original line number Original line Diff line number Diff line
@@ -78,6 +78,10 @@ public class MediaPlayerListTest {
        when(mMockContext.getSystemServiceName(AudioManager.class))
        when(mMockContext.getSystemServiceName(AudioManager.class))
                .thenReturn(Context.AUDIO_SERVICE);
                .thenReturn(Context.AUDIO_SERVICE);


        // MediaSessionManager is final and Bluetooth can't use extended Mockito to mock it. Thus,
        // using this as is risks leaking device state into the tests. To avoid this, the injected
        // controller and player below in the factory pattern will essentially replace each found
        // player with the *same* mock, giving us only one player in the end-- "testPlayer"
        mMediaSessionManager =
        mMediaSessionManager =
                InstrumentationRegistry.getTargetContext()
                InstrumentationRegistry.getTargetContext()
                        .getSystemService(MediaSessionManager.class);
                        .getSystemService(MediaSessionManager.class);
@@ -87,9 +91,6 @@ public class MediaPlayerListTest {
        when(mMockContext.getSystemServiceName(MediaSessionManager.class))
        when(mMockContext.getSystemServiceName(MediaSessionManager.class))
                .thenReturn(Context.MEDIA_SESSION_SERVICE);
                .thenReturn(Context.MEDIA_SESSION_SERVICE);


        mMediaPlayerList =
                new MediaPlayerList(Looper.myLooper(), InstrumentationRegistry.getTargetContext());

        when(mMockContext.registerReceiver(any(), any())).thenReturn(null);
        when(mMockContext.registerReceiver(any(), any())).thenReturn(null);
        when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
        when(mMockContext.getApplicationContext()).thenReturn(mMockContext);
        when(mMockContext.getPackageManager()).thenReturn(mockPackageManager);
        when(mMockContext.getPackageManager()).thenReturn(mockPackageManager);
@@ -97,13 +98,18 @@ public class MediaPlayerListTest {


        BrowsablePlayerConnector mockConnector = mock(BrowsablePlayerConnector.class);
        BrowsablePlayerConnector mockConnector = mock(BrowsablePlayerConnector.class);
        BrowsablePlayerConnector.setInstanceForTesting(mockConnector);
        BrowsablePlayerConnector.setInstanceForTesting(mockConnector);
        mMediaPlayerList.init(mMediaUpdateCallback);


        MediaControllerFactory.inject(mMockController);
        MediaControllerFactory.inject(mMockController);
        MediaPlayerWrapperFactory.inject(mMockPlayerWrapper);
        MediaPlayerWrapperFactory.inject(mMockPlayerWrapper);


        doReturn("testPlayer").when(mMockController).getPackageName();
        doReturn("testPlayer").when(mMockController).getPackageName();
        when(mMockPlayerWrapper.isMetadataSynced()).thenReturn(false);
        when(mMockPlayerWrapper.isMetadataSynced()).thenReturn(false);

        // Be sure to do this setup last, after factor injections, or you risk leaking device state
        // into the tests
        mMediaPlayerList =
                new MediaPlayerList(Looper.myLooper(), InstrumentationRegistry.getTargetContext());
        mMediaPlayerList.init(mMediaUpdateCallback);
        mMediaPlayerList.setActivePlayer(mMediaPlayerList.addMediaPlayer(mMockController));
        mMediaPlayerList.setActivePlayer(mMediaPlayerList.addMediaPlayer(mMockController));


        verify(mMockPlayerWrapper).registerCallback(mPlayerWrapperCb.capture());
        verify(mMockPlayerWrapper).registerCallback(mPlayerWrapperCb.capture());