chromium/chrome/android/java/src/org/chromium/chrome/browser/app/feed/NavigationRecorderTest.java

// Copyright 2017 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.app.feed;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

import androidx.test.filters.SmallTest;

import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.chromium.base.Callback;
import org.chromium.base.Log;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.Tab.LoadUrlResult;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule;
import org.chromium.chrome.test.util.ChromeTabUtils;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.net.test.EmbeddedTestServer;
import org.chromium.url.GURL;

import java.util.concurrent.TimeoutException;

/** Instrumentation tests for {@link NavigationRecorder}. */
@RunWith(ChromeJUnit4ClassRunner.class)
@Batch(Batch.PER_CLASS)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class NavigationRecorderTest {
    private static final String TAG = "NavRecorderTest";

    @ClassRule
    public static ChromeTabbedActivityTestRule sTestSetupRule = new ChromeTabbedActivityTestRule();

    @Rule
    public BlankCTATabInitialStateRule mBlankCTATabInitialStateRule =
            new BlankCTATabInitialStateRule(sTestSetupRule, false);

    private EmbeddedTestServer mTestServer;
    private String mNavUrl;
    private Tab mInitialTab;

    @Before
    public void setUp() {
        mTestServer = sTestSetupRule.getEmbeddedTestServerRule().getServer();
        mNavUrl = mTestServer.getURL("/chrome/test/data/android/google.html");

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mInitialTab = sTestSetupRule.getActivity().getActivityTab();
                    // Add logging to debug flaky test: crbug.com/1297086.
                    mInitialTab.addObserver(
                            new EmptyTabObserver() {
                                @Override
                                public void onPageLoadStarted(Tab tab, GURL url) {
                                    Log.e(TAG, "onPageLoadStarted " + url.getSpec());
                                }

                                @Override
                                public void onPageLoadFinished(Tab tab, GURL url) {
                                    Log.e(TAG, "onPageLoadFinished " + url.getSpec());
                                }

                                @Override
                                public void onPageLoadFailed(Tab tab, int errorCode) {
                                    Log.e(TAG, "onPageLoadFailed " + errorCode);
                                }
                            });
                });
    }

    @Test
    @SmallTest
    public void testRecordVisitInCurrentTabEndsWithBack() throws TimeoutException {
        final CallbackHelper callback = new CallbackHelper();
        loadUrlAndRecordVisit(
                mNavUrl,
                new Callback<NavigationRecorder.VisitData>() {
                    @Override
                    public void onResult(NavigationRecorder.VisitData visit) {
                        // When the tab is hidden we receive a notification with no end URL.
                        assertEquals("about:blank", visit.endUrl.getSpec());
                        callback.notifyCalled();
                    }
                });

        ChromeTabUtils.waitForTabPageLoaded(mInitialTab, (String) null);
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mInitialTab.goBack();
                });

        callback.waitForCallback(0);
    }

    @Test
    @SmallTest
    public void testRecordVisitInCurrentTabEndsWhenHidden() throws TimeoutException {
        final CallbackHelper callback = new CallbackHelper();
        loadUrlAndRecordVisit(
                mNavUrl,
                new Callback<NavigationRecorder.VisitData>() {
                    @Override
                    public void onResult(NavigationRecorder.VisitData visit) {
                        // When the tab is hidden we receive a notification with no end URL.
                        assertNull(visit.endUrl);
                        callback.notifyCalled();
                    }
                });

        sTestSetupRule.loadUrlInNewTab(null);
        callback.waitForCallback(0);
    }

    @Test
    @SmallTest
    public void testRecordVisitInCurrentTabEndsWhenURLTyped() throws TimeoutException {
        final CallbackHelper callback = new CallbackHelper();
        loadUrlAndRecordVisit(
                mNavUrl,
                new Callback<NavigationRecorder.VisitData>() {
                    @Override
                    public void onResult(NavigationRecorder.VisitData visit) {
                        // When the visit is hidden because of the transition type we get no URL.
                        assertNull(visit.endUrl);
                        callback.notifyCalled();
                    }
                });

        sTestSetupRule.loadUrl(mTestServer.getURL("/chrome/test/data/android/simple.html"));
        callback.waitForCallback(0);
    }

    /** Loads the provided URL in the current tab and sets up navigation recording for it. */
    private void loadUrlAndRecordVisit(
            final String url, Callback<NavigationRecorder.VisitData> visitCallback) {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    LoadUrlResult result = mInitialTab.loadUrl(new LoadUrlParams(url));
                    Log.e(TAG, "loadUrl status=" + result.tabLoadStatus);
                    NavigationRecorder.record(mInitialTab, visitCallback);
                });
    }
}