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/files/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/server_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 class DummyServerSocket : public net::ServerSocket { 27 public: 28 DummyServerSocket() {} 29 30 // net::ServerSocket "implementation" 31 virtual int Listen(const net::IPEndPoint& address, int backlog) OVERRIDE { 32 return net::OK; 33 } 34 35 virtual int ListenWithAddressAndPort(const std::string& ip_address, 36 int port, 37 int backlog) OVERRIDE { 38 return net::OK; 39 } 40 41 virtual int GetLocalAddress(net::IPEndPoint* address) const OVERRIDE { 42 net::IPAddressNumber number; 43 EXPECT_TRUE(net::ParseIPLiteralToNumber("127.0.0.1", &number)); 44 *address = net::IPEndPoint(number, kDummyPort); 45 return net::OK; 46 } 47 48 virtual int Accept(scoped_ptr<net::StreamSocket>* socket, 49 const net::CompletionCallback& callback) OVERRIDE { 50 return net::ERR_IO_PENDING; 51 } 52 }; 53 54 class DummyServerSocketFactory 55 : public DevToolsHttpHandler::ServerSocketFactory { 56 public: 57 DummyServerSocketFactory(base::Closure quit_closure_1, 58 base::Closure quit_closure_2) 59 : DevToolsHttpHandler::ServerSocketFactory("", 0, 0), 60 quit_closure_1_(quit_closure_1), 61 quit_closure_2_(quit_closure_2) {} 62 63 virtual ~DummyServerSocketFactory() { 64 BrowserThread::PostTask( 65 BrowserThread::UI, FROM_HERE, quit_closure_2_); 66 } 67 68 private: 69 virtual scoped_ptr<net::ServerSocket> Create() const OVERRIDE { 70 BrowserThread::PostTask( 71 BrowserThread::UI, FROM_HERE, quit_closure_1_); 72 return scoped_ptr<net::ServerSocket>(new DummyServerSocket()); 73 } 74 75 base::Closure quit_closure_1_; 76 base::Closure quit_closure_2_; 77 }; 78 79 class DummyDelegate : public DevToolsHttpHandlerDelegate { 80 public: 81 virtual std::string GetDiscoveryPageHTML() OVERRIDE { return std::string(); } 82 83 virtual bool BundlesFrontendResources() OVERRIDE { return true; } 84 85 virtual base::FilePath GetDebugFrontendDir() OVERRIDE { 86 return base::FilePath(); 87 } 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 104 protected: 105 virtual void SetUp() { 106 file_thread_.reset(new BrowserThreadImpl(BrowserThread::FILE)); 107 file_thread_->Start(); 108 } 109 110 virtual void TearDown() { 111 file_thread_->Stop(); 112 } 113 114 private: 115 base::MessageLoopForIO message_loop_; 116 BrowserThreadImpl ui_thread_; 117 scoped_ptr<BrowserThreadImpl> file_thread_; 118 }; 119 120 TEST_F(DevToolsHttpHandlerTest, TestStartStop) { 121 base::RunLoop run_loop, run_loop_2; 122 scoped_ptr<DevToolsHttpHandler::ServerSocketFactory> factory( 123 new DummyServerSocketFactory(run_loop.QuitClosure(), 124 run_loop_2.QuitClosure())); 125 content::DevToolsHttpHandler* devtools_http_handler_ = 126 content::DevToolsHttpHandler::Start(factory.Pass(), 127 std::string(), 128 new DummyDelegate(), 129 base::FilePath()); 130 // Our dummy socket factory will post a quit message once the server will 131 // become ready. 132 run_loop.Run(); 133 devtools_http_handler_->Stop(); 134 // Make sure the handler actually stops. 135 run_loop_2.Run(); 136 } 137 138 TEST_F(DevToolsHttpHandlerTest, TestDevToolsActivePort) { 139 base::RunLoop run_loop, run_loop_2; 140 base::ScopedTempDir temp_dir; 141 EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); 142 scoped_ptr<DevToolsHttpHandler::ServerSocketFactory> factory( 143 new DummyServerSocketFactory(run_loop.QuitClosure(), 144 run_loop_2.QuitClosure())); 145 content::DevToolsHttpHandler* devtools_http_handler_ = 146 content::DevToolsHttpHandler::Start(factory.Pass(), 147 std::string(), 148 new DummyDelegate(), 149 temp_dir.path()); 150 // Our dummy socket factory will post a quit message once the server will 151 // become ready. 152 run_loop.Run(); 153 devtools_http_handler_->Stop(); 154 // Make sure the handler actually stops. 155 run_loop_2.Run(); 156 157 // Now make sure the DevToolsActivePort was written into the 158 // temporary directory and its contents are as expected. 159 base::FilePath active_port_file = temp_dir.path().Append( 160 kDevToolsActivePortFileName); 161 EXPECT_TRUE(base::PathExists(active_port_file)); 162 std::string file_contents; 163 EXPECT_TRUE(base::ReadFileToString(active_port_file, &file_contents)); 164 int port = 0; 165 EXPECT_TRUE(base::StringToInt(file_contents, &port)); 166 EXPECT_EQ(kDummyPort, port); 167 } 168 169 } // namespace content 170