From b788ebafa2f4b4364dfaadfef74d1f84d61b8646 Mon Sep 17 00:00:00 2001 From: Andrew Melton Date: Fri, 25 Jan 2013 18:17:18 -0500 Subject: [PATCH 1/3] Worker unit tests --- .coverage | Bin 28443 -> 0 bytes .gitignore | 2 ++ run_tests.sh | 2 +- tests/unit/test_worker.py | 36 ++++++++++++++++++++++++++++++++++++ worker/__init__.py | 0 5 files changed, 39 insertions(+), 1 deletion(-) delete mode 100644 .coverage create mode 100644 tests/unit/test_worker.py create mode 100644 worker/__init__.py diff --git a/.coverage b/.coverage deleted file mode 100644 index 9b42c3f9c16d0982b464e58741d43b6f15a912e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28443 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 diff --git a/.gitignore b/.gitignore index 54ef793..618391f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ *.pyc local_settings.py +.coverage +worker.log diff --git a/run_tests.sh b/run_tests.sh index 54904d1..d5e661f 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -1,2 +1,2 @@ #!/bin/bash -nosetests tests --exclude-dir=stacktach --with-coverage --cover-package=stacktach +nosetests tests --exclude-dir=stacktach --with-coverage --cover-package=stacktach,worker diff --git a/tests/unit/test_worker.py b/tests/unit/test_worker.py new file mode 100644 index 0000000..cfb534b --- /dev/null +++ b/tests/unit/test_worker.py @@ -0,0 +1,36 @@ +import unittest + +import kombu +import kombu.entity +import mox + +import worker.worker as worker + +class NovaConsumerTestCase(unittest.TestCase): + def setUp(self): + self.mox = mox.Mox() + + def test_get_consumer(self): + created_queues = None + created_callback = None + created_consumers = [] + def Consumer(queues=None, callbacks=None): + created_queues = queues + created_callback = callbacks + consumer = self.mox.CreateMockAnything() + created_consumers.append(consumer) + return consumer + self.mox.StubOutClassWithMocks(kombu.entity, 'Exchange') + self.mox.StubOutClassWithMocks(kombu, 'Queue') + kombu.entity.Exchange('nova', type='topic', exclusive=False, + durable=True, auto_delete=False) + kombu.Queue('monitor.info', kombu.entity.Exchange, auto_delete=False, + durable=True, exclusive=False, routing_key='monitor.info') + kombu.Queue('monitor.error', kombu.entity.Exchange, auto_delete=False, + durable=True, exclusive=False, routing_key='monitor.error') + consumer = worker.NovaConsumer('test', None, None, True) + self.mox.ReplayAll() + consumers = consumer.get_consumers(Consumer, None) + self.assertEqual(len(consumers), len(created_consumers)) + self.assertEqual(consumers[0], created_consumers[0]) + self.mox.VerifyAll() \ No newline at end of file diff --git a/worker/__init__.py b/worker/__init__.py new file mode 100644 index 0000000..e69de29 From 5243cbc24e42ecdb8a7eec33ff032e62411b8597 Mon Sep 17 00:00:00 2001 From: Andrew Melton Date: Mon, 28 Jan 2013 17:44:54 -0500 Subject: [PATCH 2/3] Queue args in deployment config, worker tests --- stacktach/db.py | 3 + stacktach/models.py | 3 +- tests/unit/test_worker.py | 169 +++++++++++++++++++++++++++++++++++--- worker/worker.py | 32 +++++--- 4 files changed, 181 insertions(+), 26 deletions(-) diff --git a/stacktach/db.py b/stacktach/db.py index a00d70e..23db4fb 100644 --- a/stacktach/db.py +++ b/stacktach/db.py @@ -1,5 +1,8 @@ import models +def get_or_create_deployment(name): + return models.Deployment.objects.get_or_create(name=name) + def create_rawdata(**kwargs): return models.RawData(**kwargs) diff --git a/stacktach/models.py b/stacktach/models.py index 3ae2ae1..e4ff911 100644 --- a/stacktach/models.py +++ b/stacktach/models.py @@ -21,8 +21,7 @@ class Deployment(models.Model): name = models.CharField(max_length=50) -def get_or_create_deployment(name): - return Deployment.objects.get_or_create(name=name) + class RawData(models.Model): diff --git a/tests/unit/test_worker.py b/tests/unit/test_worker.py index cfb534b..eccd830 100644 --- a/tests/unit/test_worker.py +++ b/tests/unit/test_worker.py @@ -1,22 +1,28 @@ +import json import unittest import kombu import kombu.entity +import kombu.connection import mox +from stacktach import db, views import worker.worker as worker class NovaConsumerTestCase(unittest.TestCase): def setUp(self): self.mox = mox.Mox() - def test_get_consumer(self): - created_queues = None - created_callback = None + def tearDown(self): + self.mox.UnsetStubs() + + def test_get_consumers(self): + created_queues = [] + created_callbacks = [] created_consumers = [] def Consumer(queues=None, callbacks=None): - created_queues = queues - created_callback = callbacks + created_queues.extend(queues) + created_callbacks.extend(callbacks) consumer = self.mox.CreateMockAnything() created_consumers.append(consumer) return consumer @@ -24,13 +30,154 @@ class NovaConsumerTestCase(unittest.TestCase): self.mox.StubOutClassWithMocks(kombu, 'Queue') kombu.entity.Exchange('nova', type='topic', exclusive=False, durable=True, auto_delete=False) - kombu.Queue('monitor.info', kombu.entity.Exchange, auto_delete=False, - durable=True, exclusive=False, routing_key='monitor.info') - kombu.Queue('monitor.error', kombu.entity.Exchange, auto_delete=False, - durable=True, exclusive=False, routing_key='monitor.error') - consumer = worker.NovaConsumer('test', None, None, True) + info_queue = kombu.Queue('monitor.info', kombu.entity.Exchange, + auto_delete=False, durable=True, + exclusive=False, routing_key='monitor.info', + queue_arguments={}) + error_queue = kombu.Queue('monitor.error', kombu.entity.Exchange, + auto_delete=False, durable=True, + exclusive=False, routing_key='monitor.error', + queue_arguments={}) + consumer = worker.NovaConsumer('test', None, None, True, {}) self.mox.ReplayAll() consumers = consumer.get_consumers(Consumer, None) - self.assertEqual(len(consumers), len(created_consumers)) + self.assertEqual(len(consumers), 1) self.assertEqual(consumers[0], created_consumers[0]) + self.assertEqual(len(created_queues), 2) + self.assertTrue(info_queue in created_queues) + self.assertTrue(error_queue in created_queues) + self.assertEqual(len(created_callbacks), 1) + self.assertTrue(consumer.on_nova in created_callbacks) + self.mox.VerifyAll() + + def test_get_consumers_queue_args(self): + created_queues = [] + created_callbacks = [] + created_consumers = [] + def Consumer(queues=None, callbacks=None): + created_queues.extend(queues) + created_callbacks.extend(callbacks) + consumer = self.mox.CreateMockAnything() + created_consumers.append(consumer) + return consumer + self.mox.StubOutClassWithMocks(kombu.entity, 'Exchange') + self.mox.StubOutClassWithMocks(kombu, 'Queue') + kombu.entity.Exchange('nova', type='topic', exclusive=False, + durable=True, auto_delete=False) + queue_args = {'arg': 'val'} + info_queue = kombu.Queue('monitor.info', kombu.entity.Exchange, + auto_delete=False, durable=True, + exclusive=False, routing_key='monitor.info', + queue_arguments=queue_args) + error_queue = kombu.Queue('monitor.error', kombu.entity.Exchange, + auto_delete=False, durable=True, + exclusive=False, routing_key='monitor.error', + queue_arguments=queue_args) + consumer = worker.NovaConsumer('test', None, None, True, queue_args) + self.mox.ReplayAll() + consumers = consumer.get_consumers(Consumer, None) + self.assertEqual(len(consumers), 1) + self.assertEqual(consumers[0], created_consumers[0]) + self.assertEqual(len(created_queues), 2) + self.assertTrue(info_queue in created_queues) + self.assertTrue(error_queue in created_queues) + self.assertEqual(len(created_callbacks), 1) + self.assertTrue(consumer.on_nova in created_callbacks) + self.mox.VerifyAll() + + def test_process(self): + deployment = self.mox.CreateMockAnything() + raw = self.mox.CreateMockAnything() + message = self.mox.CreateMockAnything() + + consumer = worker.NovaConsumer('test', None, deployment, True, {}) + routing_key = 'monitor.info' + message.delivery_info = {'routing_key': routing_key} + body_dict = {u'key': u'value'} + message.body = json.dumps(body_dict) + self.mox.StubOutWithMock(views, 'process_raw_data', + use_mock_anything=True) + args = (routing_key, body_dict) + views.process_raw_data(deployment, args, json.dumps(args))\ + .AndReturn(raw) + self.mox.StubOutWithMock(consumer, '_check_memory', + use_mock_anything=True) + consumer._check_memory() + self.mox.ReplayAll() + consumer._process(message) + self.assertEqual(consumer.processed, 1) + self.mox.VerifyAll() + + def test_run(self): + config = { + 'name': 'east_coast.prod.global', + 'durable_queue': False, + 'rabbit_host': '10.0.0.1', + 'rabbit_port': 5672, + 'rabbit_userid': 'rabbit', + 'rabbit_password': 'rabbit', + 'rabbit_virtual_host': '/' + } + self.mox.StubOutWithMock(db, 'get_or_create_deployment') + deployment = self.mox.CreateMockAnything() + db.get_or_create_deployment(config['name'])\ + .AndReturn((deployment, True)) + self.mox.StubOutWithMock(kombu.connection, 'BrokerConnection') + params = dict(hostname=config['rabbit_host'], + port=config['rabbit_port'], + userid=config['rabbit_userid'], + password=config['rabbit_password'], + transport="librabbitmq", + virtual_host=config['rabbit_virtual_host']) + self.mox.StubOutWithMock(worker, "continue_running") + worker.continue_running().AndReturn(True) + conn = self.mox.CreateMockAnything() + kombu.connection.BrokerConnection(**params).AndReturn(conn) + conn.__enter__().AndReturn(conn) + conn.__exit__(None, None, None).AndReturn(None) + self.mox.StubOutClassWithMocks(worker, 'NovaConsumer') + consumer = worker.NovaConsumer(config['name'], conn, deployment, + config['durable_queue'], {}) + consumer.run() + worker.continue_running().AndReturn(False) + self.mox.ReplayAll() + worker.run(config) + self.mox.VerifyAll() + + def test_run_queue_args(self): + config = { + 'name': 'east_coast.prod.global', + 'durable_queue': False, + 'rabbit_host': '10.0.0.1', + 'rabbit_port': 5672, + 'rabbit_userid': 'rabbit', + 'rabbit_password': 'rabbit', + 'rabbit_virtual_host': '/', + 'queue_arguments': {'x-ha-policy': 'all'} + } + self.mox.StubOutWithMock(db, 'get_or_create_deployment') + deployment = self.mox.CreateMockAnything() + db.get_or_create_deployment(config['name'])\ + .AndReturn((deployment, True)) + self.mox.StubOutWithMock(kombu.connection, 'BrokerConnection') + params = dict(hostname=config['rabbit_host'], + port=config['rabbit_port'], + userid=config['rabbit_userid'], + password=config['rabbit_password'], + transport="librabbitmq", + virtual_host=config['rabbit_virtual_host']) + self.mox.StubOutWithMock(worker, "continue_running") + worker.continue_running().AndReturn(True) + conn = self.mox.CreateMockAnything() + kombu.connection.BrokerConnection(**params).AndReturn(conn) + conn.__enter__().AndReturn(conn) + conn.__exit__(None, None, None).AndReturn(None) + self.mox.StubOutClassWithMocks(worker, 'NovaConsumer') + consumer = worker.NovaConsumer(config['name'], conn, deployment, + config['durable_queue'], + config['queue_arguments']) + consumer.run() + worker.continue_running().AndReturn(False) + self.mox.ReplayAll() + worker.run(config) self.mox.VerifyAll() \ No newline at end of file diff --git a/worker/worker.py b/worker/worker.py index 9a3165f..21a78ea 100644 --- a/worker/worker.py +++ b/worker/worker.py @@ -19,7 +19,6 @@ import datetime import json import kombu -import kombu.connection import kombu.entity import kombu.mixins import logging @@ -27,8 +26,7 @@ import time from pympler.process import ProcessMemoryInfo -from stacktach import models, views -from stacktach import datetime_to_decimal as dt +from stacktach import db, views LOG = logging.getLogger(__name__) @@ -39,10 +37,11 @@ LOG.addHandler(handler) class NovaConsumer(kombu.mixins.ConsumerMixin): - def __init__(self, name, connection, deployment, durable): + def __init__(self, name, connection, deployment, durable, queue_arguments): self.connection = connection self.deployment = deployment self.durable = durable + self.queue_arguments = queue_arguments self.name = name self.last_time = None self.pmi = None @@ -56,19 +55,19 @@ class NovaConsumer(kombu.mixins.ConsumerMixin): nova_queues = [ kombu.Queue("monitor.info", nova_exchange, durable=self.durable, - auto_delete=False, - exclusive=False, routing_key='monitor.info'), + auto_delete=False, exclusive=False, + queue_arguments=self.queue_arguments, + routing_key='monitor.info'), kombu.Queue("monitor.error", nova_exchange, durable=self.durable, auto_delete=False, + queue_arguments=self.queue_arguments, exclusive=False, routing_key='monitor.error'), ] return [Consumer(queues=nova_queues, callbacks=[self.on_nova])] - def _process(self, body, message): + def _process(self, message): routing_key = message.delivery_info['routing_key'] - payload = (routing_key, body) - jvalues = json.dumps(payload) body = str(message.body) args = (routing_key, json.loads(body)) @@ -110,12 +109,16 @@ class NovaConsumer(kombu.mixins.ConsumerMixin): def on_nova(self, body, message): try: - self._process(body, message) + self._process(message) except Exception, e: LOG.exception("Problem %s" % e) message.ack() +def continue_running(): + return True + + def run(deployment_config): name = deployment_config['name'] host = deployment_config.get('rabbit_host', 'localhost') @@ -124,8 +127,9 @@ def run(deployment_config): password = deployment_config.get('rabbit_password', 'rabbit') virtual_host = deployment_config.get('rabbit_virtual_host', '/') durable = deployment_config.get('durable_queue', True) + queue_arguments = deployment_config.get('queue_arguments', {}) - deployment, new = models.get_or_create_deployment(name) + deployment, new = db.get_or_create_deployment(name) print "Starting worker for '%s'" % name LOG.info("%s: %s %s %s %s" % (name, host, port, user_id, virtual_host)) @@ -137,14 +141,16 @@ def run(deployment_config): transport="librabbitmq", virtual_host=virtual_host) - while True: + while continue_running(): LOG.debug("Processing on '%s'" % name) with kombu.connection.BrokerConnection(**params) as conn: try: - consumer = NovaConsumer(name, conn, deployment, durable) + consumer = NovaConsumer(name, conn, deployment, durable, + queue_arguments) consumer.run() except Exception as e: LOG.exception("name=%s, exception=%s. Reconnecting in 5s" % (name, e)) time.sleep(5) LOG.debug("Completed processing on '%s'" % name) + From da5e6765af7a18e365330193b12dd164d0cfd62c Mon Sep 17 00:00:00 2001 From: Andrew Melton Date: Tue, 29 Jan 2013 16:33:30 -0500 Subject: [PATCH 3/3] Refactoring worker and tests --- stacktach/models.py | 3 -- tests/unit/test_worker.py | 88 +++++++++++++++++++++------------------ worker/worker.py | 25 ++++++----- 3 files changed, 61 insertions(+), 55 deletions(-) diff --git a/stacktach/models.py b/stacktach/models.py index e4ff911..ca2ea94 100644 --- a/stacktach/models.py +++ b/stacktach/models.py @@ -21,9 +21,6 @@ class Deployment(models.Model): name = models.CharField(max_length=50) - - - class RawData(models.Model): deployment = models.ForeignKey(Deployment) tenant = models.CharField(max_length=50, null=True, blank=True, diff --git a/tests/unit/test_worker.py b/tests/unit/test_worker.py index eccd830..ada86bb 100644 --- a/tests/unit/test_worker.py +++ b/tests/unit/test_worker.py @@ -26,19 +26,17 @@ class NovaConsumerTestCase(unittest.TestCase): consumer = self.mox.CreateMockAnything() created_consumers.append(consumer) return consumer - self.mox.StubOutClassWithMocks(kombu.entity, 'Exchange') - self.mox.StubOutClassWithMocks(kombu, 'Queue') - kombu.entity.Exchange('nova', type='topic', exclusive=False, - durable=True, auto_delete=False) - info_queue = kombu.Queue('monitor.info', kombu.entity.Exchange, - auto_delete=False, durable=True, - exclusive=False, routing_key='monitor.info', - queue_arguments={}) - error_queue = kombu.Queue('monitor.error', kombu.entity.Exchange, - auto_delete=False, durable=True, - exclusive=False, routing_key='monitor.error', - queue_arguments={}) + self.mox.StubOutWithMock(worker.NovaConsumer, '_create_exchange') + self.mox.StubOutWithMock(worker.NovaConsumer, '_create_queue') consumer = worker.NovaConsumer('test', None, None, True, {}) + exchange = self.mox.CreateMockAnything() + consumer._create_exchange('nova', 'topic').AndReturn(exchange) + info_queue = self.mox.CreateMockAnything() + error_queue = self.mox.CreateMockAnything() + consumer._create_queue('monitor.info', exchange, 'monitor.info')\ + .AndReturn(info_queue) + consumer._create_queue('monitor.error', exchange, 'monitor.error')\ + .AndReturn(error_queue) self.mox.ReplayAll() consumers = consumer.get_consumers(Consumer, None) self.assertEqual(len(consumers), 1) @@ -50,39 +48,47 @@ class NovaConsumerTestCase(unittest.TestCase): self.assertTrue(consumer.on_nova in created_callbacks) self.mox.VerifyAll() - def test_get_consumers_queue_args(self): - created_queues = [] - created_callbacks = [] - created_consumers = [] - def Consumer(queues=None, callbacks=None): - created_queues.extend(queues) - created_callbacks.extend(callbacks) - consumer = self.mox.CreateMockAnything() - created_consumers.append(consumer) - return consumer + def test_create_exchange(self): + args = {'key': 'value'} + consumer = worker.NovaConsumer('test', None, None, True, args) + self.mox.StubOutClassWithMocks(kombu.entity, 'Exchange') + exchange = kombu.entity.Exchange('nova', type='topic', exclusive=False, + durable=True, auto_delete=False) + self.mox.ReplayAll() + actual_exchange = consumer._create_exchange('nova', 'topic') + self.assertEqual(actual_exchange, exchange) + self.mox.VerifyAll() + + def test_create_queue(self): self.mox.StubOutClassWithMocks(kombu, 'Queue') - kombu.entity.Exchange('nova', type='topic', exclusive=False, - durable=True, auto_delete=False) - queue_args = {'arg': 'val'} - info_queue = kombu.Queue('monitor.info', kombu.entity.Exchange, - auto_delete=False, durable=True, - exclusive=False, routing_key='monitor.info', - queue_arguments=queue_args) - error_queue = kombu.Queue('monitor.error', kombu.entity.Exchange, - auto_delete=False, durable=True, - exclusive=False, routing_key='monitor.error', - queue_arguments=queue_args) + exchange = self.mox.CreateMockAnything() + queue = kombu.Queue('name', exchange, auto_delete=False, durable=True, + exclusive=False, routing_key='routing.key', + queue_arguments={}) + consumer = worker.NovaConsumer('test', None, None, True, {}) + self.mox.ReplayAll() + actual_queue = consumer._create_queue('name', exchange, 'routing.key', + exclusive=False, + auto_delete=False) + self.assertEqual(actual_queue, queue) + self.mox.VerifyAll() + + + + def test_create_queue_with_queue_args(self): + self.mox.StubOutClassWithMocks(kombu, 'Queue') + exchange = self.mox.CreateMockAnything() + queue_args = {'key': 'value'} + queue = kombu.Queue('name', exchange, auto_delete=False, durable=True, + exclusive=False, routing_key='routing.key', + queue_arguments=queue_args) consumer = worker.NovaConsumer('test', None, None, True, queue_args) self.mox.ReplayAll() - consumers = consumer.get_consumers(Consumer, None) - self.assertEqual(len(consumers), 1) - self.assertEqual(consumers[0], created_consumers[0]) - self.assertEqual(len(created_queues), 2) - self.assertTrue(info_queue in created_queues) - self.assertTrue(error_queue in created_queues) - self.assertEqual(len(created_callbacks), 1) - self.assertTrue(consumer.on_nova in created_callbacks) + actual_queue = consumer._create_queue('name', exchange, 'routing.key', + exclusive=False, + auto_delete=False) + self.assertEqual(actual_queue, queue) self.mox.VerifyAll() def test_process(self): diff --git a/worker/worker.py b/worker/worker.py index 21a78ea..db7a22b 100644 --- a/worker/worker.py +++ b/worker/worker.py @@ -48,20 +48,23 @@ class NovaConsumer(kombu.mixins.ConsumerMixin): self.processed = 0 self.total_processed = 0 + def _create_exchange(self, name, type, exclusive=False, auto_delete=False): + return kombu.entity.Exchange(name, type=type, exclusive=exclusive, + durable=self.durable, auto_delete=auto_delete) + + def _create_queue(self, name, nova_exchange, routing_key, exclusive=False, + auto_delete=False): + return kombu.Queue(name, nova_exchange, durable=self.durable, + auto_delete=exclusive, exclusive=auto_delete, + queue_arguments=self.queue_arguments, + routing_key=routing_key) + def get_consumers(self, Consumer, channel): - nova_exchange = kombu.entity.Exchange("nova", type="topic", - exclusive=False, durable=self.durable, - auto_delete=False) + nova_exchange = self._create_exchange("nova", "topic") nova_queues = [ - kombu.Queue("monitor.info", nova_exchange, durable=self.durable, - auto_delete=False, exclusive=False, - queue_arguments=self.queue_arguments, - routing_key='monitor.info'), - kombu.Queue("monitor.error", nova_exchange, durable=self.durable, - auto_delete=False, - queue_arguments=self.queue_arguments, - exclusive=False, routing_key='monitor.error'), + self._create_queue('monitor.info', nova_exchange, 'monitor.info'), + self._create_queue('monitor.error', nova_exchange, 'monitor.error') ] return [Consumer(queues=nova_queues, callbacks=[self.on_nova])]