From 57f19304b07f39a11ed247a5b17e36e82afa95cd Mon Sep 17 00:00:00 2001 From: Bill Lin Date: Wed, 9 Oct 2019 18:35:20 +0800 Subject: [PATCH] Implement ApexManager UnitTest Create ApexManagerTest.java for ApexManager Fixes: 136247730 Fixes: 142384111 Test: atest ApexManagerTest Test: atest CtsStagedInstallHostTestCases Change-Id: Ie4ef02cbd993d97a6e407a508ef33ee219c3fbb9 --- .../com/android/server/pm/ApexManager.java | 4 +- .../servicestests/res/raw/apex_test.apex | Bin 0 -> 318688 bytes .../android/server/pm/ApexManagerTest.java | 298 ++++++++++++++++++ 3 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 services/tests/servicestests/res/raw/apex_test.apex create mode 100644 services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index dc00cb45596c8..8e9dcf0d0fcf6 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -38,6 +38,7 @@ import android.sysprop.ApexProperties; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.util.IndentingPrintWriter; @@ -217,7 +218,8 @@ abstract class ApexManager { * An implementation of {@link ApexManager} that should be used in case device supports updating * APEX packages. */ - private static class ApexManagerImpl extends ApexManager { + @VisibleForTesting + static class ApexManagerImpl extends ApexManager { private final IApexService mApexService; private final Context mContext; private final Object mLock = new Object(); diff --git a/services/tests/servicestests/res/raw/apex_test.apex b/services/tests/servicestests/res/raw/apex_test.apex new file mode 100644 index 0000000000000000000000000000000000000000..19b1c5e2e1c67b0eba95fc77ebaceb86ce355feb GIT binary patch literal 318688 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 BYr_Bl literal 0 HcmV?d00001 diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java new file mode 100644 index 0000000000000..6bb4202fa759c --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2019 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.pm; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertThrows; + +import android.apex.ApexInfo; +import android.apex.ApexSessionInfo; +import android.apex.IApexService; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.os.FileUtils; +import android.os.RemoteException; +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.frameworks.servicestests.R; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +@SmallTest +@Presubmit +@RunWith(AndroidJUnit4.class) +public class ApexManagerTest { + private static final String TEST_APEX_PKG = "com.android.apex.test"; + private static final int TEST_SESSION_ID = 99999999; + private static final int[] TEST_CHILD_SESSION_ID = {8888, 7777}; + private ApexManager mApexManager; + private Context mContext; + + private IApexService mApexService = mock(IApexService.class); + + @Before + public void setUp() throws RemoteException { + mContext = InstrumentationRegistry.getInstrumentation().getContext(); + mApexManager = new ApexManager.ApexManagerImpl(mContext, mApexService); + } + + @Test + public void testGetPackageInfo_setFlagsMatchActivePackage() throws RemoteException { + when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false)); + final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG, + ApexManager.MATCH_ACTIVE_PACKAGE); + + assertThat(activePkgPi).isNotNull(); + assertThat(activePkgPi.packageName).contains(TEST_APEX_PKG); + + final PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG, + ApexManager.MATCH_FACTORY_PACKAGE); + + assertThat(factoryPkgPi).isNull(); + } + + @Test + public void testGetPackageInfo_setFlagsMatchFactoryPackage() throws RemoteException { + when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); + PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG, + ApexManager.MATCH_FACTORY_PACKAGE); + + assertThat(factoryPkgPi).isNotNull(); + assertThat(factoryPkgPi.packageName).contains(TEST_APEX_PKG); + + final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG, + ApexManager.MATCH_ACTIVE_PACKAGE); + + assertThat(activePkgPi).isNull(); + } + + @Test + public void testGetPackageInfo_setFlagsNone() throws RemoteException { + when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); + + assertThat(mApexManager.getPackageInfo(TEST_APEX_PKG, 0)).isNull(); + } + + @Test + public void testGetActivePackages() throws RemoteException { + when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, true)); + + assertThat(mApexManager.getActivePackages()).isNotEmpty(); + } + + @Test + public void testGetActivePackages_noneActivePackages() throws RemoteException { + when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); + + assertThat(mApexManager.getActivePackages()).isEmpty(); + } + + @Test + public void testGetFactoryPackages() throws RemoteException { + when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); + + assertThat(mApexManager.getFactoryPackages()).isNotEmpty(); + } + + @Test + public void testGetFactoryPackages_noneFactoryPackages() throws RemoteException { + when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false)); + + assertThat(mApexManager.getFactoryPackages()).isEmpty(); + } + + @Test + public void testGetInactivePackages() throws RemoteException { + when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); + + assertThat(mApexManager.getInactivePackages()).isNotEmpty(); + } + + @Test + public void testGetInactivePackages_noneInactivePackages() throws RemoteException { + when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false)); + + assertThat(mApexManager.getInactivePackages()).isEmpty(); + } + + @Test + public void testIsApexPackage() throws RemoteException { + when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); + + assertThat(mApexManager.isApexPackage(TEST_APEX_PKG)).isTrue(); + } + + @Test + public void testIsApexSupported() { + assertThat(mApexManager.isApexSupported()).isTrue(); + } + + @Test + public void testGetStagedSessionInfo() throws RemoteException { + when(mApexService.getStagedSessionInfo(anyInt())).thenReturn( + getFakeStagedSessionInfo()); + + mApexManager.getStagedSessionInfo(TEST_SESSION_ID); + verify(mApexService, times(1)).getStagedSessionInfo(TEST_SESSION_ID); + } + + @Test + public void testGetStagedSessionInfo_unKnownStagedSessionId() throws RemoteException { + when(mApexService.getStagedSessionInfo(anyInt())).thenReturn( + getFakeUnknownSessionInfo()); + + assertThat(mApexManager.getStagedSessionInfo(TEST_SESSION_ID)).isNull(); + } + + @Test + public void testSubmitStagedSession_throwPackageManagerException() throws RemoteException { + doAnswer(invocation -> { + throw new Exception(); + }).when(mApexService).submitStagedSession(anyInt(), any(), any()); + + assertThrows(PackageManagerException.class, + () -> mApexManager.submitStagedSession(TEST_SESSION_ID, TEST_CHILD_SESSION_ID)); + } + + @Test + public void testSubmitStagedSession_throwRunTimeException() throws RemoteException { + doThrow(RemoteException.class).when(mApexService).submitStagedSession(anyInt(), any(), + any()); + + assertThrows(RuntimeException.class, + () -> mApexManager.submitStagedSession(TEST_SESSION_ID, TEST_CHILD_SESSION_ID)); + } + + @Test + public void testMarkStagedSessionReady_throwPackageManagerException() throws RemoteException { + doAnswer(invocation -> { + throw new Exception(); + }).when(mApexService).markStagedSessionReady(anyInt()); + + assertThrows(PackageManagerException.class, + () -> mApexManager.markStagedSessionReady(TEST_SESSION_ID)); + } + + @Test + public void testMarkStagedSessionReady_throwRunTimeException() throws RemoteException { + doThrow(RemoteException.class).when(mApexService).markStagedSessionReady(anyInt()); + + assertThrows(RuntimeException.class, + () -> mApexManager.markStagedSessionReady(TEST_SESSION_ID)); + } + + @Test + public void testAbortActiveSession_remoteException() throws RemoteException { + doThrow(RemoteException.class).when(mApexService).abortActiveSession(); + + try { + assertThat(mApexManager.abortActiveSession()).isFalse(); + } catch (Exception e) { + throw new AssertionError("ApexManager should not raise Exception"); + } + } + + @Test + public void testMarkStagedSessionSuccessful_throwRemoteException() throws RemoteException { + doThrow(RemoteException.class).when(mApexService).markStagedSessionSuccessful(anyInt()); + + assertThrows(RuntimeException.class, + () -> mApexManager.markStagedSessionSuccessful(TEST_SESSION_ID)); + } + + @Test + public void testUninstallApex_throwException_returnFalse() throws RemoteException { + doAnswer(invocation -> { + throw new Exception(); + }).when(mApexService).unstagePackages(any()); + + assertThat(mApexManager.uninstallApex(TEST_APEX_PKG)).isFalse(); + } + + private ApexInfo[] createApexInfo(boolean isActive, boolean isFactory) { + File apexFile = copyRawResourceToFile(TEST_APEX_PKG, R.raw.apex_test); + ApexInfo apexInfo = new ApexInfo(); + apexInfo.isActive = isActive; + apexInfo.isFactory = isFactory; + apexInfo.moduleName = TEST_APEX_PKG; + apexInfo.modulePath = apexFile.getPath(); + apexInfo.versionCode = 191000070; + + return new ApexInfo[]{apexInfo}; + } + + private ApexSessionInfo getFakeStagedSessionInfo() { + ApexSessionInfo stagedSessionInfo = new ApexSessionInfo(); + stagedSessionInfo.sessionId = TEST_SESSION_ID; + stagedSessionInfo.isStaged = true; + + return stagedSessionInfo; + } + + private ApexSessionInfo getFakeUnknownSessionInfo() { + ApexSessionInfo stagedSessionInfo = new ApexSessionInfo(); + stagedSessionInfo.sessionId = TEST_SESSION_ID; + stagedSessionInfo.isUnknown = true; + + return stagedSessionInfo; + } + + /** + * Copies a specified {@code resourceId} to a temp file. Returns a non-null file if the copy + * succeeded + */ + File copyRawResourceToFile(String baseName, int resourceId) { + File outFile; + try { + outFile = File.createTempFile(baseName, ".apex"); + } catch (IOException e) { + throw new AssertionError("CreateTempFile IOException" + e); + } + + try (InputStream is = mContext.getResources().openRawResource(resourceId); + FileOutputStream os = new FileOutputStream(outFile)) { + assertThat(FileUtils.copy(is, os)).isGreaterThan(0L); + } catch (FileNotFoundException e) { + throw new AssertionError("File not found exception " + e); + } catch (IOException e) { + throw new AssertionError("IOException" + e); + } + + return outFile; + } +}