Changeset - 974bf2de0a2c
[Not reviewed]
0 3 0
Jan Kaluza - 13 years ago 2012-08-16 14:43:00
hanzz.k@gmail.com
adhoc tests
3 files changed with 123 insertions and 4 deletions:
0 comments (0 inline, 0 general)
src/adhocmanager.cpp
Show inline comments
 
/**
 
 * XMPP - libpurple transport
 
 *
 
 * Copyright (C) 2012, Jan Kaluza <hanzz@soc.pidgin.im>
 
 *
 
 * This program is free software; you can redistribute it and/or modify
 
 * it under the terms of the GNU General Public License as published by
 
 * the Free Software Foundation; either version 2 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * This program is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU General Public License
 
 * along with this program; if not, write to the Free Software
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 
 */
 

	
 
#include "transport/adhocmanager.h"
 
#include "transport/adhoccommandfactory.h"
 
#include "transport/discoitemsresponder.h"
 
#include "transport/conversation.h"
 
#include "transport/usermanager.h"
 
#include "transport/buddy.h"
 
#include "transport/factory.h"
 
#include "transport/user.h"
 
#include "transport/logging.h"
 

	
 
namespace Transport {
 

	
 
DEFINE_LOGGER(logger, "AdHocManager");
 

	
 
AdHocManager::AdHocManager(Component *component, DiscoItemsResponder *discoItemsResponder) : Swift::Responder<Swift::Command>(component->getIQRouter()){
 
	m_component = component;
 
	m_discoItemsResponder = discoItemsResponder;
 

	
 
	m_collectTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(20);
 
	m_collectTimer->onTick.connect(boost::bind(&AdHocManager::removeOldSessions, this));
 
	m_collectTimer->start();
 
}
 

	
 
AdHocManager::~AdHocManager() {
 
	m_collectTimer->stop();
 
	stop();
 
}
 

	
 
void AdHocManager::start() {
 
	Swift::Responder<Swift::Command>::start();
 
}
 

	
 
void AdHocManager::stop() {
 
	Swift::Responder<Swift::Command>::stop();
 

	
 
	for (SessionsMap::iterator it = m_sessions.begin(); it != m_sessions.end(); it++) {
 
		std::vector<std::string> candidates;
 
		for (CommandsMap::iterator ct = it->second.begin(); ct != it->second.end(); ct++) {
 
			delete ct->second;
 
		}
 
	}
 

	
 
	m_sessions.clear();
 
}
 

	
 
void AdHocManager::addAdHocCommand(AdHocCommandFactory *factory) {
 
	if (m_factories.find(factory->getNode()) != m_factories.end()) {
 
		LOG4CXX_ERROR(logger, "Command with node " << factory->getNode() << " is already registered. Ignoring this attempt.");
 
		return;
 
	}
 

	
 
	m_factories[factory->getNode()] = factory;
 
	m_discoItemsResponder->addAdHocCommand(factory->getNode(), factory->getName());
 
}
 

	
 
void AdHocManager::removeOldSessions() {
 
	unsigned long removedCommands = 0;
 
	time_t now = time(NULL);
 

	
 
	std::vector<std::string> toRemove;
 
	for (SessionsMap::iterator it = m_sessions.begin(); it != m_sessions.end(); it++) {
 
		std::vector<std::string> candidates;
 
		for (CommandsMap::iterator ct = it->second.begin(); ct != it->second.end(); ct++) {
 
			if (now - ct->second->getLastActivity() > 15*60) {
 
				candidates.push_back(it->first);
 
				delete ct->second;
 
				removedCommands++;
 
			}
 
		}
 

	
 
		BOOST_FOREACH(std::string &key, candidates) {
 
			it->second.erase(key);
 
		}
 

	
 
		if (it->second.empty()) {
 
			toRemove.push_back(it->first);
 
		}
 
	}
 

	
 
	BOOST_FOREACH(std::string &key, toRemove) {
 
		m_sessions.erase(key);
 
	}
 

	
 
	if (removedCommands > 0) {
 
		LOG4CXX_INFO(logger, "Removed " << removedCommands << " old commands sessions.");
 
	}
 
}
 

	
 
bool AdHocManager::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::Command> payload) {
 
	return false;
 
}
 

	
 
bool AdHocManager::handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::Command> payload) {
 
	AdHocCommand *command = NULL;
 
	// Try to find AdHocCommand according to 'from' and session_id
 
	if (m_sessions.find(from) != m_sessions.end() && m_sessions[from].find(payload->getSessionID()) != m_sessions[from].end()) {
 
	if (m_sessions.find(from) != m_sessions.end()) {
 
		if (m_sessions[from].find(payload->getSessionID()) != m_sessions[from].end()) {
 
			command = m_sessions[from][payload->getSessionID()];
 
		}
 
		else {
 
			LOG4CXX_ERROR(logger, from.toString() << ": Unknown session id " << payload->getSessionID() << " - ignoring");
 
			sendError(from, id, Swift::ErrorPayload::BadRequest, Swift::ErrorPayload::Modify);
 
			return true;
 
		}
 
	}
 
	// Check if we can create command with this node
 
	else if (m_factories.find(payload->getNode()) != m_factories.end()) {
 
		command = m_factories[payload->getNode()]->createAdHocCommand(m_component, from, to);
 
		m_sessions[from][command->getId()] = command;
 
		LOG4CXX_INFO(logger, from.toString() << ": Started new AdHoc command session with node " << payload->getNode());
 
	}
 
	else {
 
		LOG4CXX_INFO(logger, from.toString() << ": Unknown node " << payload->getNode() << ". Can't start AdHoc command session.");
 
		sendError(from, id, Swift::ErrorPayload::BadRequest, Swift::ErrorPayload::Modify);
 
		return true;
 
	}
 

	
 
	if (!command) {
 
		LOG4CXX_ERROR(logger, from.toString() << ": createAdHocCommand for node " << payload->getNode() << " returned NULL pointer");
 
		sendError(from, id, Swift::ErrorPayload::BadRequest, Swift::ErrorPayload::Modify);
 
		return true;
 
	}
 

	
 
	boost::shared_ptr<Swift::Command> response = command->handleRequest(payload);
 
	if (!response) {
 
		LOG4CXX_ERROR(logger, from.toString() << ": handleRequest for node " << payload->getNode() << " returned NULL pointer");
 
		sendError(from, id, Swift::ErrorPayload::BadRequest, Swift::ErrorPayload::Modify);
 
		return true;
 
	}
 

	
 
	response->setSessionID(command->getId());
 

	
 
	sendResponse(from, id, response);
 

	
 
	command->refreshLastActivity();
 

	
 
	// Command completed, so we can remove it now
 
	if (response->getStatus() == Swift::Command::Completed) {
 
	if (response->getStatus() == Swift::Command::Completed || response->getStatus() == Swift::Command::Canceled) {
 
		m_sessions[from].erase(command->getId());
 
		if (m_sessions[from].empty()) {
 
			m_sessions.erase(from);
 
		}
 
		delete command;
 
	}
 
	
 

	
 
	return true;
 
}
 

	
 
}
src/settingsadhoccommand.cpp
Show inline comments
 
/**
 
 * XMPP - libpurple transport
 
 *
 
 * Copyright (C) 2012, Jan Kaluza <hanzz@soc.pidgin.im>
 
 *
 
 * This program is free software; you can redistribute it and/or modify
 
 * it under the terms of the GNU General Public License as published by
 
 * the Free Software Foundation; either version 2 of the License, or
 
 * (at your option) any later version.
 
 *
 
 * This program is distributed in the hope that it will be useful,
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 * GNU General Public License for more details.
 
 *
 
 * You should have received a copy of the GNU General Public License
 
 * along with this program; if not, write to the Free Software
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 
 */
 

	
 
#include "transport/settingsadhoccommand.h"
 
#include "transport/conversation.h"
 
#include "transport/usermanager.h"
 
#include "transport/buddy.h"
 
#include "transport/factory.h"
 
#include "transport/user.h"
 
#include "transport/logging.h"
 

	
 
namespace Transport {
 

	
 
DEFINE_LOGGER(logger, "SettingsAdHocCommand");
 

	
 
SettingsAdHocCommand::SettingsAdHocCommand(Component *component, const Swift::JID &initiator, const Swift::JID &to) : AdHocCommand(component, initiator, to) {
 
	m_state = Init;
 
}
 

	
 
SettingsAdHocCommand::~SettingsAdHocCommand() {
 
}
 

	
 
boost::shared_ptr<Swift::Command> SettingsAdHocCommand::getForm() {
 
	boost::shared_ptr<Swift::Command> response(new Swift::Command("settings", m_id, Swift::Command::Executing));
 
	boost::shared_ptr<Swift::Form> form(new Swift::Form());
 

	
 
	BOOST_FOREACH(Swift::FormField::ref field, m_fields) {
 
		form->addField(field);
 
	}
 

	
 
	response->setForm(form);
 
	return response;
 
}
 

	
 
boost::shared_ptr<Swift::Command> SettingsAdHocCommand::handleResponse(boost::shared_ptr<Swift::Command> payload) {
 
	
 
	
 

	
 
	boost::shared_ptr<Swift::Command> response;
 
	response->setStatus(Swift::Command::Completed);
 
	boost::shared_ptr<Swift::Command> response(new Swift::Command("settings", m_id, Swift::Command::Completed));
 
	return response;
 
}
 

	
 
boost::shared_ptr<Swift::Command> SettingsAdHocCommand::handleRequest(boost::shared_ptr<Swift::Command> payload) {
 
	boost::shared_ptr<Swift::Command> response;
 
	if (payload->getAction() == Swift::Command::Cancel) {
 
		response = boost::shared_ptr<Swift::Command>(new Swift::Command("settings", m_id, Swift::Command::Canceled));
 
		return response;
 
	}
 

	
 
	switch (m_state) {
 
		case Init:
 
			response = getForm();
 
			m_state = WaitingForResponse;
 
			break;
 
		case WaitingForResponse:
 
			response = handleResponse(payload);
 
			break;
 
		default:
 
			break;
 
	}
 
	
 
	return response;
 
}
 

	
 
}
src/tests/settingsadhoccommand.cpp
Show inline comments
 
#include "transport/userregistry.h"
 
#include "transport/userregistration.h"
 
#include "transport/config.h"
 
#include "transport/storagebackend.h"
 
#include "transport/user.h"
 
#include "transport/transport.h"
 
#include "transport/conversation.h"
 
#include "transport/usermanager.h"
 
#include "transport/localbuddy.h"
 
#include "transport/settingsadhoccommand.h"
 
#include "transport/adhocmanager.h"
 
#include <cppunit/TestFixture.h>
 
#include <cppunit/extensions/HelperMacros.h>
 
#include <Swiften/Swiften.h>
 
#include <Swiften/EventLoop/DummyEventLoop.h>
 
#include <Swiften/Server/Server.h>
 
#include <Swiften/Network/DummyNetworkFactories.h>
 
#include <Swiften/Network/DummyConnectionServer.h>
 
#include "Swiften/Server/ServerStanzaChannel.h"
 
#include "Swiften/Server/ServerFromClientSession.h"
 
#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
 
#include "basictest.h"
 

	
 
using namespace Transport;
 

	
 
class SettingsAdHocCommandTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
 
	CPPUNIT_TEST_SUITE(SettingsAdHocCommandTest);
 
	CPPUNIT_TEST(getItems);
 
	CPPUNIT_TEST(execute);
 
	CPPUNIT_TEST(executeBadSessionID);
 
	CPPUNIT_TEST(cancel);
 
	CPPUNIT_TEST_SUITE_END();
 

	
 
	public:
 
		AdHocManager *adhoc;
 
		SettingsAdHocCommandFactory *settings;
 

	
 
		void setUp (void) {
 
			setMeUp();
 

	
 
			adhoc = new AdHocManager(component, itemsResponder);
 
			adhoc->start();
 
			settings = new SettingsAdHocCommandFactory();
 
			adhoc->addAdHocCommand(settings);
 

	
 
			received.clear();
 
		}
 

	
 
		void tearDown (void) {
 
			received.clear();
 
			delete adhoc;
 
			delete settings;
 
			tearMeDown();
 
		}
 

	
 
		void getItems() {
 
			boost::shared_ptr<Swift::DiscoItems> payload(new Swift::DiscoItems());
 
			payload->setNode("http://jabber.org/protocol/commands");
 
			boost::shared_ptr<Swift::IQ> iq = Swift::IQ::createRequest(Swift::IQ::Get, Swift::JID("localhost"), "id", payload);
 
			iq->setFrom("user@localhost");
 
			injectIQ(iq);
 
			loop->processEvents();
 

	
 
			CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
 

	
 
			CPPUNIT_ASSERT(dynamic_cast<Swift::IQ *>(getStanza(received[0])));
 
			CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast<Swift::IQ *>(getStanza(received[0]))->getType());
 
			CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoItems>());
 
			CPPUNIT_ASSERT_EQUAL(std::string("settings"), getStanza(received[0])->getPayload<Swift::DiscoItems>()->getItems()[0].getNode());
 
		}
 

	
 
		void execute() {
 
			boost::shared_ptr<Swift::Command> payload(new Swift::Command("settings"));
 
			boost::shared_ptr<Swift::IQ> iq = Swift::IQ::createRequest(Swift::IQ::Set, Swift::JID("localhost"), "id", payload);
 
			iq->setFrom("user@localhost");
 
			injectIQ(iq);
 
			loop->processEvents();
 

	
 
			CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
 

	
 
			CPPUNIT_ASSERT(dynamic_cast<Swift::IQ *>(getStanza(received[0])));
 
			CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast<Swift::IQ *>(getStanza(received[0]))->getType());
 

	
 
			CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::Command>());
 
			CPPUNIT_ASSERT_EQUAL(std::string("settings"), getStanza(received[0])->getPayload<Swift::Command>()->getNode());
 
			CPPUNIT_ASSERT_EQUAL(Swift::Command::Executing, getStanza(received[0])->getPayload<Swift::Command>()->getStatus());
 

	
 
			CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::Command>()->getForm());
 

	
 
			std::string sessionId = getStanza(received[0])->getPayload<Swift::Command>()->getSessionID();
 

	
 
			// finish the command
 
			payload = boost::shared_ptr<Swift::Command>(new Swift::Command("settings"));
 
			payload->setSessionID(sessionId);
 
			payload->setForm(getStanza(received[0])->getPayload<Swift::Command>()->getForm());
 
			iq = Swift::IQ::createRequest(Swift::IQ::Set, Swift::JID("localhost"), "id", payload);
 
			iq->setFrom("user@localhost");
 
			received.clear();
 
			injectIQ(iq);
 
			loop->processEvents();
 

	
 
			CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
 

	
 
			CPPUNIT_ASSERT(dynamic_cast<Swift::IQ *>(getStanza(received[0])));
 
			CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast<Swift::IQ *>(getStanza(received[0]))->getType());
 

	
 
			CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::Command>());
 
			CPPUNIT_ASSERT_EQUAL(std::string("settings"), getStanza(received[0])->getPayload<Swift::Command>()->getNode());
 
			CPPUNIT_ASSERT_EQUAL(Swift::Command::Completed, getStanza(received[0])->getPayload<Swift::Command>()->getStatus());
 
		}
 

	
 
		void executeBadSessionID() {
 
			boost::shared_ptr<Swift::Command> payload(new Swift::Command("settings"));
 
			boost::shared_ptr<Swift::IQ> iq = Swift::IQ::createRequest(Swift::IQ::Set, Swift::JID("localhost"), "id", payload);
 
			iq->setFrom("user@localhost");
 
			injectIQ(iq);
 
			loop->processEvents();
 

	
 
			CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
 

	
 
			CPPUNIT_ASSERT(dynamic_cast<Swift::IQ *>(getStanza(received[0])));
 
			CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast<Swift::IQ *>(getStanza(received[0]))->getType());
 

	
 
			CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::Command>());
 
			CPPUNIT_ASSERT_EQUAL(std::string("settings"), getStanza(received[0])->getPayload<Swift::Command>()->getNode());
 
			CPPUNIT_ASSERT_EQUAL(Swift::Command::Executing, getStanza(received[0])->getPayload<Swift::Command>()->getStatus());
 

	
 
			CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::Command>()->getForm());
 

	
 
			std::string sessionId = "somethingwrong";
 

	
 
			// finish the command
 
			payload = boost::shared_ptr<Swift::Command>(new Swift::Command("settings"));
 
			payload->setSessionID(sessionId);
 
			payload->setForm(getStanza(received[0])->getPayload<Swift::Command>()->getForm());
 
			iq = Swift::IQ::createRequest(Swift::IQ::Set, Swift::JID("localhost"), "id", payload);
 
			iq->setFrom("user@localhost");
 
			received.clear();
 
			injectIQ(iq);
 
			loop->processEvents();
 

	
 
			CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
 
			CPPUNIT_ASSERT(dynamic_cast<Swift::IQ *>(getStanza(received[0])));
 
			CPPUNIT_ASSERT_EQUAL(Swift::IQ::Error, dynamic_cast<Swift::IQ *>(getStanza(received[0]))->getType());
 
		}
 

	
 
		void cancel() {
 
			boost::shared_ptr<Swift::Command> payload(new Swift::Command("settings"));
 
			boost::shared_ptr<Swift::IQ> iq = Swift::IQ::createRequest(Swift::IQ::Set, Swift::JID("localhost"), "id", payload);
 
			iq->setFrom("user@localhost");
 
			injectIQ(iq);
 
			loop->processEvents();
 

	
 
			CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
 

	
 
			CPPUNIT_ASSERT(dynamic_cast<Swift::IQ *>(getStanza(received[0])));
 
			CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast<Swift::IQ *>(getStanza(received[0]))->getType());
 

	
 
			CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::Command>());
 
			CPPUNIT_ASSERT_EQUAL(std::string("settings"), getStanza(received[0])->getPayload<Swift::Command>()->getNode());
 
			CPPUNIT_ASSERT_EQUAL(Swift::Command::Executing, getStanza(received[0])->getPayload<Swift::Command>()->getStatus());
 

	
 
			CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::Command>()->getForm());
 

	
 
			std::string sessionId = getStanza(received[0])->getPayload<Swift::Command>()->getSessionID();
 

	
 
			// cancel the command
 
			payload = boost::shared_ptr<Swift::Command>(new Swift::Command("settings"));
 
			payload->setSessionID(sessionId);
 
			payload->setAction(Swift::Command::Cancel);
 
			iq = Swift::IQ::createRequest(Swift::IQ::Set, Swift::JID("localhost"), "id", payload);
 
			iq->setFrom("user@localhost");
 
			received.clear();
 
			injectIQ(iq);
 
			loop->processEvents();
 

	
 
			CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
 

	
 
			CPPUNIT_ASSERT(dynamic_cast<Swift::IQ *>(getStanza(received[0])));
 
			CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast<Swift::IQ *>(getStanza(received[0]))->getType());
 

	
 
			CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::Command>());
 
			CPPUNIT_ASSERT_EQUAL(std::string("settings"), getStanza(received[0])->getPayload<Swift::Command>()->getNode());
 
			CPPUNIT_ASSERT_EQUAL(Swift::Command::Canceled, getStanza(received[0])->getPayload<Swift::Command>()->getStatus());
 
		}
 

	
 
};
 

	
 
CPPUNIT_TEST_SUITE_REGISTRATION (SettingsAdHocCommandTest);
0 comments (0 inline, 0 general)