blob: f28f694a2856ae894db4e51bed4b33deadda8f67 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.components.module_installer.engine;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.Activity;
import com.google.android.play.core.splitinstall.SplitInstallException;
import com.google.android.play.core.splitinstall.SplitInstallManager;
import com.google.android.play.core.splitinstall.SplitInstallRequest;
import com.google.android.play.core.splitinstall.SplitInstallSessionState;
import com.google.android.play.core.splitinstall.SplitInstallStateUpdatedListener;
import com.google.android.play.core.splitinstall.model.SplitInstallErrorCode;
import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus;
import com.google.android.play.core.tasks.OnFailureListener;
import com.google.android.play.core.tasks.Task;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.components.module_installer.logger.Logger;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Test suite for the SplitCompatEngine class.
*/
@RunWith(BaseRobolectricTestRunner.class)
public class SplitCompatEngineTest {
@Mock
private Logger mLogger;
@Mock
private SplitInstallManager mManager;
@Mock
private SplitInstallRequest mInstallRequest;
@Mock
private Task<Integer> mTask;
private SplitCompatEngine mInstaller;
private SplitCompatEngineFacade mInstallerFacade;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mInstallerFacade = mock(SplitCompatEngineFacade.class);
// Mock SplitCompatEngineFacade.
doReturn(mLogger).when(mInstallerFacade).getLogger();
doReturn(mManager).when(mInstallerFacade).getSplitManager();
doReturn(mInstallRequest).when(mInstallerFacade).createSplitInstallRequest(any());
// Mock SplitInstallManager.
doReturn(mTask).when(mManager).startInstall(any());
mInstaller = new SplitCompatEngine(mInstallerFacade);
mInstaller.resetSessionQueue();
}
@Test
public void whenConstructed_verifySplitInitialized() {
// Arrange.
InOrder inOrder = inOrder(mInstallerFacade, mManager);
// Act & Assert.
inOrder.verify(mInstallerFacade).initApplicationContext(mInstaller);
inOrder.verifyNoMoreInteractions();
}
@Test
public void whenInitActivity_verifyActivityInstalled() {
// Arrange.
Activity activityMock = mock(Activity.class);
// Act.
mInstaller.initActivity(activityMock);
// Assert.
verify(mInstallerFacade, times(1)).installActivity(activityMock);
}
@Test
public void whenIsInstalled_verifyModuleIsInstalled() {
// Arrange.
String installedModule = "m1";
String uninstalledModule = "m2";
Set<String> installedModules = new HashSet<String>() {
{ add(installedModule); }
};
doReturn(installedModules).when(mManager).getInstalledModules();
// Act & Assert.
assertTrue(mInstaller.isInstalled(installedModule));
assertFalse(mInstaller.isInstalled(uninstalledModule));
}
@Test
public void whenInstallDeferred_verifyModuleInstalled() {
// Arrange.
String moduleName = "whenInstallDeferred_verifyModuleInstalled";
List<String> moduleList = Collections.singletonList(moduleName);
// Act.
mInstaller.installDeferred(moduleName);
// Assert.
verify(mManager, times(1)).deferredInstall(moduleList);
verify(mLogger, times(1)).logRequestDeferredStart(moduleName);
}
@Test
public void whenInstalling_verifyInstallSequence() {
// Arrange.
String moduleName = "whenInstalling_verifyInstallSequence";
InstallListener listener = mock(InstallListener.class);
InOrder inOrder = inOrder(mInstallerFacade, mManager, mLogger, mTask);
// Act.
mInstaller.install(moduleName, listener);
// Assert.
inOrder.verify(mManager).registerListener(any());
inOrder.verify(mInstallerFacade).createSplitInstallRequest(moduleName);
inOrder.verify(mManager).startInstall(mInstallRequest);
inOrder.verify(mTask).addOnFailureListener(any());
inOrder.verify(mLogger).logRequestStart(moduleName);
inOrder.verifyNoMoreInteractions();
}
@Test
public void whenInstallingSameModuleConcurrently_verifySingleInstall() {
// Arrange.
String moduleName = "whenInstallingSameModuleConcurrently_verifySingleInstall";
InstallListener listener = mock(InstallListener.class);
SplitCompatEngine instance1 = new SplitCompatEngine(mInstallerFacade);
SplitCompatEngine instance2 = new SplitCompatEngine(mInstallerFacade);
// Act.
instance1.install(moduleName, listener);
instance1.install(moduleName, listener);
instance2.install(moduleName, listener);
instance2.install(moduleName, listener);
// Assert.
verify(mInstallerFacade, times(1)).createSplitInstallRequest(moduleName);
}
@Test
public void whenInstallingWithException_verifyErrorHandled() {
// Arrange.
String moduleName = "whenInstallingWithException_verifyErrorHandled";
String exceptionMessage = moduleName + "_ex_msg";
Integer errorCode = -1;
InstallListener listener = mock(InstallListener.class);
ArgumentCaptor<OnFailureListener> arg = ArgumentCaptor.forClass(OnFailureListener.class);
doReturn(errorCode).when(mLogger).getUnknownRequestErrorCode();
// Act.
mInstaller.install(moduleName, listener);
verify(mTask).addOnFailureListener(arg.capture());
arg.getValue().onFailure(new Exception(exceptionMessage));
// Assert.
verify(mLogger, times(1)).logRequestFailure(moduleName, errorCode);
verify(listener, times(1)).onComplete(false);
}
@Test
public void whenInstallingWithSplitException_verifyErrorHandled() {
// Arrange.
String moduleName = "whenInstallingWithSplitException_verifyErrorHandled";
InstallListener listener = mock(InstallListener.class);
ArgumentCaptor<OnFailureListener> arg = ArgumentCaptor.forClass(OnFailureListener.class);
// Act.
mInstaller.install(moduleName, listener);
verify(mTask).addOnFailureListener(arg.capture());
arg.getValue().onFailure(new SplitInstallException(-1));
// Assert.
verify(mLogger, times(1)).logRequestFailure(moduleName, -1);
verify(listener, times(1)).onComplete(false);
}
@Test
public void whenInstallingWithException_verifyCanTryAgainAfterFailure() {
// Arrange.
String moduleName = "whenInstallingWithException_verifyCanTryAgainAfterFailure";
ArgumentCaptor<OnFailureListener> arg = ArgumentCaptor.forClass(OnFailureListener.class);
// Act.
mInstaller.install(moduleName, mock(InstallListener.class));
verify(mTask).addOnFailureListener(arg.capture());
arg.getValue().onFailure(new Exception(""));
mInstaller.install(moduleName, mock(InstallListener.class)); // 2nd call.
// Assert.
verify(mLogger, times(2)).logRequestStart(moduleName);
}
@Test
public void whenInstalled_verifyListenerAndLogger() {
// Arrange.
String moduleName = "whenInstalled_verifyListenerAndLogger";
Integer status = SplitInstallSessionStatus.INSTALLED;
String message = String.format("Module '%s' Installed", moduleName);
InstallListener listener = mock(InstallListener.class);
// Mock SplitInstallSessionState
SplitInstallSessionState state = mock(SplitInstallSessionState.class);
doReturn(status).when(state).status();
doReturn(Arrays.asList(moduleName)).when(state).moduleNames();
InOrder inOrder = inOrder(listener, mManager, mLogger);
ArgumentCaptor<SplitInstallStateUpdatedListener> arg =
ArgumentCaptor.forClass(SplitInstallStateUpdatedListener.class);
// Act.
mInstaller.install(moduleName, listener);
verify(mManager).registerListener(arg.capture());
arg.getValue().onStateUpdate(state);
// Assert.
inOrder.verify(listener, times(1)).onComplete(true);
inOrder.verify(mManager, times(1)).unregisterListener(any());
inOrder.verify(mLogger, times(1)).logStatus(moduleName, status);
inOrder.verifyNoMoreInteractions();
}
@Test
public void whenFailureToInstall_verifyListenerAndLogger() {
// Arrange.
String moduleName = "whenFailureToInstall_verifyListenerAndLogger";
Integer status = SplitInstallSessionStatus.FAILED;
Integer errorCode = SplitInstallErrorCode.NO_ERROR;
String message = String.format("Failed with code: %d", errorCode);
InstallListener listener = mock(InstallListener.class);
// Mock SplitInstallSessionState.
SplitInstallSessionState state = mock(SplitInstallSessionState.class);
doReturn(status).when(state).status();
doReturn(errorCode).when(state).errorCode();
doReturn(Arrays.asList(moduleName)).when(state).moduleNames();
InOrder inOrder = inOrder(listener, mLogger, mManager);
ArgumentCaptor<SplitInstallStateUpdatedListener> arg =
ArgumentCaptor.forClass(SplitInstallStateUpdatedListener.class);
// Act.
mInstaller.install(moduleName, listener);
verify(mManager).registerListener(arg.capture());
arg.getValue().onStateUpdate(state);
// Assert.
inOrder.verify(listener, times(1)).onComplete(false);
inOrder.verify(mManager, times(1)).unregisterListener(any());
inOrder.verify(mLogger, times(1)).logStatusFailure(moduleName, errorCode);
inOrder.verify(mLogger, times(1)).logStatus(moduleName, status);
inOrder.verifyNoMoreInteractions();
}
@Test
public void whenNotInstalledOrFailed_verifyStatusLogged() {
// Arrange.
String moduleName = "whenNotInstalledOrFailed_verifyStatusLogged";
Integer status = SplitInstallSessionStatus.UNKNOWN;
InstallListener listener = mock(InstallListener.class);
// Mock SplitInstallSessionState.
SplitInstallSessionState state = mock(SplitInstallSessionState.class);
doReturn(status).when(state).status();
doReturn(Arrays.asList(moduleName)).when(state).moduleNames();
InOrder inOrder = inOrder(listener, mLogger);
ArgumentCaptor<SplitInstallStateUpdatedListener> arg =
ArgumentCaptor.forClass(SplitInstallStateUpdatedListener.class);
// Act.
mInstaller.install(moduleName, mock(InstallListener.class));
verify(mManager).registerListener(arg.capture());
arg.getValue().onStateUpdate(state);
// Assert.
inOrder.verify(mLogger, times(1)).logStatus(moduleName, status);
inOrder.verifyNoMoreInteractions();
}
}