blob: b6a87bf948bbe7a74075b6dc3050a91d7f01890c [file] [log] [blame]
// Copyright 2014 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 "base/command_line.h"
#include "base/path_service.h"
#include "base/strings/stringprintf.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_restrictions.h"
#include "components/guest_view/browser/guest_view_manager.h"
#include "components/guest_view/browser/guest_view_manager_factory.h"
#include "components/guest_view/browser/test_guest_view_manager.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_paths.h"
#include "extensions/shell/browser/shell_app_delegate.h"
#include "extensions/shell/browser/shell_app_view_guest_delegate.h"
#include "extensions/shell/browser/shell_content_browser_client.h"
#include "extensions/shell/browser/shell_extension_system.h"
#include "extensions/shell/browser/shell_extensions_api_client.h"
#include "extensions/shell/browser/shell_extensions_browser_client.h"
#include "extensions/shell/test/shell_test.h"
#include "extensions/test/extension_test_message_listener.h"
#include "net/base/filename_util.h"
#include "testing/gtest/include/gtest/gtest.h"
using guest_view::GuestViewManager;
using guest_view::TestGuestViewManager;
using guest_view::TestGuestViewManagerFactory;
namespace {
class MockShellAppDelegate : public extensions::ShellAppDelegate {
public:
MockShellAppDelegate() : requested_(false) {
DCHECK(instance_ == nullptr);
instance_ = this;
}
~MockShellAppDelegate() override { instance_ = nullptr; }
void RequestMediaAccessPermission(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
const content::MediaResponseCallback& callback,
const extensions::Extension* extension) override {
requested_ = true;
if (request_message_loop_runner_.get())
request_message_loop_runner_->Quit();
}
void WaitForRequestMediaPermission() {
if (requested_)
return;
request_message_loop_runner_ = new content::MessageLoopRunner;
request_message_loop_runner_->Run();
}
static MockShellAppDelegate* Get() { return instance_; }
private:
bool requested_;
scoped_refptr<content::MessageLoopRunner> request_message_loop_runner_;
static MockShellAppDelegate* instance_;
};
MockShellAppDelegate* MockShellAppDelegate::instance_ = nullptr;
class MockShellAppViewGuestDelegate
: public extensions::ShellAppViewGuestDelegate {
public:
MockShellAppViewGuestDelegate() {}
extensions::AppDelegate* CreateAppDelegate() override {
return new MockShellAppDelegate();
}
};
class MockExtensionsAPIClient : public extensions::ShellExtensionsAPIClient {
public:
MockExtensionsAPIClient() {}
extensions::AppViewGuestDelegate* CreateAppViewGuestDelegate()
const override {
return new MockShellAppViewGuestDelegate();
}
};
} // namespace
namespace extensions {
class AppViewTest : public AppShellTest,
public testing::WithParamInterface<bool> {
protected:
AppViewTest() { GuestViewManager::set_factory_for_testing(&factory_); }
TestGuestViewManager* GetGuestViewManager() {
return static_cast<TestGuestViewManager*>(
TestGuestViewManager::FromBrowserContext(
ShellContentBrowserClient::Get()->GetBrowserContext()));
}
content::WebContents* GetFirstAppWindowWebContents() {
const AppWindowRegistry::AppWindowList& app_window_list =
AppWindowRegistry::Get(browser_context_)->app_windows();
DCHECK(app_window_list.size() == 1);
return (*app_window_list.begin())->web_contents();
}
const Extension* LoadApp(const std::string& app_location) {
base::ScopedAllowBlockingForTesting allow_blocking;
base::FilePath test_data_dir;
PathService::Get(DIR_TEST_DATA, &test_data_dir);
test_data_dir = test_data_dir.AppendASCII(app_location.c_str());
return extension_system_->LoadApp(test_data_dir);
}
void RunTest(const std::string& test_name,
const std::string& app_location,
const std::string& app_to_embed) {
const Extension* app_embedder = LoadApp(app_location);
ASSERT_TRUE(app_embedder);
const Extension* app_embedded = LoadApp(app_to_embed);
ASSERT_TRUE(app_embedded);
extension_system_->LaunchApp(app_embedder->id());
ExtensionTestMessageListener launch_listener("LAUNCHED", false);
ASSERT_TRUE(launch_listener.WaitUntilSatisfied());
embedder_web_contents_ = GetFirstAppWindowWebContents();
ExtensionTestMessageListener done_listener("TEST_PASSED", false);
done_listener.set_failure_message("TEST_FAILED");
ASSERT_TRUE(
content::ExecuteScript(embedder_web_contents_,
base::StringPrintf("runTest('%s', '%s')",
test_name.c_str(),
app_embedded->id().c_str())))
<< "Unable to start test.";
ASSERT_TRUE(done_listener.WaitUntilSatisfied());
}
void SetUpCommandLine(base::CommandLine* command_line) override {
AppShellTest::SetUpCommandLine(command_line);
// This switch ensures that there will always be at least one media device,
// even on machines without physical devices. This is required by tests that
// request permission to use media devices.
command_line->AppendSwitch("use-fake-device-for-media-stream");
bool use_cross_process_frames_for_guests = GetParam();
if (use_cross_process_frames_for_guests) {
scoped_feature_list_.InitAndEnableFeature(
features::kGuestViewCrossProcessFrames);
} else {
scoped_feature_list_.InitAndDisableFeature(
features::kGuestViewCrossProcessFrames);
}
}
content::WebContents* embedder_web_contents_;
TestGuestViewManagerFactory factory_;
base::test::ScopedFeatureList scoped_feature_list_;
};
INSTANTIATE_TEST_CASE_P(AppViewTests, AppViewTest, testing::Bool());
#if defined(OS_WIN)
#define MAYBE_TestAppViewGoodDataShouldSucceed \
DISABLED_TestAppViewGoodDataShouldSucceed
#else
#define MAYBE_TestAppViewGoodDataShouldSucceed TestAppViewGoodDataShouldSucceed
#endif
// Tests that <appview> correctly processes parameters passed on connect.
IN_PROC_BROWSER_TEST_P(AppViewTest, MAYBE_TestAppViewGoodDataShouldSucceed) {
RunTest("testAppViewGoodDataShouldSucceed",
"app_view/apitest",
"app_view/apitest/skeleton");
}
// Tests that <appview> can handle media permission requests.
IN_PROC_BROWSER_TEST_P(AppViewTest, TestAppViewMediaRequest) {
static_cast<ShellExtensionsBrowserClient*>(ExtensionsBrowserClient::Get())
->SetAPIClientForTest(nullptr);
static_cast<ShellExtensionsBrowserClient*>(ExtensionsBrowserClient::Get())
->SetAPIClientForTest(new MockExtensionsAPIClient);
RunTest("testAppViewMediaRequest", "app_view/apitest",
"app_view/apitest/media_request");
MockShellAppDelegate::Get()->WaitForRequestMediaPermission();
}
// Tests that <appview> correctly processes parameters passed on connect.
// This test should fail to connect because the embedded app (skeleton) will
// refuse the data passed by the embedder app and deny the request.
IN_PROC_BROWSER_TEST_P(AppViewTest, TestAppViewRefusedDataShouldFail) {
RunTest("testAppViewRefusedDataShouldFail",
"app_view/apitest",
"app_view/apitest/skeleton");
}
#if defined(OS_WIN) || defined(OS_CHROMEOS)
#define MAYBE_TestAppViewWithUndefinedDataShouldSucceed \
DISABLED_TestAppViewWithUndefinedDataShouldSucceed
#else
#define MAYBE_TestAppViewWithUndefinedDataShouldSucceed \
TestAppViewWithUndefinedDataShouldSucceed
#endif
// Tests that <appview> is able to navigate to another installed app.
IN_PROC_BROWSER_TEST_P(AppViewTest,
MAYBE_TestAppViewWithUndefinedDataShouldSucceed) {
RunTest("testAppViewWithUndefinedDataShouldSucceed",
"app_view/apitest",
"app_view/apitest/skeleton");
}
} // namespace extensions