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 "base/thread_task_runner_handle.h"
13 #include "jingle/notifier/base/const_communicator.h"
14 #include "jingle/notifier/base/fake_base_task.h"
15 #include "jingle/notifier/communicator/login_settings.h"
16 #include "net/dns/mock_host_resolver.h"
17 #include "net/url_request/url_request_test_util.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
20 #include "webrtc/libjingle/xmpp/constants.h"
21 #include "webrtc/libjingle/xmpp/xmppengine.h"
24 class XmppTaskParentInterface
;
32 IDLE
, CONNECTED
, REDIRECTED
, CREDENTIALS_REJECTED
, SETTINGS_EXHAUSTED
35 class FakeDelegate
: public SingleLoginAttempt::Delegate
{
37 FakeDelegate() : state_(IDLE
) {}
40 base::WeakPtr
<buzz::XmppTaskParentInterface
> base_task
) override
{
42 base_task_
= base_task
;
45 void OnRedirect(const ServerInformation
& redirect_server
) override
{
47 redirect_server_
= redirect_server
;
50 void OnCredentialsRejected() override
{ state_
= CREDENTIALS_REJECTED
; }
52 void OnSettingsExhausted() override
{ state_
= SETTINGS_EXHAUSTED
; }
54 DelegateState
state() const { return state_
; }
56 base::WeakPtr
<buzz::XmppTaskParentInterface
> base_task() const {
60 const ServerInformation
& redirect_server() const {
61 return redirect_server_
;
66 base::WeakPtr
<buzz::XmppTaskParentInterface
> base_task_
;
67 ServerInformation redirect_server_
;
70 class MyTestURLRequestContext
: public net::TestURLRequestContext
{
72 MyTestURLRequestContext() : TestURLRequestContext(true) {
73 context_storage_
.set_host_resolver(
74 scoped_ptr
<net::HostResolver
>(new net::HangingHostResolver()));
77 ~MyTestURLRequestContext() override
{}
80 class SingleLoginAttemptTest
: public ::testing::Test
{
82 SingleLoginAttemptTest()
84 buzz::XmppClientSettings(),
85 new net::TestURLRequestContextGetter(
86 base::ThreadTaskRunnerHandle::Get(),
87 scoped_ptr
<net::TestURLRequestContext
>(
88 new MyTestURLRequestContext())),
92 net::HostPortPair("example.com", 100), SUPPORTS_SSLTCP
)),
93 false /* try_ssltcp_first */,
95 attempt_(new SingleLoginAttempt(login_settings_
, &fake_delegate_
)) {}
97 void TearDown() override
{ message_loop_
.RunUntilIdle(); }
99 void FireRedirect(buzz::XmlElement
* redirect_error
) {
100 attempt_
->OnError(buzz::XmppEngine::ERROR_STREAM
, 0, redirect_error
);
103 ~SingleLoginAttemptTest() override
{
105 message_loop_
.RunUntilIdle();
109 base::MessageLoop message_loop_
;
110 const LoginSettings login_settings_
;
113 scoped_ptr
<SingleLoginAttempt
> attempt_
;
114 FakeDelegate fake_delegate_
;
115 FakeBaseTask fake_base_task_
;
118 // Fire OnConnect and make sure the base task gets passed to the
119 // delegate properly.
120 TEST_F(SingleLoginAttemptTest
, Basic
) {
121 attempt_
->OnConnect(fake_base_task_
.AsWeakPtr());
122 EXPECT_EQ(CONNECTED
, fake_delegate_
.state());
123 EXPECT_EQ(fake_base_task_
.AsWeakPtr().get(),
124 fake_delegate_
.base_task().get());
127 // Fire OnErrors and make sure the delegate gets the
128 // OnSettingsExhausted() event.
129 TEST_F(SingleLoginAttemptTest
, Error
) {
130 for (int i
= 0; i
< 2; ++i
) {
131 EXPECT_EQ(IDLE
, fake_delegate_
.state());
132 attempt_
->OnError(buzz::XmppEngine::ERROR_NONE
, 0, NULL
);
134 EXPECT_EQ(SETTINGS_EXHAUSTED
, fake_delegate_
.state());
137 // Fire OnErrors but replace the last one with OnConnect, and make
138 // sure the delegate still gets the OnConnect message.
139 TEST_F(SingleLoginAttemptTest
, ErrorThenSuccess
) {
140 attempt_
->OnError(buzz::XmppEngine::ERROR_NONE
, 0, NULL
);
141 attempt_
->OnConnect(fake_base_task_
.AsWeakPtr());
142 EXPECT_EQ(CONNECTED
, fake_delegate_
.state());
143 EXPECT_EQ(fake_base_task_
.AsWeakPtr().get(),
144 fake_delegate_
.base_task().get());
147 buzz::XmlElement
* MakeRedirectError(const std::string
& redirect_server
) {
148 buzz::XmlElement
* stream_error
=
149 new buzz::XmlElement(buzz::QN_STREAM_ERROR
, true);
150 stream_error
->AddElement(
151 new buzz::XmlElement(buzz::QN_XSTREAM_SEE_OTHER_HOST
, true));
152 buzz::XmlElement
* text
=
153 new buzz::XmlElement(buzz::QN_XSTREAM_TEXT
, true);
154 stream_error
->AddElement(text
);
155 text
->SetBodyText(redirect_server
);
159 // Fire a redirect and make sure the delegate gets the proper redirect
161 TEST_F(SingleLoginAttemptTest
, Redirect
) {
162 const ServerInformation
redirect_server(
163 net::HostPortPair("example.com", 1000),
166 scoped_ptr
<buzz::XmlElement
> redirect_error(
167 MakeRedirectError(redirect_server
.server
.ToString()));
168 FireRedirect(redirect_error
.get());
170 EXPECT_EQ(REDIRECTED
, fake_delegate_
.state());
171 EXPECT_TRUE(fake_delegate_
.redirect_server().Equals(redirect_server
));
174 // Fire a redirect with the host only and make sure the delegate gets
175 // the proper redirect server info with the default XMPP port.
176 TEST_F(SingleLoginAttemptTest
, RedirectHostOnly
) {
177 const ServerInformation
redirect_server(
178 net::HostPortPair("example.com", kDefaultXmppPort
),
181 scoped_ptr
<buzz::XmlElement
> redirect_error(
182 MakeRedirectError(redirect_server
.server
.host()));
183 FireRedirect(redirect_error
.get());
185 EXPECT_EQ(REDIRECTED
, fake_delegate_
.state());
186 EXPECT_TRUE(fake_delegate_
.redirect_server().Equals(redirect_server
));
189 // Fire a redirect with a zero port and make sure the delegate gets
190 // the proper redirect server info with the default XMPP port.
191 TEST_F(SingleLoginAttemptTest
, RedirectZeroPort
) {
192 const ServerInformation
redirect_server(
193 net::HostPortPair("example.com", kDefaultXmppPort
),
196 scoped_ptr
<buzz::XmlElement
> redirect_error(
197 MakeRedirectError(redirect_server
.server
.host() + ":0"));
198 FireRedirect(redirect_error
.get());
200 EXPECT_EQ(REDIRECTED
, fake_delegate_
.state());
201 EXPECT_TRUE(fake_delegate_
.redirect_server().Equals(redirect_server
));
204 // Fire a redirect with an invalid port and make sure the delegate
205 // gets the proper redirect server info with the default XMPP port.
206 TEST_F(SingleLoginAttemptTest
, RedirectInvalidPort
) {
207 const ServerInformation
redirect_server(
208 net::HostPortPair("example.com", kDefaultXmppPort
),
211 scoped_ptr
<buzz::XmlElement
> redirect_error(
212 MakeRedirectError(redirect_server
.server
.host() + ":invalidport"));
213 FireRedirect(redirect_error
.get());
215 EXPECT_EQ(REDIRECTED
, fake_delegate_
.state());
216 EXPECT_TRUE(fake_delegate_
.redirect_server().Equals(redirect_server
));
219 // Fire an empty redirect and make sure the delegate does not get a
221 TEST_F(SingleLoginAttemptTest
, RedirectEmpty
) {
222 scoped_ptr
<buzz::XmlElement
> redirect_error(MakeRedirectError(std::string()));
223 FireRedirect(redirect_error
.get());
224 EXPECT_EQ(IDLE
, fake_delegate_
.state());
227 // Fire a redirect with a missing text element and make sure the
228 // delegate does not get a redirect.
229 TEST_F(SingleLoginAttemptTest
, RedirectMissingText
) {
230 scoped_ptr
<buzz::XmlElement
> redirect_error(MakeRedirectError(std::string()));
231 redirect_error
->RemoveChildAfter(redirect_error
->FirstChild());
232 FireRedirect(redirect_error
.get());
233 EXPECT_EQ(IDLE
, fake_delegate_
.state());
236 // Fire a redirect with a missing see-other-host element and make sure
237 // the delegate does not get a redirect.
238 TEST_F(SingleLoginAttemptTest
, RedirectMissingSeeOtherHost
) {
239 scoped_ptr
<buzz::XmlElement
> redirect_error(MakeRedirectError(std::string()));
240 redirect_error
->RemoveChildAfter(NULL
);
241 FireRedirect(redirect_error
.get());
242 EXPECT_EQ(IDLE
, fake_delegate_
.state());
245 // Fire 'Unauthorized' errors and make sure the delegate gets the
246 // OnCredentialsRejected() event.
247 TEST_F(SingleLoginAttemptTest
, CredentialsRejected
) {
248 attempt_
->OnError(buzz::XmppEngine::ERROR_UNAUTHORIZED
, 0, NULL
);
249 EXPECT_EQ(CREDENTIALS_REJECTED
, fake_delegate_
.state());
254 } // namespace notifier