chromium/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.webapps;

import android.content.Context;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.LooperMode;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.shadows.ShadowLooper;

import org.chromium.base.ContextUtils;
import org.chromium.base.FakeTimeTestRule;
import org.chromium.base.PathUtils;
import org.chromium.base.ThreadUtils;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.task.test.CustomShadowAsyncTask;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Feature;
import org.chromium.webapk.lib.common.WebApkConstants;

import java.io.File;
import java.util.concurrent.TimeUnit;

/** Tests that directories for WebappActivities are managed correctly. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(
        manifest = Config.NONE,
        shadows = {CustomShadowAsyncTask.class})
@LooperMode(LooperMode.Mode.LEGACY)
public class WebappDirectoryManagerTest {
    @Rule public FakeTimeTestRule mClockRule = new FakeTimeTestRule();

    private static final String WEBAPK_PACKAGE_NAME_1 = "webapk_1";
    private static final String WEBAPK_PACKAGE_NAME_2 = "webapk_2";
    private static final String WEBAPK_ID_1 =
            WebApkConstants.WEBAPK_ID_PREFIX + WEBAPK_PACKAGE_NAME_1;
    private static final String WEBAPK_ID_2 =
            WebApkConstants.WEBAPK_ID_PREFIX + WEBAPK_PACKAGE_NAME_2;

    private Context mContext;

    @Before
    public void setUp() {
        mContext = RuntimeEnvironment.application;
        ContextUtils.initApplicationContext(mContext);
        ThreadUtils.setThreadAssertsDisabledForTesting(true);
        PathUtils.setPrivateDataDirectorySuffix("chrome");
        WebappDirectoryManager.resetForTesting();
    }

    public void registerWebapp(String webappId) {
        WebappRegistry.getInstance()
                .register(
                        webappId,
                        new WebappRegistry.FetchWebappDataStorageCallback() {
                            @Override
                            public void onWebappDataStorageRetrieved(WebappDataStorage storage) {}
                        });
        ShadowApplication.runBackgroundTasks();
    }

    @Test
    @Feature({"Webapps"})
    public void testDeletesObsoleteDirectories() {
        // Seed the base directory with folders that correspond to pre-L web apps.
        File baseDirectory = mContext.getDataDir();
        File webappDirectory = new File(baseDirectory, "app_WebappActivity");
        File nonWebappDirectory = new File(baseDirectory, "app_ChromeDocumentActivity");
        Assert.assertTrue(webappDirectory.mkdirs());
        Assert.assertTrue(nonWebappDirectory.mkdirs());

        // Make sure only the web app folders are deleted.
        runCleanup();
        Assert.assertFalse(webappDirectory.exists());
        Assert.assertTrue(nonWebappDirectory.exists());

        Assert.assertTrue(webappDirectory.mkdirs());
        // Make sure the second cleanup call no-ops.
        runCleanup();
        Assert.assertTrue(webappDirectory.exists());
        Assert.assertTrue(nonWebappDirectory.exists());
    }

    /**
     * Test that WebApk.Update.NumStaleUpdateRequestFiles counts "update request" files for WebAPKs
     * which have been uninstalled.
     */
    @Test
    @Feature({"Webapps"})
    public void testCountsUpdateFilesForUninstalledWebApks() {
        File directory1 = new File(WebappDirectoryManager.getWebApkUpdateDirectory(), WEBAPK_ID_1);
        directory1.mkdirs();
        File directory2 = new File(WebappDirectoryManager.getWebApkUpdateDirectory(), WEBAPK_ID_2);
        directory2.mkdirs();

        // No entry for WEBAPK_ID_1 and WEBAPK_ID_2 in WebappRegistry because the WebAPKs have been
        // uninstalled.

        runCleanup();
        Assert.assertEquals(
                1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "WebApk.Update.NumStaleUpdateRequestFiles", 2));
    }

    /**
     * Test that WebApk.Update.NumStaleUpdateRequestFiles counts "update request" files for WebAPKs
     * for which an update was requested a long time ago.
     */
    @Test
    @Feature({"Webapps"})
    public void testCountsOldWebApkUpdateFiles() {
        File directory = new File(WebappDirectoryManager.getWebApkUpdateDirectory(), WEBAPK_ID_1);
        directory.mkdirs();
        registerWebapp(WEBAPK_ID_1);
        WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataStorage(WEBAPK_ID_1);
        storage.updateTimeOfLastCheckForUpdatedWebManifest();
        mClockRule.advanceMillis(TimeUnit.DAYS.toMillis(30));

        runCleanup();
        Assert.assertEquals(
                1,
                RecordHistogram.getHistogramValueCountForTesting(
                        "WebApk.Update.NumStaleUpdateRequestFiles", 1));
    }

    /**
     * Test that WebApk.Update.NumStaleUpdateRequestFiles does not count "update request" files for
     * WebAPKs for which an update was recently requested. There is a 1-23 hour delay between
     * a WebAPK update being scheduled to the WebAPK being updated.
     */
    @Test
    @Feature({"Webapps"})
    public void testDoesNotCountFilesForNewlyScheduledUpdates() {
        File directory = new File(WebappDirectoryManager.getWebApkUpdateDirectory(), WEBAPK_ID_1);
        directory.mkdirs();
        registerWebapp(WEBAPK_ID_1);
        WebappDataStorage storage = WebappRegistry.getInstance().getWebappDataStorage(WEBAPK_ID_1);
        storage.updateTimeOfLastCheckForUpdatedWebManifest();
        mClockRule.advanceMillis(1);

        runCleanup();
        Assert.assertEquals(
                0,
                RecordHistogram.getHistogramValueCountForTesting(
                        "WebApk.Update.NumStaleUpdateRequestFiles", 1));
    }

    private void runCleanup() {
        WebappDirectoryManager.cleanUpDirectories();
        ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
    }
}