jingle_messages_unittest.cc 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  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. #include "remoting/protocol/jingle_messages.h"
  5. #include <stddef.h>
  6. #include "base/strings/string_util.h"
  7. #include "remoting/protocol/content_description.h"
  8. #include "remoting/signaling/xmpp_constants.h"
  9. #include "testing/gmock/include/gmock/gmock.h"
  10. #include "testing/gtest/include/gtest/gtest.h"
  11. #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
  12. using jingle_xmpp::QName;
  13. using jingle_xmpp::XmlAttr;
  14. using jingle_xmpp::XmlElement;
  15. namespace remoting {
  16. namespace protocol {
  17. namespace {
  18. const char kXmlNsNs[] = "http://www.w3.org/2000/xmlns/";
  19. const char kXmlNs[] = "xmlns";
  20. // Compares two XML blobs and returns true if they are
  21. // equivalent. Otherwise |error| is set to error message that
  22. // specifies the first test.
  23. bool VerifyXml(const XmlElement* exp,
  24. const XmlElement* val,
  25. std::string* error) {
  26. if (exp->Name() != val->Name()) {
  27. *error = "<" + exp->Name().Merged() + ">" + " is expected, but " +
  28. "<" + val->Name().Merged() + ">" + " found";
  29. return false;
  30. }
  31. if (exp->BodyText() != val->BodyText()) {
  32. *error = "<" + exp->Name().LocalPart() + ">" + exp->BodyText() +
  33. "</" + exp->Name().LocalPart() + ">" " is expected, but found " +
  34. "<" + exp->Name().LocalPart() + ">" + val->BodyText() +
  35. "</" + exp->Name().LocalPart() + ">";
  36. return false;
  37. }
  38. for (const XmlAttr* exp_attr = exp->FirstAttr(); exp_attr != nullptr;
  39. exp_attr = exp_attr->NextAttr()) {
  40. if (exp_attr->Name().Namespace() == kXmlNsNs ||
  41. exp_attr->Name() == QName(kXmlNs)) {
  42. continue; // Skip NS attributes.
  43. }
  44. if (val->Attr(exp_attr->Name()) != exp_attr->Value()) {
  45. *error = "In <" + exp->Name().LocalPart() + "> attribute " +
  46. exp_attr->Name().LocalPart() + " is expected to be set to " +
  47. exp_attr->Value();
  48. return false;
  49. }
  50. }
  51. for (const XmlAttr* val_attr = val->FirstAttr(); val_attr;
  52. val_attr = val_attr->NextAttr()) {
  53. if (val_attr->Name().Namespace() == kXmlNsNs ||
  54. val_attr->Name() == QName(kXmlNs)) {
  55. continue; // Skip NS attributes.
  56. }
  57. if (exp->Attr(val_attr->Name()) != val_attr->Value()) {
  58. *error = "In <" + exp->Name().LocalPart() + "> unexpected attribute " +
  59. val_attr->Name().LocalPart();
  60. return false;
  61. }
  62. }
  63. const XmlElement* exp_child = exp->FirstElement();
  64. const XmlElement* val_child = val->FirstElement();
  65. while (exp_child && val_child) {
  66. if (!VerifyXml(exp_child, val_child, error))
  67. return false;
  68. exp_child = exp_child->NextElement();
  69. val_child = val_child->NextElement();
  70. }
  71. if (exp_child) {
  72. *error = "<" + exp_child->Name().Merged() + "> is expected, but not found";
  73. return false;
  74. }
  75. if (val_child) {
  76. *error = "Unexpected <" + val_child->Name().Merged() + "> found";
  77. return false;
  78. }
  79. return true;
  80. }
  81. // Parses |message_text| to JingleMessage.
  82. void ParseJingleMessageFromXml(const char* message_text,
  83. JingleMessage* parsed) {
  84. std::unique_ptr<XmlElement> source_message(XmlElement::ForStr(message_text));
  85. ASSERT_TRUE(source_message.get());
  86. EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get()));
  87. std::string error;
  88. EXPECT_TRUE(parsed->ParseXml(source_message.get(), &error)) << error;
  89. }
  90. // Parses |message_text| to JingleMessage then attempts to format it to XML and
  91. // verifies that the same XML content is generated.
  92. void ParseFormatAndCompare(const char* message_text, JingleMessage* parsed) {
  93. std::unique_ptr<XmlElement> source_message(XmlElement::ForStr(message_text));
  94. ASSERT_TRUE(source_message.get());
  95. EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get()));
  96. std::string error;
  97. EXPECT_TRUE(parsed->ParseXml(source_message.get(), &error)) << error;
  98. std::unique_ptr<XmlElement> formatted_message(parsed->ToXml());
  99. ASSERT_TRUE(formatted_message.get());
  100. EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error))
  101. << error;
  102. }
  103. } // namespace
  104. // Session-initiate message for current ICE-based protocol.
  105. TEST(JingleMessageTest, SessionInitiate) {
  106. const char* kTestSessionInitiateMessage =
  107. "<iq to='user@gmail.com/chromoting016DBB07' type='set' "
  108. "from='user@gmail.com/chromiumsy5C6A652D' "
  109. "xmlns='jabber:client'>"
  110. "<jingle xmlns='urn:xmpp:jingle:1' "
  111. "action='session-initiate' sid='2227053353' "
  112. "initiator='user@gmail.com/chromiumsy5C6A652D'>"
  113. "<content name='chromoting' creator='initiator'>"
  114. "<description xmlns='google:remoting'>"
  115. "<standard-ice/>"
  116. "<control transport='stream' version='2'/>"
  117. "<event transport='stream' version='2'/>"
  118. "<video transport='stream' version='2' codec='vp8'/>"
  119. "<audio transport='stream' version='2' codec='verbatim'/>"
  120. "<authentication><auth-token>"
  121. "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw="
  122. "</auth-token></authentication>"
  123. "</description>"
  124. "</content>"
  125. "</jingle>"
  126. "</iq>";
  127. JingleMessage message;
  128. ParseFormatAndCompare(kTestSessionInitiateMessage, &message);
  129. EXPECT_EQ(message.action, JingleMessage::SESSION_INITIATE);
  130. EXPECT_FALSE(message.description->config()->webrtc_supported());
  131. EXPECT_TRUE(message.description->config()->ice_supported());
  132. }
  133. // Session-initiate message for WebRTC-based protocol.
  134. TEST(JingleMessageTest, SessionInitiateWebrtc) {
  135. const char* kTestSessionInitiateMessage =
  136. "<iq to='user@gmail.com/chromoting016DBB07' type='set' "
  137. "from='user@gmail.com/chromiumsy5C6A652D' "
  138. "xmlns='jabber:client'>"
  139. "<jingle xmlns='urn:xmpp:jingle:1' "
  140. "action='session-initiate' sid='2227053353' "
  141. "initiator='user@gmail.com/chromiumsy5C6A652D'>"
  142. "<content name='chromoting' creator='initiator'>"
  143. "<description xmlns='google:remoting'>"
  144. "<authentication><auth-token>"
  145. "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw="
  146. "</auth-token></authentication>"
  147. "</description>"
  148. "<transport xmlns='google:remoting:webrtc' />"
  149. "</content>"
  150. "</jingle>"
  151. "</iq>";
  152. JingleMessage message;
  153. ParseFormatAndCompare(kTestSessionInitiateMessage, &message);
  154. EXPECT_EQ(message.action, JingleMessage::SESSION_INITIATE);
  155. EXPECT_TRUE(message.description->config()->webrtc_supported());
  156. EXPECT_FALSE(message.description->config()->ice_supported());
  157. }
  158. // Session-initiate message for hybrid clients that support both versions of the
  159. // protocol.
  160. TEST(JingleMessageTest, SessionInitiateHybrid) {
  161. const char* kTestSessionInitiateMessage =
  162. "<iq to='user@gmail.com/chromoting016DBB07' type='set' "
  163. "from='user@gmail.com/chromiumsy5C6A652D' "
  164. "xmlns='jabber:client'>"
  165. "<jingle xmlns='urn:xmpp:jingle:1' "
  166. "action='session-initiate' sid='2227053353' "
  167. "initiator='user@gmail.com/chromiumsy5C6A652D'>"
  168. "<content name='chromoting' creator='initiator'>"
  169. "<description xmlns='google:remoting'>"
  170. "<standard-ice/>"
  171. "<control transport='stream' version='2'/>"
  172. "<event transport='stream' version='2'/>"
  173. "<video transport='stream' version='2' codec='vp8'/>"
  174. "<audio transport='stream' version='2' codec='verbatim'/>"
  175. "<authentication><auth-token>"
  176. "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw="
  177. "</auth-token></authentication>"
  178. "</description>"
  179. "<transport xmlns='google:remoting:webrtc' />"
  180. "</content>"
  181. "</jingle>"
  182. "</iq>";
  183. JingleMessage message;
  184. ParseFormatAndCompare(kTestSessionInitiateMessage, &message);
  185. EXPECT_EQ(message.action, JingleMessage::SESSION_INITIATE);
  186. EXPECT_TRUE(message.description->config()->webrtc_supported());
  187. EXPECT_TRUE(message.description->config()->ice_supported());
  188. }
  189. // Old GICE session-initiate message from older clients that are no longer
  190. // supported.
  191. TEST(JingleMessageTest, SessionInitiateNoIce) {
  192. const char* kTestSessionInitiateMessage =
  193. "<iq to='user@gmail.com/chromoting016DBB07' type='set' "
  194. "from='user@gmail.com/chromiumsy5C6A652D' "
  195. "xmlns='jabber:client'>"
  196. "<jingle xmlns='urn:xmpp:jingle:1' "
  197. "action='session-initiate' sid='2227053353' "
  198. "initiator='user@gmail.com/chromiumsy5C6A652D'>"
  199. "<content name='chromoting' creator='initiator'>"
  200. "<description xmlns='google:remoting'>"
  201. "<control transport='stream' version='2'/>"
  202. "<event transport='stream' version='2'/>"
  203. "<video transport='stream' version='2' codec='vp8'/>"
  204. "<audio transport='stream' version='2' codec='verbatim'/>"
  205. "<authentication><auth-token>"
  206. "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw="
  207. "</auth-token></authentication>"
  208. "</description>"
  209. "</content>"
  210. "</jingle>"
  211. "</iq>";
  212. JingleMessage message;
  213. ParseJingleMessageFromXml(kTestSessionInitiateMessage, &message);
  214. EXPECT_EQ(message.action, JingleMessage::SESSION_INITIATE);
  215. EXPECT_FALSE(message.description->config()->ice_supported());
  216. }
  217. // Session-accept message for current ICE-based protocol.
  218. TEST(JingleMessageTest, SessionAccept) {
  219. const char* kTestSessionAcceptMessage =
  220. "<cli:iq from='user@gmail.com/chromoting016DBB07' "
  221. "to='user@gmail.com/chromiumsy5C6A652D' type='set' "
  222. "xmlns:cli='jabber:client'>"
  223. "<jingle action='session-accept' sid='2227053353' "
  224. "xmlns='urn:xmpp:jingle:1'>"
  225. "<content creator='initiator' name='chromoting'>"
  226. "<description xmlns='google:remoting'>"
  227. "<standard-ice/>"
  228. "<control transport='stream' version='2'/>"
  229. "<event transport='stream' version='2'/>"
  230. "<video codec='vp8' transport='stream' version='2'/>"
  231. "<audio transport='stream' version='2' codec='verbatim'/>"
  232. "<authentication><certificate>"
  233. "MIICpjCCAY6gW0Cert0TANBgkqhkiG9w0BAQUFA="
  234. "</certificate></authentication>"
  235. "</description>"
  236. "</content>"
  237. "</jingle>"
  238. "</cli:iq>";
  239. JingleMessage message;
  240. ParseFormatAndCompare(kTestSessionAcceptMessage, &message);
  241. EXPECT_EQ(message.action, JingleMessage::SESSION_ACCEPT);
  242. EXPECT_FALSE(message.description->config()->webrtc_supported());
  243. EXPECT_TRUE(message.description->config()->ice_supported());
  244. }
  245. // Session-accept message for WebRTC-based protocol.
  246. TEST(JingleMessageTest, SessionAcceptWebrtc) {
  247. const char* kTestSessionAcceptMessage =
  248. "<cli:iq from='user@gmail.com/chromoting016DBB07' "
  249. "to='user@gmail.com/chromiumsy5C6A652D' type='set' "
  250. "xmlns:cli='jabber:client'>"
  251. "<jingle action='session-accept' sid='2227053353' "
  252. "xmlns='urn:xmpp:jingle:1'>"
  253. "<content creator='initiator' name='chromoting'>"
  254. "<description xmlns='google:remoting'>"
  255. "<authentication><certificate>"
  256. "MIICpjCCAY6gW0Cert0TANBgkqhkiG9w0BAQUFA="
  257. "</certificate></authentication>"
  258. "</description>"
  259. "<transport xmlns='google:remoting:webrtc' />"
  260. "</content>"
  261. "</jingle>"
  262. "</cli:iq>";
  263. JingleMessage message;
  264. ParseFormatAndCompare(kTestSessionAcceptMessage, &message);
  265. EXPECT_EQ(message.action, JingleMessage::SESSION_ACCEPT);
  266. EXPECT_TRUE(message.description->config()->webrtc_supported());
  267. EXPECT_FALSE(message.description->config()->ice_supported());
  268. }
  269. // Old GICE session-accept message from older host that are no longer
  270. // supported.
  271. TEST(JingleMessageTest, SessionAcceptNoIce) {
  272. const char* kTestSessionAcceptMessage =
  273. "<cli:iq from='user@gmail.com/chromoting016DBB07' "
  274. "to='user@gmail.com/chromiumsy5C6A652D' type='set' "
  275. "xmlns:cli='jabber:client'>"
  276. "<jingle action='session-accept' sid='2227053353' "
  277. "xmlns='urn:xmpp:jingle:1'>"
  278. "<content creator='initiator' name='chromoting'>"
  279. "<description xmlns='google:remoting'>"
  280. "<control transport='stream' version='2'/>"
  281. "<event transport='stream' version='2'/>"
  282. "<video codec='vp8' transport='stream' version='2'/>"
  283. "<audio transport='stream' version='2' codec='verbatim'/>"
  284. "<authentication><certificate>"
  285. "MIICpjCCAY6gW0Cert0TANBgkqhkiG9w0BAQUFA="
  286. "</certificate></authentication>"
  287. "</description>"
  288. "</content>"
  289. "</jingle>"
  290. "</cli:iq>";
  291. JingleMessage message;
  292. ParseJingleMessageFromXml(kTestSessionAcceptMessage, &message);
  293. EXPECT_EQ(message.action, JingleMessage::SESSION_ACCEPT);
  294. EXPECT_FALSE(message.description->config()->ice_supported());
  295. EXPECT_FALSE(message.description->config()->webrtc_supported());
  296. }
  297. TEST(JingleMessageTest, IceTransportInfo) {
  298. const char* kTestIceTransportInfoMessage =
  299. "<cli:iq to='user@gmail.com/chromoting016DBB07' "
  300. " from='foo@bar.com/resource' "
  301. " type='set' xmlns:cli='jabber:client'>"
  302. " <jingle xmlns='urn:xmpp:jingle:1' action='transport-info' "
  303. " sid='2227053353'>"
  304. " <content name='chromoting' creator='initiator'>"
  305. " <transport xmlns='google:remoting:ice'>"
  306. " <credentials channel='event' ufrag='tPUyEAmQrEw3y7hi' "
  307. " password='2iRdhLfawKZC5ydJ'/>"
  308. " <credentials channel='video' ufrag='EPK3CXo5sTLJSez0' "
  309. " password='eM0VUfUkZ+1Pyi0M'/>"
  310. " <candidate name='event' foundation='725747215' "
  311. " address='172.23.164.186' port='59089' type='local' "
  312. " protocol='udp' priority='2122194688' generation='0'/>"
  313. " <candidate name='video' foundation='3623806809' "
  314. " address='172.23.164.186' port='57040' type='local' "
  315. " protocol='udp' priority='2122194688' generation='0'/>"
  316. " </transport>"
  317. " </content>"
  318. " </jingle>"
  319. "</cli:iq>";
  320. JingleMessage message;
  321. ParseFormatAndCompare(kTestIceTransportInfoMessage, &message);
  322. EXPECT_EQ(message.action, JingleMessage::TRANSPORT_INFO);
  323. IceTransportInfo transport_info;
  324. EXPECT_TRUE(transport_info.ParseXml(message.transport_info.get()));
  325. EXPECT_EQ(transport_info.ice_credentials.size(), 2U);
  326. EXPECT_EQ(transport_info.candidates.size(), 2U);
  327. }
  328. TEST(JingleMessageTest, SessionTerminate) {
  329. const char* kTestSessionTerminateMessage =
  330. "<cli:iq from='user@gmail.com/chromoting016DBB07' "
  331. "to='user@gmail.com/chromiumsy5C6A652D' type='set' "
  332. "xmlns:cli='jabber:client'><jingle action='session-terminate' "
  333. "sid='2227053353' xmlns='urn:xmpp:jingle:1'><reason><success/>"
  334. "</reason></jingle></cli:iq>";
  335. JingleMessage message;
  336. ParseFormatAndCompare(kTestSessionTerminateMessage, &message);
  337. EXPECT_EQ(message.action, JingleMessage::SESSION_TERMINATE);
  338. }
  339. TEST(JingleMessageTest, SessionInfo) {
  340. const char* kTestSessionInfoMessage =
  341. "<cli:iq from='user@gmail.com/chromoting016DBB07' "
  342. "to='user@gmail.com/chromiumsy5C6A652D' type='set' "
  343. "xmlns:cli='jabber:client'><jingle action='session-info' "
  344. "sid='2227053353' xmlns='urn:xmpp:jingle:1'><test-info>TestMessage"
  345. "</test-info></jingle></cli:iq>";
  346. JingleMessage message;
  347. ParseFormatAndCompare(kTestSessionInfoMessage, &message);
  348. EXPECT_EQ(message.action, JingleMessage::SESSION_INFO);
  349. ASSERT_TRUE(message.info.get() != nullptr);
  350. EXPECT_TRUE(message.info->Name() ==
  351. jingle_xmpp::QName("urn:xmpp:jingle:1", "test-info"));
  352. }
  353. TEST(JingleMessageReplyTest, ToXml) {
  354. const char* kTestIncomingMessage1 =
  355. "<cli:iq from='user@gmail.com/chromoting016DBB07' id='4' "
  356. "to='user@gmail.com/chromiumsy5C6A652D' type='set' "
  357. "xmlns:cli='jabber:client'><jingle action='session-terminate' "
  358. "sid='2227053353' xmlns='urn:xmpp:jingle:1'><reason><success/>"
  359. "</reason></jingle></cli:iq>";
  360. const char* kTestIncomingMessage2 =
  361. "<cli:iq from='remoting@bot.talk.google.com' id='4' "
  362. "to='user@gmail.com/chromoting_ftl_5C6A652D' type='set' "
  363. "xmlns:cli='jabber:client'><jingle action='session-terminate' "
  364. "sid='2227053353' xmlns='urn:xmpp:jingle:1'><reason><success/>"
  365. "</reason></jingle></cli:iq>";
  366. struct TestCase {
  367. const JingleMessageReply::ErrorType error;
  368. std::string error_text;
  369. std::string expected_text;
  370. std::string incoming_message;
  371. } tests[] = {
  372. {JingleMessageReply::BAD_REQUEST, "",
  373. "<iq xmlns='jabber:client' "
  374. "to='user@gmail.com/chromoting016DBB07' id='4' type='error'><jingle "
  375. "action='session-terminate' sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
  376. "<reason><success/></reason></jingle><error type='modify'><bad-request/>"
  377. "</error></iq>",
  378. kTestIncomingMessage1},
  379. {JingleMessageReply::BAD_REQUEST, "ErrorText",
  380. "<iq xmlns='jabber:client' "
  381. "to='user@gmail.com/chromoting016DBB07' id='4' type='error'><jingle "
  382. "action='session-terminate' sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
  383. "<reason><success/></reason></jingle><error type='modify'><bad-request/>"
  384. "<text xml:lang='en'>ErrorText</text></error></iq>",
  385. kTestIncomingMessage1},
  386. {JingleMessageReply::NOT_IMPLEMENTED, "",
  387. "<iq xmlns='jabber:client' "
  388. "to='user@gmail.com/chromoting016DBB07' id='4' type='error'><jingle "
  389. "action='session-terminate' sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
  390. "<reason><success/></reason></jingle><error type='cancel'>"
  391. "<feature-bad-request/></error></iq>",
  392. kTestIncomingMessage1},
  393. {JingleMessageReply::INVALID_SID, "",
  394. "<iq xmlns='jabber:client' "
  395. "to='user@gmail.com/chromoting016DBB07' id='4' type='error'><jingle "
  396. "action='session-terminate' sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
  397. "<reason><success/></reason></jingle><error type='modify'>"
  398. "<item-not-found/><text xml:lang='en'>Invalid SID</text></error></iq>",
  399. kTestIncomingMessage1},
  400. {JingleMessageReply::INVALID_SID, "ErrorText",
  401. "<iq xmlns='jabber:client' "
  402. "to='user@gmail.com/chromoting016DBB07' id='4' type='error'><jingle "
  403. "action='session-terminate' sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
  404. "<reason><success/></reason></jingle><error type='modify'>"
  405. "<item-not-found/><text xml:lang='en'>ErrorText</text></error></iq>",
  406. kTestIncomingMessage1},
  407. {JingleMessageReply::UNEXPECTED_REQUEST, "",
  408. "<iq xmlns='jabber:client' "
  409. "to='user@gmail.com/chromoting016DBB07' id='4' type='error'><jingle "
  410. "action='session-terminate' sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
  411. "<reason><success/></reason></jingle><error type='modify'>"
  412. "<unexpected-request/></error></iq>",
  413. kTestIncomingMessage1},
  414. {JingleMessageReply::INVALID_SID, "ErrorText",
  415. "<iq xmlns='jabber:client' "
  416. "to='remoting@bot.talk.google.com' id='4' "
  417. "type='error'><jingle "
  418. "action='session-terminate' sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
  419. "<reason><success/></reason></jingle><error type='modify'>"
  420. "<item-not-found/><text xml:lang='en'>ErrorText</text></error></iq>",
  421. kTestIncomingMessage2},
  422. {JingleMessageReply::NONE, "",
  423. "<iq xmlns='jabber:client' to='remoting@bot.talk.google.com' id='4' "
  424. "type='result'><jingle xmlns='urn:xmpp:jingle:1'/></iq>",
  425. kTestIncomingMessage2},
  426. };
  427. for (size_t i = 0; i < std::size(tests); ++i) {
  428. std::unique_ptr<XmlElement> incoming_message(
  429. XmlElement::ForStr(tests[i].incoming_message));
  430. ASSERT_TRUE(incoming_message.get());
  431. SCOPED_TRACE(testing::Message() << "Running test case: " << i);
  432. JingleMessageReply reply_msg;
  433. if (tests[i].error_text.empty()) {
  434. reply_msg = JingleMessageReply(tests[i].error);
  435. } else {
  436. reply_msg = JingleMessageReply(tests[i].error, tests[i].error_text);
  437. }
  438. std::unique_ptr<XmlElement> reply(reply_msg.ToXml(incoming_message.get()));
  439. std::unique_ptr<XmlElement> expected(
  440. XmlElement::ForStr(tests[i].expected_text));
  441. ASSERT_TRUE(expected.get());
  442. std::string error;
  443. EXPECT_TRUE(VerifyXml(expected.get(), reply.get(), &error)) << error;
  444. }
  445. }
  446. TEST(JingleMessageTest, ErrorMessage) {
  447. const char* kTestSessionInitiateErrorMessage =
  448. "<iq to='user@gmail.com/chromoting016DBB07' type='error' "
  449. "from='user@gmail.com/chromiumsy5C6A652D' "
  450. "xmlns='jabber:client'>"
  451. "<jingle xmlns='urn:xmpp:jingle:1' "
  452. "action='session-initiate' sid='2227053353' "
  453. "initiator='user@gmail.com/chromiumsy5C6A652D'>"
  454. "<content name='chromoting' creator='initiator'>"
  455. "<description xmlns='google:remoting'>"
  456. "<control transport='stream' version='2'/>"
  457. "<event transport='stream' version='2'/>"
  458. "<video transport='stream' version='2' codec='vp8'/>"
  459. "<audio transport='stream' version='2' codec='verbatim'/>"
  460. "<authentication><auth-token>"
  461. "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw="
  462. "</auth-token></authentication>"
  463. "</description>"
  464. "</content>"
  465. "</jingle>"
  466. "<error code='501' type='cancel'>"
  467. "<feature-not-implemented "
  468. "xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"
  469. "</error>"
  470. "</iq>";
  471. std::unique_ptr<XmlElement> source_message(
  472. XmlElement::ForStr(kTestSessionInitiateErrorMessage));
  473. ASSERT_TRUE(source_message.get());
  474. EXPECT_FALSE(JingleMessage::IsJingleMessage(source_message.get()));
  475. JingleMessage message;
  476. std::string error;
  477. EXPECT_FALSE(message.ParseXml(source_message.get(), &error));
  478. EXPECT_FALSE(error.empty());
  479. }
  480. TEST(JingleMessageTest, RemotingErrorCode) {
  481. const char* kTestSessionTerminateMessageBegin =
  482. "<cli:iq from='user@gmail.com/chromoting016DBB07' "
  483. "to='user@gmail.com/chromiumsy5C6A652D' type='set' "
  484. "xmlns:cli='jabber:client'><jingle action='session-terminate' "
  485. "sid='2227053353' xmlns='urn:xmpp:jingle:1'><reason><decline/></reason>"
  486. "<gr:error-code xmlns:gr='google:remoting'>";
  487. const char* kTestSessionTerminateMessageEnd =
  488. "</gr:error-code>"
  489. "</jingle></cli:iq>";
  490. for (int i = OK; i <= ERROR_CODE_MAX; i++) {
  491. ErrorCode error = static_cast<ErrorCode>(i);
  492. std::string message_str = kTestSessionTerminateMessageBegin;
  493. message_str.append(ErrorCodeToString(error));
  494. message_str.append(kTestSessionTerminateMessageEnd);
  495. JingleMessage message;
  496. if (error == UNKNOWN_ERROR) {
  497. // We do not include UNKNOWN_ERROR in xml output, so VerifyXml will fail.
  498. ParseJingleMessageFromXml(message_str.c_str(), &message);
  499. } else {
  500. ParseFormatAndCompare(message_str.c_str(), &message);
  501. }
  502. EXPECT_EQ(message.action, JingleMessage::SESSION_TERMINATE);
  503. EXPECT_EQ(message.reason, JingleMessage::DECLINE);
  504. EXPECT_EQ(message.error_code, error);
  505. }
  506. }
  507. TEST(JingleMessageTest, AttachmentsMessage) {
  508. // Ordering of the "attachments" tag and other tags are irrelevant. But the
  509. // JingleMessage implementation always puts it before other tags, so we do the
  510. // same thing in test cases.
  511. const char* kMessageWithPluginTag =
  512. "<cli:iq from='user@gmail.com/chromoting016DBB07' "
  513. "to='user@gmail.com/chromiumsy5C6A652D' type='set' "
  514. "xmlns:cli='jabber:client'><jingle action='$1' "
  515. "sid='2227053353' xmlns='urn:xmpp:jingle:1'>"
  516. "<gr:attachments xmlns:gr='google:remoting'>"
  517. "<gr:sometag>some-message</gr:sometag>"
  518. "</gr:attachments>$2</jingle></cli:iq>";
  519. for (int i = JingleMessage::SESSION_INITIATE;
  520. i <= JingleMessage::TRANSPORT_INFO; i++) {
  521. JingleMessage::ActionType action_type =
  522. static_cast<JingleMessage::ActionType>(i);
  523. std::vector<std::string> substitutes = {
  524. JingleMessage::GetActionName(action_type)
  525. };
  526. if (action_type == JingleMessage::SESSION_INFO) {
  527. substitutes.push_back("<test-info>test-message</test-info>");
  528. } else if (action_type == JingleMessage::SESSION_TERMINATE) {
  529. substitutes.emplace_back();
  530. } else if (action_type == JingleMessage::TRANSPORT_INFO) {
  531. substitutes.push_back(
  532. "<content name='chromoting' creator='initiator'>"
  533. "<transport xmlns='google:remoting:webrtc'>"
  534. "<credentials channel='event' ufrag='tPUyEAmQrEw3y7hi' "
  535. "password='2iRdhLfawKZC5ydJ'/>"
  536. "<credentials channel='video' ufrag='EPK3CXo5sTLJSez0' "
  537. "password='eM0VUfUkZ+1Pyi0M'/>"
  538. "<candidate name='event' foundation='725747215' "
  539. "address='172.23.164.186' port='59089' type='local' "
  540. "protocol='udp' priority='2122194688' generation='0'/>"
  541. "<candidate name='video' foundation='3623806809' "
  542. "address='172.23.164.186' port='57040' type='local' "
  543. "protocol='udp' priority='2122194688' generation='0'/>"
  544. "</transport>"
  545. "</content>");
  546. } else {
  547. substitutes.push_back("<content name='chromoting' creator='initiator'>"
  548. "<description xmlns='google:remoting'>"
  549. "<authentication><auth-token>"
  550. "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw="
  551. "</auth-token></authentication>"
  552. "</description>"
  553. "<transport xmlns='google:remoting:webrtc' />"
  554. "</content>");
  555. }
  556. std::string message_str = base::ReplaceStringPlaceholders(
  557. kMessageWithPluginTag, substitutes, nullptr);
  558. JingleMessage message;
  559. ParseFormatAndCompare(message_str.c_str(), &message);
  560. EXPECT_TRUE(message.attachments);
  561. XmlElement expected(QName("google:remoting", "attachments"));
  562. expected.AddElement(new XmlElement(QName("google:remoting", "sometag")));
  563. expected.FirstElement()->SetBodyText("some-message");
  564. std::string error;
  565. EXPECT_TRUE(VerifyXml(&expected, message.attachments.get(), &error))
  566. << error;
  567. }
  568. }
  569. } // namespace protocol
  570. } // namespace remoting