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