1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/bind.h"
6 #include "base/callback.h"
7 #include "base/check_op.h"
8 #include "base/test/scoped_run_loop_timeout.h"
9 #include "chromecast/base/chromecast_switches.h"
10 #include "chromecast/browser/cast_browser_process.h"
11 #include "chromecast/browser/extensions/cast_extension_system_factory.h"
12 #include "chromecast/browser/webview/webview_controller.h"
13 #include "components/keyed_service/content/browser_context_dependency_manager.h"
14 #include "content/public/common/content_switches.h"
15 #include "content/public/test/browser_test.h"
16 #include "content/public/test/browser_test_base.h"
17 #include "content/public/test/test_browser_context.h"
18 #include "content/public/test/web_contents_tester.h"
19 #include "net/dns/mock_host_resolver.h"
20 #include "net/http/http_status_code.h"
21 #include "net/test/embedded_test_server/http_request.h"
22 #include "net/test/embedded_test_server/http_response.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 using testing::_;
27 using testing::Truly;
28 
29 namespace chromecast {
30 namespace {
31 constexpr base::TimeDelta kDefaultTimeout =
32     base::TimeDelta::FromMilliseconds(5000);
33 }
34 
35 class MockClient : public WebviewController::Client {
36  public:
37   MOCK_METHOD(void,
38               EnqueueSend,
39               (std::unique_ptr<webview::WebviewResponse> response));
40   MOCK_METHOD(void, OnError, (const std::string& error_message));
41 };
42 
43 class WebviewTest : public content::BrowserTestBase {
44  protected:
45   WebviewTest() = default;
46   ~WebviewTest() override = default;
47 
PreRunTestOnMainThread()48   void PreRunTestOnMainThread() override {
49     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
50     base::RunLoop().RunUntilIdle();
51 
52     context_ = std::make_unique<content::TestBrowserContext>();
53     run_loop_.reset(new base::RunLoop());
54   }
SetUp()55   void SetUp() final {
56     SetUpCommandLine(base::CommandLine::ForCurrentProcess());
57     embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
58         &WebviewTest::HandleRequest, base::Unretained(this)));
59     ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
60     BrowserTestBase::SetUp();
61   }
SetUpOnMainThread()62   void SetUpOnMainThread() final {
63     host_resolver()->AddRule("*", "127.0.0.1");
64     embedded_test_server()->StartAcceptingConnections();
65   }
TearDownOnMainThread()66   void TearDownOnMainThread() final {
67     BrowserContextDependencyManager::GetInstance()
68         ->DestroyBrowserContextServices(context_.get());
69     context_.reset();
70   }
SetUpCommandLine(base::CommandLine * command_line)71   void SetUpCommandLine(base::CommandLine* command_line) final {
72     command_line->AppendSwitchASCII(switches::kTestType, "browser");
73   }
RunTestOnMainThread()74   void RunTestOnMainThread() override {}
PostRunTestOnMainThread()75   void PostRunTestOnMainThread() override {}
76 
RunMessageLoop()77   void RunMessageLoop() {
78     base::test::ScopedRunLoopTimeout timeout(
79         FROM_HERE, kDefaultTimeout,
80         base::BindRepeating(&WebviewTest::OnTimeout, base::Unretained(this)));
81     run_loop_->Run();
82   }
83 
HandleRequest(const net::test_server::HttpRequest & request)84   std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
85       const net::test_server::HttpRequest& request) {
86     GURL absolute_url = embedded_test_server()->GetURL(request.relative_url);
87     if (absolute_url.path() != "/test")
88       return std::unique_ptr<net::test_server::HttpResponse>();
89 
90     auto http_response =
91         std::make_unique<net::test_server::BasicHttpResponse>();
92     http_response->set_code(net::HTTP_OK);
93     http_response->set_content("hello");
94     http_response->set_content_type("text/plain");
95     return http_response;
96   }
97 
OnTimeout()98   std::string OnTimeout() {
99     Quit();
100     return "Timeout in webview browsertest";
101   }
102 
Quit()103   void Quit() { run_loop_->QuitWhenIdle(); }
104 
105   std::unique_ptr<content::TestBrowserContext> context_;
106   std::unique_ptr<base::RunLoop> run_loop_;
107   MockClient client_;
108 };
109 
IN_PROC_BROWSER_TEST_F(WebviewTest,Navigate)110 IN_PROC_BROWSER_TEST_F(WebviewTest, Navigate) {
111   auto check = [](const std::unique_ptr<webview::WebviewResponse>& response) {
112     return response->has_page_event() &&
113            response->page_event().current_page_state() ==
114                webview::AsyncPageEvent_State_LOADED;
115   };
116   EXPECT_CALL(client_, EnqueueSend(_)).Times(testing::AnyNumber());
117   EXPECT_CALL(client_, EnqueueSend(Truly(check)))
118       .Times(testing::AtLeast(1))
119       .WillOnce([this](std::unique_ptr<webview::WebviewResponse> response) {
120         Quit();
121       });
122   WebviewController webview(context_.get(), &client_, true);
123 
124   GURL test_url = embedded_test_server()->GetURL("foo.com", "/test");
125 
126   webview::WebviewRequest nav;
127   nav.mutable_navigate()->set_url(test_url.spec());
128   webview.ProcessRequest(nav);
129 
130   RunMessageLoop();
131 }
132 
133 }  // namespace chromecast
134