From 3caf61a74c9b70d510bd2e7c8a3d6682ab5a41b7 Mon Sep 17 00:00:00 2001 From: Erik Olof Gunnar Andersson Date: Fri, 21 Aug 2015 15:23:51 +0200 Subject: [PATCH] Release 1.2.3 --- .travis.yml | 1 - CHANGELOG | 8 ++-- amqpstorm/connection.py | 2 +- amqpstorm/io.py | 3 +- examples/__init__.py | 2 +- examples/basic_error_handling.py | 1 - examples/basic_get.py | 1 - examples/basic_publisher.py | 1 - examples/basic_publisher_confirms.py | 1 - examples/basic_rpc_server.py | 2 +- examples/basic_ssl_publisher.py | 1 - examples/basic_threaded_consumer.py | 1 - examples/basic_threaded_consumer2.py | 1 - examples/basic_threaded_publisher.py | 2 - examples/flask_threaded_rpc_client.py | 1 - examples/simple_generator_consumer.py | 1 - examples/simple_publisher.py | 1 - examples/simple_rpc_client.py | 1 + setup.py | 2 +- test-requirements.txt | 3 +- tests/__init__.py | 2 +- tests/base_tests.py | 1 - tests/basic_tests.py | 1 - tests/channel0_tests.py | 1 - tests/channel_tests.py | 1 - tests/compatiblity_tests.py | 1 - tests/connection_tests.py | 65 ++++++++++++++++++++++++++- tests/functional_tests.py | 1 - tests/heartbeat_tests.py | 12 ++++- 29 files changed, 88 insertions(+), 33 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9f13dbed..ea3a2f07 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,6 @@ python: - 3.2 - 3.3 - 3.4 - - "nightly" - pypy - pypy3 install: diff --git a/CHANGELOG b/CHANGELOG index 7c682783..1d229c40 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,9 +1,9 @@ # Changelog -### Version 1.2.3-dev -- Added Client-side Heartbeat monitor. -- Added a Connection Timeout to Connection.open. -- Fixed potential bug in the Socket Poller Error handling. +### Version 1.2.3 +- Added a Client-side Heartbeat monitor. +- Added Timeout to Connection.open. +- Fixed potential bug in the Socket Poller error handling. ### Version 1.2.2 - Added shortcuts for common properties in the Message class, e.g. message.app_id. diff --git a/amqpstorm/connection.py b/amqpstorm/connection.py index 222d310a..0872a5d9 100644 --- a/amqpstorm/connection.py +++ b/amqpstorm/connection.py @@ -54,13 +54,13 @@ def __init__(self, hostname, username, password, port=5672, **kwargs): 'ssl': kwargs.get('ssl', False), 'ssl_options': kwargs.get('ssl_options', {}) } + self._validate_parameters() self.io = IO(self.parameters, on_read=self._read_buffer, on_error=self._handle_socket_error) self.heartbeat = Heartbeat(self.parameters['heartbeat']) self._channel0 = Channel0(self) self._channels = {} - self._validate_parameters() if not kwargs.get('lazy', False): self.open() diff --git a/amqpstorm/io.py b/amqpstorm/io.py index f0f3c102..11a92f58 100644 --- a/amqpstorm/io.py +++ b/amqpstorm/io.py @@ -66,10 +66,9 @@ def is_ready(self): class IO(Stateful): - lock = threading.Lock() - def __init__(self, parameters, on_read=None, on_error=None): super(IO, self).__init__() + self.lock = threading.Lock() self.socket = None self.poller = None self.inbound_thread = None diff --git a/examples/__init__.py b/examples/__init__.py index d9eba2ad..d64b561d 100644 --- a/examples/__init__.py +++ b/examples/__init__.py @@ -3,4 +3,4 @@ HOST = '127.0.0.1' USERNAME = 'guest' PASSWORD = 'guest' -URI = 'amqp://guest:guest@127.0.0.1:5672/%2F' \ No newline at end of file +URI = 'amqp://guest:guest@127.0.0.1:5672/%2F' diff --git a/examples/basic_error_handling.py b/examples/basic_error_handling.py index bc052e0d..ee054383 100644 --- a/examples/basic_error_handling.py +++ b/examples/basic_error_handling.py @@ -9,7 +9,6 @@ from examples import USERNAME from examples import PASSWORD - logging.basicConfig(level=logging.DEBUG) diff --git a/examples/basic_get.py b/examples/basic_get.py index 826d2ef7..8d7c7378 100644 --- a/examples/basic_get.py +++ b/examples/basic_get.py @@ -8,7 +8,6 @@ from examples import USERNAME from examples import PASSWORD - logging.basicConfig(level=logging.DEBUG) QUEUE_NAME = 'simple_queue' diff --git a/examples/basic_publisher.py b/examples/basic_publisher.py index 54834cc4..99d34d03 100644 --- a/examples/basic_publisher.py +++ b/examples/basic_publisher.py @@ -8,7 +8,6 @@ from examples import USERNAME from examples import PASSWORD - logging.basicConfig(level=logging.DEBUG) diff --git a/examples/basic_publisher_confirms.py b/examples/basic_publisher_confirms.py index f341f90d..d7e2a023 100644 --- a/examples/basic_publisher_confirms.py +++ b/examples/basic_publisher_confirms.py @@ -9,7 +9,6 @@ from examples import USERNAME from examples import PASSWORD - logging.basicConfig(level=logging.DEBUG) diff --git a/examples/basic_rpc_server.py b/examples/basic_rpc_server.py index 37afa2d1..4afc9a3a 100644 --- a/examples/basic_rpc_server.py +++ b/examples/basic_rpc_server.py @@ -9,7 +9,6 @@ from examples import USERNAME from examples import PASSWORD - CONNECTION = amqpstorm.Connection(HOST, USERNAME, PASSWORD) CHANNEL = CONNECTION.channel() CHANNEL.queue.declare(queue='rpc_queue') @@ -38,6 +37,7 @@ def on_request(body, channel, header, properties): body=str(response)) channel.basic.ack(delivery_tag=header['delivery_tag']) + if __name__ == '__main__': CHANNEL.basic.qos(prefetch_count=1) CHANNEL.basic.consume(on_request, queue='rpc_queue') diff --git a/examples/basic_ssl_publisher.py b/examples/basic_ssl_publisher.py index ef0b9ec2..240d162a 100644 --- a/examples/basic_ssl_publisher.py +++ b/examples/basic_ssl_publisher.py @@ -9,7 +9,6 @@ from examples import USERNAME from examples import PASSWORD - logging.basicConfig(level=logging.DEBUG) diff --git a/examples/basic_threaded_consumer.py b/examples/basic_threaded_consumer.py index 9a1f0650..690e8fc1 100644 --- a/examples/basic_threaded_consumer.py +++ b/examples/basic_threaded_consumer.py @@ -27,7 +27,6 @@ from examples import USERNAME from examples import PASSWORD - logging.basicConfig(level=logging.DEBUG) diff --git a/examples/basic_threaded_consumer2.py b/examples/basic_threaded_consumer2.py index b1aaf6de..ef139a18 100644 --- a/examples/basic_threaded_consumer2.py +++ b/examples/basic_threaded_consumer2.py @@ -25,7 +25,6 @@ from examples import USERNAME from examples import PASSWORD - logging.basicConfig(level=logging.DEBUG) diff --git a/examples/basic_threaded_publisher.py b/examples/basic_threaded_publisher.py index f21fc719..0d0ef5cb 100644 --- a/examples/basic_threaded_publisher.py +++ b/examples/basic_threaded_publisher.py @@ -10,7 +10,6 @@ from examples import USERNAME from examples import PASSWORD - logging.basicConfig(level=logging.DEBUG) @@ -54,4 +53,3 @@ def send_messages(connection): time.sleep(1) CONNECTION.close() - diff --git a/examples/flask_threaded_rpc_client.py b/examples/flask_threaded_rpc_client.py index 53e65f73..3d1b70a4 100644 --- a/examples/flask_threaded_rpc_client.py +++ b/examples/flask_threaded_rpc_client.py @@ -13,7 +13,6 @@ from examples import USERNAME from examples import PASSWORD - app = Flask(__name__) diff --git a/examples/simple_generator_consumer.py b/examples/simple_generator_consumer.py index 9a73754d..1e1f4a28 100644 --- a/examples/simple_generator_consumer.py +++ b/examples/simple_generator_consumer.py @@ -8,7 +8,6 @@ from examples import USERNAME from examples import PASSWORD - logging.basicConfig(level=logging.DEBUG) diff --git a/examples/simple_publisher.py b/examples/simple_publisher.py index 34cfdce5..3da53078 100644 --- a/examples/simple_publisher.py +++ b/examples/simple_publisher.py @@ -8,7 +8,6 @@ from examples import USERNAME from examples import PASSWORD - logging.basicConfig(level=logging.DEBUG) diff --git a/examples/simple_rpc_client.py b/examples/simple_rpc_client.py index 3247eab4..a07aed7e 100644 --- a/examples/simple_rpc_client.py +++ b/examples/simple_rpc_client.py @@ -64,6 +64,7 @@ def _on_response(self, message): return self.response = message.body + if __name__ == '__main__': fibonacci_rpc = FibonacciRpcClient(HOST, USERNAME, PASSWORD) diff --git a/setup.py b/setup.py index 78427aff..80582795 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ """ setup(name='AMQP-Storm', - version='1.2.2', + version='1.2.3', description='Thread-safe Python AMQP Client Library based on pamqp.', long_description=long_description, author='Erik Olof Gunnar Andersson', diff --git a/test-requirements.txt b/test-requirements.txt index edacdc81..903c7b06 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,2 +1,3 @@ nose -mock \ No newline at end of file +mock +coverage \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py index d9eba2ad..d64b561d 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -3,4 +3,4 @@ HOST = '127.0.0.1' USERNAME = 'guest' PASSWORD = 'guest' -URI = 'amqp://guest:guest@127.0.0.1:5672/%2F' \ No newline at end of file +URI = 'amqp://guest:guest@127.0.0.1:5672/%2F' diff --git a/tests/base_tests.py b/tests/base_tests.py index 6d77e0b7..5c004ff3 100644 --- a/tests/base_tests.py +++ b/tests/base_tests.py @@ -14,7 +14,6 @@ from tests.utility import FakeConnection from tests.utility import TestPayload - logging.basicConfig(level=logging.DEBUG) diff --git a/tests/basic_tests.py b/tests/basic_tests.py index a74d360b..f2152098 100644 --- a/tests/basic_tests.py +++ b/tests/basic_tests.py @@ -18,7 +18,6 @@ from tests.utility import FakeConnection - logging.basicConfig(level=logging.DEBUG) diff --git a/tests/channel0_tests.py b/tests/channel0_tests.py index 3a5cbf29..7fcba6f6 100644 --- a/tests/channel0_tests.py +++ b/tests/channel0_tests.py @@ -15,7 +15,6 @@ from tests.utility import FakeConnection - logging.basicConfig(level=logging.DEBUG) diff --git a/tests/channel_tests.py b/tests/channel_tests.py index 460073c8..8ae1aea3 100644 --- a/tests/channel_tests.py +++ b/tests/channel_tests.py @@ -18,7 +18,6 @@ from tests.utility import FakeConnection - logging.basicConfig(level=logging.DEBUG) diff --git a/tests/compatiblity_tests.py b/tests/compatiblity_tests.py index 1c6f29d8..45ae6178 100644 --- a/tests/compatiblity_tests.py +++ b/tests/compatiblity_tests.py @@ -10,7 +10,6 @@ from amqpstorm import compatibility - logging.basicConfig(level=logging.DEBUG) diff --git a/tests/connection_tests.py b/tests/connection_tests.py index dcede023..fd9bbe35 100644 --- a/tests/connection_tests.py +++ b/tests/connection_tests.py @@ -16,6 +16,8 @@ from amqpstorm import Connection from amqpstorm.exception import * +from pamqp.body import ContentBody +from pamqp.specification import Basic as spec_basic logging.basicConfig(level=logging.DEBUG) @@ -57,22 +59,59 @@ def test_invalid_hostname(self): def test_invalid_username(self): self.assertRaises(AMQPInvalidArgument, Connection, '127.0.0.1', 2, 'guest', lazy=True) + self.assertRaises(AMQPInvalidArgument, Connection, '127.0.0.1', + None, 'guest', lazy=True) def test_invalid_password(self): self.assertRaises(AMQPInvalidArgument, Connection, '127.0.0.1', 'guest', 3, lazy=True) + self.assertRaises(AMQPInvalidArgument, Connection, '127.0.0.1', + 'guest', None, lazy=True) def test_invalid_virtual_host(self): self.assertRaises(AMQPInvalidArgument, Connection, '127.0.0.1', 'guest', 'guest', virtual_host=4, lazy=True) + self.assertRaises(AMQPInvalidArgument, Connection, '127.0.0.1', + 'guest', 'guest', virtual_host=None, lazy=True) + + def test_invalid_port(self): + self.assertRaises(AMQPInvalidArgument, Connection, '127.0.0.1', + 'guest', 'guest', port='', lazy=True) + self.assertRaises(AMQPInvalidArgument, Connection, '127.0.0.1', + 'guest', 'guest', port=None, lazy=True) def test_invalid_heartbeat(self): self.assertRaises(AMQPInvalidArgument, Connection, '127.0.0.1', 'guest', 'guest', heartbeat='5', lazy=True) + self.assertRaises(AMQPInvalidArgument, Connection, '127.0.0.1', + 'guest', 'guest', heartbeat=None, lazy=True) def test_invalid_timeout(self): self.assertRaises(AMQPInvalidArgument, Connection, '127.0.0.1', 'guest', 'guest', timeout='6', lazy=True) + self.assertRaises(AMQPInvalidArgument, Connection, '127.0.0.1', + 'guest', 'guest', timeout=None, lazy=True) + + def test_server_is_blocked_default_value(self): + connection = Connection('127.0.0.1', 'guest', 'guest', lazy=True) + self.assertEqual(connection.is_blocked, False) + + def test_server_properties_default_value(self): + connection = Connection('127.0.0.1', 'guest', 'guest', lazy=True) + self.assertEqual(connection.server_properties, {}) + + def test_fileno_property(self): + connection = Connection('127.0.0.1', 'guest', 'guest', lazy=True) + connection.set_state(connection.OPENING) + io = IO(connection.parameters) + io.socket = MagicMock(name='socket', spec=socket.socket) + connection.io = io + io.socket.fileno.return_value = 5 + self.assertEqual(connection.fileno, 5) + + def test_fileno_none_when_connection_closed(self): + connection = Connection('127.0.0.1', 'guest', 'guest', lazy=True) + self.assertIsNone(connection.fileno) def test_close_state(self): connection = Connection('127.0.0.1', 'guest', 'guest', lazy=True) @@ -84,6 +123,30 @@ def test_open_channel_on_closed_connection(self): connection = Connection('127.0.0.1', 'guest', 'guest', lazy=True) self.assertRaises(AMQPConnectionError, connection.channel) + def test_basic_read_buffer(self): + connection = Connection('127.0.0.1', 'guest', 'guest', lazy=True) + cancel_ok_frame = spec_basic.CancelOk().marshal() + + self.assertEqual(connection._read_buffer(cancel_ok_frame), b'\x00') + + def test_handle_read_buffer_none_returns_none(self): + connection = Connection('127.0.0.1', 'guest', 'guest', lazy=True) + self.assertIsNone(connection._read_buffer(None)) + + def test_basic_handle_amqp_frame(self): + connection = Connection('127.0.0.1', 'guest', 'guest', lazy=True) + cancel_ok_frame = spec_basic.CancelOk().marshal() + + self.assertEqual(connection._handle_amqp_frame(cancel_ok_frame), + (b'\x00', None, None)) + + def test_handle_amqp_frame_none_returns_none(self): + connection = Connection('127.0.0.1', 'guest', 'guest', lazy=True) + result = connection._handle_amqp_frame('') + self.assertEqual(result[0], '') + self.assertIsNone(result[1]) + self.assertIsNone(result[2]) + def test_wait_for_connection(self): connection = Connection('127.0.0.1', 'guest', 'guest', timeout=5, lazy=True) @@ -95,7 +158,7 @@ def test_wait_for_connection(self): def func(conn): conn.set_state(conn.OPEN) - threading.Timer(function=func, interval=1, args=(connection, )).start() + threading.Timer(function=func, interval=1, args=(connection,)).start() connection._wait_for_connection_to_open() def test_wait_for_connection_raises_on_timeout(self): diff --git a/tests/functional_tests.py b/tests/functional_tests.py index afa29cce..f9d07135 100644 --- a/tests/functional_tests.py +++ b/tests/functional_tests.py @@ -30,7 +30,6 @@ def setUp(self): self.connection = Connection(HOST, USERNAME, PASSWORD, lazy=True) def test_open_close_loop(self): - for _ in range(10): self.connection.open() self.channel = self.connection.channel() diff --git a/tests/heartbeat_tests.py b/tests/heartbeat_tests.py index 41ba8b3f..50abb1d4 100644 --- a/tests/heartbeat_tests.py +++ b/tests/heartbeat_tests.py @@ -9,12 +9,12 @@ import unittest from amqpstorm.heartbeat import Heartbeat +from amqpstorm.exception import AMQPConnectionError logging.basicConfig(level=logging.DEBUG) class HeartbeatTests(unittest.TestCase): - def test_heartbeat_start(self): heartbeat = Heartbeat(1) heartbeat.start([]) @@ -48,3 +48,13 @@ def test_basic_raise_on_missed_heartbeats(self): heartbeat.start(exceptions) time.sleep(3) self.assertGreater(len(exceptions), 0) + + def test_basic_raise_when_check_for_life_when_exceptions_not_set(self): + heartbeat = Heartbeat(0.5) + heartbeat._beats_since_check = 0 + heartbeat._last_heartbeat = time.time() - 100 + + # Normally the exception should be passed down to the list of + # exceptions in the connection, but if that list for some obscure + # reason is None, we should raise directly in _check_for_life_signs. + self.assertRaises(AMQPConnectionError, heartbeat._check_for_life_signs)