diff --git a/.travis.yml b/.travis.yml
index c42723c22..8f0273570 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,7 +30,7 @@ before_install:
install:
- server/misc/setup-cutter.sh
- - sudo apt-get install -qq -y autotools-dev libglib2.0-dev libjson-glib-dev libsoup2.4-dev libmysqlclient-dev sqlite3 ndoutils-nagios3-mysql uuid-dev npm python-pip expect python-dev libqpidmessaging2-dev libqpidtypes1-dev libqpidcommon2-dev qpidd librabbitmq-dev
+ - sudo apt-get install -qq -y autotools-dev libglib2.0-dev libjson-glib-dev libsoup2.4-dev libmysqlclient-dev sqlite3 ndoutils-nagios3-mysql uuid-dev npm python-pip expect python-dev libqpidmessaging2-dev libqpidtypes1-dev libqpidcommon2-dev qpidd librabbitmq-dev rabbitmq-server python-pika amqp-tools
- sudo sh -c "printf '[%s]\n%s=%s\n' mysqld character-set-server utf8 > /etc/mysql/conf.d/utf8.cnf"
- sudo sh -c "printf '[%s]\n%s=%s\n' client default-character-set utf8 >> /etc/mysql/conf.d/utf8.cnf"
- mysql -u root < data/test/setup.sql
@@ -43,6 +43,8 @@ install:
- sudo pip install mysql-python
- sudo sh -c "echo acl allow all all > /etc/qpid/qpidd.acl"
- sudo /etc/init.d/qpidd restart
+ - sudo server/misc/setup-rabbitmq-server-port.sh
+ - sudo service rabbitmq-server restart
before_script:
- ./autogen.sh
- ./configure
diff --git a/server/hap2/rabbitmqconnector.py b/server/hap2/rabbitmqconnector.py
new file mode 100644
index 000000000..26228c4c8
--- /dev/null
+++ b/server/hap2/rabbitmqconnector.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+"""
+ Copyright (C) 2015 Project Hatohol
+
+ This file is part of Hatohol.
+
+ Hatohol is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License, version 3
+ as published by the Free Software Foundation.
+
+ Hatohol 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with Hatohol. If not, see
+ .
+"""
+
+import logging
+import pika
+from transporter import Transporter
+
+class RabbitMQConnector(Transporter):
+
+ def __init__(self):
+ Transporter.__init__(self)
+ self._channel = None
+
+ def setup(self, transporter_args):
+ """
+ @param transporter_args
+ The following keys shall be included.
+ - amqp_broker A broker IP or FQDN.
+ - amqp_port A broker port.
+ - amqp_vhost A virtual host.
+ - amqp_queue A queue name.
+ - amqp_user A user name.
+ - amqp_password A password.
+ """
+
+ def set_if_not_none(kwargs, key, val):
+ if val is not None:
+ kwargs[key] = val
+
+ broker = transporter_args["amqp_broker"]
+ port = transporter_args["amqp_port"]
+ vhost = transporter_args["amqp_vhost"]
+ queue_name = transporter_args["amqp_queue"]
+ user_name = transporter_args["amqp_user"]
+ password = transporter_args["amqp_password"]
+
+ logging.debug("Called stub method: call().");
+ self._queue_name = queue_name
+ credentials = pika.credentials.PlainCredentials(user_name, password)
+
+ conn_args = {}
+ set_if_not_none(conn_args, "host", broker)
+ set_if_not_none(conn_args, "port", port)
+ set_if_not_none(conn_args, "virtual_host", vhost)
+ set_if_not_none(conn_args, "credentials", credentials)
+ param = pika.connection.ConnectionParameters(**conn_args)
+ connection = pika.adapters.blocking_connection.BlockingConnection(param)
+ self._channel = connection.channel()
+ self._channel.queue_declare(queue=queue_name)
+
+ def call(self, msg):
+ self.__publish(msg)
+
+ def reply(self, msg):
+ self.__publish(msg)
+
+ def run_receive_loop(self):
+ assert self._channel != None
+
+ self._channel.basic_consume(self.__consume_handler,
+ queue=self._queue_name, no_ack=True)
+ self._channel.start_consuming()
+
+ def __consume_handler(self, ch, method, properties, body):
+ receiver = self.get_receiver()
+ if receiver is None:
+ logging.warning("Receiver is not registered.")
+ return
+ receiver(self._channel, body)
+
+ def __publish(self, msg):
+ self._channel.basic_publish(exchange="", routing_key=self._queue_name,
+ body=msg)
+
+ @classmethod
+ def define_arguments(cls, parser):
+ parser.add_argument("--amqp-broker", type=str, default="localhost")
+ parser.add_argument("--amqp-port", type=int, default=None)
+ parser.add_argument("--amqp-vhost", type=str, default=None)
+ parser.add_argument("--amqp-queue", type=str, default="hap2-queue")
+ parser.add_argument("--amqp-user", type=str, default="hatohol")
+ parser.add_argument("--amqp-password", type=str, default="hatohol")
+
+ @classmethod
+ def parse_arguments(cls, args):
+ return {"amqp_broker": args.amqp_broker,
+ "amqp_port": args.amqp_port,
+ "amqp_vhost": args.amqp_vhost,
+ "amqp_queue": args.amqp_queue,
+ "amqp_user": args.amqp_user,
+ "amqp_password": args.amqp_password}
diff --git a/server/hap2/test/README b/server/hap2/test/README
index 99bb03dc0..8e375174e 100644
--- a/server/hap2/test/README
+++ b/server/hap2/test/README
@@ -3,3 +3,8 @@ $ test/run-test.sh
# Example to run one test.
$ PYTHONPATH=test python -m unittest -v TestTransporter.TestTransporter.test_factory
+
+- How to setup for TestRabbitMQConnector for the test
+# sudo rabbitmqctl add_vhost test
+# sudo rabbitmqctl add_user test_user test_password
+# sudo rabbitmqctl set_permissions -p test test_user ".*" ".*" ".*"
diff --git a/server/hap2/test/TestRabbitMQConnector.py b/server/hap2/test/TestRabbitMQConnector.py
new file mode 100644
index 000000000..9d01385cd
--- /dev/null
+++ b/server/hap2/test/TestRabbitMQConnector.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+"""
+ Copyright (C) 2015 Project Hatohol
+
+ This file is part of Hatohol.
+
+ Hatohol is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License, version 3
+ as published by the Free Software Foundation.
+
+ Hatohol 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with Hatohol. If not, see
+ .
+"""
+import unittest
+import os
+import subprocess
+from rabbitmqconnector import RabbitMQConnector
+
+class TestRabbitMQConnector(unittest.TestCase):
+ """
+ Before executing this test, some setting for RabbitMQ is needed.
+ See README in the same directory.
+ """
+ @classmethod
+ def setUpClass(cls):
+ cls.__broker = "localhost"
+ port = os.getenv("RABBITMQ_NODE_PORT")
+ cls.__port = None
+ if port is not None:
+ cls.__port = int(port)
+ cls.__vhost = "test"
+ cls.__queue_name = "test_queue"
+ cls.__user_name = "test_user"
+ cls.__password = "test_password"
+
+ def test_setup(self):
+ conn = RabbitMQConnector()
+ conn.setup(self.__get_default_transporter_args())
+
+ def test_call(self):
+ TEST_BODY = "CALL TEST"
+ self.__delete_test_queue()
+ conn = self.__create_connected_connector()
+ conn.call(TEST_BODY)
+ self.assertEqual(self.__get_from_test_queue(), TEST_BODY)
+
+ def test_reply(self):
+ TEST_BODY = "REPLY TEST"
+ self.__delete_test_queue()
+ conn = self.__create_connected_connector()
+ conn.reply(TEST_BODY)
+ self.assertEqual(self.__get_from_test_queue(), TEST_BODY)
+
+ def test_run_receive_loop_without_connect(self):
+ conn = RabbitMQConnector()
+ self.assertRaises(AssertionError, conn.run_receive_loop)
+
+ def test_run_receive_loop(self):
+ class Receiver():
+ def __call__(self, channel, msg):
+ self.msg = msg
+ channel.stop_consuming()
+
+ TEST_BODY = "FOO"
+ self.__delete_test_queue()
+ conn = RabbitMQConnector()
+ conn.setup(self.__get_default_transporter_args())
+ receiver = Receiver()
+ conn.set_receiver(receiver)
+ self.__publish(TEST_BODY)
+ conn.run_receive_loop()
+ self.assertEquals(receiver.msg, TEST_BODY)
+
+ def __get_default_transporter_args(self):
+ args = {"amqp_broker": self.__broker, "amqp_port": self.__port,
+ "amqp_vhost": self.__vhost, "amqp_queue": self.__queue_name,
+ "amqp_user": self.__user_name, "amqp_password": self.__password}
+ return args
+
+ def __create_connected_connector(self):
+ conn = RabbitMQConnector()
+ conn.setup(self.__get_default_transporter_args())
+ return conn
+
+ def __execute(self, args):
+ subproc = subprocess.Popen(args, stdout=subprocess.PIPE)
+ output = subproc.communicate()[0]
+ self.assertEquals(subproc.returncode, 0)
+ return output
+
+
+ def __build_broker_url(self):
+ port = ""
+ if self.__port is not None:
+ port = ":%d" % self.__port
+ return "amqp://%s:%s@%s%s/%s" % (self.__user_name, self.__password,
+ self.__broker, port, self.__vhost)
+
+ def __build_broker_options(self):
+ if os.getenv("RABBITMQ_CONNECTOR_TEST_WORKAROUND") is not None:
+ return ["-u", self.__build_broker_url()]
+
+ def append_if_not_none(li, key, val):
+ if val is not None:
+ li.append(key)
+ li.append(val)
+
+ opt = []
+ server = self.__broker
+ if server is not None and self.__port is not None:
+ server += ":%d" % self.__port
+ append_if_not_none(opt, "--server", server)
+ append_if_not_none(opt, "--vhost", self.__vhost)
+ append_if_not_none(opt, "--username", self.__user_name)
+ append_if_not_none(opt, "--password", self.__password)
+ return opt
+
+ def __publish(self, body):
+ args = ["amqp-publish"]
+ args.extend(self.__build_broker_options())
+ args.extend(["-r", self.__queue_name, "-b", body])
+ subprocess.Popen(args).communicate()
+
+ def __get_from_test_queue(self):
+ args = ["amqp-get"]
+ args.extend(self.__build_broker_options())
+ args.extend(["-q", self.__queue_name])
+ return self.__execute(args)
+
+ def __delete_test_queue(self):
+ args = ["amqp-delete-queue"]
+ args.extend(self.__build_broker_options())
+ args.extend(["-q", self.__queue_name])
+ subprocess.Popen(args).communicate()
diff --git a/server/hap2/test/run-test.sh b/server/hap2/test/run-test.sh
index d3d59b89f..e7e647555 100755
--- a/server/hap2/test/run-test.sh
+++ b/server/hap2/test/run-test.sh
@@ -2,4 +2,15 @@
test_dir=$(cd $(dirname $0) && pwd)
export PYTHONPATH=$test_dir/..
+
+# Workaround: probably due to amqp-tools bug.
+if [ `cat /etc/issue | grep "^Ubuntu 14.04" | wc -l` = "1" ]; then
+ export RABBITMQ_CONNECTOR_TEST_WORKAROUND=1
+fi
+
+RABBITMQ_PORT_CONF=/etc/rabbitmq/rabbitmq.conf.d/port
+if [ -f $RABBITMQ_PORT_CONF ]; then
+ . $RABBITMQ_PORT_CONF
+ export RABBITMQ_NODE_PORT
+fi
python -m unittest discover -s $test_dir -p 'Test*.py' "$@"
diff --git a/server/hap2/test/setup.sh b/server/hap2/test/setup.sh
new file mode 100755
index 000000000..90cb5454d
--- /dev/null
+++ b/server/hap2/test/setup.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+sudo rabbitmqctl add_vhost test
+sudo rabbitmqctl add_user test_user test_password
+sudo rabbitmqctl set_permissions -p test test_user ".*" ".*" ".*"
diff --git a/server/misc/setup-rabbitmq-server-port.sh b/server/misc/setup-rabbitmq-server-port.sh
new file mode 100755
index 000000000..58e4bbf9b
--- /dev/null
+++ b/server/misc/setup-rabbitmq-server-port.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+mkdir -p /etc/rabbitmq/rabbitmq.conf.d
+echo RABBITMQ_NODE_PORT=5673 > /etc/rabbitmq/rabbitmq.conf.d/port
+echo "export RABBITMQ_NODE_PORT=5673" >> /etc/default/rabbitmq-server
diff --git a/test/run-server-test.sh b/test/run-server-test.sh
index 922db1dfc..708cf4fa6 100755
--- a/test/run-server-test.sh
+++ b/test/run-server-test.sh
@@ -7,5 +7,6 @@ TOP_DIR="$BASE_DIR/.."
${TOP_DIR}/server/mlpl/test/run-test.sh || FAILED=1
${TOP_DIR}/server/test/run-test.sh || FAILED=1
${TOP_DIR}/server/tools/test/run-test.sh || FAILED=1
+sudo ${TOP_DIR}/server/hap2/test/setup.sh || FAILED=1
${TOP_DIR}/server/hap2/test/run-test.sh || FAILED=1
exit $FAILED