Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / libjingle / xmpp / xmpplogintask_unittest.cc
1 /*
2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10
11 #include <iostream>
12 #include <sstream>
13 #include <string>
14 #include "webrtc/libjingle/xmllite/xmlelement.h"
15 #include "webrtc/libjingle/xmpp/constants.h"
16 #include "webrtc/libjingle/xmpp/plainsaslhandler.h"
17 #include "webrtc/libjingle/xmpp/saslplainmechanism.h"
18 #include "webrtc/libjingle/xmpp/util_unittest.h"
19 #include "webrtc/libjingle/xmpp/xmppengine.h"
20 #include "webrtc/base/common.h"
21 #include "webrtc/base/cryptstring.h"
22 #include "webrtc/base/gunit.h"
23
24 using buzz::Jid;
25 using buzz::QName;
26 using buzz::XmlElement;
27 using buzz::XmppEngine;
28 using buzz::XmppTestHandler;
29
30 enum XlttStage {
31   XLTT_STAGE_CONNECT = 0,
32   XLTT_STAGE_STREAMSTART,
33   XLTT_STAGE_TLS_FEATURES,
34   XLTT_STAGE_TLS_PROCEED,
35   XLTT_STAGE_ENCRYPTED_START,
36   XLTT_STAGE_AUTH_FEATURES,
37   XLTT_STAGE_AUTH_SUCCESS,
38   XLTT_STAGE_AUTHENTICATED_START,
39   XLTT_STAGE_BIND_FEATURES,
40   XLTT_STAGE_BIND_SUCCESS,
41   XLTT_STAGE_SESSION_SUCCESS,
42 };
43
44 class XmppLoginTaskTest : public testing::Test {
45  public:
46   XmppEngine* engine() { return engine_.get(); }
47   XmppTestHandler* handler() { return handler_.get(); }
48   virtual void SetUp() {
49     engine_.reset(XmppEngine::Create());
50     handler_.reset(new XmppTestHandler(engine_.get()));
51
52     Jid jid("david@my-server");
53     rtc::InsecureCryptStringImpl pass;
54     pass.password() = "david";
55     engine_->SetSessionHandler(handler_.get());
56     engine_->SetOutputHandler(handler_.get());
57     engine_->AddStanzaHandler(handler_.get());
58     engine_->SetUser(jid);
59     engine_->SetSaslHandler(
60         new buzz::PlainSaslHandler(jid, rtc::CryptString(pass), true));
61   }
62   virtual void TearDown() {
63     handler_.reset();
64     engine_.reset();
65   }
66   void RunPartialLogin(XlttStage startstage, XlttStage endstage);
67   void SetTlsOptions(buzz::TlsOptions option);
68
69  private:
70   rtc::scoped_ptr<XmppEngine> engine_;
71   rtc::scoped_ptr<XmppTestHandler> handler_;
72 };
73
74 void XmppLoginTaskTest::SetTlsOptions(buzz::TlsOptions option) {
75   engine_->SetTls(option);
76 }
77 void XmppLoginTaskTest::RunPartialLogin(XlttStage startstage,
78                                         XlttStage endstage) {
79   std::string input;
80
81   switch (startstage) {
82     case XLTT_STAGE_CONNECT: {
83       engine_->Connect();
84       XmlElement appStanza(QName("test", "app-stanza"));
85       appStanza.AddText("this-is-a-test");
86       engine_->SendStanza(&appStanza);
87
88       EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" "
89           "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" "
90           "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
91       EXPECT_EQ("[OPENING]", handler_->SessionActivity());
92       EXPECT_EQ("", handler_->StanzaActivity());
93       if (endstage == XLTT_STAGE_CONNECT)
94         return;
95     }
96
97     case XLTT_STAGE_STREAMSTART: {
98       input = "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" "
99           "xmlns:stream=\"http://etherx.jabber.org/streams\" "
100           "xmlns=\"jabber:client\">";
101       engine_->HandleInput(input.c_str(), input.length());
102       EXPECT_EQ("", handler_->StanzaActivity());
103       EXPECT_EQ("", handler_->SessionActivity());
104       EXPECT_EQ("", handler_->OutputActivity());
105       if (endstage == XLTT_STAGE_STREAMSTART)
106         return;
107     }
108
109     case XLTT_STAGE_TLS_FEATURES: {
110       input = "<stream:features>"
111         "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"
112        "</stream:features>";
113       engine_->HandleInput(input.c_str(), input.length());
114       EXPECT_EQ("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>",
115           handler_->OutputActivity());
116       EXPECT_EQ("", handler_->StanzaActivity());
117       EXPECT_EQ("", handler_->SessionActivity());
118       if (endstage == XLTT_STAGE_TLS_FEATURES)
119         return;
120     }
121
122     case XLTT_STAGE_TLS_PROCEED: {
123       input = std::string("<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
124       engine_->HandleInput(input.c_str(), input.length());
125       EXPECT_EQ("[START-TLS my-server]"
126           "<stream:stream to=\"my-server\" xml:lang=\"*\" "
127           "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" "
128           "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
129       EXPECT_EQ("", handler_->StanzaActivity());
130       EXPECT_EQ("", handler_->SessionActivity());
131        if (endstage == XLTT_STAGE_TLS_PROCEED)
132         return;
133     }
134
135     case XLTT_STAGE_ENCRYPTED_START: {
136       input = std::string("<stream:stream id=\"01234567\" version=\"1.0\" "
137           "xmlns:stream=\"http://etherx.jabber.org/streams\" "
138           "xmlns=\"jabber:client\">");
139       engine_->HandleInput(input.c_str(), input.length());
140       EXPECT_EQ("", handler_->StanzaActivity());
141       EXPECT_EQ("", handler_->SessionActivity());
142       EXPECT_EQ("", handler_->OutputActivity());
143       if (endstage == XLTT_STAGE_ENCRYPTED_START)
144         return;
145     }
146
147     case XLTT_STAGE_AUTH_FEATURES: {
148       input = "<stream:features>"
149         "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
150           "<mechanism>DIGEST-MD5</mechanism>"
151           "<mechanism>PLAIN</mechanism>"
152         "</mechanisms>"
153        "</stream:features>";
154       engine_->HandleInput(input.c_str(), input.length());
155       EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
156           "mechanism=\"PLAIN\" "
157           "auth:allow-non-google-login=\"true\" "
158           "auth:client-uses-full-bind-result=\"true\" "
159           "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
160           ">AGRhdmlkAGRhdmlk</auth>",
161           handler_->OutputActivity());
162       EXPECT_EQ("", handler_->StanzaActivity());
163       EXPECT_EQ("", handler_->SessionActivity());
164        if (endstage == XLTT_STAGE_AUTH_FEATURES)
165         return;
166     }
167
168     case XLTT_STAGE_AUTH_SUCCESS: {
169       input = "<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>";
170       engine_->HandleInput(input.c_str(), input.length());
171       EXPECT_EQ("<stream:stream to=\"my-server\" xml:lang=\"*\" "
172           "version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" "
173           "xmlns=\"jabber:client\">\r\n", handler_->OutputActivity());
174       EXPECT_EQ("", handler_->StanzaActivity());
175       EXPECT_EQ("", handler_->SessionActivity());
176        if (endstage == XLTT_STAGE_AUTH_SUCCESS)
177         return;
178     }
179
180     case XLTT_STAGE_AUTHENTICATED_START: {
181       input = std::string("<stream:stream id=\"01234567\" version=\"1.0\" "
182           "xmlns:stream=\"http://etherx.jabber.org/streams\" "
183           "xmlns=\"jabber:client\">");
184       engine_->HandleInput(input.c_str(), input.length());
185       EXPECT_EQ("", handler_->StanzaActivity());
186       EXPECT_EQ("", handler_->SessionActivity());
187       EXPECT_EQ("", handler_->OutputActivity());
188       if (endstage == XLTT_STAGE_AUTHENTICATED_START)
189         return;
190     }
191
192     case XLTT_STAGE_BIND_FEATURES: {
193       input = "<stream:features>"
194           "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>"
195           "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"
196         "</stream:features>";
197       engine_->HandleInput(input.c_str(), input.length());
198       EXPECT_EQ("<iq type=\"set\" id=\"0\">"
199           "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/></iq>",
200           handler_->OutputActivity());
201       EXPECT_EQ("", handler_->StanzaActivity());
202       EXPECT_EQ("", handler_->SessionActivity());
203       if (endstage == XLTT_STAGE_BIND_FEATURES)
204         return;
205     }
206
207     case XLTT_STAGE_BIND_SUCCESS: {
208       input = "<iq type='result' id='0'>"
209           "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>"
210           "<jid>david@my-server/test</jid></bind></iq>";
211       engine_->HandleInput(input.c_str(), input.length());
212       EXPECT_EQ("<iq type=\"set\" id=\"1\">"
213           "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/></iq>",
214           handler_->OutputActivity());
215       EXPECT_EQ("", handler_->StanzaActivity());
216       EXPECT_EQ("", handler_->SessionActivity());
217       if (endstage == XLTT_STAGE_BIND_SUCCESS)
218         return;
219     }
220
221     case XLTT_STAGE_SESSION_SUCCESS: {
222       input = "<iq type='result' id='1'/>";
223       engine_->HandleInput(input.c_str(), input.length());
224       EXPECT_EQ("<test:app-stanza xmlns:test=\"test\">this-is-a-test"
225           "</test:app-stanza>", handler_->OutputActivity());
226       EXPECT_EQ("[OPEN]", handler_->SessionActivity());
227       EXPECT_EQ("", handler_->StanzaActivity());
228       if (endstage == XLTT_STAGE_SESSION_SUCCESS)
229         return;
230     }
231   }
232 }
233
234 TEST_F(XmppLoginTaskTest, TestUtf8Good) {
235   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_CONNECT);
236
237   std::string input = "<?xml version='1.0' encoding='UTF-8'?>"
238       "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" "
239       "xmlns:stream=\"http://etherx.jabber.org/streams\" "
240       "xmlns=\"jabber:client\">";
241   engine()->HandleInput(input.c_str(), input.length());
242   EXPECT_EQ("", handler()->OutputActivity());
243   EXPECT_EQ("", handler()->SessionActivity());
244   EXPECT_EQ("", handler()->StanzaActivity());
245 }
246
247 TEST_F(XmppLoginTaskTest, TestNonUtf8Bad) {
248   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_CONNECT);
249
250   std::string input = "<?xml version='1.0' encoding='ISO-8859-1'?>"
251       "<stream:stream id=\"a5f2d8c9\" version=\"1.0\" "
252       "xmlns:stream=\"http://etherx.jabber.org/streams\" "
253       "xmlns=\"jabber:client\">";
254   engine()->HandleInput(input.c_str(), input.length());
255   EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
256   EXPECT_EQ("[CLOSED][ERROR-XML]", handler()->SessionActivity());
257   EXPECT_EQ("", handler()->StanzaActivity());
258 }
259
260 TEST_F(XmppLoginTaskTest, TestNoFeatures) {
261   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
262
263   std::string input = "<iq type='get' id='1'/>";
264   engine()->HandleInput(input.c_str(), input.length());
265
266   EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
267   EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity());
268   EXPECT_EQ("", handler()->StanzaActivity());
269 }
270
271 TEST_F(XmppLoginTaskTest, TestTlsRequiredNotPresent) {
272   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
273
274   std::string input = "<stream:features>"
275       "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
276         "<mechanism>DIGEST-MD5</mechanism>"
277         "<mechanism>PLAIN</mechanism>"
278       "</mechanisms>"
279      "</stream:features>";
280   engine()->HandleInput(input.c_str(), input.length());
281
282   EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
283   EXPECT_EQ("[CLOSED][ERROR-TLS]", handler()->SessionActivity());
284   EXPECT_EQ("", handler()->StanzaActivity());
285 }
286
287 TEST_F(XmppLoginTaskTest, TestTlsRequeiredAndPresent) {
288   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
289
290   std::string input = "<stream:features>"
291       "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'>"
292         "<required/>"
293       "</starttls>"
294       "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
295         "<mechanism>X-GOOGLE-TOKEN</mechanism>"
296         "<mechanism>PLAIN</mechanism>"
297         "<mechanism>X-OAUTH2</mechanism>"
298       "</mechanisms>"
299      "</stream:features>";
300   engine()->HandleInput(input.c_str(), input.length());
301
302   EXPECT_EQ("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>",
303       handler()->OutputActivity());
304   EXPECT_EQ("", handler()->SessionActivity());
305   EXPECT_EQ("", handler()->StanzaActivity());
306 }
307
308 TEST_F(XmppLoginTaskTest, TestTlsEnabledNotPresent) {
309   SetTlsOptions(buzz::TLS_ENABLED);
310   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
311
312   std::string input = "<stream:features>"
313       "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
314         "<mechanism>DIGEST-MD5</mechanism>"
315         "<mechanism>PLAIN</mechanism>"
316       "</mechanisms>"
317      "</stream:features>";
318   engine()->HandleInput(input.c_str(), input.length());
319
320   EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
321       "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" "
322       "auth:client-uses-full-bind-result=\"true\" "
323       "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
324       ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity());
325   EXPECT_EQ("", handler()->SessionActivity());
326   EXPECT_EQ("", handler()->StanzaActivity());
327 }
328
329 TEST_F(XmppLoginTaskTest, TestTlsEnabledAndPresent) {
330   SetTlsOptions(buzz::TLS_ENABLED);
331   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
332
333   std::string input = "<stream:features>"
334       "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
335         "<mechanism>X-GOOGLE-TOKEN</mechanism>"
336         "<mechanism>PLAIN</mechanism>"
337         "<mechanism>X-OAUTH2</mechanism>"
338       "</mechanisms>"
339       "</stream:features>";
340   engine()->HandleInput(input.c_str(), input.length());
341
342   EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
343       "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" "
344       "auth:client-uses-full-bind-result=\"true\" "
345       "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
346       ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity());
347   EXPECT_EQ("", handler()->SessionActivity());
348   EXPECT_EQ("", handler()->StanzaActivity());
349 }
350
351 TEST_F(XmppLoginTaskTest, TestTlsDisabledNotPresent) {
352   SetTlsOptions(buzz::TLS_DISABLED);
353   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
354
355     std::string input = "<stream:features>"
356       "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
357         "<mechanism>DIGEST-MD5</mechanism>"
358         "<mechanism>PLAIN</mechanism>"
359       "</mechanisms>"
360      "</stream:features>";
361   engine()->HandleInput(input.c_str(), input.length());
362
363   EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
364       "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" "
365       "auth:client-uses-full-bind-result=\"true\" "
366       "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
367       ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity());
368   EXPECT_EQ("", handler()->SessionActivity());
369   EXPECT_EQ("", handler()->StanzaActivity());
370 }
371
372 TEST_F(XmppLoginTaskTest, TestTlsDisabledAndPresent) {
373   SetTlsOptions(buzz::TLS_DISABLED);
374   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_STREAMSTART);
375
376   std::string input = "<stream:features>"
377       "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
378         "<mechanism>X-GOOGLE-TOKEN</mechanism>"
379         "<mechanism>PLAIN</mechanism>"
380         "<mechanism>X-OAUTH2</mechanism>"
381       "</mechanisms>"
382       "</stream:features>";
383   engine()->HandleInput(input.c_str(), input.length());
384
385   EXPECT_EQ("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" "
386       "mechanism=\"PLAIN\" auth:allow-non-google-login=\"true\" "
387       "auth:client-uses-full-bind-result=\"true\" "
388       "xmlns:auth=\"http://www.google.com/talk/protocol/auth\""
389       ">AGRhdmlkAGRhdmlk</auth>", handler()->OutputActivity());
390   EXPECT_EQ("", handler()->SessionActivity());
391   EXPECT_EQ("", handler()->StanzaActivity());
392 }
393
394 TEST_F(XmppLoginTaskTest, TestTlsFailure) {
395   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_TLS_FEATURES);
396
397   std::string input = "<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>";
398   engine()->HandleInput(input.c_str(), input.length());
399
400   EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
401   EXPECT_EQ("[CLOSED][ERROR-TLS]", handler()->SessionActivity());
402   EXPECT_EQ("", handler()->StanzaActivity());
403 }
404
405 TEST_F(XmppLoginTaskTest, TestTlsBadStream) {
406   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_TLS_PROCEED);
407
408   std::string input = "<wrongtag>";
409   engine()->HandleInput(input.c_str(), input.length());
410
411   EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
412   EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity());
413   EXPECT_EQ("", handler()->StanzaActivity());
414 }
415
416 TEST_F(XmppLoginTaskTest, TestMissingSaslPlain) {
417   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_ENCRYPTED_START);
418
419   std::string input = "<stream:features>"
420         "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"
421           "<mechanism>DIGEST-MD5</mechanism>"
422         "</mechanisms>"
423        "</stream:features>";
424   engine()->HandleInput(input.c_str(), input.length());
425
426   EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
427   EXPECT_EQ("[CLOSED][ERROR-AUTH]", handler()->SessionActivity());
428   EXPECT_EQ("", handler()->StanzaActivity());
429 }
430
431 TEST_F(XmppLoginTaskTest, TestWrongPassword) {
432   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTH_FEATURES);
433
434   std::string input = "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>";
435   engine()->HandleInput(input.c_str(), input.length());
436
437   EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
438   EXPECT_EQ("[CLOSED][ERROR-UNAUTHORIZED]", handler()->SessionActivity());
439   EXPECT_EQ("", handler()->StanzaActivity());
440 }
441
442 TEST_F(XmppLoginTaskTest, TestAuthBadStream) {
443   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTH_SUCCESS);
444
445   std::string input = "<wrongtag>";
446   engine()->HandleInput(input.c_str(), input.length());
447
448   EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
449   EXPECT_EQ("[CLOSED][ERROR-VERSION]", handler()->SessionActivity());
450   EXPECT_EQ("", handler()->StanzaActivity());
451 }
452
453 TEST_F(XmppLoginTaskTest, TestMissingBindFeature) {
454   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTHENTICATED_START);
455
456   std::string input = "<stream:features>"
457           "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"
458         "</stream:features>";
459   engine()->HandleInput(input.c_str(), input.length());
460
461   EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
462   EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
463 }
464
465 TEST_F(XmppLoginTaskTest, TestMissingSessionFeature) {
466   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_AUTHENTICATED_START);
467
468   std::string input = "<stream:features>"
469           "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>"
470         "</stream:features>";
471   engine()->HandleInput(input.c_str(), input.length());
472
473   EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
474   EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
475   EXPECT_EQ("", handler()->StanzaActivity());
476 }
477
478 /* TODO: Handle this case properly inside XmppLoginTask.
479 TEST_F(XmppLoginTaskTest, TestBindFailure1) {
480   // check wrong JID
481   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES);
482
483   std::string input = "<iq type='result' id='0'>"
484       "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>"
485       "<jid>davey@my-server/test</jid></bind></iq>";
486   engine()->HandleInput(input.c_str(), input.length());
487
488   EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
489   EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
490   EXPECT_EQ("", handler()->StanzaActivity());
491 }
492 */
493
494 TEST_F(XmppLoginTaskTest, TestBindFailure2) {
495   // check missing JID
496   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES);
497
498   std::string input = "<iq type='result' id='0'>"
499       "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></iq>";
500   engine()->HandleInput(input.c_str(), input.length());
501
502   EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
503   EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
504   EXPECT_EQ("", handler()->StanzaActivity());
505 }
506
507 TEST_F(XmppLoginTaskTest, TestBindFailure3) {
508   // check plain failure
509   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES);
510
511   std::string input = "<iq type='error' id='0'/>";
512   engine()->HandleInput(input.c_str(), input.length());
513
514   EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
515   EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
516   EXPECT_EQ("", handler()->StanzaActivity());
517 }
518
519 TEST_F(XmppLoginTaskTest, TestBindFailure4) {
520   // check wrong id to ignore
521   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_FEATURES);
522
523   std::string input = "<iq type='error' id='1'/>";
524   engine()->HandleInput(input.c_str(), input.length());
525
526   // continue after an ignored iq
527   RunPartialLogin(XLTT_STAGE_BIND_SUCCESS, XLTT_STAGE_SESSION_SUCCESS);
528 }
529
530 TEST_F(XmppLoginTaskTest, TestSessionFailurePlain1) {
531   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_SUCCESS);
532
533   std::string input = "<iq type='error' id='1'/>";
534   engine()->HandleInput(input.c_str(), input.length());
535
536   EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
537   EXPECT_EQ("[CLOSED][ERROR-BIND]", handler()->SessionActivity());
538 }
539
540 TEST_F(XmppLoginTaskTest, TestSessionFailurePlain2) {
541   RunPartialLogin(XLTT_STAGE_CONNECT, XLTT_STAGE_BIND_SUCCESS);
542
543   // check reverse iq to ignore
544   // TODO: consider queueing or passing through?
545   std::string input = "<iq type='get' id='1'/>";
546   engine()->HandleInput(input.c_str(), input.length());
547
548   EXPECT_EQ("", handler()->OutputActivity());
549   EXPECT_EQ("", handler()->SessionActivity());
550
551   // continue after an ignored iq
552   RunPartialLogin(XLTT_STAGE_SESSION_SUCCESS, XLTT_STAGE_SESSION_SUCCESS);
553 }
554
555 TEST_F(XmppLoginTaskTest, TestBadXml) {
556   int errorKind = 0;
557   for (XlttStage stage = XLTT_STAGE_CONNECT;
558       stage <= XLTT_STAGE_SESSION_SUCCESS;
559       stage = static_cast<XlttStage>(stage + 1)) {
560     RunPartialLogin(XLTT_STAGE_CONNECT, stage);
561
562     std::string input;
563     switch (errorKind++ % 5) {
564       case 0: input = "&syntax;"; break;
565       case 1: input = "<nons:iq/>"; break;
566       case 2: input = "<iq a='b' a='dupe'/>"; break;
567       case 3: input = "<>"; break;
568       case 4: input = "<iq a='<wrong>'>"; break;
569     }
570
571     engine()->HandleInput(input.c_str(), input.length());
572
573     EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
574     EXPECT_EQ("[CLOSED][ERROR-XML]", handler()->SessionActivity());
575
576     TearDown();
577     SetUp();
578   }
579 }
580
581 TEST_F(XmppLoginTaskTest, TestStreamError) {
582   for (XlttStage stage = XLTT_STAGE_CONNECT;
583       stage <= XLTT_STAGE_SESSION_SUCCESS;
584       stage = static_cast<XlttStage>(stage + 1)) {
585     switch (stage) {
586       case XLTT_STAGE_CONNECT:
587       case XLTT_STAGE_TLS_PROCEED:
588       case XLTT_STAGE_AUTH_SUCCESS:
589         continue;
590       default:
591         break;
592     }
593
594     RunPartialLogin(XLTT_STAGE_CONNECT, stage);
595
596     std::string input = "<stream:error>"
597         "<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>"
598         "<text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'>"
599         "Some special application diagnostic information!"
600         "</text>"
601         "<escape-your-data xmlns='application-ns'/>"
602         "</stream:error>";
603
604     engine()->HandleInput(input.c_str(), input.length());
605
606     EXPECT_EQ("[CLOSED]", handler()->OutputActivity());
607     EXPECT_EQ("[CLOSED][ERROR-STREAM]", handler()->SessionActivity());
608
609     EXPECT_EQ("<str:error xmlns:str=\"http://etherx.jabber.org/streams\">"
610         "<xml-not-well-formed xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\"/>"
611         "<text xml:lang=\"en\" xmlns=\"urn:ietf:params:xml:ns:xmpp-streams\">"
612         "Some special application diagnostic information!"
613         "</text>"
614         "<escape-your-data xmlns=\"application-ns\"/>"
615         "</str:error>", engine()->GetStreamError()->Str());
616
617     TearDown();
618     SetUp();
619   }
620 }
621