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/file_util.h" 6 #include "base/files/scoped_temp_dir.h" 7 #include "base/message_loop/message_loop.h" 8 #include "base/run_loop.h" 9 #include "base/strings/string_number_conversions.h" 10 #include "content/browser/browser_thread_impl.h" 11 #include "content/public/browser/devtools_http_handler.h" 12 #include "content/public/browser/devtools_http_handler_delegate.h" 13 #include "content/public/browser/devtools_target.h" 14 #include "net/base/ip_endpoint.h" 15 #include "net/base/net_errors.h" 16 #include "net/socket/stream_listen_socket.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 19 namespace content { 20 namespace { 21 22 const int kDummyPort = 4321; 23 const base::FilePath::CharType kDevToolsActivePortFileName[] = 24 FILE_PATH_LITERAL("DevToolsActivePort"); 25 26 using net::StreamListenSocket; 27 28 class DummyListenSocket : public StreamListenSocket, 29 public StreamListenSocket::Delegate { 30 public: 31 DummyListenSocket() 32 : StreamListenSocket(net::kInvalidSocket, this) {} 33 34 // StreamListenSocket::Delegate "implementation" 35 virtual void DidAccept(StreamListenSocket* server, 36 scoped_ptr<StreamListenSocket> connection) OVERRIDE {} 37 virtual void DidRead(StreamListenSocket* connection, 38 const char* data, 39 int len) OVERRIDE {} 40 virtual void DidClose(StreamListenSocket* sock) OVERRIDE {} 41 protected: 42 virtual ~DummyListenSocket() {} 43 virtual void Accept() OVERRIDE {} 44 virtual int GetLocalAddress(net::IPEndPoint* address) OVERRIDE { 45 net::IPAddressNumber number; 46 EXPECT_TRUE(net::ParseIPLiteralToNumber("127.0.0.1", &number)); 47 *address = net::IPEndPoint(number, kDummyPort); 48 return net::OK; 49 } 50 }; 51 52 class DummyListenSocketFactory : public net::StreamListenSocketFactory { 53 public: 54 DummyListenSocketFactory( 55 base::Closure quit_closure_1, base::Closure quit_closure_2) 56 : quit_closure_1_(quit_closure_1), quit_closure_2_(quit_closure_2) {} 57 virtual ~DummyListenSocketFactory() { 58 BrowserThread::PostTask( 59 BrowserThread::UI, FROM_HERE, quit_closure_2_); 60 } 61 62 virtual scoped_ptr<StreamListenSocket> CreateAndListen( 63 StreamListenSocket::Delegate* delegate) const OVERRIDE { 64 BrowserThread::PostTask( 65 BrowserThread::UI, FROM_HERE, quit_closure_1_); 66 return scoped_ptr<net::StreamListenSocket>(new DummyListenSocket()); 67 } 68 private: 69 base::Closure quit_closure_1_; 70 base::Closure quit_closure_2_; 71 }; 72 73 class DummyDelegate : public DevToolsHttpHandlerDelegate { 74 public: 75 virtual std::string GetDiscoveryPageHTML() OVERRIDE { return std::string(); } 76 virtual bool BundlesFrontendResources() OVERRIDE { return true; } 77 virtual base::FilePath GetDebugFrontendDir() OVERRIDE { 78 return base::FilePath(); 79 } 80 virtual std::string GetPageThumbnailData(const GURL& url) OVERRIDE { 81 return std::string(); 82 } 83 virtual scoped_ptr<DevToolsTarget> CreateNewTarget(const GURL& url) OVERRIDE { 84 return scoped_ptr<DevToolsTarget>(); 85 } 86 virtual void EnumerateTargets(TargetCallback callback) OVERRIDE { 87 callback.Run(TargetList()); 88 } 89 virtual scoped_ptr<net::StreamListenSocket> CreateSocketForTethering( 90 net::StreamListenSocket::Delegate* delegate, 91 std::string* name) OVERRIDE { 92 return scoped_ptr<net::StreamListenSocket>(); 93 } 94 }; 95 96 } 97 98 class DevToolsHttpHandlerTest : public testing::Test { 99 public: 100 DevToolsHttpHandlerTest() 101 : ui_thread_(BrowserThread::UI, &message_loop_) { 102 } 103 protected: 104 virtual void SetUp() { 105 file_thread_.reset(new BrowserThreadImpl(BrowserThread::FILE)); 106 file_thread_->Start(); 107 } 108 virtual void TearDown() { 109 file_thread_->Stop(); 110 } 111 private: 112 base::MessageLoopForIO message_loop_; 113 BrowserThreadImpl ui_thread_; 114 scoped_ptr<BrowserThreadImpl> file_thread_; 115 }; 116 117 TEST_F(DevToolsHttpHandlerTest, TestStartStop) { 118 base::RunLoop run_loop, run_loop_2; 119 content::DevToolsHttpHandler* devtools_http_handler_ = 120 content::DevToolsHttpHandler::Start( 121 new DummyListenSocketFactory(run_loop.QuitClosure(), 122 run_loop_2.QuitClosure()), 123 std::string(), 124 new DummyDelegate(), 125 base::FilePath()); 126 // Our dummy socket factory will post a quit message once the server will 127 // become ready. 128 run_loop.Run(); 129 devtools_http_handler_->Stop(); 130 // Make sure the handler actually stops. 131 run_loop_2.Run(); 132 } 133 134 TEST_F(DevToolsHttpHandlerTest, TestDevToolsActivePort) { 135 base::RunLoop run_loop, run_loop_2; 136 base::ScopedTempDir temp_dir; 137 EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); 138 content::DevToolsHttpHandler* devtools_http_handler_ = 139 content::DevToolsHttpHandler::Start( 140 new DummyListenSocketFactory(run_loop.QuitClosure(), 141 run_loop_2.QuitClosure()), 142 std::string(), 143 new DummyDelegate(), 144 temp_dir.path()); 145 // Our dummy socket factory will post a quit message once the server will 146 // become ready. 147 run_loop.Run(); 148 devtools_http_handler_->Stop(); 149 // Make sure the handler actually stops. 150 run_loop_2.Run(); 151 152 // Now make sure the DevToolsActivePort was written into the 153 // temporary directory and its contents are as expected. 154 base::FilePath active_port_file = temp_dir.path().Append( 155 kDevToolsActivePortFileName); 156 EXPECT_TRUE(base::PathExists(active_port_file)); 157 std::string file_contents; 158 EXPECT_TRUE(base::ReadFileToString(active_port_file, &file_contents)); 159 int port = 0; 160 EXPECT_TRUE(base::StringToInt(file_contents, &port)); 161 EXPECT_EQ(kDummyPort, port); 162 } 163 164 } // namespace content 165