Skip to content

Commit

Permalink
[WebLayer] Add instrumentation tests for geolocation api
Browse files Browse the repository at this point in the history
Add instrumentation tests for web geolocation api in weblayer.
This uses the private version of the WebLayer i.e. TestWebLayer.

In particular:
- Add aidl and the necessary methods to the TestWebLayer in
  order to mock-out the geolocation provider and related
  methods (i.e. setMockLocationProvider and
  isMockLocationProviderRunning).
- Use "weblayer-fake-permissions" switch to enable fake
  permissions delegate.
- Add tests for: getCurrentPosition, watchPosition,
  tab destruction and insecure origins.

BUG=1025625
TEST=run_weblayer_private_instrumentation_test_apk -f GeolocationTest*
TBR=blundell@chromium.org

Change-Id: Id420ca4a64618e62cd85b46d7759a8c4cd760bc1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2017427
Reviewed-by: Tim Volodine <timvolodine@chromium.org>
Reviewed-by: Richard Coles <torne@chromium.org>
Commit-Queue: Tim Volodine <timvolodine@chromium.org>
Cr-Commit-Position: refs/heads/master@{#736824}
  • Loading branch information
Tim Volodine authored and Commit Bot committed Jan 30, 2020
1 parent 877095c commit 981d6bf
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 0 deletions.
1 change: 1 addition & 0 deletions weblayer/browser/android/javatests/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ android_library("weblayer_java_tests") {
android_library("weblayer_private_java_tests") {
testonly = true
sources = [
"src/org/chromium/weblayer/test/GeolocationTest.java",
"src/org/chromium/weblayer/test/InstrumentationActivityTestRule.java",
"src/org/chromium/weblayer/test/NavigationWaiter.java",
"src/org/chromium/weblayer/test/NetworkChangeNotifierTest.java",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// Copyright 2020 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.weblayer.test;

import android.net.Uri;
import android.support.test.filters.MediumTest;

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.test.util.CommandLineFlags;
import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.net.test.util.TestWebServer;
import org.chromium.weblayer.Browser;
import org.chromium.weblayer.Tab;
import org.chromium.weblayer.TestWebLayer;
import org.chromium.weblayer.shell.InstrumentationActivity;

/**
* Tests that Geolocation Web API works as expected.
*/
@RunWith(WebLayerJUnit4ClassRunner.class)
@CommandLineFlags.Add("weblayer-fake-permissions")
public final class GeolocationTest {
@Rule
public InstrumentationActivityTestRule mActivityTestRule =
new InstrumentationActivityTestRule();

private InstrumentationActivity mActivity;
private TestWebLayer mTestWebLayer;
private TestWebServer mTestServer;

private static final String RAW_JAVASCRIPT =
"var positionCount = 0;"
+ "var errorCount = 0;"
+ "function gotPos(position) {"
+ " positionCount++;"
+ "}"
+ "function errorCallback(error){"
+ " errorCount++;"
+ "}"
+ "function initiate_getCurrentPosition() {"
+ " navigator.geolocation.getCurrentPosition("
+ " gotPos, errorCallback, {});"
+ "}"
+ "function initiate_watchPosition() {"
+ " navigator.geolocation.watchPosition("
+ " gotPos, errorCallback, {});"
+ "}";

private static final String RAW_HTML =
"<!doctype html>"
+ "<html>"
+ " <head>"
+ " <title>Geolocation</title>"
+ " <script>" + RAW_JAVASCRIPT + "</script>"
+ " </head>"
+ " <body>"
+ " </body>"
+ "</html>";

@Before
public void setUp() throws Throwable {
mActivity = mActivityTestRule.launchShellWithUrl("about:blank");
Assert.assertNotNull(mActivity);

mTestWebLayer = TestWebLayer.getTestWebLayer(mActivity.getApplicationContext());
mTestWebLayer.setMockLocationProvider(true /* enable */);

mTestServer = TestWebServer.start();
String testUrl = mTestServer.setResponse("/geolocation.html", RAW_HTML, null);

mActivityTestRule.navigateAndWait(testUrl);
ensureGeolocationIsRunning(false);
}

@After
public void tearDown() throws Throwable {
mTestWebLayer.setMockLocationProvider(false /* enable */);
ensureGeolocationIsRunning(false);
}

/**
* Test for navigator.getCurrentPosition.
*/
@Test
@MediumTest
public void testGeolocation_getPosition() throws Throwable {
mActivityTestRule.executeScriptSync("initiate_getCurrentPosition();", false);
waitForCountEqual("positionCount", 1);
mActivityTestRule.executeScriptSync("initiate_getCurrentPosition();", false);
waitForCountEqual("positionCount", 2);
Assert.assertEquals(0, getCountFromJS("errorCount"));
}

/**
* Test for navigator.watchPosition, should receive more than one position.
*/
@Test
@MediumTest
public void testGeolocation_watchPosition() throws Throwable {
mActivityTestRule.executeScriptSync("initiate_watchPosition();", false);
waitForCountGreaterThan("positionCount", 1);
ensureGeolocationIsRunning(true);
Assert.assertEquals(0, getCountFromJS("errorCount"));
}

/**
* Test that destroying a tab stops geolocation provider.
*/
@Test
@MediumTest
public void testGeolocation_destroyTabStopsGeolocation() throws Throwable {
mActivityTestRule.executeScriptSync("initiate_watchPosition();", false);
ensureGeolocationIsRunning(true);
TestThreadUtils.runOnUiThreadBlocking(() -> {
Browser browser = mActivity.getBrowser();
browser.destroyTab(mActivity.getBrowser().getActiveTab());
Assert.assertEquals(0, browser.getTabs().size());
});
ensureGeolocationIsRunning(false);
}

/**
* Test geolocation denied on insecure origins (e.g. javascript).
*/
@Test
@MediumTest
public void testGeolocation_denyOnInsecureOrigins() throws Throwable {
mActivityTestRule.navigateAndWait("about:blank");
TestThreadUtils.runOnUiThreadBlocking(() -> {
mActivity.getTab().getNavigationController().navigate(
Uri.parse("javascript:" + RAW_JAVASCRIPT + "initiate_getCurrentPosition();"));
});
waitForCountEqual("errorCount", 1);
Assert.assertEquals(0, getCountFromJS("positionCount"));
}

// helper methods

private void waitForCountEqual(String variableName, int count) {
CriteriaHelper.pollInstrumentationThread(
() -> { return getCountFromJS(variableName) == count; });
}

private void waitForCountGreaterThan(String variableName, int count) {
CriteriaHelper.pollInstrumentationThread(
() -> { return getCountFromJS(variableName) > count; });
}

private void ensureGeolocationIsRunning(boolean running) {
CriteriaHelper.pollInstrumentationThread(
() -> { return mTestWebLayer.isMockLocationProviderRunning() == running; });
}

private int getCountFromJS(String variableName) {
int result = -1;
try {
result = mActivityTestRule.executeScriptSync(variableName, false)
.getInt(Tab.SCRIPT_RESULT_KEY);
} catch (Exception e) {
Assert.fail("Unable to get " + variableName);
}
return result;
}
}
2 changes: 2 additions & 0 deletions weblayer/browser/java/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ android_library("test_java") {
deps = [
":weblayer_test_resources",
"//net/android:net_java",
"//services/device/public/java:geolocation_java",
"//services/device/public/java:geolocation_java_test_support",
]
srcjar_deps = [ ":test_aidl" ]
}
Expand Down
1 change: 1 addition & 0 deletions weblayer/browser/java/DEPS
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
include_rules = [
"+components/crash/android/java",
"+components/minidump_uploader",
"+services/device/public/java/src/org/chromium/device/geolocation",
]
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import android.os.IBinder;

import org.chromium.base.annotations.UsedByReflection;
import org.chromium.device.geolocation.LocationProviderOverrider;
import org.chromium.device.geolocation.MockLocationProvider;
import org.chromium.net.NetworkChangeNotifier;
import org.chromium.weblayer_private.test_interfaces.ITestWebLayer;

Expand All @@ -15,6 +17,8 @@
*/
@UsedByReflection("WebLayer")
public final class TestWebLayerImpl extends ITestWebLayer.Stub {
private MockLocationProvider mMockLocationProvider;

@UsedByReflection("WebLayer")
public static IBinder create() {
return new TestWebLayerImpl();
Expand All @@ -26,4 +30,20 @@ private TestWebLayerImpl() {}
public boolean isNetworkChangeAutoDetectOn() {
return NetworkChangeNotifier.getAutoDetectorForTest() != null;
}

@Override
public void setMockLocationProvider(boolean enable) {
if (enable) {
mMockLocationProvider = new MockLocationProvider();
LocationProviderOverrider.setLocationProviderImpl(mMockLocationProvider);
} else if (mMockLocationProvider != null) {
mMockLocationProvider.stop();
mMockLocationProvider.stopUpdates();
}
}

@Override
public boolean isMockLocationProviderRunning() {
return mMockLocationProvider.isRunning();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ package org.chromium.weblayer_private.test_interfaces;
interface ITestWebLayer {
// Force network connectivity state.
boolean isNetworkChangeAutoDetectOn() = 1;
// set mock location provider
void setMockLocationProvider(in boolean enable) = 2;
boolean isMockLocationProviderRunning() = 3;
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,12 @@ public static Context getRemoteContext(@NonNull Context appContext) {
throw new AndroidRuntimeException(e);
}
}

public void setMockLocationProvider(boolean enabled) throws RemoteException {
mITestWebLayer.setMockLocationProvider(enabled);
}

public boolean isMockLocationProviderRunning() throws RemoteException {
return mITestWebLayer.isMockLocationProviderRunning();
}
}

0 comments on commit 981d6bf

Please sign in to comment.