Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/protocol/jingle_messages.h" | 5 #include "remoting/protocol/jingle_messages.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/macros.h" | 10 #include "base/macros.h" |
| 11 #include "base/strings/string_util.h" | |
| 11 #include "remoting/protocol/content_description.h" | 12 #include "remoting/protocol/content_description.h" |
| 12 #include "testing/gmock/include/gmock/gmock.h" | 13 #include "testing/gmock/include/gmock/gmock.h" |
| 13 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
| 14 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h" | 15 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h" |
| 15 #include "third_party/webrtc/libjingle/xmpp/constants.h" | 16 #include "third_party/webrtc/libjingle/xmpp/constants.h" |
| 16 | 17 |
| 17 using buzz::QName; | 18 using buzz::QName; |
| 18 using buzz::XmlAttr; | 19 using buzz::XmlAttr; |
| 19 using buzz::XmlElement; | 20 using buzz::XmlElement; |
| 20 | 21 |
| 21 namespace remoting { | 22 namespace remoting { |
| 22 namespace protocol { | 23 namespace protocol { |
| 23 | 24 |
| 24 namespace { | 25 namespace { |
| 25 | 26 |
| 26 const char kXmlNsNs[] = "http://www.w3.org/2000/xmlns/"; | 27 const char kXmlNsNs[] = "http://www.w3.org/2000/xmlns/"; |
| 27 const char kXmlNs[] = "xmlns"; | 28 const char kXmlNs[] = "xmlns"; |
| 28 | 29 |
| 30 bool VerifyXml(const XmlElement* exp, | |
| 31 const XmlElement* val, | |
| 32 std::string* error); | |
| 33 | |
| 34 bool VerifyXmlChildrenUnordered(const XmlElement* exp, | |
| 35 const XmlElement* val, | |
| 36 bool exp_is_expected, | |
| 37 std::string* error) { | |
| 38 const XmlElement* exp_child = exp->FirstElement(); | |
| 39 while (exp_child) { | |
| 40 const XmlElement* val_child = val->FirstElement(); | |
| 41 while (val_child) { | |
| 42 if (VerifyXml(exp_child, val_child, error)) { | |
| 43 break; | |
| 44 } | |
| 45 val_child = val_child->NextElement(); | |
| 46 } | |
| 47 if (!val_child) { | |
| 48 if (error->empty()) { | |
| 49 if (exp_is_expected) { | |
| 50 *error = "<" + exp_child->Name().Merged() + "> is expected, " | |
| 51 "but not found"; | |
| 52 } else { | |
| 53 *error = "Unexpected <" + exp_child->Name().Merged() + "> found"; | |
| 54 } | |
| 55 } | |
| 56 return false; | |
| 57 } | |
| 58 exp_child = exp_child->NextElement(); | |
| 59 } | |
| 60 return true; | |
| 61 } | |
| 62 | |
| 29 // Compares two XML blobs and returns true if they are | 63 // Compares two XML blobs and returns true if they are |
| 30 // equivalent. Otherwise |error| is set to error message that | 64 // equivalent. Otherwise |error| is set to error message that |
| 31 // specifies the first test. | 65 // specifies the first test. |
| 32 bool VerifyXml(const XmlElement* exp, | 66 bool VerifyXml(const XmlElement* exp, |
|
Sergey Ulanov
2016/12/14 01:31:50
There are some messages for which order matters. P
Hzj_jie
2016/12/14 20:03:48
Got you. Then I would prefer to remove the unorder
| |
| 33 const XmlElement* val, | 67 const XmlElement* val, |
| 34 std::string* error) { | 68 std::string* error) { |
| 35 if (exp->Name() != val->Name()) { | 69 if (exp->Name() != val->Name()) { |
| 36 *error = "<" + exp->Name().Merged() + ">" + " is expected, but " + | 70 *error = "<" + exp->Name().Merged() + ">" + " is expected, but " + |
| 37 "<" + val->Name().Merged() + ">" + " found"; | 71 "<" + val->Name().Merged() + ">" + " found"; |
| 38 return false; | 72 return false; |
| 39 } | 73 } |
| 40 if (exp->BodyText() != val->BodyText()) { | 74 if (exp->BodyText() != val->BodyText()) { |
| 41 *error = "<" + exp->Name().LocalPart() + ">" + exp->BodyText() + | 75 *error = "<" + exp->Name().LocalPart() + ">" + exp->BodyText() + |
| 42 "</" + exp->Name().LocalPart() + ">" " is expected, but found " + | 76 "</" + exp->Name().LocalPart() + ">" " is expected, but found " + |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 65 val_attr->Name() == QName(kXmlNs)) { | 99 val_attr->Name() == QName(kXmlNs)) { |
| 66 continue; // Skip NS attributes. | 100 continue; // Skip NS attributes. |
| 67 } | 101 } |
| 68 if (exp->Attr(val_attr->Name()) != val_attr->Value()) { | 102 if (exp->Attr(val_attr->Name()) != val_attr->Value()) { |
| 69 *error = "In <" + exp->Name().LocalPart() + "> unexpected attribute " + | 103 *error = "In <" + exp->Name().LocalPart() + "> unexpected attribute " + |
| 70 val_attr->Name().LocalPart(); | 104 val_attr->Name().LocalPart(); |
| 71 return false; | 105 return false; |
| 72 } | 106 } |
| 73 } | 107 } |
| 74 | 108 |
| 75 const XmlElement* exp_child = exp->FirstElement(); | 109 if (!VerifyXmlChildrenUnordered(exp, val, true, error) || |
| 76 const XmlElement* val_child = val->FirstElement(); | 110 !VerifyXmlChildrenUnordered(val, exp, false, error)) { |
| 77 while (exp_child && val_child) { | |
| 78 if (!VerifyXml(exp_child, val_child, error)) | |
| 79 return false; | |
| 80 exp_child = exp_child->NextElement(); | |
| 81 val_child = val_child->NextElement(); | |
| 82 } | |
| 83 if (exp_child) { | |
| 84 *error = "<" + exp_child->Name().Merged() + "> is expected, but not found"; | |
| 85 return false; | 111 return false; |
| 86 } | 112 } |
| 87 | 113 |
| 88 if (val_child) { | |
| 89 *error = "Unexpected <" + val_child->Name().Merged() + "> found"; | |
| 90 return false; | |
| 91 } | |
| 92 | |
| 93 return true; | 114 return true; |
| 94 } | 115 } |
| 95 | 116 |
| 96 // Parses |message_text| to JingleMessage. | 117 // Parses |message_text| to JingleMessage. |
| 97 void ParseJingleMessageFromXml(const char* message_text, | 118 void ParseJingleMessageFromXml(const char* message_text, |
| 98 JingleMessage* parsed) { | 119 JingleMessage* parsed) { |
| 99 std::unique_ptr<XmlElement> source_message(XmlElement::ForStr(message_text)); | 120 std::unique_ptr<XmlElement> source_message(XmlElement::ForStr(message_text)); |
| 100 ASSERT_TRUE(source_message.get()); | 121 ASSERT_TRUE(source_message.get()); |
| 101 | 122 |
| 102 EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); | 123 EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); |
| 103 | 124 |
| 104 std::string error; | 125 std::string error; |
| 105 EXPECT_TRUE(parsed->ParseXml(source_message.get(), &error)) << error; | 126 EXPECT_TRUE(parsed->ParseXml(source_message.get(), &error)) << error; |
| 106 } | 127 } |
| 107 | 128 |
| 108 | 129 |
| 109 // Parses |message_text| to JingleMessage then attempts to format it to XML and | 130 // Parses |message_text| to JingleMessage then attempts to format it to XML and |
| 110 // verifies that the same XML content is generated. | 131 // verifies that the same XML content is generated. |
| 111 void ParseFormatAndCompare(const char* message_text, JingleMessage* parsed) { | 132 void ParseFormatAndCompare(const char* message_text, JingleMessage* parsed) { |
| 112 std::unique_ptr<XmlElement> source_message(XmlElement::ForStr(message_text)); | 133 std::unique_ptr<XmlElement> source_message(XmlElement::ForStr(message_text)); |
| 113 ASSERT_TRUE(source_message.get()); | 134 ASSERT_TRUE(source_message.get()); |
| 114 | 135 |
| 115 EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); | 136 EXPECT_TRUE(JingleMessage::IsJingleMessage(source_message.get())); |
| 116 | 137 |
| 117 std::string error; | 138 std::string error; |
| 118 EXPECT_TRUE(parsed->ParseXml(source_message.get(), &error)) << error; | 139 EXPECT_TRUE(parsed->ParseXml(source_message.get(), &error)) << error; |
| 119 | 140 |
| 120 std::unique_ptr<XmlElement> formatted_message(parsed->ToXml()); | 141 std::unique_ptr<XmlElement> formatted_message(parsed->ToXml()); |
| 121 ASSERT_TRUE(formatted_message.get()); | 142 ASSERT_TRUE(formatted_message.get()); |
| 143 | |
| 122 EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error)) | 144 EXPECT_TRUE(VerifyXml(source_message.get(), formatted_message.get(), &error)) |
| 123 << error; | 145 << error; |
| 124 } | 146 } |
| 125 | 147 |
| 126 } // namespace | 148 } // namespace |
| 127 | 149 |
| 128 // Session-initiate message for current ICE-based protocol. | 150 // Session-initiate message for current ICE-based protocol. |
| 129 TEST(JingleMessageTest, SessionInitiate) { | 151 TEST(JingleMessageTest, SessionInitiate) { |
| 130 const char* kTestSessionInitiateMessage = | 152 const char* kTestSessionInitiateMessage = |
| 131 "<iq to='user@gmail.com/chromoting016DBB07' type='set' " | 153 "<iq to='user@gmail.com/chromoting016DBB07' type='set' " |
| (...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 593 } else { | 615 } else { |
| 594 ParseFormatAndCompare(message_str.c_str(), &message); | 616 ParseFormatAndCompare(message_str.c_str(), &message); |
| 595 } | 617 } |
| 596 | 618 |
| 597 EXPECT_EQ(message.action, JingleMessage::SESSION_TERMINATE); | 619 EXPECT_EQ(message.action, JingleMessage::SESSION_TERMINATE); |
| 598 EXPECT_EQ(message.reason, JingleMessage::DECLINE); | 620 EXPECT_EQ(message.reason, JingleMessage::DECLINE); |
| 599 EXPECT_EQ(message.error_code, error); | 621 EXPECT_EQ(message.error_code, error); |
| 600 } | 622 } |
| 601 } | 623 } |
| 602 | 624 |
| 625 namespace { | |
| 626 | |
| 627 void TestPluginMessage(bool insert_before_regular_message) { | |
|
Sergey Ulanov
2016/12/12 23:00:03
I doubt it's useful to test for the case when the
Hzj_jie
2016/12/13 00:20:51
I have not found there is a strong sequence requir
Sergey Ulanov
2016/12/14 01:31:50
Yes, both formats are valid. My point was that it'
Hzj_jie
2016/12/14 20:03:48
Updated.
| |
| 628 const char* kMessageWithPluginTag = | |
| 629 "<cli:iq from='user@gmail.com/chromoting016DBB07' " | |
| 630 "to='user@gmail.com/chromiumsy5C6A652D' type='set' " | |
| 631 "xmlns:cli='jabber:client'><jingle action='$1' " | |
| 632 "sid='2227053353' xmlns='urn:xmpp:jingle:1'>$2" | |
| 633 "<gr:plugin xmlns:gr='google:remoting'>" | |
| 634 "<gr:sometag>some-message</gr:sometag>" | |
| 635 "</gr:plugin>$3</jingle></cli:iq>"; | |
| 636 for (int i = JingleMessage::SESSION_INITIATE; | |
| 637 i <= JingleMessage::TRANSPORT_INFO; i++) { | |
| 638 JingleMessage::ActionType action_type = | |
| 639 static_cast<JingleMessage::ActionType>(i); | |
| 640 std::vector<std::string> subst = { | |
|
Sergey Ulanov
2016/12/12 23:00:03
subst is not a good name
Hzj_jie
2016/12/13 00:20:51
Done.
| |
| 641 JingleMessage::GetActionName(action_type) | |
| 642 }; | |
| 643 if (insert_before_regular_message) { | |
| 644 subst.emplace_back(); | |
| 645 } | |
| 646 if (action_type == JingleMessage::SESSION_INFO) { | |
| 647 subst.push_back("<test-info>test-message</test-info>"); | |
| 648 } else if (action_type == JingleMessage::SESSION_TERMINATE) { | |
| 649 subst.emplace_back(); | |
| 650 } else if (action_type == JingleMessage::TRANSPORT_INFO) { | |
|
Sergey Ulanov
2016/12/12 23:00:03
I don't think we want to allow plugins for transpo
Hzj_jie
2016/12/13 00:20:51
I thought this before, but it would make JingleMes
Sergey Ulanov
2016/12/14 01:31:50
It would make JingleMessage very slightly more com
Hzj_jie
2016/12/14 20:03:48
I think it can make both JingleMessage and JingleS
Sergey Ulanov
2016/12/15 19:18:25
I think complexity comes not only from amount of c
Hzj_jie
2016/12/15 22:41:19
IMO how to handle the message is not part of the f
| |
| 651 subst.push_back( | |
| 652 "<content name='chromoting' creator='initiator'>" | |
| 653 "<transport xmlns='google:remoting:webrtc'>" | |
| 654 "<credentials channel='event' ufrag='tPUyEAmQrEw3y7hi' " | |
| 655 "password='2iRdhLfawKZC5ydJ'/>" | |
| 656 "<credentials channel='video' ufrag='EPK3CXo5sTLJSez0' " | |
| 657 "password='eM0VUfUkZ+1Pyi0M'/>" | |
| 658 "<candidate name='event' foundation='725747215' " | |
| 659 "address='172.23.164.186' port='59089' type='local' " | |
| 660 "protocol='udp' priority='2122194688' generation='0'/>" | |
| 661 "<candidate name='video' foundation='3623806809' " | |
| 662 "address='172.23.164.186' port='57040' type='local' " | |
| 663 "protocol='udp' priority='2122194688' generation='0'/>" | |
| 664 "</transport>" | |
| 665 "</content>"); | |
| 666 } else { | |
| 667 subst.push_back("<content name='chromoting' creator='initiator'>" | |
| 668 "<description xmlns='google:remoting'>" | |
| 669 "<authentication><auth-token>" | |
| 670 "j7whCMii0Z0AAPwj7whCM/j7whCMii0Z0AAPw=" | |
| 671 "</auth-token></authentication>" | |
| 672 "</description>" | |
| 673 "<transport xmlns='google:remoting:webrtc' />" | |
| 674 "</content>"); | |
| 675 } | |
| 676 if (!insert_before_regular_message) { | |
| 677 subst.emplace_back(); | |
| 678 } | |
| 679 std::string message_str = base::ReplaceStringPlaceholders( | |
| 680 kMessageWithPluginTag, subst, nullptr); | |
| 681 | |
| 682 JingleMessage message; | |
| 683 ParseFormatAndCompare(message_str.c_str(), &message); | |
| 684 | |
| 685 EXPECT_TRUE(message.plugin_message); | |
| 686 XmlElement expected(QName("google:remoting", "plugin")); | |
| 687 expected.AddElement(new XmlElement(QName("google:remoting", "sometag"))); | |
| 688 expected.FirstElement()->SetBodyText("some-message"); | |
| 689 std::string error; | |
| 690 EXPECT_TRUE(VerifyXml(&expected, message.plugin_message.get(), &error)) | |
| 691 << error; | |
| 692 } | |
| 693 } | |
| 694 | |
| 695 } // namespace | |
| 696 | |
| 697 TEST(JingleMessageTest, PluginMessage) { | |
| 698 TestPluginMessage(false); | |
| 699 TestPluginMessage(true); | |
| 700 } | |
| 701 | |
| 603 } // namespace protocol | 702 } // namespace protocol |
| 604 } // namespace remoting | 703 } // namespace remoting |
| OLD | NEW |