- add sources.
[platform/framework/web/crosswalk.git] / src / remoting / protocol / jingle_messages_unittest.cc
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 "remoting/protocol/jingle_messages.h"
6
7 #include "base/logging.h"
8 #include "testing/gmock/include/gmock/gmock.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "third_party/libjingle/source/talk/xmllite/xmlelement.h"
11 #include "third_party/libjingle/source/talk/xmpp/constants.h"
12
13 using buzz::QName;
14 using buzz::XmlAttr;
15 using buzz::XmlElement;
16
17 namespace remoting {
18 namespace protocol {
19
20 namespace {
21
22 const char kXmlNsNs[] = "http://www.w3.org/2000/xmlns/";
23 const char kXmlNs[] = "xmlns";
24
25 // Compares two XML blobs and returns true if they are
26 // equivalent. Otherwise |error| is set to error message that
27 // specifies the first test.
28 bool VerifyXml(const XmlElement* exp,
29                const XmlElement* val,
30                std::string* error) {
31   if (exp->Name() != val->Name()) {
32     *error = "<" + exp->Name().Merged() + ">" + " is expected, but " +
33         "<" + val->Name().Merged() + ">"  + " found";
34     return false;
35   }
36   if (exp->BodyText() != val->BodyText()) {
37     *error = "<" + exp->Name().LocalPart() + ">" + exp->BodyText() +
38         "</" + exp->Name().LocalPart() + ">" " is expected, but found " +
39         "<" + exp->Name().LocalPart() + ">" + val->BodyText() +
40         "</" + exp->Name().LocalPart() + ">";
41     return false;
42   }
43
44   for (const XmlAttr* exp_attr = exp->FirstAttr(); exp_attr != NULL;
45        exp_attr = exp_attr->NextAttr()) {
46     if (exp_attr->Name().Namespace() == kXmlNsNs ||
47         exp_attr->Name() == QName(kXmlNs)) {
48       continue; // Skip NS attributes.
49     }
50     if (val->Attr(exp_attr->Name()) != exp_attr->Value()) {
51       *error = "In <" + exp->Name().LocalPart() + "> attribute " +
52           exp_attr->Name().LocalPart() + " is expected to be set to " +
53           exp_attr->Value();
54       return false;
55     }
56   }
57
58   for (const XmlAttr* val_attr = val->FirstAttr(); val_attr;
59        val_attr = val_attr->NextAttr()) {
60     if (val_attr->Name().Namespace() == kXmlNsNs ||
61         val_attr->Name() == QName(kXmlNs)) {
62       continue; // Skip NS attributes.
63     }
64     if (exp->Attr(val_attr->Name()) != val_attr->Value()) {
65       *error = "In <" + exp->Name().LocalPart() + "> unexpected attribute " +
66           val_attr->Name().LocalPart();
67       return false;
68     }
69   }
70
71   const XmlElement* exp_child = exp->FirstElement();
72   const XmlElement* val_child = val->FirstElement();
73   while (exp_child && val_child) {
74     if (!VerifyXml(exp_child, val_child, error))
75       return false;
76     exp_child = exp_child->NextElement();
77     val_child = val_child->NextElement();
78   }
79   if (exp_child) {
80     *error = "<" + exp_child->Name().Merged() + "> is expected, but not found";
81     return false;
82   }
83
84   if (val_child) {
85     *error = "Unexpected <" + val_child->Name().Merged() + "> found";
86     return false;
87   }
88
89   return true;
90 }
91
92 }  // namespace
93
94 // Each of the tests below try to parse a message, format it again,
95 // and then verify that the formatted message is the same as the
96 // original stanza. The sample messages were generated by libjingle.
97
98 TEST(JingleMessageTest, SessionInitiate) {
99   const char* kTestSessionInitiateMessage =
100       "<iq to='user@gmail.com/chromoting016DBB07' type='set' "
101         "from='user@gmail.com/chromiumsy5C6A652D' "
102         "xmlns='jabber:client'>"
103         "<jingle xmlns='urn:xmpp:jingle:1' "
104           "action='session-initiate' sid='2227053353' "
105           "initiator='user@gmail.com/chromiumsy5C6A652D'>"
106           "<content name='chromoting' creator='initiator'>"
107             "<description xmlns='google:remoting'>"
108               "<control transport='stream' version='2'/>"
109               "<event transport='stream' version='2'/>"
110               "<video transport='stream' version='2' codec='vp8'/>"
111               "<audio transport='stream' version='2' codec='verbatim'/>"
112               "<initial-resolution width='640' height='480'/>"
113               "<authentication><auth-token>"
114                 "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw="
115               "</auth-token></authentication>"
116           "</description>"
117           "<transport xmlns='http://www.google.com/transport/p2p'/>"
118           "</content>"
119         "</jingle>"
120       "</iq>";
121   scoped_ptr<XmlElement> source_message(
122       XmlElement::ForStr(kTestSessionInitiateMessage));
123   ASSERT_TRUE(source_message.get());
124
125   EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get()));
126
127   JingleMessage message;
128   std::string error;
129   EXPECT_TRUE(message.ParseXml(source_message.get(), &error)) << error;
130
131   EXPECT_EQ(message.action, JingleMessage::SESSION_INITIATE);
132
133   scoped_ptr<XmlElement> formatted_message(message.ToXml());
134   ASSERT_TRUE(formatted_message.get());
135   EXPECT_TRUE(VerifyXml(formatted_message.get(), source_message.get(), &error))
136       << error;
137 }
138
139 TEST(JingleMessageTest, SessionAccept) {
140   const char* kTestSessionAcceptMessage =
141       "<cli:iq from='user@gmail.com/chromoting016DBB07' "
142         "to='user@gmail.com/chromiumsy5C6A652D' type='set' "
143         "xmlns:cli='jabber:client'>"
144         "<jingle action='session-accept' sid='2227053353' "
145           "xmlns='urn:xmpp:jingle:1'>i"
146           "<content creator='initiator' name='chromoting'>"
147             "<description xmlns='google:remoting'>"
148               "<control transport='stream' version='2'/>"
149               "<event transport='stream' version='2'/>"
150               "<video codec='vp8' transport='stream' version='2'/>"
151               "<audio transport='stream' version='2' codec='verbatim'/>"
152               "<initial-resolution height='480' width='640'/>"
153               "<authentication><certificate>"
154                 "MIICpjCCAY6gW0Cert0TANBgkqhkiG9w0BAQUFA="
155               "</certificate></authentication>"
156             "</description>"
157             "<transport xmlns='http://www.google.com/transport/p2p'/>"
158           "</content>"
159         "</jingle>"
160       "</cli:iq>";
161
162   scoped_ptr<XmlElement> source_message(
163       XmlElement::ForStr(kTestSessionAcceptMessage));
164   ASSERT_TRUE(source_message.get());
165
166   EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get()));
167
168   JingleMessage message;
169   std::string error;
170   EXPECT_TRUE(message.ParseXml(source_message.get(), &error)) << error;
171
172   EXPECT_EQ(message.action, JingleMessage::SESSION_ACCEPT);
173
174   scoped_ptr<XmlElement> formatted_message(message.ToXml());
175   ASSERT_TRUE(formatted_message.get());
176   EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error))
177       << error;
178 }
179
180 TEST(JingleMessageTest, TransportInfo) {
181   const char* kTestTransportInfoMessage =
182       "<cli:iq to='user@gmail.com/chromoting016DBB07' type='set' "
183       "xmlns:cli='jabber:client'><jingle xmlns='urn:xmpp:jingle:1' "
184       "action='transport-info' sid='2227053353'><content name='chromoting' "
185       "creator='initiator'><transport "
186       "xmlns='http://www.google.com/transport/p2p'><candidate name='event' "
187       "address='172.23.164.186' port='57040' preference='1' "
188       "username='tPUyEAmQrEw3y7hi' protocol='udp' generation='0' "
189       "password='2iRdhLfawKZC5ydJ' type='local'/><candidate name='video' "
190       "address='172.23.164.186' port='42171' preference='1' "
191       "username='EPK3CXo5sTLJSez0' protocol='udp' generation='0' "
192       "password='eM0VUfUkZ+1Pyi0M' type='local'/></transport></content>"
193       "</jingle></cli:iq>";
194
195   scoped_ptr<XmlElement> source_message(
196       XmlElement::ForStr(kTestTransportInfoMessage));
197   ASSERT_TRUE(source_message.get());
198
199   EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get()));
200
201   JingleMessage message;
202   std::string error;
203   EXPECT_TRUE(message.ParseXml(source_message.get(), &error)) << error;
204
205   EXPECT_EQ(message.action, JingleMessage::TRANSPORT_INFO);
206   EXPECT_EQ(message.candidates.size(), 2U);
207
208   scoped_ptr<XmlElement> formatted_message(message.ToXml());
209   ASSERT_TRUE(formatted_message.get());
210   EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error))
211       << error;
212 }
213
214 TEST(JingleMessageTest, SessionTerminate) {
215   const char* kTestSessionTerminateMessage =
216       "<cli:iq from='user@gmail.com/chromoting016DBB07' "
217       "to='user@gmail.com/chromiumsy5C6A652D' type='set' "
218       "xmlns:cli='jabber:client'><jingle action='session-terminate' "
219       "sid='2227053353' xmlns='urn:xmpp:jingle:1'><reason><success/>"
220       "</reason></jingle></cli:iq>";
221
222   scoped_ptr<XmlElement> source_message(
223       XmlElement::ForStr(kTestSessionTerminateMessage));
224   ASSERT_TRUE(source_message.get());
225
226   EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get()));
227
228   JingleMessage message;
229   std::string error;
230   EXPECT_TRUE(message.ParseXml(source_message.get(), &error)) << error;
231
232   EXPECT_EQ(message.action, JingleMessage::SESSION_TERMINATE);
233
234   scoped_ptr<XmlElement> formatted_message(message.ToXml());
235   ASSERT_TRUE(formatted_message.get());
236   EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error))
237       << error;
238 }
239
240 TEST(JingleMessageTest, SessionInfo) {
241   const char* kTestSessionTerminateMessage =
242       "<cli:iq from='user@gmail.com/chromoting016DBB07' "
243       "to='user@gmail.com/chromiumsy5C6A652D' type='set' "
244       "xmlns:cli='jabber:client'><jingle action='session-info' "
245       "sid='2227053353' xmlns='urn:xmpp:jingle:1'><test-info>TestMessage"
246       "</test-info></jingle></cli:iq>";
247
248   scoped_ptr<XmlElement> source_message(
249       XmlElement::ForStr(kTestSessionTerminateMessage));
250   ASSERT_TRUE(source_message.get());
251
252   EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get()));
253
254   JingleMessage message;
255   std::string error;
256   EXPECT_TRUE(message.ParseXml(source_message.get(), &error)) << error;
257
258   EXPECT_EQ(message.action, JingleMessage::SESSION_INFO);
259   ASSERT_TRUE(message.info.get() != NULL);
260   EXPECT_TRUE(message.info->Name() ==
261               buzz::QName("urn:xmpp:jingle:1", "test-info"));
262
263   scoped_ptr<XmlElement> formatted_message(message.ToXml());
264   ASSERT_TRUE(formatted_message.get());
265   EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error))
266       << error;
267 }
268
269 TEST(JingleMessageReplyTest, ToXml) {
270   const char* kTestIncomingMessage =
271       "<cli:iq from='user@gmail.com/chromoting016DBB07' id='4' "
272       "to='user@gmail.com/chromiumsy5C6A652D' type='set' "
273       "xmlns:cli='jabber:client'><jingle action='session-terminate' "
274       "sid='2227053353' xmlns='urn:xmpp:jingle:1'><reason><success/>"
275       "</reason></jingle></cli:iq>";
276   scoped_ptr<XmlElement> incoming_message(
277       XmlElement::ForStr(kTestIncomingMessage));
278   ASSERT_TRUE(incoming_message.get());
279
280   struct TestCase {
281     const JingleMessageReply::ErrorType error;
282     std::string error_text;
283     std::string expected_text;
284   } tests[] = {
285     { JingleMessageReply::BAD_REQUEST, "", "<iq xmlns='jabber:client' "
286       "to='user@gmail.com/chromoting016DBB07' id='4' type='error'><jingle "
287       "action='session-terminate' sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
288       "<reason><success/></reason></jingle><error type='modify'><bad-request/>"
289       "</error></iq>" },
290     { JingleMessageReply::BAD_REQUEST, "ErrorText", "<iq xmlns='jabber:client' "
291       "to='user@gmail.com/chromoting016DBB07' id='4' type='error'><jingle "
292       "action='session-terminate' sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
293       "<reason><success/></reason></jingle><error type='modify'><bad-request/>"
294       "<text xml:lang='en'>ErrorText</text></error></iq>" },
295     { JingleMessageReply::NOT_IMPLEMENTED, "", "<iq xmlns='jabber:client' "
296       "to='user@gmail.com/chromoting016DBB07' id='4' type='error'><jingle "
297       "action='session-terminate' sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
298       "<reason><success/></reason></jingle><error type='cancel'>"
299       "<feature-bad-request/></error></iq>" },
300     { JingleMessageReply::INVALID_SID, "",  "<iq xmlns='jabber:client' "
301       "to='user@gmail.com/chromoting016DBB07' id='4' type='error'><jingle "
302       "action='session-terminate' sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
303       "<reason><success/></reason></jingle><error type='modify'>"
304       "<item-not-found/><text xml:lang='en'>Invalid SID</text></error></iq>" },
305     { JingleMessageReply::INVALID_SID, "ErrorText", "<iq xmlns='jabber:client' "
306       "to='user@gmail.com/chromoting016DBB07' id='4' type='error'><jingle "
307       "action='session-terminate' sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
308       "<reason><success/></reason></jingle><error type='modify'>"
309       "<item-not-found/><text xml:lang='en'>ErrorText</text></error></iq>" },
310     { JingleMessageReply::UNEXPECTED_REQUEST, "", "<iq xmlns='jabber:client' "
311       "to='user@gmail.com/chromoting016DBB07' id='4' type='error'><jingle "
312       "action='session-terminate' sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
313       "<reason><success/></reason></jingle><error type='modify'>"
314       "<unexpected-request/></error></iq>" },
315   };
316
317   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
318     JingleMessageReply reply_msg;
319     if (tests[i].error_text.empty()) {
320       reply_msg = JingleMessageReply(tests[i].error);
321     } else {
322       reply_msg = JingleMessageReply(tests[i].error, tests[i].error_text);
323     }
324     scoped_ptr<XmlElement> reply(reply_msg.ToXml(incoming_message.get()));
325
326     scoped_ptr<XmlElement> expected(XmlElement::ForStr(tests[i].expected_text));
327     ASSERT_TRUE(expected.get());
328
329     std::string error;
330     EXPECT_TRUE(VerifyXml(expected.get(), reply.get(), &error)) << error;
331   }
332 }
333
334 TEST(JingleMessageTest, ErrorMessage) {
335   const char* kTestSessionInitiateErrorMessage =
336       "<iq to='user@gmail.com/chromoting016DBB07' type='error' "
337         "from='user@gmail.com/chromiumsy5C6A652D' "
338         "xmlns='jabber:client'>"
339         "<jingle xmlns='urn:xmpp:jingle:1' "
340         "action='session-initiate' sid='2227053353' "
341         "initiator='user@gmail.com/chromiumsy5C6A652D'>"
342           "<content name='chromoting' creator='initiator'>"
343             "<description xmlns='google:remoting'>"
344               "<control transport='stream' version='2'/>"
345               "<event transport='stream' version='2'/>"
346               "<video transport='stream' version='2' codec='vp8'/>"
347               "<audio transport='stream' version='2' codec='verbatim'/>"
348               "<initial-resolution width='800' height='600'/>"
349               "<authentication><auth-token>"
350                 "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw="
351               "</auth-token></authentication>"
352             "</description>"
353             "<transport xmlns='http://www.google.com/transport/p2p'/>"
354           "</content>"
355         "</jingle>"
356         "<error code='501' type='cancel'>"
357           "<feature-not-implemented "
358             "xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
359         "</error>"
360       "</iq>";
361   scoped_ptr<XmlElement> source_message(
362       XmlElement::ForStr(kTestSessionInitiateErrorMessage));
363   ASSERT_TRUE(source_message.get());
364
365   EXPECT_FALSE(JingleMessage::IsJingleMessage(source_message.get()));
366
367   JingleMessage message;
368   std::string error;
369   EXPECT_FALSE(message.ParseXml(source_message.get(), &error));
370   EXPECT_FALSE(error.empty());
371 }
372
373 }  // namespace protocol
374 }  // namespace remoting