Home | History | Annotate | Download | only in communicator
      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/communicator/single_login_attempt.h"
      6 
      7 #include <cstddef>
      8 
      9 #include "base/compiler_specific.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "jingle/notifier/base/const_communicator.h"
     13 #include "jingle/notifier/base/fake_base_task.h"
     14 #include "jingle/notifier/communicator/login_settings.h"
     15 #include "net/dns/mock_host_resolver.h"
     16 #include "net/url_request/url_request_test_util.h"
     17 #include "talk/xmllite/xmlelement.h"
     18 #include "talk/xmpp/constants.h"
     19 #include "talk/xmpp/xmppengine.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 
     22 namespace buzz {
     23 class XmppTaskParentInterface;
     24 }  // namespace buzz
     25 
     26 namespace notifier {
     27 
     28 namespace {
     29 
     30 enum DelegateState {
     31   IDLE, CONNECTED, REDIRECTED, CREDENTIALS_REJECTED, SETTINGS_EXHAUSTED
     32 };
     33 
     34 class FakeDelegate : public SingleLoginAttempt::Delegate {
     35  public:
     36   FakeDelegate() : state_(IDLE) {}
     37 
     38   virtual void OnConnect(
     39       base::WeakPtr<buzz::XmppTaskParentInterface> base_task) OVERRIDE {
     40     state_ = CONNECTED;
     41     base_task_ = base_task;
     42   }
     43 
     44   virtual void OnRedirect(const ServerInformation& redirect_server) OVERRIDE {
     45     state_ = REDIRECTED;
     46     redirect_server_ = redirect_server;
     47   }
     48 
     49   virtual void OnCredentialsRejected() OVERRIDE {
     50     state_ = CREDENTIALS_REJECTED;
     51   }
     52 
     53   virtual void OnSettingsExhausted() OVERRIDE {
     54     state_ = SETTINGS_EXHAUSTED;
     55   }
     56 
     57   DelegateState state() const { return state_; }
     58 
     59   base::WeakPtr<buzz::XmppTaskParentInterface> base_task() const {
     60     return base_task_;
     61   }
     62 
     63   const ServerInformation& redirect_server() const {
     64     return redirect_server_;
     65   }
     66 
     67  private:
     68   DelegateState state_;
     69   base::WeakPtr<buzz::XmppTaskParentInterface> base_task_;
     70   ServerInformation redirect_server_;
     71 };
     72 
     73 class MyTestURLRequestContext : public net::TestURLRequestContext {
     74  public:
     75   MyTestURLRequestContext() : TestURLRequestContext(true) {
     76     context_storage_.set_host_resolver(
     77         scoped_ptr<net::HostResolver>(new net::HangingHostResolver()));
     78     Init();
     79   }
     80   virtual ~MyTestURLRequestContext() {}
     81 };
     82 
     83 class SingleLoginAttemptTest : public ::testing::Test {
     84  protected:
     85   SingleLoginAttemptTest()
     86       : login_settings_(
     87           buzz::XmppClientSettings(),
     88           new net::TestURLRequestContextGetter(
     89               base::MessageLoopProxy::current(),
     90               scoped_ptr<net::TestURLRequestContext>(
     91                   new MyTestURLRequestContext())),
     92           ServerList(
     93               1,
     94               ServerInformation(
     95                   net::HostPortPair("example.com", 100), SUPPORTS_SSLTCP)),
     96           false /* try_ssltcp_first */,
     97           "auth_mechanism"),
     98         attempt_(new SingleLoginAttempt(login_settings_, &fake_delegate_)) {}
     99 
    100   virtual void TearDown() OVERRIDE {
    101     message_loop_.RunUntilIdle();
    102   }
    103 
    104   void FireRedirect(buzz::XmlElement* redirect_error) {
    105     attempt_->OnError(buzz::XmppEngine::ERROR_STREAM, 0, redirect_error);
    106   }
    107 
    108   virtual ~SingleLoginAttemptTest() {
    109     attempt_.reset();
    110     message_loop_.RunUntilIdle();
    111   }
    112 
    113  private:
    114   base::MessageLoop message_loop_;
    115   const LoginSettings login_settings_;
    116 
    117  protected:
    118   scoped_ptr<SingleLoginAttempt> attempt_;
    119   FakeDelegate fake_delegate_;
    120   FakeBaseTask fake_base_task_;
    121 };
    122 
    123 // Fire OnConnect and make sure the base task gets passed to the
    124 // delegate properly.
    125 TEST_F(SingleLoginAttemptTest, Basic) {
    126   attempt_->OnConnect(fake_base_task_.AsWeakPtr());
    127   EXPECT_EQ(CONNECTED, fake_delegate_.state());
    128   EXPECT_EQ(fake_base_task_.AsWeakPtr().get(),
    129             fake_delegate_.base_task().get());
    130 }
    131 
    132 // Fire OnErrors and make sure the delegate gets the
    133 // OnSettingsExhausted() event.
    134 TEST_F(SingleLoginAttemptTest, Error) {
    135   for (int i = 0; i < 2; ++i) {
    136     EXPECT_EQ(IDLE, fake_delegate_.state());
    137     attempt_->OnError(buzz::XmppEngine::ERROR_NONE, 0, NULL);
    138   }
    139   EXPECT_EQ(SETTINGS_EXHAUSTED, fake_delegate_.state());
    140 }
    141 
    142 // Fire OnErrors but replace the last one with OnConnect, and make
    143 // sure the delegate still gets the OnConnect message.
    144 TEST_F(SingleLoginAttemptTest, ErrorThenSuccess) {
    145   attempt_->OnError(buzz::XmppEngine::ERROR_NONE, 0, NULL);
    146   attempt_->OnConnect(fake_base_task_.AsWeakPtr());
    147   EXPECT_EQ(CONNECTED, fake_delegate_.state());
    148   EXPECT_EQ(fake_base_task_.AsWeakPtr().get(),
    149             fake_delegate_.base_task().get());
    150 }
    151 
    152 buzz::XmlElement* MakeRedirectError(const std::string& redirect_server) {
    153   buzz::XmlElement* stream_error =
    154       new buzz::XmlElement(buzz::QN_STREAM_ERROR, true);
    155   stream_error->AddElement(
    156       new buzz::XmlElement(buzz::QN_XSTREAM_SEE_OTHER_HOST, true));
    157   buzz::XmlElement* text =
    158       new buzz::XmlElement(buzz::QN_XSTREAM_TEXT, true);
    159   stream_error->AddElement(text);
    160   text->SetBodyText(redirect_server);
    161   return stream_error;
    162 }
    163 
    164 // Fire a redirect and make sure the delegate gets the proper redirect
    165 // server info.
    166 TEST_F(SingleLoginAttemptTest, Redirect) {
    167   const ServerInformation redirect_server(
    168       net::HostPortPair("example.com", 1000),
    169       SUPPORTS_SSLTCP);
    170 
    171   scoped_ptr<buzz::XmlElement> redirect_error(
    172       MakeRedirectError(redirect_server.server.ToString()));
    173   FireRedirect(redirect_error.get());
    174 
    175   EXPECT_EQ(REDIRECTED, fake_delegate_.state());
    176   EXPECT_TRUE(fake_delegate_.redirect_server().Equals(redirect_server));
    177 }
    178 
    179 // Fire a redirect with the host only and make sure the delegate gets
    180 // the proper redirect server info with the default XMPP port.
    181 TEST_F(SingleLoginAttemptTest, RedirectHostOnly) {
    182   const ServerInformation redirect_server(
    183       net::HostPortPair("example.com", kDefaultXmppPort),
    184       SUPPORTS_SSLTCP);
    185 
    186   scoped_ptr<buzz::XmlElement> redirect_error(
    187       MakeRedirectError(redirect_server.server.host()));
    188   FireRedirect(redirect_error.get());
    189 
    190   EXPECT_EQ(REDIRECTED, fake_delegate_.state());
    191   EXPECT_TRUE(fake_delegate_.redirect_server().Equals(redirect_server));
    192 }
    193 
    194 // Fire a redirect with a zero port and make sure the delegate gets
    195 // the proper redirect server info with the default XMPP port.
    196 TEST_F(SingleLoginAttemptTest, RedirectZeroPort) {
    197   const ServerInformation redirect_server(
    198       net::HostPortPair("example.com", kDefaultXmppPort),
    199       SUPPORTS_SSLTCP);
    200 
    201   scoped_ptr<buzz::XmlElement> redirect_error(
    202       MakeRedirectError(redirect_server.server.host() + ":0"));
    203   FireRedirect(redirect_error.get());
    204 
    205   EXPECT_EQ(REDIRECTED, fake_delegate_.state());
    206   EXPECT_TRUE(fake_delegate_.redirect_server().Equals(redirect_server));
    207 }
    208 
    209 // Fire a redirect with an invalid port and make sure the delegate
    210 // gets the proper redirect server info with the default XMPP port.
    211 TEST_F(SingleLoginAttemptTest, RedirectInvalidPort) {
    212   const ServerInformation redirect_server(
    213       net::HostPortPair("example.com", kDefaultXmppPort),
    214       SUPPORTS_SSLTCP);
    215 
    216   scoped_ptr<buzz::XmlElement> redirect_error(
    217       MakeRedirectError(redirect_server.server.host() + ":invalidport"));
    218   FireRedirect(redirect_error.get());
    219 
    220   EXPECT_EQ(REDIRECTED, fake_delegate_.state());
    221   EXPECT_TRUE(fake_delegate_.redirect_server().Equals(redirect_server));
    222 }
    223 
    224 // Fire an empty redirect and make sure the delegate does not get a
    225 // redirect.
    226 TEST_F(SingleLoginAttemptTest, RedirectEmpty) {
    227   scoped_ptr<buzz::XmlElement> redirect_error(MakeRedirectError(std::string()));
    228   FireRedirect(redirect_error.get());
    229   EXPECT_EQ(IDLE, fake_delegate_.state());
    230 }
    231 
    232 // Fire a redirect with a missing text element and make sure the
    233 // delegate does not get a redirect.
    234 TEST_F(SingleLoginAttemptTest, RedirectMissingText) {
    235   scoped_ptr<buzz::XmlElement> redirect_error(MakeRedirectError(std::string()));
    236   redirect_error->RemoveChildAfter(redirect_error->FirstChild());
    237   FireRedirect(redirect_error.get());
    238   EXPECT_EQ(IDLE, fake_delegate_.state());
    239 }
    240 
    241 // Fire a redirect with a missing see-other-host element and make sure
    242 // the delegate does not get a redirect.
    243 TEST_F(SingleLoginAttemptTest, RedirectMissingSeeOtherHost) {
    244   scoped_ptr<buzz::XmlElement> redirect_error(MakeRedirectError(std::string()));
    245   redirect_error->RemoveChildAfter(NULL);
    246   FireRedirect(redirect_error.get());
    247   EXPECT_EQ(IDLE, fake_delegate_.state());
    248 }
    249 
    250 // Fire 'Unauthorized' errors and make sure the delegate gets the
    251 // OnCredentialsRejected() event.
    252 TEST_F(SingleLoginAttemptTest, CredentialsRejected) {
    253   attempt_->OnError(buzz::XmppEngine::ERROR_UNAUTHORIZED, 0, NULL);
    254   EXPECT_EQ(CREDENTIALS_REJECTED, fake_delegate_.state());
    255 }
    256 
    257 }  // namespace
    258 
    259 }  // namespace notifier
    260