Vitaly Buka | 4615e0d | 2015-10-14 15:35:12 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Weave Authors. All rights reserved. |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Stefan Sauer | 2d16dfa | 2015-09-25 17:08:35 +0200 | [diff] [blame] | 5 | #include "src/notification/xmpp_iq_stanza_handler.h" |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 6 | |
| 7 | #include <map> |
| 8 | #include <memory> |
| 9 | |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 10 | #include <gmock/gmock.h> |
| 11 | #include <gtest/gtest.h> |
Vitaly Buka | 727f3e6 | 2015-09-25 17:33:43 -0700 | [diff] [blame] | 12 | #include <weave/provider/test/fake_task_runner.h> |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 13 | |
Stefan Sauer | 2d16dfa | 2015-09-25 17:08:35 +0200 | [diff] [blame] | 14 | #include "src/bind_lambda.h" |
| 15 | #include "src/notification/xml_node.h" |
| 16 | #include "src/notification/xmpp_channel.h" |
| 17 | #include "src/notification/xmpp_stream_parser.h" |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 18 | |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 19 | using testing::_; |
| 20 | |
Vitaly Buka | b6f015a | 2015-07-09 14:59:23 -0700 | [diff] [blame] | 21 | namespace weave { |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 22 | namespace { |
| 23 | |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 24 | class MockXmppChannelInterface : public XmppChannelInterface { |
| 25 | public: |
| 26 | MockXmppChannelInterface() = default; |
| 27 | |
| 28 | MOCK_METHOD1(SendMessage, void(const std::string&)); |
| 29 | |
| 30 | private: |
| 31 | DISALLOW_COPY_AND_ASSIGN(MockXmppChannelInterface); |
| 32 | }; |
| 33 | |
| 34 | // Simple class that allows to parse XML from string to XmlNode. |
| 35 | class XmlParser : public XmppStreamParser::Delegate { |
| 36 | public: |
| 37 | std::unique_ptr<XmlNode> Parse(const std::string& xml) { |
| 38 | parser_.ParseData(xml); |
| 39 | return std::move(node_); |
| 40 | } |
| 41 | |
| 42 | private: |
| 43 | // Overrides from XmppStreamParser::Delegate. |
| 44 | void OnStreamStart(const std::string& node_name, |
| 45 | std::map<std::string, std::string> attributes) override { |
| 46 | node_.reset(new XmlNode{node_name, std::move(attributes)}); |
| 47 | } |
| 48 | |
| 49 | void OnStreamEnd(const std::string& node_name) override {} |
| 50 | |
| 51 | void OnStanza(std::unique_ptr<XmlNode> stanza) override { |
| 52 | node_->AddChild(std::move(stanza)); |
| 53 | } |
| 54 | |
| 55 | std::unique_ptr<XmlNode> node_; |
| 56 | XmppStreamParser parser_{this}; |
| 57 | }; |
| 58 | |
| 59 | class MockResponseReceiver { |
| 60 | public: |
| 61 | MOCK_METHOD2(OnResponse, void(int id, const std::string&)); |
| 62 | |
| 63 | IqStanzaHandler::ResponseCallback callback(int id) { |
| 64 | return base::Bind(&MockResponseReceiver::OnResponseCallback, |
| 65 | base::Unretained(this), id); |
| 66 | } |
| 67 | |
| 68 | private: |
| 69 | void OnResponseCallback(int id, std::unique_ptr<XmlNode> response) { |
| 70 | OnResponse(id, response->children().front()->name()); |
| 71 | } |
| 72 | }; |
| 73 | |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 74 | } // anonymous namespace |
| 75 | |
| 76 | class IqStanzaHandlerTest : public testing::Test { |
| 77 | public: |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 78 | testing::StrictMock<MockXmppChannelInterface> mock_xmpp_channel_; |
Vitaly Buka | 727f3e6 | 2015-09-25 17:33:43 -0700 | [diff] [blame] | 79 | provider::test::FakeTaskRunner task_runner_; |
Vitaly Buka | 823fdda | 2015-08-13 00:33:00 -0700 | [diff] [blame] | 80 | IqStanzaHandler iq_stanza_handler_{&mock_xmpp_channel_, &task_runner_}; |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 81 | MockResponseReceiver receiver_; |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 82 | }; |
| 83 | |
| 84 | TEST_F(IqStanzaHandlerTest, SendRequest) { |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 85 | std::string expected_msg = "<iq id='1' type='set'><body/></iq>"; |
| 86 | EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 87 | iq_stanza_handler_.SendRequest("set", "", "", "<body/>", {}, {}); |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 88 | |
| 89 | expected_msg = "<iq id='2' type='get'><body/></iq>"; |
| 90 | EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 91 | iq_stanza_handler_.SendRequest("get", "", "", "<body/>", {}, {}); |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 92 | |
| 93 | expected_msg = "<iq id='3' type='query' from='foo@bar'><body/></iq>"; |
| 94 | EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 95 | iq_stanza_handler_.SendRequest("query", "foo@bar", "", "<body/>", {}, {}); |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 96 | |
| 97 | expected_msg = "<iq id='4' type='query' to='foo@bar'><body/></iq>"; |
| 98 | EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 99 | iq_stanza_handler_.SendRequest("query", "", "foo@bar", "<body/>", {}, {}); |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 100 | |
| 101 | expected_msg = "<iq id='5' type='query' from='foo@bar' to='baz'><body/></iq>"; |
| 102 | EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 103 | iq_stanza_handler_.SendRequest("query", "foo@bar", "baz", "<body/>", {}, {}); |
Bertrand SIMONNET | d282884 | 2015-08-12 12:18:02 -0700 | [diff] [blame] | 104 | // This test ignores all the posted callbacks. |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 105 | } |
| 106 | |
| 107 | TEST_F(IqStanzaHandlerTest, UnsupportedIqRequest) { |
| 108 | // Server IQ requests are not supported for now. Expect an error response. |
| 109 | std::string expected_msg = |
| 110 | "<iq id='1' type='error'><error type='modify'>" |
| 111 | "<feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" |
| 112 | "</error></iq>"; |
| 113 | EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1); |
| 114 | auto request = XmlParser{}.Parse("<iq id='1' type='set'><foo/></iq>"); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 115 | EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request))); |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 116 | } |
| 117 | |
| 118 | TEST_F(IqStanzaHandlerTest, UnknownResponseId) { |
| 119 | // No requests with ID=100 have been previously sent. |
| 120 | auto request = XmlParser{}.Parse("<iq id='100' type='result'><foo/></iq>"); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 121 | EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request))); |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 122 | } |
| 123 | |
| 124 | TEST_F(IqStanzaHandlerTest, SequentialResponses) { |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 125 | EXPECT_CALL(mock_xmpp_channel_, SendMessage(_)).Times(2); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 126 | iq_stanza_handler_.SendRequest("set", "", "", "<body/>", |
| 127 | receiver_.callback(1), {}); |
| 128 | iq_stanza_handler_.SendRequest("get", "", "", "<body/>", |
| 129 | receiver_.callback(2), {}); |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 130 | |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 131 | EXPECT_CALL(receiver_, OnResponse(1, "foo")); |
| 132 | auto request = XmlParser{}.Parse("<iq id='1' type='result'><foo/></iq>"); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 133 | EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request))); |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 134 | |
| 135 | EXPECT_CALL(receiver_, OnResponse(2, "bar")); |
| 136 | request = XmlParser{}.Parse("<iq id='2' type='result'><bar/></iq>"); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 137 | EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request))); |
Bertrand SIMONNET | d282884 | 2015-08-12 12:18:02 -0700 | [diff] [blame] | 138 | |
Vitaly Buka | 823fdda | 2015-08-13 00:33:00 -0700 | [diff] [blame] | 139 | task_runner_.Run(); |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 140 | } |
| 141 | |
| 142 | TEST_F(IqStanzaHandlerTest, OutOfOrderResponses) { |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 143 | EXPECT_CALL(mock_xmpp_channel_, SendMessage(_)).Times(2); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 144 | iq_stanza_handler_.SendRequest("set", "", "", "<body/>", |
| 145 | receiver_.callback(1), {}); |
| 146 | iq_stanza_handler_.SendRequest("get", "", "", "<body/>", |
| 147 | receiver_.callback(2), {}); |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 148 | |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 149 | EXPECT_CALL(receiver_, OnResponse(2, "bar")); |
| 150 | auto request = XmlParser{}.Parse("<iq id='2' type='result'><bar/></iq>"); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 151 | EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request))); |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 152 | |
| 153 | EXPECT_CALL(receiver_, OnResponse(1, "foo")); |
| 154 | request = XmlParser{}.Parse("<iq id='1' type='result'><foo/></iq>"); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 155 | EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request))); |
Bertrand SIMONNET | d282884 | 2015-08-12 12:18:02 -0700 | [diff] [blame] | 156 | |
Vitaly Buka | 823fdda | 2015-08-13 00:33:00 -0700 | [diff] [blame] | 157 | task_runner_.Run(); |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 158 | } |
| 159 | |
| 160 | TEST_F(IqStanzaHandlerTest, RequestTimeout) { |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 161 | bool called = false; |
| 162 | auto on_timeout = [&called]() { called = true; }; |
| 163 | |
| 164 | EXPECT_CALL(mock_xmpp_channel_, SendMessage(_)).Times(1); |
| 165 | EXPECT_FALSE(called); |
Vitaly Buka | 8e507c2 | 2015-08-12 23:37:19 -0700 | [diff] [blame] | 166 | iq_stanza_handler_.SendRequest("set", "", "", "<body/>", {}, |
| 167 | base::Bind(on_timeout)); |
Vitaly Buka | 823fdda | 2015-08-13 00:33:00 -0700 | [diff] [blame] | 168 | task_runner_.Run(); |
Alex Vakulenko | dea76b2 | 2015-06-01 13:18:06 -0700 | [diff] [blame] | 169 | EXPECT_TRUE(called); |
| 170 | } |
| 171 | |
Vitaly Buka | b6f015a | 2015-07-09 14:59:23 -0700 | [diff] [blame] | 172 | } // namespace weave |