blob: e2532af25e2f6f0eaf088c48456ca387900ab28d [file] [log] [blame]
// Copyright 2016 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/files/scoped_temp_dir.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_restrictions.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "headless/lib/browser/headless_web_contents_impl.h"
#include "headless/public/devtools/domains/runtime.h"
#include "headless/public/headless_browser.h"
#include "headless/public/headless_browser_context.h"
#include "headless/public/headless_devtools_client.h"
#include "headless/public/headless_devtools_target.h"
#include "headless/public/headless_web_contents.h"
#include "headless/test/headless_browser_test.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/size.h"
namespace headless {
namespace {
const char kMainPageCookie[] = "mood=quizzical";
const char kIsolatedPageCookie[] = "mood=quixotic";
} // namespace
// This test creates two tabs pointing to the same security origin in two
// different browser contexts and checks that they are isolated by creating two
// cookies with the same name in both tabs. The steps are:
//
// 1. Wait for tab #1 to become ready for DevTools.
// 2. Create tab #2 and wait for it to become ready for DevTools.
// 3. Navigate tab #1 to the test page and wait for it to finish loading.
// 4. Navigate tab #2 to the test page and wait for it to finish loading.
// 5. Set a cookie in tab #1.
// 6. Set the same cookie in tab #2 to a different value.
// 7. Read the cookie in tab #1 and check that it has the first value.
// 8. Read the cookie in tab #2 and check that it has the second value.
//
// If the tabs aren't properly isolated, step 7 will fail.
class HeadlessBrowserContextIsolationTest
: public HeadlessAsyncDevTooledBrowserTest {
public:
HeadlessBrowserContextIsolationTest()
: browser_context_(nullptr), web_contents2_(nullptr) {
EXPECT_TRUE(embedded_test_server()->Start());
}
// HeadlessWebContentsObserver implementation:
void DevToolsTargetReady() override {
if (!web_contents2_) {
browser_context_ = browser()->CreateBrowserContextBuilder().Build();
web_contents2_ = browser_context_->CreateWebContentsBuilder().Build();
web_contents2_->AddObserver(this);
return;
}
devtools_client2_ = HeadlessDevToolsClient::Create();
web_contents2_->GetDevToolsTarget()->AttachClient(devtools_client2_.get());
HeadlessAsyncDevTooledBrowserTest::DevToolsTargetReady();
}
void RunDevTooledTest() override {
load_observer_.reset(new LoadObserver(
devtools_client_.get(),
base::Bind(&HeadlessBrowserContextIsolationTest::OnFirstLoadComplete,
base::Unretained(this))));
devtools_client_->GetPage()->Navigate(
embedded_test_server()->GetURL("/hello.html").spec());
}
void OnFirstLoadComplete() {
EXPECT_TRUE(load_observer_->navigation_succeeded());
load_observer_.reset(new LoadObserver(
devtools_client2_.get(),
base::Bind(&HeadlessBrowserContextIsolationTest::OnSecondLoadComplete,
base::Unretained(this))));
devtools_client2_->GetPage()->Navigate(
embedded_test_server()->GetURL("/hello.html").spec());
}
void OnSecondLoadComplete() {
EXPECT_TRUE(load_observer_->navigation_succeeded());
load_observer_.reset();
devtools_client_->GetRuntime()->Evaluate(
base::StringPrintf("document.cookie = '%s'", kMainPageCookie),
base::BindOnce(
&HeadlessBrowserContextIsolationTest::OnFirstSetCookieResult,
base::Unretained(this)));
}
void OnFirstSetCookieResult(std::unique_ptr<runtime::EvaluateResult> result) {
EXPECT_EQ(kMainPageCookie, result->GetResult()->GetValue()->GetString());
devtools_client2_->GetRuntime()->Evaluate(
base::StringPrintf("document.cookie = '%s'", kIsolatedPageCookie),
base::BindOnce(
&HeadlessBrowserContextIsolationTest::OnSecondSetCookieResult,
base::Unretained(this)));
}
void OnSecondSetCookieResult(
std::unique_ptr<runtime::EvaluateResult> result) {
EXPECT_EQ(kIsolatedPageCookie,
result->GetResult()->GetValue()->GetString());
devtools_client_->GetRuntime()->Evaluate(
"document.cookie",
base::BindOnce(
&HeadlessBrowserContextIsolationTest::OnFirstGetCookieResult,
base::Unretained(this)));
}
void OnFirstGetCookieResult(std::unique_ptr<runtime::EvaluateResult> result) {
EXPECT_EQ(kMainPageCookie, result->GetResult()->GetValue()->GetString());
devtools_client2_->GetRuntime()->Evaluate(
"document.cookie",
base::BindOnce(
&HeadlessBrowserContextIsolationTest::OnSecondGetCookieResult,
base::Unretained(this)));
}
void OnSecondGetCookieResult(
std::unique_ptr<runtime::EvaluateResult> result) {
EXPECT_EQ(kIsolatedPageCookie,
result->GetResult()->GetValue()->GetString());
FinishTest();
}
void FinishTest() {
web_contents2_->RemoveObserver(this);
web_contents2_->Close();
browser_context_->Close();
FinishAsynchronousTest();
}
private:
HeadlessBrowserContext* browser_context_;
HeadlessWebContents* web_contents2_;
std::unique_ptr<HeadlessDevToolsClient> devtools_client2_;
std::unique_ptr<LoadObserver> load_observer_;
};
HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessBrowserContextIsolationTest);
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, UserDataDir) {
// We do not want to bother with posting tasks to create a temp dir.
// Just allow IO from main thread for now.
base::ThreadRestrictions::SetIOAllowed(true);
EXPECT_TRUE(embedded_test_server()->Start());
base::ScopedTempDir user_data_dir;
ASSERT_TRUE(user_data_dir.CreateUniqueTempDir());
// Newly created temp directory should be empty.
EXPECT_TRUE(base::IsDirectoryEmpty(user_data_dir.GetPath()));
HeadlessBrowserContext* browser_context =
browser()
->CreateBrowserContextBuilder()
.SetUserDataDir(user_data_dir.GetPath())
.SetIncognitoMode(false)
.Build();
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder()
.SetInitialURL(embedded_test_server()->GetURL("/hello.html"))
.Build();
EXPECT_TRUE(WaitForLoad(web_contents));
// Something should be written to this directory.
// If it is not the case, more complex page may be needed.
// ServiceWorkers may be a good option.
EXPECT_FALSE(base::IsDirectoryEmpty(user_data_dir.GetPath()));
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, IncognitoMode) {
// We do not want to bother with posting tasks to create a temp dir.
// Just allow IO from main thread for now.
base::ThreadRestrictions::SetIOAllowed(true);
EXPECT_TRUE(embedded_test_server()->Start());
base::ScopedTempDir user_data_dir;
ASSERT_TRUE(user_data_dir.CreateUniqueTempDir());
// Newly created temp directory should be empty.
EXPECT_TRUE(base::IsDirectoryEmpty(user_data_dir.GetPath()));
HeadlessBrowserContext* browser_context =
browser()
->CreateBrowserContextBuilder()
.SetUserDataDir(user_data_dir.GetPath())
.SetIncognitoMode(true)
.Build();
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder()
.SetInitialURL(embedded_test_server()->GetURL("/hello.html"))
.Build();
EXPECT_TRUE(WaitForLoad(web_contents));
// Similar to test above, but now we are in incognito mode,
// so nothing should be written to this directory.
EXPECT_TRUE(base::IsDirectoryEmpty(user_data_dir.GetPath()));
}
IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, ContextWebPreferences) {
// By default, hide_scrollbars should be false.
EXPECT_FALSE(WebPreferences().hide_scrollbars);
// Set hide_scrollbars preference to true for a new BrowserContext.
HeadlessBrowserContext* browser_context =
browser()
->CreateBrowserContextBuilder()
.SetOverrideWebPreferencesCallback(
base::Bind([](WebPreferences* preferences) {
preferences->hide_scrollbars = true;
}))
.Build();
HeadlessWebContents* web_contents =
browser_context->CreateWebContentsBuilder()
.SetInitialURL(GURL("about:blank"))
.Build();
// Verify that the preference takes effect.
HeadlessWebContentsImpl* contents_impl =
HeadlessWebContentsImpl::From(web_contents);
EXPECT_TRUE(contents_impl->web_contents()
->GetRenderViewHost()
->GetWebkitPreferences().hide_scrollbars);
}
} // namespace headless