Home | History | Annotate | Download | only in base
      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