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 |