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.
5 #include "jingle/notifier/communicator/single_login_attempt.h"
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"
23 class XmppTaskParentInterface
;
31 IDLE
, CONNECTED
, REDIRECTED
, CREDENTIALS_REJECTED
, SETTINGS_EXHAUSTED
34 class FakeDelegate
: public SingleLoginAttempt::Delegate
{
36 FakeDelegate() : state_(IDLE
) {}
38 virtual void OnConnect(
39 base::WeakPtr
<buzz::XmppTaskParentInterface
> base_task
) OVERRIDE
{
41 base_task_
= base_task
;
44 virtual void OnRedirect(const ServerInformation
& redirect_server
) OVERRIDE
{
46 redirect_server_
= redirect_server
;
49 virtual void OnCredentialsRejected() OVERRIDE
{
50 state_
= CREDENTIALS_REJECTED
;
53 virtual void OnSettingsExhausted() OVERRIDE
{
54 state_
= SETTINGS_EXHAUSTED
;
57 DelegateState
state() const { return state_
; }
59 base::WeakPtr
<buzz::XmppTaskParentInterface
> base_task() const {
63 const ServerInformation
& redirect_server() const {
64 return redirect_server_
;
69 base::WeakPtr
<buzz::XmppTaskParentInterface
> base_task_
;
70 ServerInformation redirect_server_
;
73 class MyTestURLRequestContext
: public net::TestURLRequestContext
{
75 MyTestURLRequestContext() : TestURLRequestContext(true) {
76 context_storage_
.set_host_resolver(
77 scoped_ptr
<net::HostResolver
>(new net::HangingHostResolver()));
80 virtual ~MyTestURLRequestContext() {}
83 class SingleLoginAttemptTest
: public ::testing::Test
{
85 SingleLoginAttemptTest()
87 buzz::XmppClientSettings(),
88 new net::TestURLRequestContextGetter(
89 base::MessageLoopProxy::current(),
90 scoped_ptr
<net::TestURLRequestContext
>(
91 new MyTestURLRequestContext())),
95 net::HostPortPair("example.com", 100), SUPPORTS_SSLTCP
)),
96 false /* try_ssltcp_first */,
98 attempt_(new SingleLoginAttempt(login_settings_
, &fake_delegate_
)) {}
100 virtual void TearDown() OVERRIDE
{
101 message_loop_
.RunUntilIdle();
104 void FireRedirect(buzz::XmlElement
* redirect_error
) {
105 attempt_
->OnError(buzz::XmppEngine::ERROR_STREAM
, 0, redirect_error
);
108 virtual ~SingleLoginAttemptTest() {
110 message_loop_
.RunUntilIdle();
114 base::MessageLoop message_loop_
;
115 const LoginSettings login_settings_
;
118 scoped_ptr
<SingleLoginAttempt
> attempt_
;
119 FakeDelegate fake_delegate_
;
120 FakeBaseTask fake_base_task_
;
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());
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
);
139 EXPECT_EQ(SETTINGS_EXHAUSTED
, fake_delegate_
.state());
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());
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
);
164 // Fire a redirect and make sure the delegate gets the proper redirect
166 TEST_F(SingleLoginAttemptTest
, Redirect
) {
167 const ServerInformation
redirect_server(
168 net::HostPortPair("example.com", 1000),
171 scoped_ptr
<buzz::XmlElement
> redirect_error(
172 MakeRedirectError(redirect_server
.server
.ToString()));
173 FireRedirect(redirect_error
.get());
175 EXPECT_EQ(REDIRECTED
, fake_delegate_
.state());
176 EXPECT_TRUE(fake_delegate_
.redirect_server().Equals(redirect_server
));
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
),
186 scoped_ptr
<buzz::XmlElement
> redirect_error(
187 MakeRedirectError(redirect_server
.server
.host()));
188 FireRedirect(redirect_error
.get());
190 EXPECT_EQ(REDIRECTED
, fake_delegate_
.state());
191 EXPECT_TRUE(fake_delegate_
.redirect_server().Equals(redirect_server
));
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
),
201 scoped_ptr
<buzz::XmlElement
> redirect_error(
202 MakeRedirectError(redirect_server
.server
.host() + ":0"));
203 FireRedirect(redirect_error
.get());
205 EXPECT_EQ(REDIRECTED
, fake_delegate_
.state());
206 EXPECT_TRUE(fake_delegate_
.redirect_server().Equals(redirect_server
));
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
),
216 scoped_ptr
<buzz::XmlElement
> redirect_error(
217 MakeRedirectError(redirect_server
.server
.host() + ":invalidport"));
218 FireRedirect(redirect_error
.get());
220 EXPECT_EQ(REDIRECTED
, fake_delegate_
.state());
221 EXPECT_TRUE(fake_delegate_
.redirect_server().Equals(redirect_server
));
224 // Fire an empty redirect and make sure the delegate does not get a
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());
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());
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());
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());
259 } // namespace notifier