| // Copyright 2018 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 <lib/fidl/cpp/binding.h> |
| |
| #include "base/macros.h" |
| #include "base/path_service.h" |
| #include "base/task/post_task.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/storage_partition.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/browser/web_contents_observer.h" |
| #include "content/public/common/url_constants.h" |
| #include "net/cookies/cookie_store.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "net/test/embedded_test_server/http_request.h" |
| #include "net/url_request/url_request_context.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/url_constants.h" |
| #include "webrunner/browser/frame_impl.h" |
| #include "webrunner/browser/webrunner_browser_test.h" |
| #include "webrunner/browser/webrunner_url_request_context_getter.h" |
| #include "webrunner/service/common.h" |
| |
| namespace webrunner { |
| |
| using testing::_; |
| using testing::AllOf; |
| using testing::Field; |
| using testing::InvokeWithoutArgs; |
| using testing::Mock; |
| |
| using chromium::web::NavigationEvent; |
| |
| const char kPage1Path[] = "/title1.html"; |
| const char kPage2Path[] = "/title2.html"; |
| const char kPage1Title[] = "title 1"; |
| const char kPage2Title[] = "title 2"; |
| const char kDataUrl[] = |
| "data:text/html;base64,PGI+SGVsbG8sIHdvcmxkLi4uPC9iPg=="; |
| |
| MATCHER(IsSet, "Checks if an optional field is set.") { |
| return !arg.is_null(); |
| } |
| |
| // Defines mock methods used by tests to observe NavigationStateChangeEvents |
| // and lower-level WebContentsObserver events. |
| class MockNavigationObserver : public chromium::web::NavigationEventObserver, |
| public content::WebContentsObserver { |
| public: |
| using content::WebContentsObserver::Observe; |
| |
| MockNavigationObserver() = default; |
| ~MockNavigationObserver() override = default; |
| |
| // Acknowledges processing of the most recent OnNavigationStateChanged call. |
| void Acknowledge() { |
| DCHECK(navigation_ack_callback_); |
| std::move(navigation_ack_callback_)(); |
| |
| // Pump the acknowledgement message over IPC. |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| MOCK_METHOD1(MockableOnNavigationStateChanged, |
| void(chromium::web::NavigationEvent change)); |
| |
| // chromium::web::NavigationEventObserver implementation. |
| // Proxies calls to MockableOnNavigationStateChanged(), because GMock does |
| // not work well with fit::Callbacks inside mocked actions. |
| void OnNavigationStateChanged( |
| chromium::web::NavigationEvent change, |
| OnNavigationStateChangedCallback callback) override { |
| MockableOnNavigationStateChanged(std::move(change)); |
| navigation_ack_callback_ = std::move(callback); |
| } |
| |
| // WebContentsObserver implementation. |
| MOCK_METHOD2(DidFinishLoad, |
| void(content::RenderFrameHost* render_frame_host, |
| const GURL& validated_url)); |
| |
| private: |
| OnNavigationStateChangedCallback navigation_ack_callback_; |
| |
| DISALLOW_COPY_AND_ASSIGN(MockNavigationObserver); |
| }; |
| |
| class ContextImplTest : public WebRunnerBrowserTest { |
| public: |
| ContextImplTest() : navigation_observer_binding_(&navigation_observer_) {} |
| ~ContextImplTest() = default; |
| |
| MOCK_METHOD1(OnServeHttpRequest, |
| void(const net::test_server::HttpRequest& request)); |
| |
| protected: |
| chromium::web::FramePtr CreateFrame() { |
| chromium::web::FramePtr frame; |
| context()->CreateFrame(frame.NewRequest()); |
| frame->SetNavigationEventObserver( |
| navigation_observer_binding_.NewBinding()); |
| base::RunLoop().RunUntilIdle(); |
| return frame; |
| } |
| |
| // Synchronously gets a list of cookies for this BrowserContext. |
| net::CookieList GetCookies(); |
| |
| // Navigates a |controller| to |url|, blocking until navigation is complete. |
| void CheckLoadUrl(const std::string& url, |
| const std::string& expected_title, |
| bool is_error, |
| chromium::web::NavigationController* controller) { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, |
| MockableOnNavigationStateChanged(testing::AllOf( |
| Field(&NavigationEvent::is_error, is_error), |
| Field(&NavigationEvent::title, expected_title), |
| Field(&NavigationEvent::url, url)))) |
| .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); |
| controller->LoadUrl(url, nullptr); |
| run_loop.Run(); |
| Mock::VerifyAndClearExpectations(this); |
| navigation_observer_.Acknowledge(); |
| } |
| |
| void TearDownOnMainThread() override { |
| navigation_observer_binding_.Unbind(); |
| } |
| |
| testing::StrictMock<MockNavigationObserver> navigation_observer_; |
| fidl::Binding<chromium::web::NavigationEventObserver> |
| navigation_observer_binding_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ContextImplTest); |
| }; |
| |
| class WebContentsDeletionObserver : public content::WebContentsObserver { |
| public: |
| explicit WebContentsDeletionObserver(content::WebContents* web_contents) |
| : content::WebContentsObserver(web_contents) {} |
| |
| MOCK_METHOD1(RenderViewDeleted, |
| void(content::RenderViewHost* render_view_host)); |
| }; |
| |
| // Verifies that the browser will navigate and generate a navigation observer |
| // event when LoadUrl() is called. |
| IN_PROC_BROWSER_TEST_F(ContextImplTest, NavigateFrame) { |
| chromium::web::FramePtr frame = CreateFrame(); |
| |
| chromium::web::NavigationControllerPtr controller; |
| frame->GetNavigationController(controller.NewRequest()); |
| |
| CheckLoadUrl(url::kAboutBlankURL, url::kAboutBlankURL, false, |
| controller.get()); |
| |
| frame.Unbind(); |
| } |
| |
| // Tests that navigation errors are reported as navigation events, |
| // with the original URL that caused the error. |
| IN_PROC_BROWSER_TEST_F(ContextImplTest, NavigateError) { |
| chromium::web::FramePtr frame = CreateFrame(); |
| |
| chromium::web::NavigationControllerPtr controller; |
| frame->GetNavigationController(controller.NewRequest()); |
| |
| CheckLoadUrl("http://unresolvable.foo.google.com/foo", |
| "unresolvable.foo.google.com/foo", true, controller.get()); |
| |
| CheckLoadUrl("http://unresolvable.foo.google.com/foo2", |
| "unresolvable.foo.google.com/foo2", true, controller.get()); |
| |
| CheckLoadUrl(url::kAboutBlankURL, url::kAboutBlankURL, false, |
| controller.get()); |
| |
| frame.Unbind(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ContextImplTest, NavigateDataFrame) { |
| chromium::web::FramePtr frame = CreateFrame(); |
| |
| chromium::web::NavigationControllerPtr controller; |
| frame->GetNavigationController(controller.NewRequest()); |
| |
| CheckLoadUrl(kDataUrl, kDataUrl, false, controller.get()); |
| |
| frame.Unbind(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ContextImplTest, FrameDeletedBeforeContext) { |
| chromium::web::FramePtr frame = CreateFrame(); |
| |
| // Process the frame creation message. |
| base::RunLoop().RunUntilIdle(); |
| |
| FrameImpl* frame_impl = context_impl()->GetFrameImplForTest(&frame); |
| WebContentsDeletionObserver deletion_observer( |
| frame_impl->web_contents_for_test()); |
| base::RunLoop run_loop; |
| EXPECT_CALL(deletion_observer, RenderViewDeleted(_)) |
| .WillOnce(InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); |
| |
| chromium::web::NavigationControllerPtr controller; |
| frame->GetNavigationController(controller.NewRequest()); |
| controller->LoadUrl(url::kAboutBlankURL, nullptr); |
| |
| frame.Unbind(); |
| run_loop.Run(); |
| |
| // Check that |context| remains bound after the frame is closed. |
| EXPECT_TRUE(context()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ContextImplTest, ContextDeletedBeforeFrame) { |
| chromium::web::FramePtr frame = CreateFrame(); |
| EXPECT_TRUE(frame); |
| |
| base::RunLoop run_loop; |
| frame.set_error_handler([&run_loop]() { run_loop.Quit(); }); |
| context().Unbind(); |
| run_loop.Run(); |
| EXPECT_FALSE(frame); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ContextImplTest, GoBackAndForward) { |
| chromium::web::FramePtr frame = CreateFrame(); |
| chromium::web::NavigationControllerPtr controller; |
| frame->GetNavigationController(controller.NewRequest()); |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL title1(embedded_test_server()->GetURL(kPage1Path)); |
| GURL title2(embedded_test_server()->GetURL(kPage2Path)); |
| |
| CheckLoadUrl(title1.spec(), kPage1Title, false, controller.get()); |
| CheckLoadUrl(title2.spec(), kPage2Title, false, controller.get()); |
| |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, |
| MockableOnNavigationStateChanged( |
| testing::AllOf(Field(&NavigationEvent::title, kPage1Title), |
| Field(&NavigationEvent::url, IsSet())))) |
| .WillOnce(InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); |
| controller->GoBack(); |
| run_loop.Run(); |
| navigation_observer_.Acknowledge(); |
| } |
| |
| // At the top of the navigation entry list; this should be a no-op. |
| controller->GoBack(); |
| |
| // Process the navigation request message. |
| base::RunLoop().RunUntilIdle(); |
| |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, |
| MockableOnNavigationStateChanged( |
| testing::AllOf(Field(&NavigationEvent::title, kPage2Title), |
| Field(&NavigationEvent::url, IsSet())))) |
| .WillOnce(InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); |
| controller->GoForward(); |
| run_loop.Run(); |
| navigation_observer_.Acknowledge(); |
| } |
| |
| // At the end of the navigation entry list; this should be a no-op. |
| controller->GoForward(); |
| |
| // Process the navigation request message. |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ContextImplTest, ReloadFrame) { |
| chromium::web::FramePtr frame = CreateFrame(); |
| chromium::web::NavigationControllerPtr controller; |
| frame->GetNavigationController(controller.NewRequest()); |
| |
| embedded_test_server()->RegisterRequestMonitor(base::BindRepeating( |
| &ContextImplTest::OnServeHttpRequest, base::Unretained(this))); |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL url(embedded_test_server()->GetURL(kPage1Path)); |
| |
| EXPECT_CALL(*this, OnServeHttpRequest(_)); |
| CheckLoadUrl(url.spec(), kPage1Title, false, controller.get()); |
| |
| navigation_observer_.Observe( |
| context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); |
| |
| // Reload with NO_CACHE. |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(*this, OnServeHttpRequest(_)); |
| EXPECT_CALL(navigation_observer_, DidFinishLoad(_, url)) |
| .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); |
| controller->Reload(chromium::web::ReloadType::NO_CACHE); |
| run_loop.Run(); |
| Mock::VerifyAndClearExpectations(this); |
| navigation_observer_.Acknowledge(); |
| } |
| // Reload with PARTIAL_CACHE. |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(*this, OnServeHttpRequest(_)); |
| EXPECT_CALL(navigation_observer_, DidFinishLoad(_, url)) |
| .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); |
| controller->Reload(chromium::web::ReloadType::PARTIAL_CACHE); |
| run_loop.Run(); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ContextImplTest, GetVisibleEntry) { |
| chromium::web::FramePtr frame = CreateFrame(); |
| |
| chromium::web::NavigationControllerPtr controller; |
| frame->GetNavigationController(controller.NewRequest()); |
| |
| // Verify that a Frame returns a null NavigationEntry prior to receiving any |
| // LoadUrl() calls. |
| { |
| base::RunLoop run_loop; |
| controller->GetVisibleEntry( |
| [&run_loop](std::unique_ptr<chromium::web::NavigationEntry> details) { |
| EXPECT_EQ(nullptr, details.get()); |
| run_loop.Quit(); |
| }); |
| run_loop.Run(); |
| } |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL title1(embedded_test_server()->GetURL(kPage1Path)); |
| GURL title2(embedded_test_server()->GetURL(kPage2Path)); |
| |
| // Navigate to a page. |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, |
| MockableOnNavigationStateChanged( |
| testing::AllOf(Field(&NavigationEvent::title, kPage1Title), |
| Field(&NavigationEvent::url, IsSet())))) |
| .WillOnce(testing::InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); |
| controller->LoadUrl(title1.spec(), nullptr); |
| run_loop.Run(); |
| navigation_observer_.Acknowledge(); |
| } |
| |
| // Verify that GetVisibleEntry() reflects the new Frame navigation state. |
| { |
| base::RunLoop run_loop; |
| controller->GetVisibleEntry( |
| [&run_loop, |
| &title1](std::unique_ptr<chromium::web::NavigationEntry> details) { |
| EXPECT_TRUE(details); |
| EXPECT_EQ(details->url, title1.spec()); |
| EXPECT_EQ(details->title, kPage1Title); |
| run_loop.Quit(); |
| }); |
| run_loop.Run(); |
| } |
| |
| // Navigate to another page. |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, |
| MockableOnNavigationStateChanged( |
| testing::AllOf(Field(&NavigationEvent::title, kPage2Title), |
| Field(&NavigationEvent::url, IsSet())))) |
| .WillOnce(testing::InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); |
| controller->LoadUrl(title2.spec(), nullptr); |
| run_loop.Run(); |
| navigation_observer_.Acknowledge(); |
| } |
| |
| // Verify the navigation with GetVisibleEntry(). |
| { |
| base::RunLoop run_loop; |
| controller->GetVisibleEntry( |
| [&run_loop, |
| &title2](std::unique_ptr<chromium::web::NavigationEntry> details) { |
| EXPECT_TRUE(details); |
| EXPECT_EQ(details->url, title2.spec()); |
| EXPECT_EQ(details->title, kPage2Title); |
| run_loop.Quit(); |
| }); |
| run_loop.Run(); |
| } |
| |
| // Navigate back to the first page. |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, |
| MockableOnNavigationStateChanged( |
| testing::AllOf(Field(&NavigationEvent::title, kPage1Title), |
| Field(&NavigationEvent::url, IsSet())))) |
| .WillOnce(testing::InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); |
| controller->GoBack(); |
| run_loop.Run(); |
| navigation_observer_.Acknowledge(); |
| } |
| |
| // Verify the navigation with GetVisibleEntry(). |
| { |
| base::RunLoop run_loop; |
| controller->GetVisibleEntry( |
| [&run_loop, |
| &title1](std::unique_ptr<chromium::web::NavigationEntry> details) { |
| EXPECT_TRUE(details); |
| EXPECT_EQ(details->url, title1.spec()); |
| EXPECT_EQ(details->title, kPage1Title); |
| run_loop.Quit(); |
| }); |
| run_loop.Run(); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ContextImplTest, NoNavigationObserverAttached) { |
| chromium::web::FramePtr frame; |
| context()->CreateFrame(frame.NewRequest()); |
| base::RunLoop().RunUntilIdle(); |
| |
| chromium::web::NavigationControllerPtr controller; |
| frame->GetNavigationController(controller.NewRequest()); |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL title1(embedded_test_server()->GetURL(kPage1Path)); |
| GURL title2(embedded_test_server()->GetURL(kPage2Path)); |
| |
| navigation_observer_.Observe( |
| context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); |
| |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title1)) |
| .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); |
| controller->LoadUrl(title1.spec(), nullptr); |
| run_loop.Run(); |
| } |
| |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title2)) |
| .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); |
| controller->LoadUrl(title2.spec(), nullptr); |
| run_loop.Run(); |
| } |
| } |
| |
| // Verifies that a Frame will handle navigation observer disconnection events |
| // gracefully. |
| IN_PROC_BROWSER_TEST_F(ContextImplTest, NavigationObserverDisconnected) { |
| chromium::web::FramePtr frame = CreateFrame(); |
| |
| chromium::web::NavigationControllerPtr controller; |
| frame->GetNavigationController(controller.NewRequest()); |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL title1(embedded_test_server()->GetURL(kPage1Path)); |
| GURL title2(embedded_test_server()->GetURL(kPage2Path)); |
| |
| navigation_observer_.Observe( |
| context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); |
| |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title1)); |
| EXPECT_CALL(navigation_observer_, |
| MockableOnNavigationStateChanged( |
| testing::AllOf(Field(&NavigationEvent::title, kPage1Title), |
| Field(&NavigationEvent::url, IsSet())))) |
| .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); |
| controller->LoadUrl(title1.spec(), nullptr); |
| run_loop.Run(); |
| } |
| |
| // Disconnect the observer & spin the runloop to propagate the disconnection |
| // event over IPC. |
| navigation_observer_binding_.Unbind(); |
| base::RunLoop().RunUntilIdle(); |
| |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title2)) |
| .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); |
| controller->LoadUrl(title2.spec(), nullptr); |
| run_loop.Run(); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ContextImplTest, DISABLED_DelayedNavigationEventAck) { |
| chromium::web::FramePtr frame = CreateFrame(); |
| |
| chromium::web::NavigationControllerPtr controller; |
| frame->GetNavigationController(controller.NewRequest()); |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL title1(embedded_test_server()->GetURL(kPage1Path)); |
| GURL title2(embedded_test_server()->GetURL(kPage2Path)); |
| |
| // Expect an navigation event here, but deliberately postpone acknowledgement |
| // until the end of the test. |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, |
| MockableOnNavigationStateChanged( |
| testing::AllOf(Field(&NavigationEvent::title, kPage1Title), |
| Field(&NavigationEvent::url, IsSet())))) |
| .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); |
| controller->LoadUrl(title1.spec(), nullptr); |
| run_loop.Run(); |
| Mock::VerifyAndClearExpectations(this); |
| } |
| |
| // Since we have blocked NavigationEventObserver's flow, we must observe the |
| // WebContents events directly via a test-only seam. |
| navigation_observer_.Observe( |
| context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); |
| |
| // Navigate to a second page. |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title2)) |
| .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); |
| controller->LoadUrl(title2.spec(), nullptr); |
| run_loop.Run(); |
| Mock::VerifyAndClearExpectations(this); |
| } |
| |
| // Navigate to the first page. |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, DidFinishLoad(_, title1)) |
| .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); |
| controller->LoadUrl(title1.spec(), nullptr); |
| run_loop.Run(); |
| Mock::VerifyAndClearExpectations(this); |
| } |
| |
| // Since there was no observable change in navigation state since the last |
| // ack, there should be no more NavigationEvents generated. |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, |
| MockableOnNavigationStateChanged( |
| testing::AllOf(Field(&NavigationEvent::title, kPage1Title), |
| Field(&NavigationEvent::url, IsSet())))) |
| .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); |
| navigation_observer_.Acknowledge(); |
| run_loop.Run(); |
| } |
| } |
| |
| // Observes events specific to the Stop() test case. |
| struct WebContentsObserverForStop : public content::WebContentsObserver { |
| using content::WebContentsObserver::Observe; |
| MOCK_METHOD1(DidStartNavigation, void(content::NavigationHandle*)); |
| MOCK_METHOD0(NavigationStopped, void()); |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(ContextImplTest, Stop) { |
| chromium::web::FramePtr frame = CreateFrame(); |
| |
| chromium::web::NavigationControllerPtr controller; |
| frame->GetNavigationController(controller.NewRequest()); |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| // Use a request handler that will accept the connection and stall |
| // indefinitely. |
| GURL hung_url(embedded_test_server()->GetURL("/hung")); |
| |
| WebContentsObserverForStop observer; |
| observer.Observe( |
| context_impl()->GetFrameImplForTest(&frame)->web_contents_.get()); |
| |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(observer, DidStartNavigation(_)) |
| .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); |
| controller->LoadUrl(hung_url.spec(), nullptr); |
| run_loop.Run(); |
| Mock::VerifyAndClearExpectations(this); |
| } |
| |
| EXPECT_TRUE( |
| context_impl()->GetFrameImplForTest(&frame)->web_contents_->IsLoading()); |
| |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(observer, NavigationStopped()) |
| .WillOnce(InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); })); |
| controller->Stop(); |
| run_loop.Run(); |
| Mock::VerifyAndClearExpectations(this); |
| } |
| |
| EXPECT_FALSE( |
| context_impl()->GetFrameImplForTest(&frame)->web_contents_->IsLoading()); |
| } |
| |
| void OnCookiesReceived(net::CookieList* output, |
| base::OnceClosure on_received_cb, |
| const net::CookieList& cookies) { |
| *output = cookies; |
| std::move(on_received_cb).Run(); |
| } |
| |
| net::CookieList ContextImplTest::GetCookies() { |
| net::CookieStore* cookie_store = |
| content::BrowserContext::GetDefaultStoragePartition( |
| context_impl()->browser_context_for_test()) |
| ->GetURLRequestContext() |
| ->GetURLRequestContext() |
| ->cookie_store(); |
| |
| base::RunLoop run_loop; |
| net::CookieList cookies; |
| base::PostTaskWithTraits( |
| FROM_HERE, {content::BrowserThread::IO}, |
| base::BindOnce( |
| &net::CookieStore::GetAllCookiesAsync, base::Unretained(cookie_store), |
| base::BindOnce(&OnCookiesReceived, base::Unretained(&cookies), |
| run_loop.QuitClosure()))); |
| run_loop.Run(); |
| return cookies; |
| } |
| |
| // Verifies that the BrowserContext has a working cookie store by setting |
| // cookies in the content layer and then querying the CookieStore afterward. |
| IN_PROC_BROWSER_TEST_F(ContextImplTest, VerifyPersistentCookieStore) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL cookie_url(embedded_test_server()->GetURL("/set-cookie?foo=bar")); |
| chromium::web::FramePtr frame = CreateFrame(); |
| |
| chromium::web::NavigationControllerPtr nav; |
| frame->GetNavigationController(nav.NewRequest()); |
| |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, MockableOnNavigationStateChanged(_)) |
| .WillOnce(testing::InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); |
| |
| nav->LoadUrl(cookie_url.spec(), nullptr); |
| run_loop.Run(); |
| } |
| |
| auto cookies = GetCookies(); |
| bool found = false; |
| for (auto c : cookies) { |
| if (c.Name() == "foo" && c.Value() == "bar") { |
| found = true; |
| break; |
| } |
| } |
| EXPECT_TRUE(found); |
| |
| // Check that the cookie persists beyond the lifetime of the Frame by |
| // releasing the Frame and re-querying the CookieStore. |
| frame.Unbind(); |
| base::RunLoop().RunUntilIdle(); |
| |
| found = false; |
| for (auto c : cookies) { |
| if (c.Name() == "foo" && c.Value() == "bar") { |
| found = true; |
| break; |
| } |
| } |
| EXPECT_TRUE(found); |
| } |
| |
| // Suite for tests which run the BrowserContext in incognito mode (no data |
| // directory). |
| class IncognitoContextImplTest : public ContextImplTest { |
| public: |
| IncognitoContextImplTest() = default; |
| ~IncognitoContextImplTest() override = default; |
| |
| void SetUp() override { |
| base::CommandLine::ForCurrentProcess()->AppendSwitch(kIncognitoSwitch); |
| ContextImplTest::SetUp(); |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(IncognitoContextImplTest); |
| }; |
| |
| // Verify that the browser can be initialized without a persistent data |
| // directory. |
| IN_PROC_BROWSER_TEST_F(IncognitoContextImplTest, NavigateFrame) { |
| chromium::web::FramePtr frame = CreateFrame(); |
| |
| chromium::web::NavigationControllerPtr controller; |
| frame->GetNavigationController(controller.NewRequest()); |
| |
| CheckLoadUrl(url::kAboutBlankURL, url::kAboutBlankURL, false, |
| controller.get()); |
| |
| frame.Unbind(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(IncognitoContextImplTest, VerifyInMemoryCookieStore) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL cookie_url(embedded_test_server()->GetURL("/set-cookie?foo=bar")); |
| chromium::web::FramePtr frame = CreateFrame(); |
| |
| chromium::web::NavigationControllerPtr nav; |
| frame->GetNavigationController(nav.NewRequest()); |
| |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(navigation_observer_, MockableOnNavigationStateChanged(_)) |
| .WillOnce(testing::InvokeWithoutArgs([&run_loop] { run_loop.Quit(); })); |
| |
| nav->LoadUrl(cookie_url.spec(), nullptr); |
| run_loop.Run(); |
| } |
| |
| auto cookies = GetCookies(); |
| bool found = false; |
| for (auto c : cookies) { |
| if (c.Name() == "foo" && c.Value() == "bar") { |
| found = true; |
| break; |
| } |
| } |
| EXPECT_TRUE(found); |
| } |
| |
| } // namespace webrunner |