// Copyright 2015 The Weave Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/notification/xmpp_iq_stanza_handler.h" #include #include #include #include #include #include "src/bind_lambda.h" #include "src/notification/xml_node.h" #include "src/notification/xmpp_channel.h" #include "src/notification/xmpp_stream_parser.h" using testing::_; namespace weave { namespace { class MockXmppChannelInterface : public XmppChannelInterface { public: MockXmppChannelInterface() = default; MOCK_METHOD1(SendMessage, void(const std::string&)); private: DISALLOW_COPY_AND_ASSIGN(MockXmppChannelInterface); }; // Simple class that allows to parse XML from string to XmlNode. class XmlParser : public XmppStreamParser::Delegate { public: std::unique_ptr Parse(const std::string& xml) { parser_.ParseData(xml); return std::move(node_); } private: // Overrides from XmppStreamParser::Delegate. void OnStreamStart(const std::string& node_name, std::map attributes) override { node_.reset(new XmlNode{node_name, std::move(attributes)}); } void OnStreamEnd(const std::string& node_name) override {} void OnStanza(std::unique_ptr stanza) override { node_->AddChild(std::move(stanza)); } std::unique_ptr node_; XmppStreamParser parser_{this}; }; class MockResponseReceiver { public: MOCK_METHOD2(OnResponse, void(int id, const std::string&)); IqStanzaHandler::ResponseCallback callback(int id) { return base::Bind(&MockResponseReceiver::OnResponseCallback, base::Unretained(this), id); } private: void OnResponseCallback(int id, std::unique_ptr response) { OnResponse(id, response->children().front()->name()); } }; } // anonymous namespace class IqStanzaHandlerTest : public testing::Test { public: testing::StrictMock mock_xmpp_channel_; provider::test::FakeTaskRunner task_runner_; IqStanzaHandler iq_stanza_handler_{&mock_xmpp_channel_, &task_runner_}; MockResponseReceiver receiver_; }; TEST_F(IqStanzaHandlerTest, SendRequest) { std::string expected_msg = ""; EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1); iq_stanza_handler_.SendRequest("set", "", "", "", {}, {}); expected_msg = ""; EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1); iq_stanza_handler_.SendRequest("get", "", "", "", {}, {}); expected_msg = ""; EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1); iq_stanza_handler_.SendRequest("query", "foo@bar", "", "", {}, {}); expected_msg = ""; EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1); iq_stanza_handler_.SendRequest("query", "", "foo@bar", "", {}, {}); expected_msg = ""; EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1); iq_stanza_handler_.SendRequest("query", "foo@bar", "baz", "", {}, {}); // This test ignores all the posted callbacks. } TEST_F(IqStanzaHandlerTest, UnsupportedIqRequest) { // Server IQ requests are not supported for now. Expect an error response. std::string expected_msg = "" "" ""; EXPECT_CALL(mock_xmpp_channel_, SendMessage(expected_msg)).Times(1); auto request = XmlParser{}.Parse(""); EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request))); } TEST_F(IqStanzaHandlerTest, UnknownResponseId) { // No requests with ID=100 have been previously sent. auto request = XmlParser{}.Parse(""); EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request))); } TEST_F(IqStanzaHandlerTest, SequentialResponses) { EXPECT_CALL(mock_xmpp_channel_, SendMessage(_)).Times(2); iq_stanza_handler_.SendRequest("set", "", "", "", receiver_.callback(1), {}); iq_stanza_handler_.SendRequest("get", "", "", "", receiver_.callback(2), {}); EXPECT_CALL(receiver_, OnResponse(1, "foo")); auto request = XmlParser{}.Parse(""); EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request))); EXPECT_CALL(receiver_, OnResponse(2, "bar")); request = XmlParser{}.Parse(""); EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request))); task_runner_.Run(); } TEST_F(IqStanzaHandlerTest, OutOfOrderResponses) { EXPECT_CALL(mock_xmpp_channel_, SendMessage(_)).Times(2); iq_stanza_handler_.SendRequest("set", "", "", "", receiver_.callback(1), {}); iq_stanza_handler_.SendRequest("get", "", "", "", receiver_.callback(2), {}); EXPECT_CALL(receiver_, OnResponse(2, "bar")); auto request = XmlParser{}.Parse(""); EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request))); EXPECT_CALL(receiver_, OnResponse(1, "foo")); request = XmlParser{}.Parse(""); EXPECT_TRUE(iq_stanza_handler_.HandleIqStanza(std::move(request))); task_runner_.Run(); } TEST_F(IqStanzaHandlerTest, RequestTimeout) { bool called = false; auto on_timeout = [](bool* called) { *called = true; }; EXPECT_CALL(mock_xmpp_channel_, SendMessage(_)).Times(1); EXPECT_FALSE(called); iq_stanza_handler_.SendRequest( "set", "", "", "", {}, base::Bind(on_timeout, base::Unretained(&called))); task_runner_.Run(); EXPECT_TRUE(called); } } // namespace weave