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 "jingle/notifier/base/xmpp_connection.h" 6 7 #include <string> 8 #include <vector> 9 10 #include "base/basictypes.h" 11 #include "base/memory/ref_counted.h" 12 #include "base/memory/weak_ptr.h" 13 #include "base/message_loop/message_loop.h" 14 #include "jingle/glue/mock_task.h" 15 #include "jingle/glue/task_pump.h" 16 #include "jingle/notifier/base/weak_xmpp_client.h" 17 #include "net/cert/cert_verifier.h" 18 #include "net/url_request/url_request_context_getter.h" 19 #include "net/url_request/url_request_test_util.h" 20 #include "talk/xmpp/prexmppauth.h" 21 #include "talk/xmpp/xmppclientsettings.h" 22 #include "testing/gmock/include/gmock/gmock.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 25 namespace buzz { 26 class CaptchaChallenge; 27 class Jid; 28 } // namespace buzz 29 30 namespace talk_base { 31 class CryptString; 32 class SocketAddress; 33 class Task; 34 } // namespace talk_base 35 36 namespace notifier { 37 38 using ::testing::_; 39 using ::testing::Return; 40 using ::testing::SaveArg; 41 42 class MockPreXmppAuth : public buzz::PreXmppAuth { 43 public: 44 virtual ~MockPreXmppAuth() {} 45 46 MOCK_METHOD2(ChooseBestSaslMechanism, 47 std::string(const std::vector<std::string>&, bool)); 48 MOCK_METHOD1(CreateSaslMechanism, 49 buzz::SaslMechanism*(const std::string&)); 50 MOCK_METHOD5(StartPreXmppAuth, 51 void(const buzz::Jid&, 52 const talk_base::SocketAddress&, 53 const talk_base::CryptString&, 54 const std::string&, 55 const std::string&)); 56 MOCK_CONST_METHOD0(IsAuthDone, bool()); 57 MOCK_CONST_METHOD0(IsAuthorized, bool()); 58 MOCK_CONST_METHOD0(HadError, bool()); 59 MOCK_CONST_METHOD0(GetError, int()); 60 MOCK_CONST_METHOD0(GetCaptchaChallenge, buzz::CaptchaChallenge()); 61 MOCK_CONST_METHOD0(GetAuthToken, std::string()); 62 MOCK_CONST_METHOD0(GetAuthMechanism, std::string()); 63 }; 64 65 class MockXmppConnectionDelegate : public XmppConnection::Delegate { 66 public: 67 virtual ~MockXmppConnectionDelegate() {} 68 69 MOCK_METHOD1(OnConnect, void(base::WeakPtr<buzz::XmppTaskParentInterface>)); 70 MOCK_METHOD3(OnError, 71 void(buzz::XmppEngine::Error, int, const buzz::XmlElement*)); 72 }; 73 74 class XmppConnectionTest : public testing::Test { 75 protected: 76 XmppConnectionTest() 77 : mock_pre_xmpp_auth_(new MockPreXmppAuth()), 78 url_request_context_getter_(new net::TestURLRequestContextGetter( 79 message_loop_.message_loop_proxy())) {} 80 81 virtual ~XmppConnectionTest() {} 82 83 virtual void TearDown() { 84 // Clear out any messages posted by XmppConnection's destructor. 85 message_loop_.RunUntilIdle(); 86 } 87 88 // Needed by XmppConnection. 89 base::MessageLoop message_loop_; 90 MockXmppConnectionDelegate mock_xmpp_connection_delegate_; 91 scoped_ptr<MockPreXmppAuth> mock_pre_xmpp_auth_; 92 scoped_refptr<net::TestURLRequestContextGetter> url_request_context_getter_; 93 }; 94 95 TEST_F(XmppConnectionTest, CreateDestroy) { 96 XmppConnection xmpp_connection(buzz::XmppClientSettings(), 97 url_request_context_getter_, 98 &mock_xmpp_connection_delegate_, NULL); 99 } 100 101 #if !defined(_MSC_VER) || _MSC_VER < 1700 // http://crbug.com/158570 102 TEST_F(XmppConnectionTest, ImmediateFailure) { 103 // ChromeAsyncSocket::Connect() will always return false since we're 104 // not setting a valid host, but this gets bubbled up as ERROR_NONE 105 // due to XmppClient's inconsistent error-handling. 106 EXPECT_CALL(mock_xmpp_connection_delegate_, 107 OnError(buzz::XmppEngine::ERROR_NONE, 0, NULL)); 108 109 XmppConnection xmpp_connection(buzz::XmppClientSettings(), 110 url_request_context_getter_, 111 &mock_xmpp_connection_delegate_, NULL); 112 113 // We need to do this *before* |xmpp_connection| gets destroyed or 114 // our delegate won't be called. 115 message_loop_.RunUntilIdle(); 116 } 117 118 TEST_F(XmppConnectionTest, PreAuthFailure) { 119 EXPECT_CALL(*mock_pre_xmpp_auth_, StartPreXmppAuth(_, _, _, _,_)); 120 EXPECT_CALL(*mock_pre_xmpp_auth_, IsAuthDone()).WillOnce(Return(true)); 121 EXPECT_CALL(*mock_pre_xmpp_auth_, IsAuthorized()).WillOnce(Return(false)); 122 EXPECT_CALL(*mock_pre_xmpp_auth_, HadError()).WillOnce(Return(true)); 123 EXPECT_CALL(*mock_pre_xmpp_auth_, GetError()).WillOnce(Return(5)); 124 125 EXPECT_CALL(mock_xmpp_connection_delegate_, 126 OnError(buzz::XmppEngine::ERROR_AUTH, 5, NULL)); 127 128 XmppConnection xmpp_connection( 129 buzz::XmppClientSettings(), url_request_context_getter_, 130 &mock_xmpp_connection_delegate_, mock_pre_xmpp_auth_.release()); 131 132 // We need to do this *before* |xmpp_connection| gets destroyed or 133 // our delegate won't be called. 134 message_loop_.RunUntilIdle(); 135 } 136 137 TEST_F(XmppConnectionTest, FailureAfterPreAuth) { 138 EXPECT_CALL(*mock_pre_xmpp_auth_, StartPreXmppAuth(_, _, _, _,_)); 139 EXPECT_CALL(*mock_pre_xmpp_auth_, IsAuthDone()).WillOnce(Return(true)); 140 EXPECT_CALL(*mock_pre_xmpp_auth_, IsAuthorized()).WillOnce(Return(true)); 141 EXPECT_CALL(*mock_pre_xmpp_auth_, GetAuthMechanism()).WillOnce(Return("")); 142 EXPECT_CALL(*mock_pre_xmpp_auth_, GetAuthToken()).WillOnce(Return("")); 143 144 EXPECT_CALL(mock_xmpp_connection_delegate_, 145 OnError(buzz::XmppEngine::ERROR_NONE, 0, NULL)); 146 147 XmppConnection xmpp_connection( 148 buzz::XmppClientSettings(), url_request_context_getter_, 149 &mock_xmpp_connection_delegate_, mock_pre_xmpp_auth_.release()); 150 151 // We need to do this *before* |xmpp_connection| gets destroyed or 152 // our delegate won't be called. 153 message_loop_.RunUntilIdle(); 154 } 155 156 TEST_F(XmppConnectionTest, RaisedError) { 157 EXPECT_CALL(mock_xmpp_connection_delegate_, 158 OnError(buzz::XmppEngine::ERROR_NONE, 0, NULL)); 159 160 XmppConnection xmpp_connection(buzz::XmppClientSettings(), 161 url_request_context_getter_, 162 &mock_xmpp_connection_delegate_, NULL); 163 164 xmpp_connection.weak_xmpp_client_-> 165 SignalStateChange(buzz::XmppEngine::STATE_CLOSED); 166 } 167 #endif 168 169 TEST_F(XmppConnectionTest, Connect) { 170 base::WeakPtr<talk_base::Task> weak_ptr; 171 EXPECT_CALL(mock_xmpp_connection_delegate_, OnConnect(_)). 172 WillOnce(SaveArg<0>(&weak_ptr)); 173 174 { 175 XmppConnection xmpp_connection(buzz::XmppClientSettings(), 176 url_request_context_getter_, 177 &mock_xmpp_connection_delegate_, NULL); 178 179 xmpp_connection.weak_xmpp_client_-> 180 SignalStateChange(buzz::XmppEngine::STATE_OPEN); 181 EXPECT_EQ(xmpp_connection.weak_xmpp_client_.get(), weak_ptr.get()); 182 } 183 184 EXPECT_EQ(NULL, weak_ptr.get()); 185 } 186 187 TEST_F(XmppConnectionTest, MultipleConnect) { 188 EXPECT_DEBUG_DEATH({ 189 base::WeakPtr<talk_base::Task> weak_ptr; 190 EXPECT_CALL(mock_xmpp_connection_delegate_, OnConnect(_)). 191 WillOnce(SaveArg<0>(&weak_ptr)); 192 193 XmppConnection xmpp_connection(buzz::XmppClientSettings(), 194 url_request_context_getter_, 195 &mock_xmpp_connection_delegate_, NULL); 196 197 xmpp_connection.weak_xmpp_client_-> 198 SignalStateChange(buzz::XmppEngine::STATE_OPEN); 199 for (int i = 0; i < 3; ++i) { 200 xmpp_connection.weak_xmpp_client_-> 201 SignalStateChange(buzz::XmppEngine::STATE_OPEN); 202 } 203 204 EXPECT_EQ(xmpp_connection.weak_xmpp_client_.get(), weak_ptr.get()); 205 }, "more than once"); 206 } 207 208 #if !defined(_MSC_VER) || _MSC_VER < 1700 // http://crbug.com/158570 209 TEST_F(XmppConnectionTest, ConnectThenError) { 210 base::WeakPtr<talk_base::Task> weak_ptr; 211 EXPECT_CALL(mock_xmpp_connection_delegate_, OnConnect(_)). 212 WillOnce(SaveArg<0>(&weak_ptr)); 213 EXPECT_CALL(mock_xmpp_connection_delegate_, 214 OnError(buzz::XmppEngine::ERROR_NONE, 0, NULL)); 215 216 XmppConnection xmpp_connection(buzz::XmppClientSettings(), 217 url_request_context_getter_, 218 &mock_xmpp_connection_delegate_, NULL); 219 220 xmpp_connection.weak_xmpp_client_-> 221 SignalStateChange(buzz::XmppEngine::STATE_OPEN); 222 EXPECT_EQ(xmpp_connection.weak_xmpp_client_.get(), weak_ptr.get()); 223 224 xmpp_connection.weak_xmpp_client_-> 225 SignalStateChange(buzz::XmppEngine::STATE_CLOSED); 226 EXPECT_EQ(NULL, weak_ptr.get()); 227 } 228 #endif 229 230 // We don't destroy XmppConnection's task pump on destruction, but it 231 // should still not run any more tasks. 232 TEST_F(XmppConnectionTest, TasksDontRunAfterXmppConnectionDestructor) { 233 { 234 XmppConnection xmpp_connection(buzz::XmppClientSettings(), 235 url_request_context_getter_, 236 &mock_xmpp_connection_delegate_, NULL); 237 238 jingle_glue::MockTask* task = 239 new jingle_glue::MockTask(xmpp_connection.task_pump_.get()); 240 // We have to do this since the state enum is protected in 241 // talk_base::Task. 242 const int TASK_STATE_ERROR = 3; 243 ON_CALL(*task, ProcessStart()) 244 .WillByDefault(Return(TASK_STATE_ERROR)); 245 EXPECT_CALL(*task, ProcessStart()).Times(0); 246 task->Start(); 247 } 248 249 // This should destroy |task_pump|, but |task| still shouldn't run. 250 message_loop_.RunUntilIdle(); 251 } 252 253 } // namespace notifier 254