From f39ab7029dfbd92eff75561580fb0a2b69b69e24 Mon Sep 17 00:00:00 2001 From: Ruslan Tkhakokhov Date: Wed, 24 Nov 2021 23:19:55 +0000 Subject: Rename TransportClient to TransportConnection The change is auto-generated through IDE rename function and makes the following naming changes: 1. TransportClient -> TransportConnection 2. TransportClientManager -> TransportConnectionManager 3. + corresponding test files TransportConnection is a more appropriate name for the class as it's exactly what it does - manages the connection to the remote BackupTransport service implementation. This is a preparatory change to making the BackupTransport AIDL async. TransportClient name will later be used more appropriately for a class that wraps the actual communication with the transport. Bug: 202716271 Test: m -j Change-Id: I76a98edc7102c8fcffdb050208e9e65543e6e10c --- .../server/backup/TransportManagerTest.java | 36 +- .../backup/UserBackupManagerServiceTest.java | 8 +- .../backup/internal/PerformInitializeTaskTest.java | 20 +- .../backup/keyvalue/KeyValueBackupTaskTest.java | 2 +- .../backup/restore/ActiveRestoreSessionTest.java | 10 +- .../server/backup/testing/TransportTestUtils.java | 34 +- .../transport/TransportClientManagerTest.java | 150 ------ .../backup/transport/TransportClientTest.java | 549 -------------------- .../transport/TransportConnectionManagerTest.java | 151 ++++++ .../backup/transport/TransportConnectionTest.java | 550 +++++++++++++++++++++ 10 files changed, 758 insertions(+), 752 deletions(-) delete mode 100644 services/robotests/backup/src/com/android/server/backup/transport/TransportClientManagerTest.java delete mode 100644 services/robotests/backup/src/com/android/server/backup/transport/TransportClientTest.java create mode 100644 services/robotests/backup/src/com/android/server/backup/transport/TransportConnectionManagerTest.java create mode 100644 services/robotests/backup/src/com/android/server/backup/transport/TransportConnectionTest.java (limited to 'services/robotests/backup') diff --git a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java index 42115d437ee0..b7f8c00896d4 100644 --- a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java +++ b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java @@ -55,8 +55,8 @@ import android.platform.test.annotations.Presubmit; import com.android.server.backup.testing.TransportData; import com.android.server.backup.testing.TransportTestUtils.TransportMock; import com.android.server.backup.transport.OnTransportRegisteredListener; -import com.android.server.backup.transport.TransportClient; -import com.android.server.backup.transport.TransportClientManager; +import com.android.server.backup.transport.TransportConnection; +import com.android.server.backup.transport.TransportConnectionManager; import com.android.server.backup.transport.TransportNotRegisteredException; import com.android.server.testing.shadows.ShadowApplicationPackageManager; @@ -85,7 +85,7 @@ public class TransportManagerTest { private static final String PACKAGE_B = "some.package.b"; @Mock private OnTransportRegisteredListener mListener; - @Mock private TransportClientManager mTransportClientManager; + @Mock private TransportConnectionManager mTransportConnectionManager; private TransportData mTransportA1; private TransportData mTransportA2; private TransportData mTransportB1; @@ -206,7 +206,7 @@ public class TransportManagerTest { transportManager.registerTransports(); - verify(mTransportClientManager) + verify(mTransportConnectionManager) .getTransportClient( eq(mTransportA1.getTransportComponent()), argThat( @@ -433,10 +433,10 @@ public class TransportManagerTest { TransportManager transportManager = createTransportManagerWithRegisteredTransports(mTransportA1, mTransportA2); - TransportClient transportClient = + TransportConnection transportConnection = transportManager.getTransportClient(mTransportA1.transportName, "caller"); - assertThat(transportClient.getTransportComponent()) + assertThat(transportConnection.getTransportComponent()) .isEqualTo(mTransportA1.getTransportComponent()); } @@ -453,10 +453,10 @@ public class TransportManagerTest { null, null); - TransportClient transportClient = + TransportConnection transportConnection = transportManager.getTransportClient(mTransportA1.transportName, "caller"); - assertThat(transportClient).isNull(); + assertThat(transportConnection).isNull(); } @Test @@ -471,9 +471,10 @@ public class TransportManagerTest { null, null); - TransportClient transportClient = transportManager.getTransportClient("newName", "caller"); + TransportConnection transportConnection = transportManager.getTransportClient( + "newName", "caller"); - assertThat(transportClient.getTransportComponent()) + assertThat(transportConnection.getTransportComponent()) .isEqualTo(mTransportA1.getTransportComponent()); } @@ -482,9 +483,10 @@ public class TransportManagerTest { TransportManager transportManager = createTransportManagerWithRegisteredTransports(mTransportA1, mTransportA2); - TransportClient transportClient = transportManager.getCurrentTransportClient("caller"); + TransportConnection transportConnection = transportManager.getCurrentTransportClient( + "caller"); - assertThat(transportClient.getTransportComponent()) + assertThat(transportConnection.getTransportComponent()) .isEqualTo(mTransportA1.getTransportComponent()); } @@ -660,12 +662,12 @@ public class TransportManagerTest { List transportMocks = new ArrayList<>(transports.length); for (TransportData transport : transports) { TransportMock transportMock = mockTransport(transport); - when(mTransportClientManager.getTransportClient( + when(mTransportConnectionManager.getTransportClient( eq(transport.getTransportComponent()), any())) - .thenReturn(transportMock.transportClient); - when(mTransportClientManager.getTransportClient( + .thenReturn(transportMock.mTransportConnection); + when(mTransportConnectionManager.getTransportClient( eq(transport.getTransportComponent()), any(), any())) - .thenReturn(transportMock.transportClient); + .thenReturn(transportMock.mTransportConnection); transportMocks.add(transportMock); } return transportMocks; @@ -706,7 +708,7 @@ public class TransportManagerTest { .map(TransportData::getTransportComponent) .collect(toSet()), selectedTransport != null ? selectedTransport.transportName : null, - mTransportClientManager); + mTransportConnectionManager); transportManager.setOnTransportRegisteredListener(mListener); return transportManager; } diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java index 06d51a4be920..297538ad7b4b 100644 --- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java +++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java @@ -243,7 +243,7 @@ public class UserBackupManagerServiceTest { assertThat(result).isTrue(); verify(mTransportManager) - .disposeOfTransportClient(eq(transportMock.transportClient), any()); + .disposeOfTransportClient(eq(transportMock.mTransportConnection), any()); } /** @@ -282,7 +282,7 @@ public class UserBackupManagerServiceTest { assertThat(filtered).asList().containsExactly(PACKAGE_1); verify(mTransportManager) - .disposeOfTransportClient(eq(transportMock.transportClient), any()); + .disposeOfTransportClient(eq(transportMock.mTransportConnection), any()); } /** @@ -357,7 +357,7 @@ public class UserBackupManagerServiceTest { assertThat(getSettingsTransport()).isEqualTo(mNewTransport.transportName); assertThat(oldTransport).isEqualTo(mOldTransport.transportName); verify(mTransportManager) - .disposeOfTransportClient(eq(mNewTransportMock.transportClient), any()); + .disposeOfTransportClient(eq(mNewTransportMock.mTransportConnection), any()); } /** @@ -395,7 +395,7 @@ public class UserBackupManagerServiceTest { assertThat(getSettingsTransport()).isEqualTo(mNewTransport.transportName); verify(callback).onSuccess(eq(mNewTransport.transportName)); verify(mTransportManager) - .disposeOfTransportClient(eq(mNewTransportMock.transportClient), any()); + .disposeOfTransportClient(eq(mNewTransportMock.mTransportConnection), any()); } /** diff --git a/services/robotests/backup/src/com/android/server/backup/internal/PerformInitializeTaskTest.java b/services/robotests/backup/src/com/android/server/backup/internal/PerformInitializeTaskTest.java index a14cc51a3ab6..bf4eeae4b4b2 100644 --- a/services/robotests/backup/src/com/android/server/backup/internal/PerformInitializeTaskTest.java +++ b/services/robotests/backup/src/com/android/server/backup/internal/PerformInitializeTaskTest.java @@ -50,7 +50,7 @@ import com.android.server.backup.UserBackupManagerService; import com.android.server.backup.testing.TransportData; import com.android.server.backup.testing.TransportTestUtils; import com.android.server.backup.testing.TransportTestUtils.TransportMock; -import com.android.server.backup.transport.TransportClient; +import com.android.server.backup.transport.TransportConnection; import com.android.server.testing.shadows.ShadowSlog; import org.junit.Before; @@ -285,7 +285,7 @@ public class PerformInitializeTaskTest { TransportData transport = transportsIterator.next(); verify(mTransportManager).getTransportClient(eq(transport.transportName), any()); verify(mTransportManager) - .disposeOfTransportClient(eq(transportMock.transportClient), any()); + .disposeOfTransportClient(eq(transportMock.mTransportConnection), any()); } } @@ -303,9 +303,9 @@ public class PerformInitializeTaskTest { performInitializeTask.run(); verify(mTransportManager) - .disposeOfTransportClient(eq(transportMocks.get(0).transportClient), any()); + .disposeOfTransportClient(eq(transportMocks.get(0).mTransportConnection), any()); verify(mTransportManager) - .disposeOfTransportClient(eq(transportMocks.get(1).transportClient), any()); + .disposeOfTransportClient(eq(transportMocks.get(1).mTransportConnection), any()); } @Test @@ -328,14 +328,16 @@ public class PerformInitializeTaskTest { setUpTransports(mTransportManager, transport1, transport2); String registeredTransportName = transport2.transportName; IBackupTransport registeredTransport = transportMocks.get(1).transport; - TransportClient registeredTransportClient = transportMocks.get(1).transportClient; + TransportConnection + registeredTransportConnection = transportMocks.get(1).mTransportConnection; PerformInitializeTask performInitializeTask = createPerformInitializeTask(transport1.transportName, transport2.transportName); performInitializeTask.run(); verify(registeredTransport).initializeDevice(); - verify(mTransportManager).disposeOfTransportClient(eq(registeredTransportClient), any()); + verify(mTransportManager).disposeOfTransportClient(eq(registeredTransportConnection), + any()); verify(mObserver).onResult(eq(registeredTransportName), eq(TRANSPORT_OK)); } @@ -347,7 +349,7 @@ public class PerformInitializeTaskTest { performInitializeTask.run(); verify(mTransportManager) - .disposeOfTransportClient(eq(transportMock.transportClient), any()); + .disposeOfTransportClient(eq(transportMock.mTransportConnection), any()); verify(mObserver).backupFinished(eq(TRANSPORT_ERROR)); verify(mListener).onFinished(any()); } @@ -356,13 +358,13 @@ public class PerformInitializeTaskTest { public void testRun_whenTransportThrowsDeadObjectException() throws Exception { TransportMock transportMock = setUpTransport(mTransport); IBackupTransport transport = transportMock.transport; - TransportClient transportClient = transportMock.transportClient; + TransportConnection transportConnection = transportMock.mTransportConnection; when(transport.initializeDevice()).thenThrow(DeadObjectException.class); PerformInitializeTask performInitializeTask = createPerformInitializeTask(mTransportName); performInitializeTask.run(); - verify(mTransportManager).disposeOfTransportClient(eq(transportClient), any()); + verify(mTransportManager).disposeOfTransportClient(eq(transportConnection), any()); verify(mObserver).backupFinished(eq(TRANSPORT_ERROR)); verify(mListener).onFinished(any()); } diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java index 7d17109af7d3..fd295c0739cf 100644 --- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java +++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java @@ -2665,7 +2665,7 @@ public class KeyValueBackupTaskTest { KeyValueBackupTask task = new KeyValueBackupTask( mBackupManagerService, - transportMock.transportClient, + transportMock.mTransportConnection, transportMock.transportData.transportDirName, queue, mOldJournal, diff --git a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java index 5883c1cb5995..9eb99aed2ba8 100644 --- a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java +++ b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java @@ -202,7 +202,7 @@ public class ActiveRestoreSessionTest { verify(mObserver) .restoreSetsAvailable(aryEq(new RestoreSet[] {mRestoreSet1, mRestoreSet2})); verify(mTransportManager) - .disposeOfTransportClient(eq(transportMock.transportClient), any()); + .disposeOfTransportClient(eq(transportMock.mTransportConnection), any()); assertThat(mWakeLock.isHeld()).isFalse(); } @@ -235,7 +235,7 @@ public class ActiveRestoreSessionTest { verify(mObserver).restoreSetsAvailable(isNull()); assertEventLogged(EventLogTags.RESTORE_TRANSPORT_FAILURE); verify(mTransportManager) - .disposeOfTransportClient(eq(transportMock.transportClient), any()); + .disposeOfTransportClient(eq(transportMock.mTransportConnection), any()); assertThat(mWakeLock.isHeld()).isFalse(); } @@ -253,7 +253,7 @@ public class ActiveRestoreSessionTest { mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(0); verify(mTransportManager) - .disposeOfTransportClient(eq(transportMock.transportClient), any()); + .disposeOfTransportClient(eq(transportMock.mTransportConnection), any()); assertThat(mWakeLock.isHeld()).isFalse(); assertThat(mBackupManagerService.isRestoreInProgress()).isFalse(); // Verify it created the task properly @@ -341,7 +341,7 @@ public class ActiveRestoreSessionTest { mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(0); verify(mTransportManager) - .disposeOfTransportClient(eq(transportMock.transportClient), any()); + .disposeOfTransportClient(eq(transportMock.mTransportConnection), any()); assertThat(mWakeLock.isHeld()).isFalse(); assertThat(mBackupManagerService.isRestoreInProgress()).isFalse(); ShadowPerformUnifiedRestoreTask shadowTask = @@ -463,7 +463,7 @@ public class ActiveRestoreSessionTest { mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(0); verify(mTransportManager) - .disposeOfTransportClient(eq(transportMock.transportClient), any()); + .disposeOfTransportClient(eq(transportMock.mTransportConnection), any()); assertThat(mWakeLock.isHeld()).isFalse(); assertThat(mBackupManagerService.isRestoreInProgress()).isFalse(); ShadowPerformUnifiedRestoreTask shadowTask = diff --git a/services/robotests/backup/src/com/android/server/backup/testing/TransportTestUtils.java b/services/robotests/backup/src/com/android/server/backup/testing/TransportTestUtils.java index 7dd5be53157b..ce44f067aeaa 100644 --- a/services/robotests/backup/src/com/android/server/backup/testing/TransportTestUtils.java +++ b/services/robotests/backup/src/com/android/server/backup/testing/TransportTestUtils.java @@ -36,7 +36,7 @@ import android.os.RemoteException; import com.android.internal.backup.IBackupTransport; import com.android.server.backup.TransportManager; -import com.android.server.backup.transport.TransportClient; +import com.android.server.backup.transport.TransportConnection; import com.android.server.backup.transport.TransportNotAvailableException; import com.android.server.backup.transport.TransportNotRegisteredException; @@ -91,9 +91,9 @@ public class TransportTestUtils { || status == TransportStatus.REGISTERED_UNAVAILABLE) { // Transport registered when(transportManager.getCurrentTransportClient(any())) - .thenReturn(transportMock.transportClient); + .thenReturn(transportMock.mTransportConnection); when(transportManager.getCurrentTransportClientOrThrow(any())) - .thenReturn(transportMock.transportClient); + .thenReturn(transportMock.mTransportConnection); } else { // Transport not registered when(transportManager.getCurrentTransportClient(any())).thenReturn(null); @@ -123,9 +123,9 @@ public class TransportTestUtils { || status == TransportStatus.REGISTERED_UNAVAILABLE) { // Transport registered when(transportManager.getTransportClient(eq(transportName), any())) - .thenReturn(transportMock.transportClient); + .thenReturn(transportMock.mTransportConnection); when(transportManager.getTransportClientOrThrow(eq(transportName), any())) - .thenReturn(transportMock.transportClient); + .thenReturn(transportMock.mTransportConnection); when(transportManager.getTransportName(transportComponent)).thenReturn(transportName); when(transportManager.getTransportDirName(eq(transportName))) .thenReturn(transportDirName); @@ -150,28 +150,28 @@ public class TransportTestUtils { } public static TransportMock mockTransport(TransportData transport) throws Exception { - final TransportClient transportClientMock; + final TransportConnection transportConnectionMock; int status = transport.transportStatus; ComponentName transportComponent = transport.getTransportComponent(); if (status == TransportStatus.REGISTERED_AVAILABLE || status == TransportStatus.REGISTERED_UNAVAILABLE) { // Transport registered - transportClientMock = mock(TransportClient.class); - when(transportClientMock.getTransportComponent()).thenReturn(transportComponent); + transportConnectionMock = mock(TransportConnection.class); + when(transportConnectionMock.getTransportComponent()).thenReturn(transportComponent); if (status == TransportStatus.REGISTERED_AVAILABLE) { // Transport registered and available IBackupTransport transportMock = mockTransportBinder(transport); - when(transportClientMock.connectOrThrow(any())).thenReturn(transportMock); - when(transportClientMock.connect(any())).thenReturn(transportMock); + when(transportConnectionMock.connectOrThrow(any())).thenReturn(transportMock); + when(transportConnectionMock.connect(any())).thenReturn(transportMock); - return new TransportMock(transport, transportClientMock, transportMock); + return new TransportMock(transport, transportConnectionMock, transportMock); } else { // Transport registered but unavailable - when(transportClientMock.connectOrThrow(any())) + when(transportConnectionMock.connectOrThrow(any())) .thenThrow(TransportNotAvailableException.class); - when(transportClientMock.connect(any())).thenReturn(null); + when(transportConnectionMock.connect(any())).thenReturn(null); - return new TransportMock(transport, transportClientMock, null); + return new TransportMock(transport, transportConnectionMock, null); } } else { // Transport not registered @@ -198,15 +198,15 @@ public class TransportTestUtils { public static class TransportMock { public final TransportData transportData; - @Nullable public final TransportClient transportClient; + @Nullable public final TransportConnection mTransportConnection; @Nullable public final IBackupTransport transport; private TransportMock( TransportData transportData, - @Nullable TransportClient transportClient, + @Nullable TransportConnection transportConnection, @Nullable IBackupTransport transport) { this.transportData = transportData; - this.transportClient = transportClient; + this.mTransportConnection = transportConnection; this.transport = transport; } } diff --git a/services/robotests/backup/src/com/android/server/backup/transport/TransportClientManagerTest.java b/services/robotests/backup/src/com/android/server/backup/transport/TransportClientManagerTest.java deleted file mode 100644 index f033af8a9b63..000000000000 --- a/services/robotests/backup/src/com/android/server/backup/transport/TransportClientManagerTest.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright (C) 2018 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.backup.transport; - -import static com.android.server.backup.TransportManager.SERVICE_ACTION_TRANSPORT_HOST; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.argThat; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.annotation.UserIdInt; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.Bundle; -import android.os.UserHandle; -import android.platform.test.annotations.Presubmit; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentMatcher; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; - -@RunWith(RobolectricTestRunner.class) -@Presubmit -public class TransportClientManagerTest { - private static final String PACKAGE_NAME = "random.package.name"; - private static final String CLASS_NAME = "random.package.name.transport.Transport"; - - @Mock private Context mContext; - @Mock private TransportConnectionListener mTransportConnectionListener; - private @UserIdInt int mUserId; - private TransportClientManager mTransportClientManager; - private ComponentName mTransportComponent; - private Intent mBindIntent; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - - mUserId = UserHandle.USER_SYSTEM; - mTransportClientManager = - new TransportClientManager(mUserId, mContext, new TransportStats()); - mTransportComponent = new ComponentName(PACKAGE_NAME, CLASS_NAME); - mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent); - - when(mContext.bindServiceAsUser( - any(Intent.class), - any(ServiceConnection.class), - anyInt(), - any(UserHandle.class))) - .thenReturn(true); - } - - @Test - public void testGetTransportClient() { - TransportClient transportClient = - mTransportClientManager.getTransportClient(mTransportComponent, "caller"); - - // Connect to be able to extract the intent - transportClient.connectAsync(mTransportConnectionListener, "caller"); - verify(mContext) - .bindServiceAsUser( - argThat(matchesIntentAndExtras(mBindIntent)), - any(ServiceConnection.class), - anyInt(), - any(UserHandle.class)); - } - - @Test - public void testGetTransportClient_withExtras_createsTransportClientWithCorrectIntent() { - Bundle extras = new Bundle(); - extras.putBoolean("random_extra", true); - - TransportClient transportClient = - mTransportClientManager.getTransportClient(mTransportComponent, extras, "caller"); - - transportClient.connectAsync(mTransportConnectionListener, "caller"); - mBindIntent.putExtras(extras); - verify(mContext) - .bindServiceAsUser( - argThat(matchesIntentAndExtras(mBindIntent)), - any(ServiceConnection.class), - anyInt(), - any(UserHandle.class)); - } - - @Test - public void testDisposeOfTransportClient() { - TransportClient transportClient = - spy(mTransportClientManager.getTransportClient(mTransportComponent, "caller")); - - mTransportClientManager.disposeOfTransportClient(transportClient, "caller"); - - verify(transportClient).unbind(any()); - verify(transportClient).markAsDisposed(); - } - - private ArgumentMatcher matchesIntentAndExtras(Intent expectedIntent) { - return (Intent actualIntent) -> { - if (!expectedIntent.filterEquals(actualIntent)) { - return false; - } - - Bundle expectedExtras = expectedIntent.getExtras(); - Bundle actualExtras = actualIntent.getExtras(); - - if (expectedExtras == null && actualExtras == null) { - return true; - } - - if (expectedExtras == null || actualExtras == null) { - return false; - } - - if (expectedExtras.size() != actualExtras.size()) { - return false; - } - - for (String key : expectedExtras.keySet()) { - if (!expectedExtras.get(key).equals(actualExtras.get(key))) { - return false; - } - } - - return true; - }; - } -} diff --git a/services/robotests/backup/src/com/android/server/backup/transport/TransportClientTest.java b/services/robotests/backup/src/com/android/server/backup/transport/TransportClientTest.java deleted file mode 100644 index 392f2ca9490e..000000000000 --- a/services/robotests/backup/src/com/android/server/backup/transport/TransportClientTest.java +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Copyright (C) 2017 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.backup.transport; - -import static com.android.server.backup.TransportManager.SERVICE_ACTION_TRANSPORT_HOST; -import static com.android.server.backup.testing.TestUtils.assertEventLogged; -import static com.android.server.backup.testing.TestUtils.assertLogcatAtLeast; -import static com.android.server.backup.testing.TestUtils.assertLogcatAtMost; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isNull; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.robolectric.Shadows.shadowOf; -import static org.robolectric.shadow.api.Shadow.extract; -import static org.testng.Assert.expectThrows; - -import android.annotation.Nullable; -import android.annotation.UserIdInt; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.UserHandle; -import android.platform.test.annotations.Presubmit; -import android.util.Log; - -import com.android.internal.backup.IBackupTransport; -import com.android.server.EventLogTags; -import com.android.server.testing.shadows.FrameworkShadowLooper; -import com.android.server.testing.shadows.ShadowCloseGuard; -import com.android.server.testing.shadows.ShadowEventLog; -import com.android.server.testing.shadows.ShadowSlog; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowLog; -import org.robolectric.shadows.ShadowLooper; - -import java.util.concurrent.CompletableFuture; -import java.util.function.Supplier; - -@RunWith(RobolectricTestRunner.class) -@Config(shadows = { - ShadowEventLog.class, - ShadowCloseGuard.class, - ShadowSlog.class, - FrameworkShadowLooper.class - }) -@Presubmit -public class TransportClientTest { - private static final String PACKAGE_NAME = "some.package.name"; - - @Mock private Context mContext; - @Mock private TransportConnectionListener mTransportConnectionListener; - @Mock private TransportConnectionListener mTransportConnectionListener2; - @Mock private IBackupTransport.Stub mTransportBinder; - @UserIdInt private int mUserId; - private TransportStats mTransportStats; - private TransportClient mTransportClient; - private ComponentName mTransportComponent; - private String mTransportString; - private Intent mBindIntent; - private FrameworkShadowLooper mShadowMainLooper; - private ShadowLooper mShadowWorkerLooper; - private Handler mWorkerHandler; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - - mUserId = UserHandle.USER_SYSTEM; - Looper mainLooper = Looper.getMainLooper(); - mShadowMainLooper = extract(mainLooper); - mTransportComponent = - new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".transport.Transport"); - mTransportString = mTransportComponent.flattenToShortString(); - mTransportStats = new TransportStats(); - mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent); - mTransportClient = - new TransportClient( - mUserId, - mContext, - mTransportStats, - mBindIntent, - mTransportComponent, - "1", - "caller", - new Handler(mainLooper)); - - when(mContext.bindServiceAsUser( - eq(mBindIntent), - any(ServiceConnection.class), - anyInt(), - any(UserHandle.class))) - .thenReturn(true); - - HandlerThread workerThread = new HandlerThread("worker"); - workerThread.start(); - mShadowWorkerLooper = shadowOf(workerThread.getLooper()); - mWorkerHandler = workerThread.getThreadHandler(); - } - - @Test - public void testGetTransportComponent_returnsTransportComponent() { - assertThat(mTransportClient.getTransportComponent()).isEqualTo(mTransportComponent); - } - - @Test - public void testConnectAsync_callsBindService() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller"); - - verify(mContext) - .bindServiceAsUser( - eq(mBindIntent), - any(ServiceConnection.class), - anyInt(), - any(UserHandle.class)); - } - - @Test - public void testConnectAsync_callsListenerWhenConnected() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - - connection.onServiceConnected(mTransportComponent, mTransportBinder); - - mShadowMainLooper.runToEndOfTasks(); - verify(mTransportConnectionListener) - .onTransportConnectionResult(any(IBackupTransport.class), eq(mTransportClient)); - } - - @Test - public void testConnectAsync_whenPendingConnection_callsAllListenersWhenConnected() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - - mTransportClient.connectAsync(mTransportConnectionListener2, "caller2"); - - connection.onServiceConnected(mTransportComponent, mTransportBinder); - mShadowMainLooper.runToEndOfTasks(); - verify(mTransportConnectionListener) - .onTransportConnectionResult(any(IBackupTransport.class), eq(mTransportClient)); - verify(mTransportConnectionListener2) - .onTransportConnectionResult(any(IBackupTransport.class), eq(mTransportClient)); - } - - @Test - public void testConnectAsync_whenAlreadyConnected_callsListener() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - connection.onServiceConnected(mTransportComponent, mTransportBinder); - - mTransportClient.connectAsync(mTransportConnectionListener2, "caller2"); - - mShadowMainLooper.runToEndOfTasks(); - verify(mTransportConnectionListener2) - .onTransportConnectionResult(any(IBackupTransport.class), eq(mTransportClient)); - } - - @Test - public void testConnectAsync_whenFrameworkDoesntBind_callsListener() { - when(mContext.bindServiceAsUser( - eq(mBindIntent), - any(ServiceConnection.class), - anyInt(), - any(UserHandle.class))) - .thenReturn(false); - - mTransportClient.connectAsync(mTransportConnectionListener, "caller"); - - mShadowMainLooper.runToEndOfTasks(); - verify(mTransportConnectionListener) - .onTransportConnectionResult(isNull(), eq(mTransportClient)); - } - - @Test - public void testConnectAsync_whenFrameworkDoesNotBind_releasesConnection() { - when(mContext.bindServiceAsUser( - eq(mBindIntent), - any(ServiceConnection.class), - anyInt(), - any(UserHandle.class))) - .thenReturn(false); - - mTransportClient.connectAsync(mTransportConnectionListener, "caller"); - - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - verify(mContext).unbindService(eq(connection)); - } - - @Test - public void testConnectAsync_afterOnServiceDisconnectedBeforeNewConnection_callsListener() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - connection.onServiceConnected(mTransportComponent, mTransportBinder); - connection.onServiceDisconnected(mTransportComponent); - - mTransportClient.connectAsync(mTransportConnectionListener2, "caller1"); - - verify(mTransportConnectionListener2) - .onTransportConnectionResult(isNull(), eq(mTransportClient)); - } - - @Test - public void testConnectAsync_afterOnServiceDisconnectedAfterNewConnection_callsListener() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - connection.onServiceConnected(mTransportComponent, mTransportBinder); - connection.onServiceDisconnected(mTransportComponent); - connection.onServiceConnected(mTransportComponent, mTransportBinder); - - mTransportClient.connectAsync(mTransportConnectionListener2, "caller1"); - - // Yes, it should return null because the object became unusable, check design doc - verify(mTransportConnectionListener2) - .onTransportConnectionResult(isNull(), eq(mTransportClient)); - } - - @Test - public void testConnectAsync_callsListenerIfBindingDies() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - - connection.onBindingDied(mTransportComponent); - - mShadowMainLooper.runToEndOfTasks(); - verify(mTransportConnectionListener) - .onTransportConnectionResult(isNull(), eq(mTransportClient)); - } - - @Test - public void testConnectAsync_whenPendingConnection_callsListenersIfBindingDies() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - - mTransportClient.connectAsync(mTransportConnectionListener2, "caller2"); - - connection.onBindingDied(mTransportComponent); - mShadowMainLooper.runToEndOfTasks(); - verify(mTransportConnectionListener) - .onTransportConnectionResult(isNull(), eq(mTransportClient)); - verify(mTransportConnectionListener2) - .onTransportConnectionResult(isNull(), eq(mTransportClient)); - } - - @Test - public void testConnectAsync_beforeFrameworkCall_logsBoundTransitionEvent() { - ShadowEventLog.setUp(); - - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - - assertEventLogged(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, mTransportString, 1); - } - - @Test - public void testConnectAsync_afterOnServiceConnected_logsBoundAndConnectedTransitionEvents() { - ShadowEventLog.setUp(); - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - - connection.onServiceConnected(mTransportComponent, mTransportBinder); - - assertEventLogged(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, mTransportString, 1); - assertEventLogged(EventLogTags.BACKUP_TRANSPORT_CONNECTION, mTransportString, 1); - } - - @Test - public void testConnectAsync_afterOnBindingDied_logsBoundAndUnboundTransitionEvents() { - ShadowEventLog.setUp(); - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - - connection.onBindingDied(mTransportComponent); - - assertEventLogged(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, mTransportString, 1); - assertEventLogged(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, mTransportString, 0); - } - - @Test - public void testConnect_whenConnected_returnsTransport() throws Exception { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - connection.onServiceConnected(mTransportComponent, mTransportBinder); - - IBackupTransport transportBinder = - runInWorkerThread(() -> mTransportClient.connect("caller2")); - - assertThat(transportBinder).isNotNull(); - } - - @Test - public void testConnect_afterOnServiceDisconnected_returnsNull() throws Exception { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - connection.onServiceConnected(mTransportComponent, mTransportBinder); - connection.onServiceDisconnected(mTransportComponent); - - IBackupTransport transportBinder = - runInWorkerThread(() -> mTransportClient.connect("caller2")); - - assertThat(transportBinder).isNull(); - } - - @Test - public void testConnect_afterOnBindingDied_returnsNull() throws Exception { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - connection.onBindingDied(mTransportComponent); - - IBackupTransport transportBinder = - runInWorkerThread(() -> mTransportClient.connect("caller2")); - - assertThat(transportBinder).isNull(); - } - - @Test - public void testConnect_callsThroughToConnectAsync() throws Exception { - // We can't mock bindServiceAsUser() instead of connectAsync() and call the listener inline - // because in our code in TransportClient we assume this is NOT run inline, such that the - // reentrant lock can't be acquired by the listener at the call-site of bindServiceAsUser(), - // which is what would happened if we mocked bindServiceAsUser() to call the listener - // inline. - TransportClient transportClient = spy(mTransportClient); - doAnswer( - invocation -> { - TransportConnectionListener listener = invocation.getArgument(0); - listener.onTransportConnectionResult(mTransportBinder, transportClient); - return null; - }) - .when(transportClient) - .connectAsync(any(), any()); - - IBackupTransport transportBinder = - runInWorkerThread(() -> transportClient.connect("caller")); - - assertThat(transportBinder).isNotNull(); - } - - @Test - public void testUnbind_whenConnected_logsDisconnectedAndUnboundTransitionEvents() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - connection.onServiceConnected(mTransportComponent, mTransportBinder); - ShadowEventLog.setUp(); - - mTransportClient.unbind("caller1"); - - assertEventLogged(EventLogTags.BACKUP_TRANSPORT_CONNECTION, mTransportString, 0); - assertEventLogged(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, mTransportString, 0); - } - - @Test - public void - testOnServiceDisconnected_whenConnected_logsDisconnectedAndUnboundTransitionEvents() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - connection.onServiceConnected(mTransportComponent, mTransportBinder); - ShadowEventLog.setUp(); - - connection.onServiceDisconnected(mTransportComponent); - - assertEventLogged(EventLogTags.BACKUP_TRANSPORT_CONNECTION, mTransportString, 0); - assertEventLogged(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, mTransportString, 0); - } - - @Test - public void testOnBindingDied_whenConnected_logsDisconnectedAndUnboundTransitionEvents() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - connection.onServiceConnected(mTransportComponent, mTransportBinder); - ShadowEventLog.setUp(); - - connection.onBindingDied(mTransportComponent); - - assertEventLogged(EventLogTags.BACKUP_TRANSPORT_CONNECTION, mTransportString, 0); - assertEventLogged(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, mTransportString, 0); - } - - @Test - public void testMarkAsDisposed_whenCreated() { - mTransportClient.markAsDisposed(); - - // No exception thrown - } - - @Test - public void testMarkAsDisposed_afterOnBindingDied() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - connection.onBindingDied(mTransportComponent); - - mTransportClient.markAsDisposed(); - - // No exception thrown - } - - @Test - public void testMarkAsDisposed_whenConnectedAndUnbound() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - connection.onServiceConnected(mTransportComponent, mTransportBinder); - mTransportClient.unbind("caller1"); - - mTransportClient.markAsDisposed(); - - // No exception thrown - } - - @Test - public void testMarkAsDisposed_afterOnServiceDisconnected() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - connection.onServiceConnected(mTransportComponent, mTransportBinder); - connection.onServiceDisconnected(mTransportComponent); - - mTransportClient.markAsDisposed(); - - // No exception thrown - } - - @Test - public void testMarkAsDisposed_whenBound() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - - expectThrows(RuntimeException.class, mTransportClient::markAsDisposed); - } - - @Test - public void testMarkAsDisposed_whenConnected() { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - connection.onServiceConnected(mTransportComponent, mTransportBinder); - - expectThrows(RuntimeException.class, mTransportClient::markAsDisposed); - } - - @Test - @SuppressWarnings("FinalizeCalledExplicitly") - public void testFinalize_afterCreated() throws Throwable { - ShadowLog.reset(); - - mTransportClient.finalize(); - - assertLogcatAtMost(TransportClient.TAG, Log.INFO); - } - - @Test - @SuppressWarnings("FinalizeCalledExplicitly") - public void testFinalize_whenBound() throws Throwable { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ShadowLog.reset(); - - mTransportClient.finalize(); - - assertLogcatAtLeast(TransportClient.TAG, Log.ERROR); - } - - @Test - @SuppressWarnings("FinalizeCalledExplicitly") - public void testFinalize_whenConnected() throws Throwable { - mTransportClient.connectAsync(mTransportConnectionListener, "caller1"); - ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); - connection.onServiceConnected(mTransportComponent, mTransportBinder); - ShadowLog.reset(); - - mTransportClient.finalize(); - - expectThrows( - TransportNotAvailableException.class, - () -> mTransportClient.getConnectedTransport("caller1")); - assertLogcatAtLeast(TransportClient.TAG, Log.ERROR); - } - - @Test - @SuppressWarnings("FinalizeCalledExplicitly") - public void testFinalize_whenNotMarkedAsDisposed() throws Throwable { - ShadowCloseGuard.setUp(); - - mTransportClient.finalize(); - - assertThat(ShadowCloseGuard.hasReported()).isTrue(); - } - - @Test - @SuppressWarnings("FinalizeCalledExplicitly") - public void testFinalize_whenMarkedAsDisposed() throws Throwable { - mTransportClient.markAsDisposed(); - ShadowCloseGuard.setUp(); - - mTransportClient.finalize(); - - assertThat(ShadowCloseGuard.hasReported()).isFalse(); - } - - @Nullable - private T runInWorkerThread(Supplier supplier) throws Exception { - CompletableFuture future = new CompletableFuture<>(); - mWorkerHandler.post(() -> future.complete(supplier.get())); - // Although we are using a separate looper, we are still calling runToEndOfTasks() in the - // main thread (Robolectric only *simulates* multi-thread). The only option left is to fool - // the caller. - mShadowMainLooper.setCurrentThread(false); - mShadowWorkerLooper.runToEndOfTasks(); - mShadowMainLooper.reset(); - return future.get(); - } - - private ServiceConnection verifyBindServiceAsUserAndCaptureServiceConnection(Context context) { - ArgumentCaptor connectionCaptor = - ArgumentCaptor.forClass(ServiceConnection.class); - verify(context) - .bindServiceAsUser( - any(Intent.class), - connectionCaptor.capture(), - anyInt(), - any(UserHandle.class)); - return connectionCaptor.getValue(); - } -} diff --git a/services/robotests/backup/src/com/android/server/backup/transport/TransportConnectionManagerTest.java b/services/robotests/backup/src/com/android/server/backup/transport/TransportConnectionManagerTest.java new file mode 100644 index 000000000000..102f594003fa --- /dev/null +++ b/services/robotests/backup/src/com/android/server/backup/transport/TransportConnectionManagerTest.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2018 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.backup.transport; + +import static com.android.server.backup.TransportManager.SERVICE_ACTION_TRANSPORT_HOST; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.argThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.annotation.UserIdInt; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.UserHandle; +import android.platform.test.annotations.Presubmit; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentMatcher; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +@Presubmit +public class TransportConnectionManagerTest { + private static final String PACKAGE_NAME = "random.package.name"; + private static final String CLASS_NAME = "random.package.name.transport.Transport"; + + @Mock private Context mContext; + @Mock private TransportConnectionListener mTransportConnectionListener; + private @UserIdInt int mUserId; + private TransportConnectionManager mTransportConnectionManager; + private ComponentName mTransportComponent; + private Intent mBindIntent; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mUserId = UserHandle.USER_SYSTEM; + mTransportConnectionManager = + new TransportConnectionManager(mUserId, mContext, new TransportStats()); + mTransportComponent = new ComponentName(PACKAGE_NAME, CLASS_NAME); + mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent); + + when(mContext.bindServiceAsUser( + any(Intent.class), + any(ServiceConnection.class), + anyInt(), + any(UserHandle.class))) + .thenReturn(true); + } + + @Test + public void testGetTransportClient() { + TransportConnection transportConnection = + mTransportConnectionManager.getTransportClient(mTransportComponent, "caller"); + + // Connect to be able to extract the intent + transportConnection.connectAsync(mTransportConnectionListener, "caller"); + verify(mContext) + .bindServiceAsUser( + argThat(matchesIntentAndExtras(mBindIntent)), + any(ServiceConnection.class), + anyInt(), + any(UserHandle.class)); + } + + @Test + public void testGetTransportClient_withExtras_createsTransportClientWithCorrectIntent() { + Bundle extras = new Bundle(); + extras.putBoolean("random_extra", true); + + TransportConnection transportConnection = + mTransportConnectionManager.getTransportClient(mTransportComponent, extras, + "caller"); + + transportConnection.connectAsync(mTransportConnectionListener, "caller"); + mBindIntent.putExtras(extras); + verify(mContext) + .bindServiceAsUser( + argThat(matchesIntentAndExtras(mBindIntent)), + any(ServiceConnection.class), + anyInt(), + any(UserHandle.class)); + } + + @Test + public void testDisposeOfTransportClient() { + TransportConnection transportConnection = + spy(mTransportConnectionManager.getTransportClient(mTransportComponent, "caller")); + + mTransportConnectionManager.disposeOfTransportClient(transportConnection, "caller"); + + verify(transportConnection).unbind(any()); + verify(transportConnection).markAsDisposed(); + } + + private ArgumentMatcher matchesIntentAndExtras(Intent expectedIntent) { + return (Intent actualIntent) -> { + if (!expectedIntent.filterEquals(actualIntent)) { + return false; + } + + Bundle expectedExtras = expectedIntent.getExtras(); + Bundle actualExtras = actualIntent.getExtras(); + + if (expectedExtras == null && actualExtras == null) { + return true; + } + + if (expectedExtras == null || actualExtras == null) { + return false; + } + + if (expectedExtras.size() != actualExtras.size()) { + return false; + } + + for (String key : expectedExtras.keySet()) { + if (!expectedExtras.get(key).equals(actualExtras.get(key))) { + return false; + } + } + + return true; + }; + } +} diff --git a/services/robotests/backup/src/com/android/server/backup/transport/TransportConnectionTest.java b/services/robotests/backup/src/com/android/server/backup/transport/TransportConnectionTest.java new file mode 100644 index 000000000000..de4aec61aef2 --- /dev/null +++ b/services/robotests/backup/src/com/android/server/backup/transport/TransportConnectionTest.java @@ -0,0 +1,550 @@ +/* + * Copyright (C) 2017 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.backup.transport; + +import static com.android.server.backup.TransportManager.SERVICE_ACTION_TRANSPORT_HOST; +import static com.android.server.backup.testing.TestUtils.assertEventLogged; +import static com.android.server.backup.testing.TestUtils.assertLogcatAtLeast; +import static com.android.server.backup.testing.TestUtils.assertLogcatAtMost; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.robolectric.Shadows.shadowOf; +import static org.robolectric.shadow.api.Shadow.extract; +import static org.testng.Assert.expectThrows; + +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.UserHandle; +import android.platform.test.annotations.Presubmit; +import android.util.Log; + +import com.android.internal.backup.IBackupTransport; +import com.android.server.EventLogTags; +import com.android.server.testing.shadows.FrameworkShadowLooper; +import com.android.server.testing.shadows.ShadowCloseGuard; +import com.android.server.testing.shadows.ShadowEventLog; +import com.android.server.testing.shadows.ShadowSlog; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowLog; +import org.robolectric.shadows.ShadowLooper; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = { + ShadowEventLog.class, + ShadowCloseGuard.class, + ShadowSlog.class, + FrameworkShadowLooper.class + }) +@Presubmit +public class TransportConnectionTest { + private static final String PACKAGE_NAME = "some.package.name"; + + @Mock private Context mContext; + @Mock private TransportConnectionListener mTransportConnectionListener; + @Mock private TransportConnectionListener mTransportConnectionListener2; + @Mock private IBackupTransport.Stub mTransportBinder; + @UserIdInt private int mUserId; + private TransportStats mTransportStats; + private TransportConnection mTransportConnection; + private ComponentName mTransportComponent; + private String mTransportString; + private Intent mBindIntent; + private FrameworkShadowLooper mShadowMainLooper; + private ShadowLooper mShadowWorkerLooper; + private Handler mWorkerHandler; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + mUserId = UserHandle.USER_SYSTEM; + Looper mainLooper = Looper.getMainLooper(); + mShadowMainLooper = extract(mainLooper); + mTransportComponent = + new ComponentName(PACKAGE_NAME, PACKAGE_NAME + ".transport.Transport"); + mTransportString = mTransportComponent.flattenToShortString(); + mTransportStats = new TransportStats(); + mBindIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST).setComponent(mTransportComponent); + mTransportConnection = + new TransportConnection( + mUserId, + mContext, + mTransportStats, + mBindIntent, + mTransportComponent, + "1", + "caller", + new Handler(mainLooper)); + + when(mContext.bindServiceAsUser( + eq(mBindIntent), + any(ServiceConnection.class), + anyInt(), + any(UserHandle.class))) + .thenReturn(true); + + HandlerThread workerThread = new HandlerThread("worker"); + workerThread.start(); + mShadowWorkerLooper = shadowOf(workerThread.getLooper()); + mWorkerHandler = workerThread.getThreadHandler(); + } + + @Test + public void testGetTransportComponent_returnsTransportComponent() { + assertThat(mTransportConnection.getTransportComponent()).isEqualTo(mTransportComponent); + } + + @Test + public void testConnectAsync_callsBindService() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller"); + + verify(mContext) + .bindServiceAsUser( + eq(mBindIntent), + any(ServiceConnection.class), + anyInt(), + any(UserHandle.class)); + } + + @Test + public void testConnectAsync_callsListenerWhenConnected() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + + connection.onServiceConnected(mTransportComponent, mTransportBinder); + + mShadowMainLooper.runToEndOfTasks(); + verify(mTransportConnectionListener) + .onTransportConnectionResult(any(IBackupTransport.class), eq(mTransportConnection)); + } + + @Test + public void testConnectAsync_whenPendingConnection_callsAllListenersWhenConnected() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + + mTransportConnection.connectAsync(mTransportConnectionListener2, "caller2"); + + connection.onServiceConnected(mTransportComponent, mTransportBinder); + mShadowMainLooper.runToEndOfTasks(); + verify(mTransportConnectionListener) + .onTransportConnectionResult(any(IBackupTransport.class), eq(mTransportConnection)); + verify(mTransportConnectionListener2) + .onTransportConnectionResult(any(IBackupTransport.class), eq(mTransportConnection)); + } + + @Test + public void testConnectAsync_whenAlreadyConnected_callsListener() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + connection.onServiceConnected(mTransportComponent, mTransportBinder); + + mTransportConnection.connectAsync(mTransportConnectionListener2, "caller2"); + + mShadowMainLooper.runToEndOfTasks(); + verify(mTransportConnectionListener2) + .onTransportConnectionResult(any(IBackupTransport.class), eq(mTransportConnection)); + } + + @Test + public void testConnectAsync_whenFrameworkDoesntBind_callsListener() { + when(mContext.bindServiceAsUser( + eq(mBindIntent), + any(ServiceConnection.class), + anyInt(), + any(UserHandle.class))) + .thenReturn(false); + + mTransportConnection.connectAsync(mTransportConnectionListener, "caller"); + + mShadowMainLooper.runToEndOfTasks(); + verify(mTransportConnectionListener) + .onTransportConnectionResult(isNull(), eq(mTransportConnection)); + } + + @Test + public void testConnectAsync_whenFrameworkDoesNotBind_releasesConnection() { + when(mContext.bindServiceAsUser( + eq(mBindIntent), + any(ServiceConnection.class), + anyInt(), + any(UserHandle.class))) + .thenReturn(false); + + mTransportConnection.connectAsync(mTransportConnectionListener, "caller"); + + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + verify(mContext).unbindService(eq(connection)); + } + + @Test + public void testConnectAsync_afterOnServiceDisconnectedBeforeNewConnection_callsListener() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + connection.onServiceConnected(mTransportComponent, mTransportBinder); + connection.onServiceDisconnected(mTransportComponent); + + mTransportConnection.connectAsync(mTransportConnectionListener2, "caller1"); + + verify(mTransportConnectionListener2) + .onTransportConnectionResult(isNull(), eq(mTransportConnection)); + } + + @Test + public void testConnectAsync_afterOnServiceDisconnectedAfterNewConnection_callsListener() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + connection.onServiceConnected(mTransportComponent, mTransportBinder); + connection.onServiceDisconnected(mTransportComponent); + connection.onServiceConnected(mTransportComponent, mTransportBinder); + + mTransportConnection.connectAsync(mTransportConnectionListener2, "caller1"); + + // Yes, it should return null because the object became unusable, check design doc + verify(mTransportConnectionListener2) + .onTransportConnectionResult(isNull(), eq(mTransportConnection)); + } + + @Test + public void testConnectAsync_callsListenerIfBindingDies() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + + connection.onBindingDied(mTransportComponent); + + mShadowMainLooper.runToEndOfTasks(); + verify(mTransportConnectionListener) + .onTransportConnectionResult(isNull(), eq(mTransportConnection)); + } + + @Test + public void testConnectAsync_whenPendingConnection_callsListenersIfBindingDies() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + + mTransportConnection.connectAsync(mTransportConnectionListener2, "caller2"); + + connection.onBindingDied(mTransportComponent); + mShadowMainLooper.runToEndOfTasks(); + verify(mTransportConnectionListener) + .onTransportConnectionResult(isNull(), eq(mTransportConnection)); + verify(mTransportConnectionListener2) + .onTransportConnectionResult(isNull(), eq(mTransportConnection)); + } + + @Test + public void testConnectAsync_beforeFrameworkCall_logsBoundTransitionEvent() { + ShadowEventLog.setUp(); + + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + + assertEventLogged(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, mTransportString, 1); + } + + @Test + public void testConnectAsync_afterOnServiceConnected_logsBoundAndConnectedTransitionEvents() { + ShadowEventLog.setUp(); + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + + connection.onServiceConnected(mTransportComponent, mTransportBinder); + + assertEventLogged(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, mTransportString, 1); + assertEventLogged(EventLogTags.BACKUP_TRANSPORT_CONNECTION, mTransportString, 1); + } + + @Test + public void testConnectAsync_afterOnBindingDied_logsBoundAndUnboundTransitionEvents() { + ShadowEventLog.setUp(); + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + + connection.onBindingDied(mTransportComponent); + + assertEventLogged(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, mTransportString, 1); + assertEventLogged(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, mTransportString, 0); + } + + @Test + public void testConnect_whenConnected_returnsTransport() throws Exception { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + connection.onServiceConnected(mTransportComponent, mTransportBinder); + + IBackupTransport transportBinder = + runInWorkerThread(() -> mTransportConnection.connect("caller2")); + + assertThat(transportBinder).isNotNull(); + } + + @Test + public void testConnect_afterOnServiceDisconnected_returnsNull() throws Exception { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + connection.onServiceConnected(mTransportComponent, mTransportBinder); + connection.onServiceDisconnected(mTransportComponent); + + IBackupTransport transportBinder = + runInWorkerThread(() -> mTransportConnection.connect("caller2")); + + assertThat(transportBinder).isNull(); + } + + @Test + public void testConnect_afterOnBindingDied_returnsNull() throws Exception { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + connection.onBindingDied(mTransportComponent); + + IBackupTransport transportBinder = + runInWorkerThread(() -> mTransportConnection.connect("caller2")); + + assertThat(transportBinder).isNull(); + } + + @Test + public void testConnect_callsThroughToConnectAsync() throws Exception { + // We can't mock bindServiceAsUser() instead of connectAsync() and call the listener inline + // because in our code in TransportClient we assume this is NOT run inline, such that the + // reentrant lock can't be acquired by the listener at the call-site of bindServiceAsUser(), + // which is what would happened if we mocked bindServiceAsUser() to call the listener + // inline. + TransportConnection transportConnection = spy(mTransportConnection); + doAnswer( + invocation -> { + TransportConnectionListener listener = invocation.getArgument(0); + listener.onTransportConnectionResult(mTransportBinder, + transportConnection); + return null; + }) + .when(transportConnection) + .connectAsync(any(), any()); + + IBackupTransport transportBinder = + runInWorkerThread(() -> transportConnection.connect("caller")); + + assertThat(transportBinder).isNotNull(); + } + + @Test + public void testUnbind_whenConnected_logsDisconnectedAndUnboundTransitionEvents() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + connection.onServiceConnected(mTransportComponent, mTransportBinder); + ShadowEventLog.setUp(); + + mTransportConnection.unbind("caller1"); + + assertEventLogged(EventLogTags.BACKUP_TRANSPORT_CONNECTION, mTransportString, 0); + assertEventLogged(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, mTransportString, 0); + } + + @Test + public void + testOnServiceDisconnected_whenConnected_logsDisconnectedAndUnboundTransitionEvents() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + connection.onServiceConnected(mTransportComponent, mTransportBinder); + ShadowEventLog.setUp(); + + connection.onServiceDisconnected(mTransportComponent); + + assertEventLogged(EventLogTags.BACKUP_TRANSPORT_CONNECTION, mTransportString, 0); + assertEventLogged(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, mTransportString, 0); + } + + @Test + public void testOnBindingDied_whenConnected_logsDisconnectedAndUnboundTransitionEvents() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + connection.onServiceConnected(mTransportComponent, mTransportBinder); + ShadowEventLog.setUp(); + + connection.onBindingDied(mTransportComponent); + + assertEventLogged(EventLogTags.BACKUP_TRANSPORT_CONNECTION, mTransportString, 0); + assertEventLogged(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE, mTransportString, 0); + } + + @Test + public void testMarkAsDisposed_whenCreated() { + mTransportConnection.markAsDisposed(); + + // No exception thrown + } + + @Test + public void testMarkAsDisposed_afterOnBindingDied() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + connection.onBindingDied(mTransportComponent); + + mTransportConnection.markAsDisposed(); + + // No exception thrown + } + + @Test + public void testMarkAsDisposed_whenConnectedAndUnbound() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + connection.onServiceConnected(mTransportComponent, mTransportBinder); + mTransportConnection.unbind("caller1"); + + mTransportConnection.markAsDisposed(); + + // No exception thrown + } + + @Test + public void testMarkAsDisposed_afterOnServiceDisconnected() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + connection.onServiceConnected(mTransportComponent, mTransportBinder); + connection.onServiceDisconnected(mTransportComponent); + + mTransportConnection.markAsDisposed(); + + // No exception thrown + } + + @Test + public void testMarkAsDisposed_whenBound() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + + expectThrows(RuntimeException.class, mTransportConnection::markAsDisposed); + } + + @Test + public void testMarkAsDisposed_whenConnected() { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + connection.onServiceConnected(mTransportComponent, mTransportBinder); + + expectThrows(RuntimeException.class, mTransportConnection::markAsDisposed); + } + + @Test + @SuppressWarnings("FinalizeCalledExplicitly") + public void testFinalize_afterCreated() throws Throwable { + ShadowLog.reset(); + + mTransportConnection.finalize(); + + assertLogcatAtMost(TransportConnection.TAG, Log.INFO); + } + + @Test + @SuppressWarnings("FinalizeCalledExplicitly") + public void testFinalize_whenBound() throws Throwable { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ShadowLog.reset(); + + mTransportConnection.finalize(); + + assertLogcatAtLeast(TransportConnection.TAG, Log.ERROR); + } + + @Test + @SuppressWarnings("FinalizeCalledExplicitly") + public void testFinalize_whenConnected() throws Throwable { + mTransportConnection.connectAsync(mTransportConnectionListener, "caller1"); + ServiceConnection connection = verifyBindServiceAsUserAndCaptureServiceConnection(mContext); + connection.onServiceConnected(mTransportComponent, mTransportBinder); + ShadowLog.reset(); + + mTransportConnection.finalize(); + + expectThrows( + TransportNotAvailableException.class, + () -> mTransportConnection.getConnectedTransport("caller1")); + assertLogcatAtLeast(TransportConnection.TAG, Log.ERROR); + } + + @Test + @SuppressWarnings("FinalizeCalledExplicitly") + public void testFinalize_whenNotMarkedAsDisposed() throws Throwable { + ShadowCloseGuard.setUp(); + + mTransportConnection.finalize(); + + assertThat(ShadowCloseGuard.hasReported()).isTrue(); + } + + @Test + @SuppressWarnings("FinalizeCalledExplicitly") + public void testFinalize_whenMarkedAsDisposed() throws Throwable { + mTransportConnection.markAsDisposed(); + ShadowCloseGuard.setUp(); + + mTransportConnection.finalize(); + + assertThat(ShadowCloseGuard.hasReported()).isFalse(); + } + + @Nullable + private T runInWorkerThread(Supplier supplier) throws Exception { + CompletableFuture future = new CompletableFuture<>(); + mWorkerHandler.post(() -> future.complete(supplier.get())); + // Although we are using a separate looper, we are still calling runToEndOfTasks() in the + // main thread (Robolectric only *simulates* multi-thread). The only option left is to fool + // the caller. + mShadowMainLooper.setCurrentThread(false); + mShadowWorkerLooper.runToEndOfTasks(); + mShadowMainLooper.reset(); + return future.get(); + } + + private ServiceConnection verifyBindServiceAsUserAndCaptureServiceConnection(Context context) { + ArgumentCaptor connectionCaptor = + ArgumentCaptor.forClass(ServiceConnection.class); + verify(context) + .bindServiceAsUser( + any(Intent.class), + connectionCaptor.capture(), + anyInt(), + any(UserHandle.class)); + return connectionCaptor.getValue(); + } +} -- cgit v1.2.3-59-g8ed1b