Bug 1395409: Add testActivityStreamPocketReferrer. r=liuche

MozReview-Commit-ID: FlcMG5IewRH

--HG--
extra : rebase_source : 0d744d9f3d4ffa55a594da566f2eacea0f1a3a17
This commit is contained in:
Michael Comella 2017-08-30 17:33:08 -07:00
Родитель b0442493e5
Коммит f1b1b8b981
4 изменённых файлов: 209 добавлений и 3 удалений

Просмотреть файл

@ -8,6 +8,7 @@ package org.mozilla.gecko.activitystream.homepanel.topstories;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri;
import android.support.annotation.VisibleForTesting;
import android.support.v4.content.AsyncTaskLoader;
import android.text.TextUtils;
import android.util.Log;
@ -19,6 +20,7 @@ import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.Locales;
import org.mozilla.gecko.activitystream.homepanel.StreamRecyclerAdapter;
import org.mozilla.gecko.activitystream.homepanel.model.TopStory;
import org.mozilla.gecko.annotation.RobocopTarget;
import org.mozilla.gecko.util.FileUtils;
import org.mozilla.gecko.util.ProxySelector;
@ -53,6 +55,13 @@ public class PocketStoriesLoader extends AsyncTaskLoader<List<TopStory>> {
public static final String POCKET_REFERRER_URI = "https://getpocket.com/recommendations";
@RobocopTarget
@VisibleForTesting public static final String PLACEHOLDER_TITLE = "Placeholder ";
private static final String DEFAULT_PLACEHOLDER_URL = "https://www.mozilla.org/#";
static {
setPlaceholderUrl(DEFAULT_PLACEHOLDER_URL);
}
// Pocket SharedPreferences keys
private static final String POCKET_PREFS_FILE = "PocketStories";
private static final String CACHE_TIMESTAMP_MILLIS_PREFIX = "timestampMillis-";
@ -72,9 +81,13 @@ public class PocketStoriesLoader extends AsyncTaskLoader<List<TopStory>> {
private static final int CONNECT_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(15);
private static final int READ_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(15);
private static boolean isTesting = false;
private String localeLang;
private final SharedPreferences sharedPreferences;
private static String placeholderUrl;
public PocketStoriesLoader(Context context) {
super(context);
@ -84,7 +97,8 @@ public class PocketStoriesLoader extends AsyncTaskLoader<List<TopStory>> {
@Override
protected void onStartLoading() {
if (APIKEY == null) {
// We don't want to hit the network if we're testing.
if (APIKEY == null || isTesting) {
deliverResult(makePlaceholderStories());
return;
}
@ -187,11 +201,25 @@ public class PocketStoriesLoader extends AsyncTaskLoader<List<TopStory>> {
private static List<TopStory> makePlaceholderStories() {
final List<TopStory> stories = new LinkedList<>();
final String TITLE_PREFIX = "Placeholder ";
for (int i = 0; i < DEFAULT_COUNT; i++) {
// Urls must be different for bookmark/pinning UI to work properly. Assume this is true for Pocket stories.
stories.add(new TopStory(TITLE_PREFIX + i, "https://www.mozilla.org/#" + i, null));
stories.add(new TopStory(PLACEHOLDER_TITLE + i, placeholderUrl + i, null));
}
return stories;
}
private static void setPlaceholderUrl(String placeholderUrl) {
// See use of placeholderUrl for why suffix is necessary.
final String requiredSuffix = "#";
if (!placeholderUrl.endsWith(requiredSuffix)) {
placeholderUrl = placeholderUrl + requiredSuffix;
}
PocketStoriesLoader.placeholderUrl = placeholderUrl;
}
@RobocopTarget
@VisibleForTesting public static void configureForTesting(final String placeholderUrl) {
isTesting = true;
setPlaceholderUrl(placeholderUrl);
}
}

Просмотреть файл

@ -108,6 +108,7 @@ skip-if = android_version == "18"
[src/org/mozilla/gecko/tests/testAboutHomePageNavigation.java]
disabled=see bug 947550, bug 979038 and bug 977952
[src/org/mozilla/gecko/tests/testAboutHomeVisibility.java]
[src/org/mozilla/gecko/tests/testActivityStreamPocketReferrer.java]
[src/org/mozilla/gecko/tests/testAppMenuPathways.java]
[src/org/mozilla/gecko/tests/testBackButtonInEditMode.java]
[src/org/mozilla/gecko/tests/testBrowserDatabaseHelperUpgrades.java]

Просмотреть файл

@ -0,0 +1,133 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.tests;
import android.util.Log;
import com.robotium.solo.Condition;
import org.mozilla.gecko.activitystream.homepanel.topstories.PocketStoriesLoader;
import org.mozilla.gecko.tests.helpers.NavigationHelper;
import org.mozilla.gecko.tests.helpers.WaitHelper;
import org.mozilla.gecko.util.StringUtils;
import static org.mozilla.gecko.tests.helpers.AssertionHelper.*;
/**
* It's very important that suggestions from Pocket are opened with a Pocket URI in the referrer: this is
* what this test is for.
*
* We want to verify:
* - Clicking or long clicking a Pocket top story has a Pocket referrer.
* - Clicking or long clicking other items on top sites does not have a Pocket referrer.
*
* The ideal test is to set up a server that will assert that clicks that should have a Pocket referrer
* have one in the request headers and clicks that should not have a referrer do not have one. However,
* it's non-trivial to set up such a server in our harness so we instead intercept Tab:Load JS events
* and verify they have the referrer. This isn't ideal because we might drop the ball passing the referrer
* to Gecko, or Gecko might drop the ball, but this test should help regressions if we manually test the
* referrers are working.
*/
public class testActivityStreamPocketReferrer extends JavascriptBridgeTest {
private static final String LOGTAG =
StringUtils.safeSubstring(testActivityStreamPocketReferrer.class.getSimpleName(), 0, 23);
private static final String JS_FILE = "testActivityStreamPocketReferrer.js";
private boolean wasTabLoadReceived = false;
private boolean tabLoadContainsPocketReferrer = false;
@Override
public void setUp() throws Exception {
super.setUp();
// Override the default placeholder URL so we don't access the network during testing.
// Note: this actually only seems to take effect after we load a page and go back to about:home.
PocketStoriesLoader.configureForTesting(getAbsoluteHostnameUrl(StringHelper.get().ROBOCOP_BLANK_PAGE_01_URL));
}
public void testActivityStreamPocketReferrer() throws Exception {
blockForReadyAndLoadJS(JS_FILE);
NavigationHelper.goBack(); // to top sites.
checkReferrerInTopStories();
checkReferrerInTopStoriesContextMenu();
checkNoReferrerInTopSites(); // relies on changes to Top Sites from previous tests.
// Ideally, we'd also test that there is no referrer for highlights but it's more
// challenging to get an item to show up in highlights (bookmark the page) and to scroll
// to open it: to save time, I chose not to implement it.
}
private void checkReferrerInTopStories() {
Log.d(LOGTAG, "testReferrerInTopStories");
WaitHelper.waitForPageLoad(new Runnable() {
@Override
public void run() {
mSolo.clickOnText(PocketStoriesLoader.PLACEHOLDER_TITLE); // Click Top Story placeholder item.
}
});
assertTabLoadEventContainsPocketReferrer(true);
NavigationHelper.goBack(); // to top sites.
}
private void checkReferrerInTopStoriesContextMenu() throws Exception {
Log.d(LOGTAG, "testReferrerInTopStoriesContextMenu");
mSolo.clickLongOnText(PocketStoriesLoader.PLACEHOLDER_TITLE); // Open Top Story context menu.
mSolo.clickOnText(StringHelper.get().CONTEXT_MENU_OPEN_IN_NEW_TAB);
WaitHelper.waitFor("context menu to close after item selection.", new Condition() {
@Override
public boolean isSatisfied() {
return !mSolo.searchText(StringHelper.get().CONTEXT_MENU_OPEN_IN_NEW_TAB);
}
}, 5000);
// There's no simple way to block until a background page loads so instead, we sleep for 500ms.
// Our JS listener is attached the whole time so if the message is sent, we'll receive it and cache it
// while we're sleeping.
Thread.sleep(500);
assertTabLoadEventContainsPocketReferrer(true);
}
private void checkNoReferrerInTopSites() {
Log.d(LOGTAG, "testNoReferrerInTopSites");
WaitHelper.waitForPageLoad(new Runnable() {
@Override
public void run() {
// Through the previous tests, we've added a top site called "Browser Blank Page...".
// Only part of that label will be visible, however.
mSolo.clickOnText("Browser Bl"); // Click on a Top Site.
}
});
assertTabLoadEventContainsPocketReferrer(false);
NavigationHelper.goBack(); // to top sites.
}
private void assertTabLoadEventContainsPocketReferrer(final boolean expectedContainsReferrer) {
// We intercept the Tab:Load event in JS and, due to limitations in JavascriptBridge,
// store the data there until Java asks for it.
getJS().syncCall("copyTabLoadEventMetadataToJava"); // expected to call copyTabLoad...Receiver
fAssertTrue("Expected Tab:Load to be called", wasTabLoadReceived);
fAssertEquals("Checking for expected existence of pocket referrer from Tab:Load event in JS",
expectedContainsReferrer, tabLoadContainsPocketReferrer);
}
// JS methods.
public void copyTabLoadEventMetadataToJavaReceiver(final boolean wasTabLoadReceived, final boolean tabLoadContainsPocketReferrer) {
Log.d(LOGTAG, "setTabLoadContainsPocketReferrer called via JS: " + wasTabLoadReceived + ", " + tabLoadContainsPocketReferrer);
this.wasTabLoadReceived = wasTabLoadReceived;
this.tabLoadContainsPocketReferrer = tabLoadContainsPocketReferrer;
}
public void log(final String s) {
Log.d(LOGTAG, "jsLog: " + s);
}
}

Просмотреть файл

@ -0,0 +1,44 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Components.utils.import("resource://gre/modules/Messaging.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
let java = new JavaBridge(this);
do_register_cleanup(() => {
EventDispatcher.instance.unregisterListener(listener);
java.disconnect();
});
do_test_pending();
var wasTabLoadReceived = false;
var tabLoadContainsPocketReferrer = false;
let listener = {
onEvent: function(event, data, callback) {
java.asyncCall("log", "Tab:Load url: " + data.url);
java.asyncCall("log", "Tab:Load referrerURI: " + data.referrerURI);
if (event !== "Tab:Load" ||
data.url === "about:home") {
return;
}
wasTabLoadReceived = true;
if (data.referrerURI && data.referrerURI.search("pocket") > 0) {
tabLoadContainsPocketReferrer = true;
} else {
tabLoadContainsPocketReferrer = false;
}
}
};
let win = Services.wm.getMostRecentWindow("navigator:browser");
EventDispatcher.for(win).registerListener(listener, ["Tab:Load"]);
// Java functions.
function copyTabLoadEventMetadataToJava() {
java.syncCall("copyTabLoadEventMetadataToJavaReceiver", wasTabLoadReceived, tabLoadContainsPocketReferrer);
wasTabLoadReceived = false;
}