Commit aaa2ec5c authored by John Abd-El-Malek's avatar John Abd-El-Malek Committed by Commit Bot

Add weblayer browser_tests APK so we can run the tests on Android.

The Shell C++ class isn't used on Android (unlike in content_shell) because we want to consume WebLayer there using the idiomatic Java API. At the same time, we want to write browser tests the same way for all platforms. So fake this by creating a Shell that reuses the existing BrowserController class that was created by Java.

Change-Id: I946957f39eb79cff2e84c8abda56eed98b28d0a0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1815884Reviewed-by: default avatarClark DuVall <cduvall@chromium.org>
Commit-Queue: John Abd-El-Malek <jam@chromium.org>
Cr-Commit-Position: refs/heads/master@{#702563}
parent c81b939f
......@@ -195,12 +195,10 @@ group("gn_all") {
}
if (is_win || (is_linux && !is_chromeos) || is_android) {
deps += [ "//weblayer/shell:weblayer_shell" ]
}
# TODO: enable this on Android.
if (is_win || (is_linux && !is_chromeos)) {
deps += [ "//weblayer/test:weblayer_browsertests" ]
deps += [
"//weblayer/shell:weblayer_shell",
"//weblayer/test:weblayer_browsertests",
]
}
if (!is_ios && !is_android) {
......
......@@ -79,6 +79,11 @@ PACKAGE_INFO.update({
chrome.PackageInfo('org.chromium.webview_ui_test',
'org.chromium.webview_ui_test.WebViewUiTestActivity',
'webview-command-line', None),
'weblayer_browsertests':
chrome.PackageInfo(
'org.chromium.weblayer_browsertests_apk',
'org.chromium.weblayer_browsertests_apk.WebLayerBrowserTestsActivity',
'chrome-native-tests-command-line', None),
})
......
......@@ -61,6 +61,7 @@ android_library("native_test_java") {
"//base:base_java",
"//base:base_java_test_support",
"//testing/android/reporter:reporter_java",
"//third_party/android_deps:android_support_v4_java",
]
java_files = [
"java/src/org/chromium/native_test/NativeBrowserTest.java",
......
......@@ -4,15 +4,15 @@
package org.chromium.native_test;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import java.io.File;
/**
* An {@link android.app.Activity} for running native browser tests.
*/
public abstract class NativeBrowserTestActivity extends Activity {
public abstract class NativeBrowserTestActivity extends FragmentActivity {
private static final String TAG = "cr_NativeTest";
private NativeTest mTest = new NativeTest();
......
......@@ -24,8 +24,19 @@
namespace weblayer {
namespace {
#if defined(OS_ANDROID)
BrowserController* g_last_browser_controller;
#endif
} // namespace
BrowserControllerImpl::BrowserControllerImpl(ProfileImpl* profile)
: profile_(profile) {
#if defined(OS_ANDROID)
g_last_browser_controller = this;
#endif
content::WebContents::CreateParams create_params(
profile_->GetBrowserContext());
web_contents_ = content::WebContents::Create(create_params);
......@@ -150,4 +161,10 @@ std::unique_ptr<BrowserController> BrowserController::Create(Profile* profile) {
static_cast<ProfileImpl*>(profile));
}
#if defined(OS_ANDROID)
BrowserController* BrowserController::GetLastControllerForTesting() {
return g_last_browser_controller;
}
#endif
} // namespace weblayer
......@@ -25,6 +25,10 @@ class BrowserController {
public:
static std::unique_ptr<BrowserController> Create(Profile* profile);
#if defined(OS_ANDROID)
static BrowserController* GetLastControllerForTesting();
#endif
virtual ~BrowserController() {}
virtual void AddObserver(BrowserObserver* observer) = 0;
......
......@@ -27,6 +27,7 @@ jumbo_static_library("weblayer_shell_lib") {
"app/shell_main_params.h",
"browser/shell.cc",
"browser/shell.h",
"browser/shell_android.cc",
"common/shell_switches.cc",
"common/shell_switches.h",
]
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2019 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.chromium.weblayer_browsertests_apk">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application android:name="WebLayerBrowserTestsApplication" android:label="WebLayerBrowserTests">
<activity android:name="WebLayerBrowserTestsActivity"
android:launchMode="singleTask"
android:theme="@android:style/Theme.Holo.Light.NoActionBar"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
android:windowSoftInputMode="adjustPan|stateUnspecified">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data android:name="org.chromium.weblayer.WebLayerPackage"
android:value="org.chromium.weblayer_browsertests_apk"/>
</application>
<instrumentation android:name="org.chromium.native_test.NativeTestInstrumentationTestRunner"
android:label="WebLayerBrowserTests"
android:targetPackage="org.chromium.weblayer_browsertests_apk"
chromium-junit3="true"/>
</manifest>
include_rules = [
"+content/public/android",
"+content/public/app",
"+content/public/test",
"+ui/android",
]
// Copyright 2019 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_browsertests_apk;
import android.net.Uri;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import org.chromium.base.library_loader.LibraryProcessType;
import org.chromium.base.test.util.UrlUtils;
import org.chromium.content_public.browser.BrowserStartupController;
import org.chromium.native_test.NativeBrowserTest;
import org.chromium.native_test.NativeBrowserTestActivity;
import org.chromium.weblayer.BrowserController;
import org.chromium.weblayer.BrowserFragmentController;
import org.chromium.weblayer.BrowserObserver;
import org.chromium.weblayer.ListenableFuture;
import org.chromium.weblayer.Profile;
import org.chromium.weblayer.WebLayer;
import java.io.File;
/** An Activity base class for running browser tests against WebLayerShell. */
public class WebLayerBrowserTestsActivity extends NativeBrowserTestActivity {
private static final String TAG = "cr.native_test";
private WebLayer mWebLayer;
private Profile mProfile;
private BrowserFragmentController mBrowserFragmentController;
private BrowserController mBrowserController;
private EditText mUrlView;
private View mMainView;
@Override
protected void onDestroy() {
if (mProfile != null) mProfile.destroy();
if (mBrowserFragmentController != null) mBrowserFragmentController.destroy();
super.onDestroy();
}
@Override
protected void initializeBrowserProcess() {
BrowserStartupController.get(LibraryProcessType.PROCESS_WEBLAYER)
.setContentMainCallbackForTests(() -> {
// This jumps into C++ to set up and run the test harness. The test harness runs
// ContentMain()-equivalent code, and then waits for javaStartupTasksComplete()
// to be called.
runTests();
});
ListenableFuture<WebLayer> future = WebLayer.create(getApplication());
future.addCallback((WebLayer webLayer) -> {
mWebLayer = webLayer;
createShell();
});
NativeBrowserTest.javaStartupTasksComplete();
}
protected void createShell() {
LinearLayout mainView = new LinearLayout(this);
int viewId = View.generateViewId();
mainView.setId(viewId);
mMainView = mainView;
setContentView(mainView);
mUrlView = new EditText(this);
mUrlView.setId(View.generateViewId());
// The background of the top-view must be opaque, otherwise it bleeds through to the
// cc::Layer that mirrors the contents of the top-view.
mUrlView.setBackgroundColor(0xFFa9a9a9);
RelativeLayout topContentsContainer = new RelativeLayout(this);
topContentsContainer.addView(mUrlView,
new RelativeLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
mProfile = mWebLayer.createProfile(null);
mBrowserFragmentController = mProfile.createBrowserFragmentController(this);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(viewId, mBrowserFragmentController.getFragment());
transaction.commit();
mBrowserFragmentController.setTopView(topContentsContainer);
mBrowserController = mBrowserFragmentController.getBrowserController();
mBrowserController.addObserver(new BrowserObserver() {
@Override
public void visibleUrlChanged(Uri uri) {
mUrlView.setText(uri.toString());
}
});
}
@Override
protected File getPrivateDataDirectory() {
return new File(UrlUtils.getIsolatedTestRoot(),
WebLayerBrowserTestsApplication.PRIVATE_DATA_DIRECTORY_SUFFIX);
}
}
// Copyright 2019 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_browsertests_apk;
import android.content.Context;
import org.chromium.base.PathUtils;
import org.chromium.native_test.NativeBrowserTestApplication;
import org.chromium.ui.base.ResourceBundle;
/**
* A basic weblayer_public.browser.tests {@link android.app.Application}.
*/
public class WebLayerBrowserTestsApplication extends NativeBrowserTestApplication {
static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "weblayer_shell";
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
if (isBrowserProcess()) {
// Test-only stuff, see also NativeUnitTest.java.
PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
ResourceBundle.setNoAvailableLocalePaks();
}
}
}
// Copyright 2019 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.
#include <memory>
#include "base/android/jni_android.h"
#include "base/android/library_loader/library_loader_hooks.h"
#include "base/bind.h"
#include "base/message_loop/message_pump.h"
#include "content/public/app/content_jni_onload.h"
#include "content/public/app/content_main.h"
#include "content/public/test/nested_message_pump_android.h"
#include "testing/android/native_test/native_test_launcher.h"
#include "weblayer/app/content_main_delegate_impl.h"
#include "weblayer/shell/app/shell_main_params.h"
// This is called by the VM when the shared library is first loaded.
JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
base::android::InitVM(vm);
if (!content::android::OnJNIOnLoadInit())
return -1;
// This needs to be done before base::TestSuite::Initialize() is called,
// as it also tries to set MessagePumpForUIFactory.
base::MessagePump::OverrideMessagePumpForUIFactory(
[]() -> std::unique_ptr<base::MessagePump> {
return std::make_unique<content::NestedMessagePumpAndroid>();
});
content::SetContentMainDelegate(
new weblayer::ContentMainDelegateImpl(weblayer::CreateMainParams()));
return JNI_VERSION_1_4;
}
......@@ -32,11 +32,13 @@ std::vector<Shell*> Shell::windows_;
Shell::Shell(std::unique_ptr<BrowserController> browser_controller)
: browser_controller_(std::move(browser_controller)), window_(nullptr) {
windows_.push_back(this);
browser_controller_->AddObserver(this);
if (browser_controller_)
browser_controller_->AddObserver(this);
}
Shell::~Shell() {
browser_controller_->RemoveObserver(this);
if (browser_controller_)
browser_controller_->RemoveObserver(this);
PlatformCleanUp();
for (size_t i = 0; i < windows_.size(); ++i) {
......@@ -89,6 +91,15 @@ void Shell::SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure) {
*g_quit_main_message_loop = std::move(quit_closure);
}
BrowserController* Shell::browser_controller() {
#if defined(OS_ANDROID)
// TODO(jam): this won't work if we need more than one Shell in a test.
return BrowserController::GetLastControllerForTesting();
#else
return browser_controller_.get();
#endif
}
void Shell::Initialize() {
PlatformInitialize(GetShellDefaultSize());
}
......@@ -122,7 +133,11 @@ gfx::Size Shell::AdjustWindowSize(const gfx::Size& initial_size) {
Shell* Shell::CreateNewWindow(weblayer::Profile* web_profile,
const GURL& url,
const gfx::Size& initial_size) {
#if defined(OS_ANDROID)
std::unique_ptr<BrowserController> browser_controller;
#else
auto browser_controller = BrowserController::Create(web_profile);
#endif
Shell* shell = CreateShell(std::move(browser_controller),
AdjustWindowSize(initial_size));
......@@ -132,24 +147,24 @@ Shell* Shell::CreateNewWindow(weblayer::Profile* web_profile,
}
void Shell::LoadURL(const GURL& url) {
browser_controller_->GetNavigationController()->Navigate(url);
browser_controller()->GetNavigationController()->Navigate(url);
}
void Shell::GoBackOrForward(int offset) {
if (offset == -1)
browser_controller_->GetNavigationController()->GoBack();
browser_controller()->GetNavigationController()->GoBack();
else if (offset == 1)
browser_controller_->GetNavigationController()->GoForward();
browser_controller()->GetNavigationController()->GoForward();
}
void Shell::Reload() {
browser_controller_->GetNavigationController()->Reload();
browser_controller()->GetNavigationController()->Reload();
}
void Shell::ReloadBypassingCache() {}
void Shell::Stop() {
browser_controller_->GetNavigationController()->Stop();
browser_controller()->GetNavigationController()->Stop();
}
gfx::Size Shell::GetShellDefaultSize() {
......
......@@ -38,6 +38,9 @@ class Profile;
// This represents one window of the Web Shell, i.e. all the UI including
// buttons and url bar, as well as the web content area.
// On desktop this is used for the demo Shell application and also
// weblayer_browsertests. On Android this is only used for
// weblayer_browsertests.
class Shell : public BrowserObserver {
public:
~Shell() override;
......@@ -67,7 +70,7 @@ class Shell : public BrowserObserver {
// instance is destroyed.
static void SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure);
BrowserController* browser_controller() { return browser_controller_.get(); }
BrowserController* browser_controller();
gfx::NativeWindow window() { return window_; }
......
// Copyright 2019 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.
#include "weblayer/shell/browser/shell.h"
namespace weblayer {
// Shell is only used on Android for weblayer_browsertests. So no need to
// implement these methods.
void Shell::PlatformInitialize(const gfx::Size& default_window_size) {}
void Shell::PlatformExit() {}
void Shell::PlatformCleanUp() {}
void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {}
void Shell::PlatformSetAddressBarURL(const GURL& url) {}
void Shell::PlatformSetLoadProgress(double progress) {}
void Shell::PlatformCreateWindow(int width, int height) {}
void Shell::PlatformSetContents() {}
void Shell::PlatformResizeSubViews() {}
void Shell::Close() {}
void Shell::PlatformSetTitle(const base::string16& title) {}
} // namespace weblayer
......@@ -8,6 +8,60 @@ import("//testing/test.gni")
import("//tools/grit/grit_rule.gni")
import("//tools/v8_context_snapshot/v8_context_snapshot.gni")
if (is_android) {
import("//build/config/android/rules.gni")
weblayer_browsertests_manifest =
"${target_gen_dir}/weblayer_browsertests_manifest/AndroidManifest.xml"
jinja_template("weblayer_browsertests_manifest") {
testonly = true
input = "//weblayer/shell/android/browsertests_apk/AndroidManifest.xml"
output = weblayer_browsertests_manifest
}
android_library("weblayer_browsertests_java") {
testonly = true
java_files = [
"../shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsActivity.java",
"../shell/android/browsertests_apk/src/org/chromium/weblayer_browsertests_apk/WebLayerBrowserTestsApplication.java",
]
deps = [
":weblayer_browsertests_manifest",
"//base:base_java",
"//base:base_java_test_support",
"//content/public/android:content_java",
"//content/public/test/android:content_java_test_support",
"//testing/android/native_test:native_test_java",
"//third_party/android_deps:android_support_v4_java",
"//third_party/android_deps:com_android_support_support_compat_java",
"//ui/android:ui_java",
"//weblayer/public/java",
]
android_manifest_for_lint = weblayer_browsertests_manifest
}
}
if (is_android) {
android_assets("weblayer_test_assets") {
testonly = true
sources = [
"$root_out_dir/weblayer.pak",
]
disable_compression = true
deps = [
"//third_party/icu:icu_assets",
"//weblayer/shell:pak",
]
if (use_v8_context_snapshot) {
deps += [ "//tools/v8_context_snapshot:v8_context_snapshot_assets" ]
} else {
deps += [ "//v8:v8_external_startup_data_assets" ]
}
}
}
test("weblayer_browsertests") {
data = [
"$root_out_dir/weblayer_shell.pak",
......@@ -44,4 +98,28 @@ test("weblayer_browsertests") {
"weblayer_browser_test_utils.cc",
"weblayer_browser_test_utils.h",
]
if (is_android) {
sources += [
"../shell/android/browsertests_apk/weblayer_browser_tests_jni_onload.cc",
]
deps += [
":weblayer_browsertests_java",
":weblayer_test_assets",
"//content/public/test/android:android_test_message_pump_support_java",
"//content/test:android_test_message_pump_support",
"//content/test:android_test_message_pump_support",
"//services/tracing:test_utils",
"//testing/android/native_test:native_test_support",
"//ui/android:android",
"//ui/touch_selection:touch_selection",
# Needed for WebLayerImpl.
"//weblayer/browser/java",
]
android_manifest =
"${target_gen_dir}/weblayer_browsertests_manifest/AndroidManifest.xml"
android_manifest_dep = ":weblayer_browsertests_manifest"
use_default_launcher = false
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment