1 // Copyright 2013 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/command_line.h" 7 #include "base/files/file_path.h" 8 #include "chrome/browser/extensions/api/cast_channel/cast_channel_api.h" 9 #include "chrome/browser/extensions/api/cast_channel/cast_socket.h" 10 #include "chrome/browser/extensions/extension_apitest.h" 11 #include "chrome/browser/extensions/extension_service.h" 12 #include "chrome/common/extensions/api/cast_channel.h" 13 #include "content/public/browser/browser_thread.h" 14 #include "extensions/common/switches.h" 15 #include "net/base/capturing_net_log.h" 16 #include "net/base/completion_callback.h" 17 #include "net/base/net_errors.h" 18 #include "testing/gmock/include/gmock/gmock.h" 19 #include "testing/gmock_mutant.h" 20 21 namespace cast_channel = extensions::api::cast_channel; 22 using cast_channel::CastSocket; 23 using cast_channel::ChannelError; 24 using cast_channel::MessageInfo; 25 using cast_channel::ReadyState; 26 27 using ::testing::_; 28 using ::testing::A; 29 using ::testing::DoAll; 30 using ::testing::Invoke; 31 using ::testing::InSequence; 32 using ::testing::Return; 33 34 namespace { 35 36 const char kTestExtensionId[] = "ddchlicdkolnonkihahngkmmmjnjlkkf"; 37 38 static void FillMessageInfo(MessageInfo* message_info, 39 const std::string& message) { 40 message_info->namespace_ = "foo"; 41 message_info->source_id = "src"; 42 message_info->destination_id = "dest"; 43 message_info->data.reset(new base::StringValue(message)); 44 } 45 46 ACTION_TEMPLATE(InvokeCompletionCallback, 47 HAS_1_TEMPLATE_PARAMS(int, k), 48 AND_1_VALUE_PARAMS(result)) { 49 ::std::tr1::get<k>(args).Run(result); 50 } 51 52 ACTION_P2(InvokeDelegateOnError, api_test, api) { 53 api_test->CallOnError(api); 54 } 55 56 class MockCastSocket : public CastSocket { 57 public: 58 explicit MockCastSocket(CastSocket::Delegate* delegate, 59 net::IPEndPoint ip_endpoint, 60 net::NetLog* net_log) 61 : CastSocket(kTestExtensionId, ip_endpoint, 62 cast_channel::CHANNEL_AUTH_TYPE_SSL, delegate, net_log) {} 63 virtual ~MockCastSocket() {} 64 65 virtual bool CalledOnValidThread() const OVERRIDE { 66 // Always return true in testing. 67 return true; 68 } 69 70 MOCK_METHOD1(Connect, void(const net::CompletionCallback& callback)); 71 MOCK_METHOD2(SendMessage, void(const MessageInfo& message, 72 const net::CompletionCallback& callback)); 73 MOCK_METHOD1(Close, void(const net::CompletionCallback& callback)); 74 MOCK_CONST_METHOD0(ready_state, cast_channel::ReadyState()); 75 MOCK_CONST_METHOD0(error_state, cast_channel::ChannelError()); 76 }; 77 78 } // namespace 79 80 class CastChannelAPITest : public ExtensionApiTest { 81 public: 82 CastChannelAPITest() {} 83 84 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 85 ExtensionApiTest::SetUpCommandLine(command_line); 86 command_line->AppendSwitchASCII( 87 extensions::switches::kWhitelistedExtensionID, 88 kTestExtensionId); 89 } 90 91 void SetUpMockCastSocket() { 92 extensions::CastChannelAPI* api = GetApi(); 93 net::IPAddressNumber ip_number; 94 net::ParseIPLiteralToNumber("192.168.1.1", &ip_number); 95 net::IPEndPoint ip_endpoint(ip_number, 8009); 96 mock_cast_socket_ = new MockCastSocket(api, ip_endpoint, 97 &capturing_net_log_); 98 // Transfers ownership of the socket. 99 api->SetSocketForTest( 100 make_scoped_ptr<CastSocket>(mock_cast_socket_).Pass()); 101 102 // Set expectations on error_state(). 103 EXPECT_CALL(*mock_cast_socket_, error_state()) 104 .WillRepeatedly(Return(cast_channel::CHANNEL_ERROR_NONE)); 105 } 106 107 extensions::CastChannelAPI* GetApi() { 108 return extensions::CastChannelAPI::Get(profile()); 109 } 110 111 void CallOnError(extensions::CastChannelAPI* api) { 112 api->OnError(mock_cast_socket_, 113 cast_channel::CHANNEL_ERROR_CONNECT_ERROR); 114 } 115 116 protected: 117 void CallOnMessage(const std::string& message) { 118 content::BrowserThread::PostTask( 119 content::BrowserThread::IO, 120 FROM_HERE, 121 base::Bind(&CastChannelAPITest::DoCallOnMessage, this, 122 GetApi(), mock_cast_socket_, message)); 123 } 124 125 void DoCallOnMessage(extensions::CastChannelAPI* api, 126 MockCastSocket* cast_socket, 127 const std::string& message) { 128 MessageInfo message_info; 129 FillMessageInfo(&message_info, message); 130 api->OnMessage(cast_socket, message_info); 131 } 132 133 MockCastSocket* mock_cast_socket_; 134 net::CapturingNetLog capturing_net_log_; 135 }; 136 137 // TODO(munjal): Win Dbg has a workaround that makes RunExtensionSubtest 138 // always return true without actually running the test. Remove when fixed. 139 #if defined(OS_WIN) && !defined(NDEBUG) 140 #define MAYBE_TestOpenSendClose DISABLED_TestOpenSendClose 141 #else 142 #define MAYBE_TestOpenSendClose TestOpenSendClose 143 #endif 144 // Test loading extension, opening a channel with ConnectInfo, adding a 145 // listener, writing, reading, and closing. 146 IN_PROC_BROWSER_TEST_F(CastChannelAPITest, MAYBE_TestOpenSendClose) { 147 SetUpMockCastSocket(); 148 149 { 150 InSequence dummy; 151 EXPECT_CALL(*mock_cast_socket_, Connect(_)) 152 .WillOnce(InvokeCompletionCallback<0>(net::OK)); 153 EXPECT_CALL(*mock_cast_socket_, ready_state()) 154 .WillOnce(Return(cast_channel::READY_STATE_OPEN)); 155 EXPECT_CALL(*mock_cast_socket_, SendMessage(A<const MessageInfo&>(), _)) 156 .WillOnce(InvokeCompletionCallback<1>(net::OK)); 157 EXPECT_CALL(*mock_cast_socket_, ready_state()) 158 .WillOnce(Return(cast_channel::READY_STATE_OPEN)); 159 EXPECT_CALL(*mock_cast_socket_, Close(_)) 160 .WillOnce(InvokeCompletionCallback<0>(net::OK)); 161 EXPECT_CALL(*mock_cast_socket_, ready_state()) 162 .WillOnce(Return(cast_channel::READY_STATE_CLOSED)); 163 } 164 165 EXPECT_TRUE(RunExtensionSubtest("cast_channel/api", 166 "test_open_send_close.html")); 167 } 168 169 // TODO(munjal): Win Dbg has a workaround that makes RunExtensionSubtest 170 // always return true without actually running the test. Remove when fixed. 171 #if defined(OS_WIN) && !defined(NDEBUG) 172 #define MAYBE_TestOpenSendCloseWithUrl DISABLED_TestOpenSendCloseWithUrl 173 #else 174 #define MAYBE_TestOpenSendCloseWithUrl TestOpenSendCloseWithUrl 175 #endif 176 // Test loading extension, opening a channel with a URL, adding a listener, 177 // writing, reading, and closing. 178 IN_PROC_BROWSER_TEST_F(CastChannelAPITest, MAYBE_TestOpenSendCloseWithUrl) { 179 SetUpMockCastSocket(); 180 181 { 182 InSequence dummy; 183 EXPECT_CALL(*mock_cast_socket_, Connect(_)) 184 .WillOnce(InvokeCompletionCallback<0>(net::OK)); 185 EXPECT_CALL(*mock_cast_socket_, ready_state()) 186 .WillOnce(Return(cast_channel::READY_STATE_OPEN)); 187 EXPECT_CALL(*mock_cast_socket_, SendMessage(A<const MessageInfo&>(), _)) 188 .WillOnce(InvokeCompletionCallback<1>(net::OK)); 189 EXPECT_CALL(*mock_cast_socket_, ready_state()) 190 .WillOnce(Return(cast_channel::READY_STATE_OPEN)); 191 EXPECT_CALL(*mock_cast_socket_, Close(_)) 192 .WillOnce(InvokeCompletionCallback<0>(net::OK)); 193 EXPECT_CALL(*mock_cast_socket_, ready_state()) 194 .WillOnce(Return(cast_channel::READY_STATE_CLOSED)); 195 } 196 197 EXPECT_TRUE(RunExtensionSubtest("cast_channel/api", 198 "test_open_send_close_url.html")); 199 } 200 201 // TODO(munjal): Win Dbg has a workaround that makes RunExtensionSubtest 202 // always return true without actually running the test. Remove when fixed. 203 #if defined(OS_WIN) && !defined(NDEBUG) 204 #define MAYBE_TestOpenReceiveClose DISABLED_TestOpenReceiveClose 205 #else 206 #define MAYBE_TestOpenReceiveClose TestOpenReceiveClose 207 #endif 208 // Test loading extension, opening a channel, adding a listener, 209 // writing, reading, and closing. 210 IN_PROC_BROWSER_TEST_F(CastChannelAPITest, MAYBE_TestOpenReceiveClose) { 211 SetUpMockCastSocket(); 212 213 { 214 InSequence dummy; 215 EXPECT_CALL(*mock_cast_socket_, Connect(_)) 216 .WillOnce(InvokeCompletionCallback<0>(net::OK)); 217 EXPECT_CALL(*mock_cast_socket_, ready_state()) 218 .Times(3) 219 .WillRepeatedly(Return(cast_channel::READY_STATE_OPEN)); 220 EXPECT_CALL(*mock_cast_socket_, Close(_)) 221 .WillOnce(InvokeCompletionCallback<0>(net::OK)); 222 EXPECT_CALL(*mock_cast_socket_, ready_state()) 223 .WillOnce(Return(cast_channel::READY_STATE_CLOSED)); 224 } 225 226 EXPECT_TRUE(RunExtensionSubtest("cast_channel/api", 227 "test_open_receive_close.html")); 228 229 ResultCatcher catcher; 230 CallOnMessage("some-message"); 231 CallOnMessage("some-message"); 232 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 233 } 234 235 // TODO(munjal): Win Dbg has a workaround that makes RunExtensionSubtest 236 // always return true without actually running the test. Remove when fixed. 237 #if defined(OS_WIN) && !defined(NDEBUG) 238 #define MAYBE_TestOpenError DISABLED_TestOpenError 239 #else 240 #define MAYBE_TestOpenError TestOpenError 241 #endif 242 // Test the case when socket open results in an error. 243 IN_PROC_BROWSER_TEST_F(CastChannelAPITest, MAYBE_TestOpenError) { 244 SetUpMockCastSocket(); 245 246 EXPECT_CALL(*mock_cast_socket_, Connect(_)) 247 .WillOnce(DoAll( 248 InvokeDelegateOnError(this, GetApi()), 249 InvokeCompletionCallback<0>(net::ERR_FAILED))); 250 EXPECT_CALL(*mock_cast_socket_, ready_state()) 251 .WillRepeatedly(Return(cast_channel::READY_STATE_CLOSED)); 252 EXPECT_CALL(*mock_cast_socket_, Close(_)); 253 254 EXPECT_TRUE(RunExtensionSubtest("cast_channel/api", 255 "test_open_error.html")); 256 257 ResultCatcher catcher; 258 EXPECT_TRUE(catcher.GetNextResult()) << catcher.message(); 259 } 260 261