Home | History | Annotate | Download | only in devtools
      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.
      4 
      5 #include "base/basictypes.h"
      6 #include "base/memory/scoped_ptr.h"
      7 #include "base/time/time.h"
      8 #include "content/browser/devtools/devtools_manager.h"
      9 #include "content/browser/devtools/render_view_devtools_agent_host.h"
     10 #include "content/common/view_messages.h"
     11 #include "content/public/browser/content_browser_client.h"
     12 #include "content/public/browser/devtools_agent_host.h"
     13 #include "content/public/browser/devtools_external_agent_proxy.h"
     14 #include "content/public/browser/devtools_external_agent_proxy_delegate.h"
     15 #include "content/public/browser/web_contents_delegate.h"
     16 #include "content/test/test_content_browser_client.h"
     17 #include "content/test/test_render_view_host.h"
     18 #include "content/test/test_web_contents.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 using base::TimeDelta;
     22 
     23 namespace content {
     24 namespace {
     25 
     26 class TestDevToolsClientHost : public DevToolsAgentHostClient {
     27  public:
     28   TestDevToolsClientHost()
     29       : last_sent_message(NULL),
     30         closed_(false) {
     31   }
     32 
     33   virtual ~TestDevToolsClientHost() {
     34     EXPECT_TRUE(closed_);
     35   }
     36 
     37   void Close() {
     38     EXPECT_FALSE(closed_);
     39     close_counter++;
     40     agent_host_->DetachClient();
     41     closed_ = true;
     42   }
     43 
     44   virtual void AgentHostClosed(
     45       DevToolsAgentHost* agent_host, bool replaced) OVERRIDE {
     46     FAIL();
     47   }
     48 
     49   virtual void DispatchProtocolMessage(
     50       DevToolsAgentHost* agent_host, const std::string& message) OVERRIDE {
     51     last_sent_message = &message;
     52   }
     53 
     54   void InspectAgentHost(DevToolsAgentHost* agent_host) {
     55     agent_host_ = agent_host;
     56     agent_host_->AttachClient(this);
     57   }
     58 
     59   DevToolsAgentHost* agent_host() { return agent_host_.get(); }
     60 
     61   static void ResetCounters() {
     62     close_counter = 0;
     63   }
     64 
     65   static int close_counter;
     66 
     67   const std::string* last_sent_message;
     68 
     69  private:
     70   bool closed_;
     71   scoped_refptr<DevToolsAgentHost> agent_host_;
     72 
     73   DISALLOW_COPY_AND_ASSIGN(TestDevToolsClientHost);
     74 };
     75 
     76 int TestDevToolsClientHost::close_counter = 0;
     77 
     78 
     79 class TestWebContentsDelegate : public WebContentsDelegate {
     80  public:
     81   TestWebContentsDelegate() : renderer_unresponsive_received_(false) {}
     82 
     83   // Notification that the contents is hung.
     84   virtual void RendererUnresponsive(WebContents* source) OVERRIDE {
     85     renderer_unresponsive_received_ = true;
     86   }
     87 
     88   bool renderer_unresponsive_received() const {
     89     return renderer_unresponsive_received_;
     90   }
     91 
     92  private:
     93   bool renderer_unresponsive_received_;
     94 };
     95 
     96 }  // namespace
     97 
     98 class DevToolsManagerTest : public RenderViewHostImplTestHarness {
     99  protected:
    100   virtual void SetUp() OVERRIDE {
    101     RenderViewHostImplTestHarness::SetUp();
    102     TestDevToolsClientHost::ResetCounters();
    103   }
    104 };
    105 
    106 TEST_F(DevToolsManagerTest, OpenAndManuallyCloseDevToolsClientHost) {
    107   scoped_refptr<DevToolsAgentHost> agent(
    108       DevToolsAgentHost::GetOrCreateFor(web_contents()));
    109   EXPECT_FALSE(agent->IsAttached());
    110 
    111   TestDevToolsClientHost client_host;
    112   client_host.InspectAgentHost(agent.get());
    113   // Test that the connection is established.
    114   EXPECT_TRUE(agent->IsAttached());
    115   EXPECT_EQ(0, TestDevToolsClientHost::close_counter);
    116 
    117   client_host.Close();
    118   EXPECT_EQ(1, TestDevToolsClientHost::close_counter);
    119   EXPECT_FALSE(agent->IsAttached());
    120 }
    121 
    122 TEST_F(DevToolsManagerTest, NoUnresponsiveDialogInInspectedContents) {
    123   TestRenderViewHost* inspected_rvh = test_rvh();
    124   inspected_rvh->set_render_view_created(true);
    125   EXPECT_FALSE(contents()->GetDelegate());
    126   TestWebContentsDelegate delegate;
    127   contents()->SetDelegate(&delegate);
    128 
    129   TestDevToolsClientHost client_host;
    130   scoped_refptr<DevToolsAgentHost> agent_host(DevToolsAgentHost::GetOrCreateFor(
    131       WebContents::FromRenderViewHost(inspected_rvh)));
    132   client_host.InspectAgentHost(agent_host.get());
    133 
    134   // Start with a short timeout.
    135   inspected_rvh->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(10));
    136   // Wait long enough for first timeout and see if it fired.
    137   base::MessageLoop::current()->PostDelayedTask(
    138       FROM_HERE,
    139       base::MessageLoop::QuitClosure(),
    140       TimeDelta::FromMilliseconds(10));
    141   base::MessageLoop::current()->Run();
    142   EXPECT_FALSE(delegate.renderer_unresponsive_received());
    143 
    144   // Now close devtools and check that the notification is delivered.
    145   client_host.Close();
    146   // Start with a short timeout.
    147   inspected_rvh->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(10));
    148   // Wait long enough for first timeout and see if it fired.
    149   base::MessageLoop::current()->PostDelayedTask(
    150       FROM_HERE,
    151       base::MessageLoop::QuitClosure(),
    152       TimeDelta::FromMilliseconds(10));
    153   base::MessageLoop::current()->Run();
    154   EXPECT_TRUE(delegate.renderer_unresponsive_received());
    155 
    156   contents()->SetDelegate(NULL);
    157 }
    158 
    159 TEST_F(DevToolsManagerTest, ReattachOnCancelPendingNavigation) {
    160   // Navigate to URL.  First URL should use first RenderViewHost.
    161   const GURL url("http://www.google.com");
    162   controller().LoadURL(
    163       url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    164   contents()->TestDidNavigate(
    165       contents()->GetMainFrame(), 1, url, ui::PAGE_TRANSITION_TYPED);
    166   EXPECT_FALSE(contents()->cross_navigation_pending());
    167 
    168   TestDevToolsClientHost client_host;
    169   client_host.InspectAgentHost(
    170       DevToolsAgentHost::GetOrCreateFor(web_contents()).get());
    171 
    172   // Navigate to new site which should get a new RenderViewHost.
    173   const GURL url2("http://www.yahoo.com");
    174   controller().LoadURL(
    175       url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    176   EXPECT_TRUE(contents()->cross_navigation_pending());
    177   EXPECT_EQ(client_host.agent_host(),
    178             DevToolsAgentHost::GetOrCreateFor(web_contents()).get());
    179 
    180   // Interrupt pending navigation and navigate back to the original site.
    181   controller().LoadURL(
    182       url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
    183   contents()->TestDidNavigate(
    184       contents()->GetMainFrame(), 1, url, ui::PAGE_TRANSITION_TYPED);
    185   EXPECT_FALSE(contents()->cross_navigation_pending());
    186   EXPECT_EQ(client_host.agent_host(),
    187             DevToolsAgentHost::GetOrCreateFor(web_contents()).get());
    188   client_host.Close();
    189 }
    190 
    191 class TestExternalAgentDelegate: public DevToolsExternalAgentProxyDelegate {
    192   std::map<std::string,int> event_counter_;
    193 
    194   void recordEvent(const std::string& name) {
    195     if (event_counter_.find(name) == event_counter_.end())
    196       event_counter_[name] = 0;
    197     event_counter_[name] = event_counter_[name] + 1;
    198   }
    199 
    200   void expectEvent(int count, const std::string& name) {
    201     EXPECT_EQ(count, event_counter_[name]);
    202   }
    203 
    204   virtual void Attach(DevToolsExternalAgentProxy* proxy) OVERRIDE {
    205     recordEvent("Attach");
    206   };
    207 
    208   virtual void Detach() OVERRIDE {
    209     recordEvent("Detach");
    210   };
    211 
    212   virtual void SendMessageToBackend(const std::string& message) OVERRIDE {
    213     recordEvent(std::string("SendMessageToBackend.") + message);
    214   };
    215 
    216  public :
    217   virtual ~TestExternalAgentDelegate() {
    218     expectEvent(1, "Attach");
    219     expectEvent(1, "Detach");
    220     expectEvent(0, "SendMessageToBackend.message0");
    221     expectEvent(1, "SendMessageToBackend.message1");
    222     expectEvent(2, "SendMessageToBackend.message2");
    223   }
    224 };
    225 
    226 TEST_F(DevToolsManagerTest, TestExternalProxy) {
    227   TestExternalAgentDelegate* delegate = new TestExternalAgentDelegate();
    228 
    229   scoped_refptr<DevToolsAgentHost> agent_host =
    230       DevToolsAgentHost::Create(delegate);
    231   EXPECT_EQ(agent_host, DevToolsAgentHost::GetForId(agent_host->GetId()));
    232 
    233   TestDevToolsClientHost client_host;
    234   client_host.InspectAgentHost(agent_host.get());
    235   agent_host->DispatchProtocolMessage("message1");
    236   agent_host->DispatchProtocolMessage("message2");
    237   agent_host->DispatchProtocolMessage("message2");
    238 
    239   client_host.Close();
    240 }
    241 
    242 }  // namespace content
    243