def test_nack_invalid_frame(self): self.engine.connected = True self.engine.process_frame(Frame(frames.NACK, headers={'subscription': 'foo'})) self.assertIsInstance(self.conn.frames[-1], ErrorFrame) self.engine.process_frame(Frame(frames.NACK, headers={'message-id': 1})) self.assertIsInstance(self.conn.frames[-1], ErrorFrame)
def test_ack_basic(self): """ Test reliable client (ACK) behavior. """ dest = '/queue/ack-basic' conn1 = MockConnection() conn1.reliable_subscriber = True self.qm.subscribe(conn1, dest) m1 = Frame(frames.MESSAGE, headers={'destination': dest}, body='Message body (1)') self.qm.send(m1) self.assertEqual(conn1.frames[0], m1) m2 = Frame(frames.MESSAGE, headers={'destination': dest}, body='Message body (2)') self.qm.send(m2) self.assertEqual(len(conn1.frames), 1) self.assertEqual(conn1.frames[0], m1) ack = Frame(frames.ACK, headers={ 'destination': dest, 'message-id': m1.headers['message-id'] }) self.qm.ack(conn1, ack) self.assertEqual(len(conn1.frames), 2, "Expected 2 frames now, after ACK.") self.assertEqual(conn1.frames[1], m2)
def test_send_backlog_err_unreliable(self): """ Test errors when sending backlog to reliable subscriber. """ class ExcThrowingConn(object): reliable_subscriber = False def send_frame(self, frame): raise RuntimeError("Error sending data.") dest = '/queue/dest' f = Frame(frames.SEND, headers={'destination': dest}, body='123') self.qm.send(f) f2 = Frame(frames.SEND, headers={'destination': dest}, body='12345') self.qm.send(f2) conn = ExcThrowingConn() try: self.qm.subscribe(conn, dest) self.fail("Expected error when sending backlog.") except RuntimeError: pass # The message will have been requeued at this point, so add a valid # subscriber self.qm.subscribe(self.conn, dest) self.assertEqual(len(self.conn.frames), 2, "Expected frame to be delivered") self.assertListEqual(list(self.conn.frames), [f2, f])
def test_receipt(self): """ Test pushing frames with a receipt specified. """ self._connect() receipt_id = 'FOOBAR' msg = Frame('SEND', headers={ 'destination': '/queue/foo', 'receipt': receipt_id }, body='QUEUEMSG-BODY') self.engine.process_frame(msg) rframe = self.conn.frames[-1] self.assertIsInstance(rframe, ReceiptFrame) self.assertEqual(receipt_id, rframe.headers.get('receipt-id')) receipt_id = 'FOOBAR2' self.engine.process_frame( Frame('SUBSCRIBE', headers={ 'destination': '/queue/bar', 'receipt': receipt_id })) rframe = self.conn.frames[-1] self.assertIsInstance(rframe, ReceiptFrame) self.assertEqual(receipt_id, rframe.headers.get('receipt-id'))
def test_dequeue_specific(self): """ Test that we only dequeue from the correct queue. """ dest = '/queue/foo' notdest = '/queue/other' frame1 = Frame('MESSAGE', headers={ 'message-id': str(uuid.uuid4())}, body='message-1') self.store.enqueue(dest, frame1) frame2 = Frame('MESSAGE', headers={ 'message-id': str(uuid.uuid4())}, body='message-2') self.store.enqueue(notdest, frame2) frame3 = Frame('MESSAGE', headers={ 'message-id': str(uuid.uuid4())}, body='message-3') self.store.enqueue(dest, frame3) self.assertTrue(self.store.has_frames(dest)) self.assertEqual(self.store.size(dest), 2) rframe1 = self.store.dequeue(dest) self.assertEqual(frame1, rframe1) rframe2 = self.store.dequeue(dest) self.assertEqual(frame3, rframe2) self.assertFalse(self.store.has_frames(dest)) self.assertEqual(self.store.size(dest), 0)
def test_dequeue_order(self): """ Test the order that frames are returned by dequeue() method. """ dest = '/queue/foo' frame1 = Frame('MESSAGE', headers={ 'message-id': str(uuid.uuid4())}, body='message-1') self.store.enqueue(dest, frame1) frame2 = Frame('MESSAGE', headers={ 'message-id': str(uuid.uuid4())}, body='message-2') self.store.enqueue(dest, frame2) frame3 = Frame('MESSAGE', headers={ 'message-id': str(uuid.uuid4())}, body='message-3') self.store.enqueue(dest, frame3) self.assertTrue(self.store.has_frames(dest)) self.assertEqual(self.store.size(dest), 3) rframe1 = self.store.dequeue(dest) self.assertEqual(frame1, rframe1) rframe2 = self.store.dequeue(dest) self.assertEqual(frame2, rframe2) rframe3 = self.store.dequeue(dest) self.assertEqual(frame3, rframe3) self.assertFalse(self.store.has_frames(dest)) self.assertEqual(self.store.size(dest), 0)
def test_sync_checkpoint_timeout(self): """ Test a expected sync behavior with checkpoint_timeout param. """ data_dir = tempfile.mkdtemp(prefix='coilmq-dbm-test') try: store = DbmQueue(data_dir, checkpoint_timeout=0.5) dest = '/queue/foo' frame = Frame('MESSAGE', headers={'message-id': str(uuid.uuid4())}, body='some data -1') store.enqueue(dest, frame) time.sleep(0.5) frame = Frame('MESSAGE', headers={'message-id': str(uuid.uuid4())}, body='some data -2') store.enqueue(dest, frame) self.assertEqual(store.size(dest), 2) # No close()! store2 = DbmQueue(data_dir) self.assertEqual(store2.size(dest), 2) except: shutil.rmtree(data_dir, ignore_errors=True) raise
def test_subscribe_noack(self): """ Test subscribing to topics and queues w/ no ACK. """ self._connect() self.engine.process_frame( Frame('SUBSCRIBE', headers={'destination': '/queue/bar'})) assert self.conn in self.qm.queues['/queue/bar'] self.engine.process_frame( Frame('SUBSCRIBE', headers={'destination': '/foo/bar'})) assert self.conn in self.tm.topics['/foo/bar']
def test_ack_transaction(self): """ Test the reliable client (ACK) behavior with transactions. """ dest = '/queue/ack-transaction' conn1 = MockConnection() conn1.reliable_subscriber = True self.qm.subscribe(conn1, dest) m1 = Frame(frames.MESSAGE, headers={ 'destination': dest, }, body='Message body (1)') self.qm.send(m1) assert conn1.frames[0] == m1 m2 = Frame(frames.MESSAGE, headers={'destination': dest}, body='Message body (2)') self.qm.send(m2) assert len(conn1.frames ) == 1, "Expected connection to still only have 1 frame." assert conn1.frames[0] == m1 ack = Frame(frames.ACK, headers={ 'destination': dest, 'transaction': 'abc', 'message-id': m1.headers.get('message-id') }) self.qm.ack(conn1, ack, transaction='abc') ack = Frame(frames.ACK, headers={ 'destination': dest, 'transaction': 'abc', 'message-id': m2.headers.get('message-id') }) self.qm.ack(conn1, ack, transaction='abc') self.assertEqual(len(conn1.frames), 2, "Expected 2 frames now, after ACK.") self.assertEqual(conn1.frames[1], m2) self.qm.resend_transaction_frames(conn1, transaction='abc') self.assertEqual(len(conn1.frames), 3, "Expected 3 frames after re-transmit.") self.assertTrue(self.qm._pending[conn1], "Expected 1 pending (waiting on ACK) frame." "")
def test_unsubscribe(self): """ Test the UNSUBSCRIBE command. """ self._connect() self.engine.process_frame( Frame('SUBSCRIBE', headers={'destination': '/queue/bar'})) assert self.conn in self.qm.queues['/queue/bar'] self.engine.process_frame( Frame('UNSUBSCRIBE', headers={'destination': '/queue/bar'})) assert self.conn not in self.qm.queues['/queue/bar'] self.engine.process_frame( Frame('UNSUBSCRIBE', headers={'destination': '/invalid'}))
def test_send_reliableFirst(self): """ Test that messages are prioritized to reliable subscribers. This is actually a test of the underlying scheduler more than it is a test of the send message, per se. """ dest = '/queue/dest' conn1 = MockConnection() conn1.reliable_subscriber = True self.qm.subscribe(conn1, dest) conn2 = MockConnection() conn2.reliable_subscriber = False self.qm.subscribe(conn2, dest) f = Frame(frames.MESSAGE, headers={ 'destination': dest, 'message-id': uuid.uuid4() }, body='Empty') self.qm.send(f) self.assertEqual(len(conn1.frames), 1) self.assertEqual(len(conn2.frames), 0)
def test_no_heartbeat_from_client(self): with self.with_heartbeat(STOMP11(self.engine, receive_heartbeat_interval=50)): self.engine.process_frame(Frame(frames.CONNECT, headers={'heart-beat': '50,50', 'accept-version': '1.1'})) self.assertTrue(self.engine.connected) self.assertTrue(self.engine.protocol.timer._running) time.sleep(0.53) self.assertFalse(self.engine.connected)
def test_send_subscriber_timeout(self): """ Test a send command when one subscriber errs out. """ class TimeoutConnection(object): reliable_subscriber = False def send_frame(self, frame): raise socket.timeout("timed out") def reset(self): pass dest = '/topic/dest' bad_client = TimeoutConnection() # Subscribe both a good client and a bad client. self.tm.subscribe(bad_client, dest) self.tm.subscribe(self.conn, dest) f = Frame('message', headers={'destination': dest}, body='Empty') self.tm.send(f) # Make sure out good client got the message. self.assertEqual(len(self.conn.frames), 1) self.assertEqual(self.conn.frames[0], f) # Make sure our bad client got disconnected # (This might be a bit too intimate.) self.assertNotIn(bad_client, self.tm._topics[dest])
def test_unsubscribe(self): """ Test unsubscribing a connection from the queue. """ dest = '/topic/dest' self.tm.subscribe(self.conn, dest) f = Frame(frames.MESSAGE, headers={'destination': dest}, body='Empty') self.tm.send(f) self.assertEqual(len(self.conn.frames), 1) self.assertEqual(self.conn.frames[0], f) self.tm.unsubscribe(self.conn, dest) f = Frame(frames.MESSAGE, headers={'destination': dest}, body='Empty') self.tm.send(f) self.assertEqual(len(self.conn.frames), 1)
def test_connect_auth(self): """ Test the CONNECT command when auth is required. """ self.engine.authenticator = self.auth assert self.engine.connected == False self.engine.process_frame(Frame('CONNECT')) self.assertErrorFrame(self.conn.frames[-1], 'Auth') assert self.engine.connected == False self.engine.process_frame( Frame('CONNECT', headers={ 'login': MockAuthenticator.LOGIN, 'passcode': MockAuthenticator.PASSCODE })) assert self.engine.connected == True
def test_sync_checkpoint_ops(self): """ Test a expected sync behavior with checkpoint_operations param. """ data_dir = tempfile.mkdtemp(prefix='coilmq-dbm-test') max_ops = 5 try: store = DbmQueue(data_dir, checkpoint_operations=max_ops) dest = '/queue/foo' for i in range(max_ops + 1): frame = Frame('MESSAGE', headers={'message-id': str(uuid.uuid4())}, body='some data - %d' % i) store.enqueue(dest, frame) self.assertEqual(store.size(dest), max_ops + 1) # No close()! store2 = DbmQueue(data_dir) self.assertEqual(store2.size(dest), max_ops + 1) except: shutil.rmtree(data_dir, ignore_errors=True) raise
def test_dequeue_order(self): """ Test the order that frames are returned by dequeue() method. """ dest = '/queue/foo' frame1 = Frame('MESSAGE', headers={'message-id': 'id-1'}, body='message-1') self.store.enqueue(dest, frame1) frame2 = Frame('MESSAGE', headers={'message-id': 'id-2'}, body='message-2') self.store.enqueue(dest, frame2) frame3 = Frame('MESSAGE', headers={'message-id': 'id-3'}, body='message-3') self.store.enqueue(dest, frame3) self.assertTrue(self.store.has_frames(dest)) self.assertEqual(self.store.size(dest), 3) # Perform some updates to change the expected order. sess = meta.Session() sess.execute(model.frames_table.update().where( model.frames_table.c.message_id == 'id-1').values( queued=datetime.datetime(2010, 1, 1))) sess.execute(model.frames_table.update().where( model.frames_table.c.message_id == 'id-2').values( queued=datetime.datetime(2009, 1, 1))) sess.execute(model.frames_table.update().where( model.frames_table.c.message_id == 'id-3').values( queued=datetime.datetime(2004, 1, 1))) sess.commit() rframe1 = self.store.dequeue(dest) assert frame3 == rframe1 rframe2 = self.store.dequeue(dest) assert frame2 == rframe2 rframe3 = self.store.dequeue(dest) assert frame1 == rframe3 assert self.store.has_frames(dest) == False assert self.store.size(dest) == 0
def connect(self, frame, response=None): connected_frame = Frame(frames.CONNECTED) self._negotiate_protocol(frame, connected_frame) heart_beat = frame.headers.get('heart-beat', '0,0') if heart_beat: self.enable_heartbeat(*map(int, heart_beat.split(',')), response=connected_frame) super(STOMP11, self).connect(frame, response=connected_frame)
def test_abort_invalid(self): """ Test invalid states for transaction ABORT. """ self._connect() self.engine.process_frame( Frame('ABORT', headers={'transaction': 'abc'})) self.assertErrorFrame(self.conn.frames[-1], 'invalid transaction') self.engine.process_frame( Frame('BEGIN', headers={'transaction': 'abc'})) self.engine.process_frame( Frame('ABORT', headers={'transaction': 'abc'})) self.engine.process_frame( Frame('ABORT', headers={'transaction': 'abc2'})) self.assertErrorFrame(self.conn.frames[-1], 'invalid transaction')
def test_begin(self): """ Test transaction BEGIN. """ self._connect() self.engine.process_frame( Frame('BEGIN', headers={'transaction': 'abc'})) assert 'abc' in self.engine.transactions assert len(self.engine.transactions['abc']) == 0
def test_enqueue(self): """ Test the enqueue() method. """ dest = '/queue/foo' frame = Frame('MESSAGE', headers={ 'message-id': str(uuid.uuid4())}, body='some data') self.store.enqueue(dest, frame) self.assertTrue(self.store.has_frames(dest)) self.assertEqual(self.store.size(dest), 1)
def test_send_simple(self): """ Test a basic send command. """ dest = '/topic/dest' f = Frame(frames.SEND, headers={'destination': dest}, body='Empty') self.tm.send(f) # Assert some side-effects self.assertIn('message-id', f.headers) self.assertEqual(f.cmd, 'message')
def test_send(self): """ Test sending to a topic and queue. """ self._connect() msg = Frame('SEND', headers={'destination': '/queue/foo'}, body='QUEUEMSG-BODY') self.engine.process_frame(msg) self.assertEqual(msg, self.qm.messages[-1]) msg = Frame('SEND', headers={'destination': '/topic/foo'}, body='TOPICMSG-BODY') self.engine.process_frame(msg) self.assertEqual(msg, self.tm.messages[-1]) msg = Frame('SEND', headers={}, body='TOPICMSG-BODY') self.engine.process_frame(msg) self.assertErrorFrame(self.conn.frames[-1], 'Missing destination')
def send(self, destination, message, set_content_length=True, extra_headers=None): headers = extra_headers or {} headers['destination'] = destination if set_content_length: headers['content-length'] = len(message) self.send_frame(Frame('send', headers=headers, body=message))
def test_subscribe_ack(self): """ Test subscribing to a queue with ack=true """ self._connect() self.engine.process_frame( Frame('SUBSCRIBE', headers={ 'destination': '/queue/bar', 'ack': 'client' })) assert self.conn.reliable_subscriber == True assert self.conn in self.qm.queues['/queue/bar']
def test_commit_invalid(self): """ Test invalid states for transaction COMMIT. """ self._connect() # Send a message with invalid transaction f = Frame('SEND', headers={ 'destination': '/dest', 'transaction': '123' }, body='ASDF') self.engine.process_frame(f) self.assertErrorFrame(self.conn.frames[-1], 'invalid transaction') # Attempt to commit invalid transaction self.engine.process_frame( Frame('COMMIT', headers={'transaction': 'abc'})) # Attempt to commit already-committed transaction self.engine.process_frame( Frame('BEGIN', headers={'transaction': 'abc'})) self.engine.process_frame( Frame('SEND', headers={ 'destination': '/dest', 'transaction': 'abc' }, body='FOO')) self.engine.process_frame( Frame('COMMIT', headers={'transaction': 'abc'})) self.engine.process_frame( Frame('COMMIT', headers={'transaction': 'abc'})) self.assertErrorFrame(self.conn.frames[-1], 'invalid transaction')
def send_simple(self): """ Test a basic send command. """ dest = '/queue/dest' f = Frame(frames.SEND, headers={'destination': dest}, body='Empty') self.qm.send(f) self.assertIn(dest, self.store.destinations()) self.assertEqua(len(self.store.frames(dest)), 1) # Assert some side-effects self.assertIn('message-id', f.headers) self.assertEqual(f.command, frames.MESSAGE)
def test_dequeue_identity(self): """ Test the dequeue() method. """ dest = '/queue/foo' frame = Frame('MESSAGE', headers={'message-id': str(uuid.uuid4())}, body='some data') self.store.enqueue(dest, frame) self.assertTrue(self.store.has_frames(dest)) self.assertEqual(self.store.size(dest), 1) rframe = self.store.dequeue(dest) self.assertEqual(frame, rframe) self.assertIsNot(frame, rframe) self.assertFalse(self.store.has_frames(dest)) self.assertEqual(self.store.size(dest), 0)
def test_dequeue(self): """ Test the dequeue() method. """ dest = '/queue/foo' frame = Frame('MESSAGE', headers={ 'message-id': str(uuid.uuid4())}, body='some data') self.store.enqueue(dest, frame) self.assertTrue(self.store.has_frames(dest)) self.assertEqual(self.store.size(dest), 1) rframe = self.store.dequeue(dest) self.assertEqual(frame, rframe) # We cannot generically assert whether or not frame and rframe are # the *same* object. self.assertFalse(self.store.has_frames(dest)) self.assertEqual(self.store.size(dest), 0)
def test_sync_loss(self): """ Test metadata loss behavior. """ data_dir = tempfile.mkdtemp(prefix='coilmq-dbm-test') try: store = DbmQueue(data_dir) dest = '/queue/foo' frame = Frame('MESSAGE', headers={'message-id': str(uuid.uuid4())}, body='some data') store.enqueue(dest, frame) self.assertEqual(store.size(dest), 1) store2 = DbmQueue(data_dir) self.assertEqual(store2.size(dest), 0) except: shutil.rmtree(data_dir, ignore_errors=True) raise
def test_pack_binary(self): bin_body = "\x00\x00HELLO\x00\x00DONKEY\x00\x00" frame = Frame(frames.CONNECT, body=bin_body) self.assertEqual(frame.pack( ), b'CONNECT\ncontent-length:17\n\n\x00\x00HELLO\x00\x00DONKEY\x00\x00\x00')
def test_pack(self): frame = Frame(frames.CONNECT, OrderedDict(foo='bar'), 'body') self.assertEqual( frame.pack(), b'CONNECT\nfoo:bar\ncontent-length:4\n\nbody\x00')
def test_parse_frame_empty_body(self): buff = io.BytesIO( b'SUBSCRIBE\nack:auto\ndestination:/queue/test\n\n\x00fdffdfd') f = Frame.from_buffer(buff)
def test_parse_frame_body_not_terminated(self): buff = io.BytesIO(b'CONNECT\ncontent-length:10\n\n0123456789') self.assertRaises(BodyNotTerminated, lambda: Frame.from_buffer(buff))
def test_parse_frame_incomplete_body(self): buff = io.BytesIO(b'CONNECT\ncontent-length:1000\n\n0123456789\x00') self.assertRaises(IncompleteFrame, lambda: Frame.from_buffer(buff))