#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/process_map.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tab_contents/tab_contents.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "net/base/mock_host_resolver.h"
#include "sync/api/string_ordinal.h"
using content::NavigationController;
using content::RenderViewHost;
using content::WebContents;
using extensions::Extension;
class AppApiTest : public ExtensionApiTest {
protected:
GURL GetTestBaseURL(std::string test_directory) {
GURL::Replacements replace_host;
std::string host_str("localhost");
replace_host.SetHostStr(host_str);
GURL base_url = test_server()->GetURL(
"files/extensions/api_test/" + test_directory + "/");
return base_url.ReplaceComponents(replace_host);
}
void SetUpCommandLine(CommandLine* command_line) {
ExtensionApiTest::SetUpCommandLine(command_line);
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kDisablePopupBlocking);
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kAllowHTTPBackgroundPage);
}
void TestAppInstancesHelper(std::string app_name) {
LOG(INFO) << "Start of test.";
extensions::ProcessMap* process_map =
browser()->profile()->GetExtensionService()->process_map();
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII(app_name)));
GURL base_url = GetTestBaseURL(app_name);
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
LOG(INFO) << "Nav 1.";
EXPECT_TRUE(process_map->Contains(
chrome::GetWebContentsAt(browser(), 1)->GetRenderProcessHost()->GetID()));
EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 1)->GetWebUI());
content::WindowedNotificationObserver tab_added_observer(
chrome::NOTIFICATION_TAB_ADDED,
content::NotificationService::AllSources());
chrome::NewTab(browser());
tab_added_observer.Wait();
LOG(INFO) << "New tab.";
ui_test_utils::NavigateToURL(browser(),
base_url.Resolve("path2/empty.html"));
LOG(INFO) << "Nav 2.";
EXPECT_TRUE(process_map->Contains(
chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost()->GetID()));
EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 2)->GetWebUI());
ASSERT_EQ(3, browser()->tab_count());
WebContents* tab1 = chrome::GetWebContentsAt(browser(), 1);
WebContents* tab2 = chrome::GetWebContentsAt(browser(), 2);
EXPECT_NE(tab1->GetRenderProcessHost(), tab2->GetRenderProcessHost());
ASSERT_EQ(1u, browser::GetBrowserCount(browser()->profile()));
OpenWindow(tab1, base_url.Resolve("path1/empty.html"), true, NULL);
LOG(INFO) << "WindowOpenHelper 1.";
OpenWindow(tab2, base_url.Resolve("path2/empty.html"), true, NULL);
LOG(INFO) << "End of test.";
}
};
class BlockedAppApiTest : public AppApiTest {
protected:
void SetUpCommandLine(CommandLine* command_line) {
ExtensionApiTest::SetUpCommandLine(command_line);
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kAllowHTTPBackgroundPage);
}
};
IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcess) {
LOG(INFO) << "Start of test.";
extensions::ProcessMap* process_map =
browser()->profile()->GetExtensionService()->process_map();
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
LOG(INFO) << "Loaded extension.";
GURL base_url = GetTestBaseURL("app_process");
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
EXPECT_TRUE(process_map->Contains(
chrome::GetWebContentsAt(browser(), 1)->GetRenderProcessHost()->GetID()));
EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 1)->GetWebUI());
LOG(INFO) << "Nav 1.";
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("path2/empty.html"), NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
EXPECT_TRUE(process_map->Contains(
chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost()->GetID()));
EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 2)->GetWebUI());
LOG(INFO) << "Nav 2.";
content::WindowedNotificationObserver tab_added_observer(
chrome::NOTIFICATION_TAB_ADDED,
content::NotificationService::AllSources());
chrome::NewTab(browser());
tab_added_observer.Wait();
LOG(INFO) << "New tab.";
ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path3/empty.html"));
LOG(INFO) << "Nav 3.";
EXPECT_FALSE(process_map->Contains(
chrome::GetWebContentsAt(browser(), 3)->GetRenderProcessHost()->GetID()));
EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 3)->GetWebUI());
ASSERT_EQ(4, browser()->tab_count());
WebContents* tab = chrome::GetWebContentsAt(browser(), 1);
EXPECT_EQ(tab->GetRenderProcessHost(),
chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
EXPECT_NE(tab->GetRenderProcessHost(),
chrome::GetWebContentsAt(browser(), 3)->GetRenderProcessHost());
ASSERT_EQ(1u, browser::GetBrowserCount(browser()->profile()));
OpenWindow(tab, base_url.Resolve("path1/empty.html"), true, NULL);
LOG(INFO) << "WindowOpenHelper 1.";
OpenWindow(tab, base_url.Resolve("path2/empty.html"), true, NULL);
LOG(INFO) << "WindowOpenHelper 2.";
OpenWindow(tab, base_url.Resolve("path3/empty.html"), true, NULL);
LOG(INFO) << "WindowOpenHelper 3.";
const GURL& app_url(base_url.Resolve("path1/empty.html"));
const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
NavigateInRenderer(chrome::GetWebContentsAt(browser(), 2), non_app_url);
LOG(INFO) << "NavigateTabHelper 1.";
NavigateInRenderer(chrome::GetWebContentsAt(browser(), 3), app_url);
LOG(INFO) << "NavigateTabHelper 2.";
EXPECT_NE(tab->GetRenderProcessHost(),
chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
EXPECT_EQ(tab->GetRenderProcessHost(),
chrome::GetWebContentsAt(browser(), 3)->GetRenderProcessHost());
NavigateInRenderer(chrome::GetWebContentsAt(browser(), 6), app_url);
LOG(INFO) << "NavigateTabHelper 3.";
EXPECT_EQ(tab->GetRenderProcessHost(),
chrome::GetWebContentsAt(browser(), 6)->GetRenderProcessHost());
bool windowOpenerValid = false;
ASSERT_TRUE(content::ExecuteJavaScriptAndExtractBool(
chrome::GetWebContentsAt(browser(), 6)->GetRenderViewHost(), L"",
L"window.domAutomationController.send(window.opener != null)",
&windowOpenerValid));
ASSERT_TRUE(windowOpenerValid);
LOG(INFO) << "End of test.";
}
IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessInstances) {
TestAppInstancesHelper("app_process_instances");
}
IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessBackgroundInstances) {
TestAppInstancesHelper("app_process_background_instances");
}
IN_PROC_BROWSER_TEST_F(AppApiTest, BookmarkAppGetsNormalProcess) {
ExtensionService* service = browser()->profile()->GetExtensionService();
extensions::ProcessMap* process_map = service->process_map();
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
GURL base_url = GetTestBaseURL("app_process");
std::string error;
scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
test_data_dir_.AppendASCII("app_process"),
Extension::LOAD,
Extension::FROM_BOOKMARK,
&error));
service->OnExtensionInstalled(extension, false,
syncer::StringOrdinal::CreateInitialOrdinal(),
false );
ASSERT_TRUE(extension.get());
ASSERT_TRUE(extension->from_bookmark());
ui_test_utils::NavigateToURLWithDisposition(
browser(), base_url.Resolve("path1/empty.html"), NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
EXPECT_FALSE(process_map->Contains(
chrome::GetWebContentsAt(browser(), 1)->GetRenderProcessHost()->GetID()));
EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 1)->GetWebUI());
content::WindowedNotificationObserver tab_added_observer(
chrome::NOTIFICATION_TAB_ADDED,
content::NotificationService::AllSources());
chrome::NewTab(browser());
tab_added_observer.Wait();
ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path2/empty.html"));
EXPECT_FALSE(process_map->Contains(
chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost()->GetID()));
EXPECT_FALSE(chrome::GetWebContentsAt(browser(), 2)->GetWebUI());
ASSERT_EQ(3, browser()->tab_count());
WebContents* tab = chrome::GetWebContentsAt(browser(), 1);
EXPECT_NE(tab->GetRenderProcessHost(),
chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
ASSERT_EQ(1u, browser::GetBrowserCount(browser()->profile()));
OpenWindow(tab, base_url.Resolve("path1/empty.html"), true, NULL);
OpenWindow(tab, base_url.Resolve("path2/empty.html"), true, NULL);
const GURL& app_url(base_url.Resolve("path1/empty.html"));
const GURL& non_app_url(base_url.Resolve("path3/empty.html"));
RenderViewHost* host2 =
chrome::GetWebContentsAt(browser(), 2)->GetRenderViewHost();
NavigateInRenderer(chrome::GetWebContentsAt(browser(), 2), non_app_url);
EXPECT_EQ(host2->GetProcess(),
chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
NavigateInRenderer(chrome::GetWebContentsAt(browser(), 2), app_url);
EXPECT_EQ(host2->GetProcess(),
chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
}
IN_PROC_BROWSER_TEST_F(AppApiTest, AppProcessRedirectBack) {
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
GURL base_url = GetTestBaseURL("app_process");
chrome::NewTab(browser());
ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
chrome::NewTab(browser());
ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
browser(), base_url.Resolve("path1/redirect.html"), 2);
ASSERT_EQ(3, browser()->tab_count());
EXPECT_EQ("/files/extensions/api_test/app_process/path1/empty.html",
chrome::GetWebContentsAt(browser(), 2)->GetController().
GetLastCommittedEntry()->GetURL().path());
EXPECT_EQ(chrome::GetWebContentsAt(browser(), 1)->GetRenderProcessHost(),
chrome::GetWebContentsAt(browser(), 2)->GetRenderProcessHost());
}
#if defined(ADDRESS_SANITIZER)
#define MAYBE_ReloadIntoAppProcess DISABLED_ReloadIntoAppProcess
#else
#define MAYBE_ReloadIntoAppProcess ReloadIntoAppProcess
#endif
IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_ReloadIntoAppProcess) {
extensions::ProcessMap* process_map =
browser()->profile()->GetExtensionService()->process_map();
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
GURL base_url = GetTestBaseURL("app_process");
ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
WebContents* contents = chrome::GetWebContentsAt(browser(), 0);
EXPECT_FALSE(process_map->Contains(
contents->GetRenderProcessHost()->GetID()));
const Extension* app =
LoadExtension(test_data_dir_.AppendASCII("app_process"));
ASSERT_TRUE(app);
ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
EXPECT_TRUE(process_map->Contains(
contents->GetRenderProcessHost()->GetID()));
DisableExtension(app->id());
ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
EXPECT_FALSE(process_map->Contains(
contents->GetRenderProcessHost()->GetID()));
EnableExtension(app->id());
content::WindowedNotificationObserver reload_observer(
content::NOTIFICATION_LOAD_STOP,
content::Source<NavigationController>(
&chrome::GetActiveWebContents(browser())->GetController()));
chrome::Reload(browser(), CURRENT_TAB);
reload_observer.Wait();
EXPECT_TRUE(process_map->Contains(
contents->GetRenderProcessHost()->GetID()));
DisableExtension(app->id());
content::WindowedNotificationObserver reload_observer2(
content::NOTIFICATION_LOAD_STOP,
content::Source<NavigationController>(
&chrome::GetActiveWebContents(browser())->GetController()));
chrome::Reload(browser(), CURRENT_TAB);
reload_observer2.Wait();
EXPECT_FALSE(process_map->Contains(
contents->GetRenderProcessHost()->GetID()));
EnableExtension(app->id());
content::WindowedNotificationObserver js_reload_observer(
content::NOTIFICATION_LOAD_STOP,
content::Source<NavigationController>(
&chrome::GetActiveWebContents(browser())->GetController()));
ASSERT_TRUE(content::ExecuteJavaScript(contents->GetRenderViewHost(),
L"", L"location.reload();"));
js_reload_observer.Wait();
EXPECT_TRUE(process_map->Contains(
contents->GetRenderProcessHost()->GetID()));
DisableExtension(app->id());
content::WindowedNotificationObserver js_reload_observer2(
content::NOTIFICATION_LOAD_STOP,
content::Source<NavigationController>(
&chrome::GetActiveWebContents(browser())->GetController()));
ASSERT_TRUE(content::ExecuteJavaScript(contents->GetRenderViewHost(),
L"", L"location = location;"));
js_reload_observer2.Wait();
EXPECT_FALSE(process_map->Contains(
contents->GetRenderProcessHost()->GetID()));
}
IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromIframe) {
extensions::ProcessMap* process_map =
browser()->profile()->GetExtensionService()->process_map();
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
GURL base_url = GetTestBaseURL("app_process");
const Extension* app =
LoadExtension(test_data_dir_.AppendASCII("app_process"));
ASSERT_TRUE(app);
content::WindowedNotificationObserver popup_observer(
content::NOTIFICATION_RENDER_VIEW_HOST_CREATED,
content::NotificationService::AllSources());
ui_test_utils::NavigateToURL(browser(),
base_url.Resolve("path3/container.html"));
EXPECT_FALSE(process_map->Contains(
chrome::GetWebContentsAt(browser(), 0)->GetRenderProcessHost()->GetID()));
popup_observer.Wait();
RenderViewHost* popup_host =
content::Source<RenderViewHost>(popup_observer.source()).ptr();
EXPECT_TRUE(process_map->Contains(popup_host->GetProcess()->GetID()));
}
IN_PROC_BROWSER_TEST_F(BlockedAppApiTest, OpenAppFromIframe) {
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
const Extension* app =
LoadExtension(test_data_dir_.AppendASCII("app_process"));
ASSERT_TRUE(app);
content::WindowedNotificationObserver blocker_observer(
chrome::NOTIFICATION_CONTENT_BLOCKED_STATE_CHANGED,
content::NotificationService::AllSources());
ui_test_utils::NavigateToURL(
browser(), GetTestBaseURL("app_process").Resolve("path3/container.html"));
blocker_observer.Wait();
WebContents* tab = chrome::GetActiveWebContents(browser());
BlockedContentTabHelper* blocked_content_tab_helper =
BlockedContentTabHelper::FromWebContents(tab);
std::vector<WebContents*> blocked_contents;
blocked_content_tab_helper->GetBlockedContents(&blocked_contents);
EXPECT_EQ(blocked_contents.size(), 1u);
}
IN_PROC_BROWSER_TEST_F(AppApiTest, OpenAppFromExtension) {
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(StartTestServer());
LoadExtension(test_data_dir_.AppendASCII("app_process"));
const Extension* launcher =
LoadExtension(test_data_dir_.AppendASCII("app_launcher"));
content::TestNavigationObserver test_navigation_observer(
content::NotificationService::AllSources(),
NULL,
3);
ui_test_utils::NavigateToURLWithDisposition(
browser(),
launcher->GetResourceURL("main.html"),
CURRENT_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
test_navigation_observer.WaitForObservation(
base::Bind(&content::RunMessageLoop),
base::Bind(&MessageLoop::Quit,
base::Unretained(MessageLoopForUI::current())));
bool is_installed = false;
ASSERT_TRUE(content::ExecuteJavaScriptAndExtractBool(
chrome::GetActiveWebContents(browser())->GetRenderViewHost(), L"",
L"window.domAutomationController.send(chrome.app.isInstalled)",
&is_installed));
ASSERT_TRUE(is_installed);
}
IN_PROC_BROWSER_TEST_F(AppApiTest, OpenWebPopupFromWebIframe) {
extensions::ProcessMap* process_map =
browser()->profile()->GetExtensionService()->process_map();
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
GURL base_url = GetTestBaseURL("app_process");
const Extension* app =
LoadExtension(test_data_dir_.AppendASCII("app_process"));
ASSERT_TRUE(app);
content::WindowedNotificationObserver popup_observer(
content::NOTIFICATION_RENDER_VIEW_HOST_CREATED,
content::NotificationService::AllSources());
ui_test_utils::NavigateToURL(browser(),
base_url.Resolve("path1/container.html"));
content::RenderProcessHost* process =
chrome::GetWebContentsAt(browser(), 0)->GetRenderProcessHost();
EXPECT_TRUE(process_map->Contains(process->GetID()));
popup_observer.Wait();
RenderViewHost* popup_host =
content::Source<RenderViewHost>(popup_observer.source()).ptr();
EXPECT_EQ(process, popup_host->GetProcess());
}
#if defined(OS_MACOSX) || defined(OS_LINUX)
#define MAYBE_ReloadAppAfterCrash DISABLED_ReloadAppAfterCrash
#else
#define MAYBE_ReloadAppAfterCrash ReloadAppAfterCrash
#endif
IN_PROC_BROWSER_TEST_F(AppApiTest, MAYBE_ReloadAppAfterCrash) {
extensions::ProcessMap* process_map =
browser()->profile()->GetExtensionService()->process_map();
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(test_server()->Start());
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("app_process")));
GURL base_url = GetTestBaseURL("app_process");
ui_test_utils::NavigateToURL(browser(), base_url.Resolve("path1/empty.html"));
WebContents* contents = chrome::GetWebContentsAt(browser(), 0);
EXPECT_TRUE(process_map->Contains(
contents->GetRenderProcessHost()->GetID()));
bool is_installed = false;
ASSERT_TRUE(content::ExecuteJavaScriptAndExtractBool(
contents->GetRenderViewHost(), L"",
L"window.domAutomationController.send(chrome.app.isInstalled)",
&is_installed));
ASSERT_TRUE(is_installed);
content::CrashTab(chrome::GetActiveWebContents(browser()));
content::WindowedNotificationObserver observer(
content::NOTIFICATION_LOAD_STOP,
content::Source<NavigationController>(
&chrome::GetActiveWebContents(browser())->GetController()));
chrome::Reload(browser(), CURRENT_TAB);
observer.Wait();
ASSERT_TRUE(content::ExecuteJavaScriptAndExtractBool(
contents->GetRenderViewHost(), L"",
L"window.domAutomationController.send(chrome.app.isInstalled)",
&is_installed));
ASSERT_TRUE(is_installed);
}