chromium/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/MHTMLPageTest.java

// Copyright 2016 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.offlinepages;

import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.UrlUtils;
import org.chromium.chrome.browser.download.DownloadTestRule;
import org.chromium.chrome.browser.download.DownloadTestRule.CustomMainActivityStart;
import org.chromium.chrome.browser.download.items.OfflineContentAggregatorFactory;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.components.offline_items_collection.ContentId;
import org.chromium.components.offline_items_collection.OfflineContentProvider;
import org.chromium.components.offline_items_collection.OfflineItem;
import org.chromium.components.offline_items_collection.UpdateDelta;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.net.test.EmbeddedTestServer;
import org.chromium.net.test.ServerCertificate;
import org.chromium.ui.base.PageTransition;

import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/** Unit tests for offline page request handling. */
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class MHTMLPageTest implements CustomMainActivityStart {
    @Rule public DownloadTestRule mDownloadTestRule = new DownloadTestRule(this);

    private static final int TIMEOUT_MS = 5000;
    private static final String[] TEST_FILES = new String[] {"hello.mhtml", "test.mht"};

    private EmbeddedTestServer mTestServer;

    /**
     * Observes the download updates from the new download backend. Depending on whether the new
     * download backend is enabled or not, either this class or TestDownloadNotificationService will
     * receive the update.
     */
    private static class TestNewDownloadBackendObserver implements OfflineContentProvider.Observer {
        private Semaphore mSemaphore;

        TestNewDownloadBackendObserver(Semaphore semaphore) {
            mSemaphore = semaphore;
        }

        @Override
        public void onItemsAdded(List<OfflineItem> items) {}

        @Override
        public void onItemRemoved(ContentId id) {}

        @Override
        public void onItemUpdated(OfflineItem item, UpdateDelta updateDelta) {
            mSemaphore.release();
        }
    }

    @Before
    public void setUp() {
        deleteTestFiles();
        mTestServer =
                EmbeddedTestServer.createAndStartHTTPSServer(
                        ApplicationProvider.getApplicationContext(), ServerCertificate.CERT_OK);
    }

    @After
    public void tearDown() {
        mTestServer.stopAndDestroyServer();
        deleteTestFiles();
    }

    @Override
    public void customMainActivityStart() throws InterruptedException {
        mDownloadTestRule.startMainActivityOnBlankPage();
    }

    @Test
    @SmallTest
    @DisabledTest(message = "Flaky. crbug.com/1030558")
    public void testDownloadMultipartRelatedPageFromServer() throws Exception {
        // .mhtml file is mapped to "multipart/related" by the test server.
        final String url = mTestServer.getURL("/chrome/test/data/android/hello.mhtml");
        final Tab tab = mDownloadTestRule.getActivity().getActivityTab();
        final Semaphore semaphore = new Semaphore(0);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    OfflineContentAggregatorFactory.get()
                            .addObserver(new TestNewDownloadBackendObserver(semaphore));
                    tab.loadUrl(
                            new LoadUrlParams(
                                    url, PageTransition.TYPED | PageTransition.FROM_ADDRESS_BAR));
                });

        Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS));
    }

    @Test
    @SmallTest
    public void testDownloadMessageRfc822PageFromServer() throws Exception {
        // .mht file is mapped to "message/rfc822" by the test server.
        final String url = mTestServer.getURL("/chrome/test/data/android/test.mht");
        final Tab tab = mDownloadTestRule.getActivity().getActivityTab();
        final Semaphore semaphore = new Semaphore(0);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    OfflineContentAggregatorFactory.get()
                            .addObserver(new TestNewDownloadBackendObserver(semaphore));
                    tab.loadUrl(
                            new LoadUrlParams(
                                    url, PageTransition.TYPED | PageTransition.FROM_ADDRESS_BAR));
                });

        Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS));
    }

    @Test
    @SmallTest
    public void testLoadMultipartRelatedPageFromLocalFile() {
        // .mhtml file is mapped to "multipart/related" by the test server.
        String url = UrlUtils.getIsolatedTestFileUrl("chrome/test/data/android/hello.mhtml");
        mDownloadTestRule.loadUrl(url);
    }

    @Test
    @SmallTest
    public void testLoadMessageRfc822PageFromLocalFile() {
        // .mht file is mapped to "message/rfc822" by the test server.
        String url = UrlUtils.getIsolatedTestFileUrl("chrome/test/data/android/test.mht");
        mDownloadTestRule.loadUrl(url);
    }

    /**
     * Makes sure there are no files with names identical to the ones this test uses in the
     * downloads directory
     */
    private void deleteTestFiles() {
        mDownloadTestRule.deleteFilesInDownloadDirectory(TEST_FILES);
    }
}