1 // Copyright (c) 2012 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.
5 #include "base/basictypes.h"
6 #include "base/location.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "base/time/time.h"
11 #include "content/browser/devtools/devtools_manager.h"
12 #include "content/browser/devtools/shared_worker_devtools_manager.h"
13 #include "content/browser/shared_worker/shared_worker_instance.h"
14 #include "content/browser/shared_worker/worker_storage_partition.h"
15 #include "content/common/view_messages.h"
16 #include "content/public/browser/browser_context.h"
17 #include "content/public/browser/content_browser_client.h"
18 #include "content/public/browser/devtools_agent_host.h"
19 #include "content/public/browser/devtools_external_agent_proxy.h"
20 #include "content/public/browser/devtools_external_agent_proxy_delegate.h"
21 #include "content/public/browser/web_contents_delegate.h"
22 #include "content/public/test/test_utils.h"
23 #include "content/test/test_content_browser_client.h"
24 #include "content/test/test_render_view_host.h"
25 #include "content/test/test_web_contents.h"
26 #include "testing/gtest/include/gtest/gtest.h"
28 using base::TimeDelta
;
33 class TestDevToolsClientHost
: public DevToolsAgentHostClient
{
35 TestDevToolsClientHost()
36 : last_sent_message(NULL
),
40 ~TestDevToolsClientHost() override
{ EXPECT_TRUE(closed_
); }
43 EXPECT_FALSE(closed_
);
45 agent_host_
->DetachClient();
49 void AgentHostClosed(DevToolsAgentHost
* agent_host
, bool replaced
) override
{
53 void DispatchProtocolMessage(DevToolsAgentHost
* agent_host
,
54 const std::string
& message
) override
{
55 last_sent_message
= &message
;
58 void InspectAgentHost(DevToolsAgentHost
* agent_host
) {
59 agent_host_
= agent_host
;
60 agent_host_
->AttachClient(this);
63 DevToolsAgentHost
* agent_host() { return agent_host_
.get(); }
65 static void ResetCounters() {
69 static int close_counter
;
71 const std::string
* last_sent_message
;
75 scoped_refptr
<DevToolsAgentHost
> agent_host_
;
77 DISALLOW_COPY_AND_ASSIGN(TestDevToolsClientHost
);
80 int TestDevToolsClientHost::close_counter
= 0;
83 class TestWebContentsDelegate
: public WebContentsDelegate
{
85 TestWebContentsDelegate() : renderer_unresponsive_received_(false) {}
87 // Notification that the contents is hung.
88 void RendererUnresponsive(WebContents
* source
) override
{
89 renderer_unresponsive_received_
= true;
92 bool renderer_unresponsive_received() const {
93 return renderer_unresponsive_received_
;
97 bool renderer_unresponsive_received_
;
102 class DevToolsManagerTest
: public RenderViewHostImplTestHarness
{
104 DevToolsManagerTest() {}
107 void SetUp() override
{
108 RenderViewHostImplTestHarness::SetUp();
109 TestDevToolsClientHost::ResetCounters();
113 TEST_F(DevToolsManagerTest
, OpenAndManuallyCloseDevToolsClientHost
) {
114 scoped_refptr
<DevToolsAgentHost
> agent(
115 DevToolsAgentHost::GetOrCreateFor(web_contents()));
116 EXPECT_FALSE(agent
->IsAttached());
118 TestDevToolsClientHost client_host
;
119 client_host
.InspectAgentHost(agent
.get());
120 // Test that the connection is established.
121 EXPECT_TRUE(agent
->IsAttached());
122 EXPECT_EQ(0, TestDevToolsClientHost::close_counter
);
125 EXPECT_EQ(1, TestDevToolsClientHost::close_counter
);
126 EXPECT_FALSE(agent
->IsAttached());
129 TEST_F(DevToolsManagerTest
, NoUnresponsiveDialogInInspectedContents
) {
130 const GURL
url("http://www.google.com");
131 contents()->NavigateAndCommit(url
);
132 TestRenderViewHost
* inspected_rvh
= test_rvh();
133 EXPECT_TRUE(inspected_rvh
->IsRenderViewLive());
134 EXPECT_FALSE(contents()->GetDelegate());
135 TestWebContentsDelegate delegate
;
136 contents()->SetDelegate(&delegate
);
138 TestDevToolsClientHost client_host
;
139 scoped_refptr
<DevToolsAgentHost
> agent_host(DevToolsAgentHost::GetOrCreateFor(
140 WebContents::FromRenderViewHost(inspected_rvh
)));
141 client_host
.InspectAgentHost(agent_host
.get());
143 // Start with a short timeout.
144 inspected_rvh
->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(10));
145 // Wait long enough for first timeout and see if it fired.
146 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
147 FROM_HERE
, base::MessageLoop::QuitClosure(),
148 TimeDelta::FromMilliseconds(10));
149 base::MessageLoop::current()->Run();
150 EXPECT_FALSE(delegate
.renderer_unresponsive_received());
152 // Now close devtools and check that the notification is delivered.
154 // Start with a short timeout.
155 inspected_rvh
->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(10));
156 // Wait long enough for first timeout and see if it fired.
157 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
158 FROM_HERE
, base::MessageLoop::QuitClosure(),
159 TimeDelta::FromMilliseconds(10));
160 base::MessageLoop::current()->Run();
161 EXPECT_TRUE(delegate
.renderer_unresponsive_received());
163 contents()->SetDelegate(NULL
);
166 TEST_F(DevToolsManagerTest
, ReattachOnCancelPendingNavigation
) {
167 // Navigate to URL. First URL should use first RenderViewHost.
168 const GURL
url("http://www.google.com");
169 controller().LoadURL(
170 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
171 int pending_id
= controller().GetPendingEntry()->GetUniqueID();
172 contents()->GetMainFrame()->PrepareForCommit();
173 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, pending_id
, true,
174 url
, ui::PAGE_TRANSITION_TYPED
);
175 contents()->GetMainFrame()->SimulateNavigationStop();
176 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
178 TestDevToolsClientHost client_host
;
179 client_host
.InspectAgentHost(
180 DevToolsAgentHost::GetOrCreateFor(web_contents()).get());
182 // Navigate to new site which should get a new RenderViewHost.
183 const GURL
url2("http://www.yahoo.com");
184 controller().LoadURL(
185 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
186 contents()->GetMainFrame()->PrepareForCommit();
187 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
188 EXPECT_EQ(client_host
.agent_host(),
189 DevToolsAgentHost::GetOrCreateFor(web_contents()).get());
191 // Interrupt pending navigation and navigate back to the original site.
192 controller().LoadURL(
193 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
194 pending_id
= controller().GetPendingEntry()->GetUniqueID();
195 contents()->GetMainFrame()->PrepareForCommit();
196 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, pending_id
, false,
197 url
, ui::PAGE_TRANSITION_TYPED
);
198 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
199 EXPECT_EQ(client_host
.agent_host(),
200 DevToolsAgentHost::GetOrCreateFor(web_contents()).get());
204 class TestExternalAgentDelegate
: public DevToolsExternalAgentProxyDelegate
{
205 std::map
<std::string
,int> event_counter_
;
207 void recordEvent(const std::string
& name
) {
208 if (event_counter_
.find(name
) == event_counter_
.end())
209 event_counter_
[name
] = 0;
210 event_counter_
[name
] = event_counter_
[name
] + 1;
213 void expectEvent(int count
, const std::string
& name
) {
214 EXPECT_EQ(count
, event_counter_
[name
]);
217 void Attach(DevToolsExternalAgentProxy
* proxy
) override
{
218 recordEvent("Attach");
221 void Detach() override
{ recordEvent("Detach"); };
223 void SendMessageToBackend(const std::string
& message
) override
{
224 recordEvent(std::string("SendMessageToBackend.") + message
);
228 ~TestExternalAgentDelegate() override
{
229 expectEvent(1, "Attach");
230 expectEvent(1, "Detach");
231 expectEvent(0, "SendMessageToBackend.message0");
232 expectEvent(1, "SendMessageToBackend.message1");
233 expectEvent(2, "SendMessageToBackend.message2");
237 TEST_F(DevToolsManagerTest
, TestExternalProxy
) {
238 TestExternalAgentDelegate
* delegate
= new TestExternalAgentDelegate();
240 scoped_refptr
<DevToolsAgentHost
> agent_host
=
241 DevToolsAgentHost::Create(delegate
);
242 EXPECT_EQ(agent_host
, DevToolsAgentHost::GetForId(agent_host
->GetId()));
244 TestDevToolsClientHost client_host
;
245 client_host
.InspectAgentHost(agent_host
.get());
246 agent_host
->DispatchProtocolMessage("message1");
247 agent_host
->DispatchProtocolMessage("message2");
248 agent_host
->DispatchProtocolMessage("message2");
253 } // namespace content