blob: 052b7c5ddb89651402fef3011b2fcb292ae5cf3a [file] [log] [blame]
Vitaly Buka4615e0d2015-10-14 15:35:12 -07001// Copyright 2015 The Weave Authors. All rights reserved.
Alex Vakulenkodea76b22015-06-01 13:18:06 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Stefan Sauer2d16dfa2015-09-25 17:08:35 +02005#include "src/notification/xmpp_iq_stanza_handler.h"
Alex Vakulenkodea76b22015-06-01 13:18:06 -07006
7#include <map>
8#include <memory>
9
Alex Vakulenkodea76b22015-06-01 13:18:06 -070010#include <gmock/gmock.h>
11#include <gtest/gtest.h>
Vitaly Buka727f3e62015-09-25 17:33:43 -070012#include <weave/provider/test/fake_task_runner.h>
Alex Vakulenkodea76b22015-06-01 13:18:06 -070013
Stefan Sauer2d16dfa2015-09-25 17:08:35 +020014#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 Vakulenkodea76b22015-06-01 13:18:06 -070018
Alex Vakulenkodea76b22015-06-01 13:18:06 -070019using testing::_;
20
Vitaly Bukab6f015a2015-07-09 14:59:23 -070021namespace weave {
Alex Vakulenkodea76b22015-06-01 13:18:06 -070022namespace {
23
Alex Vakulenkodea76b22015-06-01 13:18:06 -070024class 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.
35class 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
59class 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 Vakulenkodea76b22015-06-01 13:18:06 -070074} // anonymous namespace
75
76class IqStanzaHandlerTest : public testing::Test {
77 public:
Alex Vakulenkodea76b22015-06-01 13:18:06 -070078 testing::StrictMock<MockXmppChannelInterface> mock_xmpp_channel_;
Vitaly Buka727f3e62015-09-25 17:33:43 -070079 provider::test::FakeTaskRunner task_runner_;
Vitaly Buka823fdda2015-08-13 00:33:00 -070080 IqStanzaHandler iq_stanza_handler_{&mock_xmpp_channel_, &task_runner_};
Alex Vakulenkodea76b22015-06-01 13:18:06 -070081 MockResponseReceiver receiver_;
Alex Vakulenkodea76b22015-06-01 13:18:06 -070082};
83
84TEST_F(IqStanzaHandlerTest, SendRequest) {
Alex Vakulenkodea76b22015-06-01 13:18:06 -070085 std::string expected_msg = "<iq id='1' type='set'><body/></iq>";
86 EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1);
Vitaly Buka8e507c22015-08-12 23:37:19 -070087 iq_stanza_handler_.SendRequest("set", "", "", "<body/>", {}, {});
Alex Vakulenkodea76b22015-06-01 13:18:06 -070088
89 expected_msg = "<iq id='2' type='get'><body/></iq>";
90 EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1);
Vitaly Buka8e507c22015-08-12 23:37:19 -070091 iq_stanza_handler_.SendRequest("get", "", "", "<body/>", {}, {});
Alex Vakulenkodea76b22015-06-01 13:18:06 -070092
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 Buka8e507c22015-08-12 23:37:19 -070095 iq_stanza_handler_.SendRequest("query", "foo@bar", "", "<body/>", {}, {});
Alex Vakulenkodea76b22015-06-01 13:18:06 -070096
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 Buka8e507c22015-08-12 23:37:19 -070099 iq_stanza_handler_.SendRequest("query", "", "foo@bar", "<body/>", {}, {});
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700100
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 Buka8e507c22015-08-12 23:37:19 -0700103 iq_stanza_handler_.SendRequest("query", "foo@bar", "baz", "<body/>", {}, {});
Bertrand SIMONNETd2828842015-08-12 12:18:02 -0700104 // This test ignores all the posted callbacks.
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700105}
106
107TEST_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 Buka8e507c22015-08-12 23:37:19 -0700115 EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request)));
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700116}
117
118TEST_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 Buka8e507c22015-08-12 23:37:19 -0700121 EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request)));
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700122}
123
124TEST_F(IqStanzaHandlerTest, SequentialResponses) {
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700125 EXPECT_CALL(mock_xmpp_channel_, SendMessage(_)).Times(2);
Vitaly Buka8e507c22015-08-12 23:37:19 -0700126 iq_stanza_handler_.SendRequest("set", "", "", "<body/>",
127 receiver_.callback(1), {});
128 iq_stanza_handler_.SendRequest("get", "", "", "<body/>",
129 receiver_.callback(2), {});
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700130
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700131 EXPECT_CALL(receiver_, OnResponse(1, "foo"));
132 auto request = XmlParser{}.Parse("<iq id='1' type='result'><foo/></iq>");
Vitaly Buka8e507c22015-08-12 23:37:19 -0700133 EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request)));
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700134
135 EXPECT_CALL(receiver_, OnResponse(2, "bar"));
136 request = XmlParser{}.Parse("<iq id='2' type='result'><bar/></iq>");
Vitaly Buka8e507c22015-08-12 23:37:19 -0700137 EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request)));
Bertrand SIMONNETd2828842015-08-12 12:18:02 -0700138
Vitaly Buka823fdda2015-08-13 00:33:00 -0700139 task_runner_.Run();
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700140}
141
142TEST_F(IqStanzaHandlerTest, OutOfOrderResponses) {
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700143 EXPECT_CALL(mock_xmpp_channel_, SendMessage(_)).Times(2);
Vitaly Buka8e507c22015-08-12 23:37:19 -0700144 iq_stanza_handler_.SendRequest("set", "", "", "<body/>",
145 receiver_.callback(1), {});
146 iq_stanza_handler_.SendRequest("get", "", "", "<body/>",
147 receiver_.callback(2), {});
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700148
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700149 EXPECT_CALL(receiver_, OnResponse(2, "bar"));
150 auto request = XmlParser{}.Parse("<iq id='2' type='result'><bar/></iq>");
Vitaly Buka8e507c22015-08-12 23:37:19 -0700151 EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request)));
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700152
153 EXPECT_CALL(receiver_, OnResponse(1, "foo"));
154 request = XmlParser{}.Parse("<iq id='1' type='result'><foo/></iq>");
Vitaly Buka8e507c22015-08-12 23:37:19 -0700155 EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request)));
Bertrand SIMONNETd2828842015-08-12 12:18:02 -0700156
Vitaly Buka823fdda2015-08-13 00:33:00 -0700157 task_runner_.Run();
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700158}
159
160TEST_F(IqStanzaHandlerTest, RequestTimeout) {
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700161 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 Buka8e507c22015-08-12 23:37:19 -0700166 iq_stanza_handler_.SendRequest("set", "", "", "<body/>", {},
167 base::Bind(on_timeout));
Vitaly Buka823fdda2015-08-13 00:33:00 -0700168 task_runner_.Run();
Alex Vakulenkodea76b22015-06-01 13:18:06 -0700169 EXPECT_TRUE(called);
170}
171
Vitaly Bukab6f015a2015-07-09 14:59:23 -0700172} // namespace weave