| Index: chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/HostBrowserClassLoaderTest.java
|
| diff --git a/chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/HostBrowserClassLoaderTest.java b/chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/HostBrowserClassLoaderTest.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2df3aa6f7d9ee590c9ce52e8bfc5c6c8bc601624
|
| --- /dev/null
|
| +++ b/chrome/android/webapk/shell_apk/junit/src/org/chromium/webapk/shell_apk/HostBrowserClassLoaderTest.java
|
| @@ -0,0 +1,171 @@
|
| +// Copyright 2016 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.webapk.shell_apk;
|
| +
|
| +import android.content.Context;
|
| +import android.content.pm.PackageInfo;
|
| +import android.content.res.AssetManager;
|
| +
|
| +import org.chromium.testing.local.LocalRobolectricTestRunner;
|
| +import org.chromium.webapk.lib.common.WebApkVersionUtils;
|
| +
|
| +import org.junit.Assert;
|
| +import org.junit.Before;
|
| +import org.junit.Test;
|
| +import org.junit.runner.RunWith;
|
| +import org.mockito.Mockito;
|
| +import org.robolectric.Robolectric;
|
| +import org.robolectric.annotation.Config;
|
| +import org.robolectric.res.builder.RobolectricPackageManager;
|
| +
|
| +import java.io.ByteArrayInputStream;
|
| +import java.io.File;
|
| +import java.io.InputStream;
|
| +
|
| +/**
|
| + * Tests HostBrowserClassLoader.
|
| + */
|
| +@RunWith(LocalRobolectricTestRunner.class)
|
| +@Config(manifest = Config.NONE)
|
| +public class HostBrowserClassLoaderTest {
|
| +
|
| + /**
|
| + * Mock package name for the remote host browser.
|
| + */
|
| + private static final String REMOTE_PACKAGE_NAME = "remote_package";
|
| +
|
| + private static final int REMOTE_DEX_VERSION = 1;
|
| + private static final int REMOTE_VERSION_CODE = 5;
|
| +
|
| + private Context mContext;
|
| + private Context mRemoteContext;
|
| + private AssetManager mRemoteAssetManager;
|
| + private RobolectricPackageManager mPackageManager;
|
| +
|
| + /**
|
| + * Stub DexLoader. Used to verify the version of the runtime library dex which is used to build
|
| + * the ClassLoader.
|
| + */
|
| + private DexLoader mMockDexLoader;
|
| +
|
| + @Before
|
| + public void setUp() {
|
| + mContext = Robolectric.application;
|
| + mPackageManager = (RobolectricPackageManager) mContext.getPackageManager();
|
| + setRemoteVersionCode(REMOTE_VERSION_CODE);
|
| +
|
| + mRemoteAssetManager = Mockito.mock(AssetManager.class);
|
| + setRemoteDexVersion(REMOTE_DEX_VERSION);
|
| +
|
| + mRemoteContext = Mockito.mock(Context.class);
|
| + Mockito.when(mRemoteContext.getAssets()).thenReturn(mRemoteAssetManager);
|
| + Mockito.when(mRemoteContext.getPackageName()).thenReturn(REMOTE_PACKAGE_NAME);
|
| + Mockito.when(mRemoteContext.getPackageManager()).thenReturn(mPackageManager);
|
| +
|
| + mMockDexLoader = Mockito.mock(DexLoader.class);
|
| + }
|
| +
|
| + /**
|
| + * Test upgrading to a new runtime dex version.
|
| + */
|
| + @Test
|
| + public void testNewRuntimeDexVersion() {
|
| + HostBrowserClassLoader.createClassLoader(mContext, mRemoteContext, mMockDexLoader, null);
|
| +
|
| + String expectedDexName = WebApkVersionUtils.getRuntimeDexName(REMOTE_DEX_VERSION);
|
| + verifyDexLoaderLoadCall(expectedDexName);
|
| + Mockito.reset(mMockDexLoader);
|
| +
|
| + setRemoteVersionCode(REMOTE_VERSION_CODE + 1);
|
| + setRemoteDexVersion(REMOTE_DEX_VERSION + 1);
|
| + HostBrowserClassLoader.createClassLoader(mContext, mRemoteContext, mMockDexLoader, null);
|
| +
|
| + expectedDexName = WebApkVersionUtils.getRuntimeDexName(REMOTE_DEX_VERSION + 1);
|
| + verifyDexLoaderLoadCall(expectedDexName);
|
| + }
|
| +
|
| + /**
|
| + * Test that HostBrowserClassLoader#deleteCachedDexes() is not called if nothing has changed
|
| + * between calls to HostBrowserClassLoader#createClassLoader().
|
| + */
|
| + @Test
|
| + public void testCreateClassLoaderTwiceSameCachedData() {
|
| + String expectedDexName = WebApkVersionUtils.getRuntimeDexName(REMOTE_DEX_VERSION);
|
| + HostBrowserClassLoader.createClassLoader(mContext, mRemoteContext, mMockDexLoader, null);
|
| + verifyDexLoaderLoadCall(expectedDexName);
|
| + Mockito.reset(mMockDexLoader);
|
| +
|
| + HostBrowserClassLoader.createClassLoader(mContext, mRemoteContext, mMockDexLoader, null);
|
| + verifyDexLoaderLoadCall(expectedDexName);
|
| + Mockito.verify(mMockDexLoader, Mockito.never()).deleteCachedDexes(Mockito.any(File.class));
|
| + }
|
| +
|
| + /**
|
| + * Test that the ClassLoader is reused if nothing changed since the last call to
|
| + * HostBrowserClassLoader#createClassLoader() and HostBrowserClassLoader is still running.
|
| + * Reusing the ClassLoader whenever possible is important because building the ClassLoader is
|
| + * expensive.
|
| + */
|
| + @Test
|
| + public void testCanReuseClassLoader() {
|
| + HostBrowserClassLoader.createClassLoader(mContext, mRemoteContext, mMockDexLoader, null);
|
| + Assert.assertTrue(
|
| + HostBrowserClassLoader.canReuseClassLoaderInstance(mContext, mRemoteContext));
|
| + }
|
| +
|
| + /**
|
| + * Test that the ClassLoader is not reused (even if there is no new runtime dex version) if
|
| + * Chrome is updated but WebAPK is still running.
|
| + */
|
| + @Test
|
| + public void testDontReuseClassLoaderRemoteVersionCodeChange() {
|
| + HostBrowserClassLoader.createClassLoader(mContext, mRemoteContext, mMockDexLoader, null);
|
| + setRemoteVersionCode(REMOTE_VERSION_CODE + 1);
|
| + Assert.assertFalse(
|
| + HostBrowserClassLoader.canReuseClassLoaderInstance(mContext, mRemoteContext));
|
| + }
|
| +
|
| + /**
|
| + * Creates an InputStream with {@link value} as its data.
|
| + */
|
| + public InputStream createIntInputStream(int value) {
|
| + String stringValue = "" + value;
|
| + return new ByteArrayInputStream(stringValue.getBytes());
|
| + }
|
| +
|
| + /**
|
| + * Sets the remote host browser's version code.
|
| + */
|
| + public void setRemoteVersionCode(int versionCode) {
|
| + PackageInfo packageInfo = new PackageInfo();
|
| + packageInfo.packageName = REMOTE_PACKAGE_NAME;
|
| + packageInfo.versionCode = versionCode;
|
| + mPackageManager.addPackage(packageInfo);
|
| + }
|
| +
|
| + /**
|
| + * Sets the version of the current runtime library dex stored in the remote host browser's
|
| + * assets.
|
| + */
|
| + public void setRemoteDexVersion(int dexVersion) {
|
| + try {
|
| + Mockito.when(mRemoteAssetManager.open("webapk_dex_version.txt"))
|
| + .thenReturn(createIntInputStream(dexVersion));
|
| + } catch (Exception e) {
|
| + Assert.fail();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Verifies {@link DexLoader#load()} call.
|
| + * @param expectedDexName The name of the dex in the remote host browser's assets that
|
| + * {@link DexLoader#load()} should have been called with.
|
| + */
|
| + public void verifyDexLoaderLoadCall(String expectedDexName) {
|
| + Mockito.verify(mMockDexLoader)
|
| + .load(Mockito.any(Context.class), Mockito.eq(expectedDexName), Mockito.anyString(),
|
| + Mockito.any(File.class), Mockito.any(File.class));
|
| + }
|
| +}
|
|
|