コード例 #1
0
 def test_ack_basic(self):
     """ Test reliable client (ACK) behavior. """
     
     dest = '/queue/dest'
     conn1 = MockConnection()
     conn1.reliable_subscriber = True
     
     self.qm.subscribe(conn1, dest)
     
     m1 = StompFrame('MESSAGE', headers={'destination': dest}, body='Message body (1)')
     self.qm.send(m1)
     
     assert conn1.frames[0] == m1
     
     m2 = StompFrame('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 = StompFrame('ACK', headers={'destination': dest, 'message-id': m1.message_id})
     self.qm.ack(conn1, ack)
     
     print conn1.frames
     assert len(conn1.frames) == 2, "Expected 2 frames now, after ACK."
     assert conn1.frames[1] == m2
コード例 #2
0
 def test_ack_transaction(self):
     """ Test the reliable client (ACK) behavior with transactions. """
             
     dest = '/queue/dest'
     conn1 = MockConnection()
     conn1.reliable_subscriber = True
     
     self.qm.subscribe(conn1, dest)
     
     m1 = StompFrame('MESSAGE', headers={'destination': dest, }, body='Message body (1)')
     self.qm.send(m1)
     
     assert conn1.frames[0] == m1
     
     m2 = StompFrame('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 = StompFrame('ACK', headers={'destination': dest, 'transaction': 'abc', 'message-id': m1.message_id})
     self.qm.ack(conn1, ack, transaction='abc')
     
     ack = StompFrame('ACK', headers={'destination': dest, 'transaction': 'abc', 'message-id': m2.message_id})
     self.qm.ack(conn1, ack, transaction='abc')
     
     assert len(conn1.frames) == 2, "Expected 2 frames now, after ACK."
     assert conn1.frames[1] == m2
     
     self.qm.resend_transaction_frames(conn1, transaction='abc')
     
     assert len(conn1.frames) == 3, "Expected 3 frames after re-transmit."
     assert bool(self.qm._pending[conn1]) == True, "Expected 1 pending (waiting on ACK) frame.""" 
     
コード例 #3
0
    def test_ack_basic(self):
        """ Test reliable client (ACK) behavior. """

        dest = '/queue/dest'
        conn1 = MockConnection()
        conn1.reliable_subscriber = True

        self.qm.subscribe(conn1, dest)

        m1 = StompFrame('MESSAGE',
                        headers={'destination': dest},
                        body='Message body (1)')
        self.qm.send(m1)

        assert conn1.frames[0] == m1

        m2 = StompFrame('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 = StompFrame('ACK',
                         headers={
                             'destination': dest,
                             'message-id': m1.message_id
                         })
        self.qm.ack(conn1, ack)

        print conn1.frames
        assert len(conn1.frames) == 2, "Expected 2 frames now, after ACK."
        assert conn1.frames[1] == m2
コード例 #4
0
ファイル: test_queue.py プロジェクト: LucaLanziani/coilmq
 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('MESSAGE', headers={'destination': dest, }, body='Message body (1)')
     self.qm.send(m1)
     
     assert conn1.frames[0] == m1
     
     m2 = Frame('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('ACK', headers={'destination': dest, 'transaction': 'abc', 'message-id': m1.message_id})
     self.qm.ack(conn1, ack, transaction='abc')
     
     ack = Frame('ACK', headers={'destination': dest, 'transaction': 'abc', 'message-id': m2.message_id})
     self.qm.ack(conn1, ack, transaction='abc')
     
     assert len(conn1.frames) == 2, "Expected 2 frames now, after ACK."
     assert conn1.frames[1] == m2
     
     self.qm.resend_transaction_frames(conn1, transaction='abc')
     
     assert len(conn1.frames) == 3, "Expected 3 frames after re-transmit."
     assert bool(self.qm._pending[conn1]) == True, "Expected 1 pending (waiting on ACK) frame.""" 
コード例 #5
0
 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 = StompFrame('MESSAGE', headers={'destination': dest, 'message-id': uuid.uuid4()}, body='Empty')
     self.qm.send(f)
         
     print conn1.frames
     print conn2.frames
     assert len(conn1.frames) == 1
     assert len(conn2.frames) == 0
コード例 #6
0
ファイル: test_engine.py プロジェクト: LucaLanziani/coilmq
 def setUp(self):
     self.qm = MockQueueManager()
     self.tm = MockTopicManager()
     self.conn = MockConnection()
     self.auth = MockAuthenticator()
     self.engine = StompEngine(connection=self.conn,
                               queue_manager=self.qm,
                               topic_manager=self.tm,
                               authenticator=None)
コード例 #7
0
ファイル: test_scheduler.py プロジェクト: LucaLanziani/coilmq
 def test_favorReliable(self):
     """ Test the favor reliable delivery scheduler. """
     
     sched = FavorReliableSubscriberScheduler()
     
     conn1 = MockConnection()
     conn1.reliable_subscriber = True
     
     conn2 = MockConnection()
     conn2.reliable_subscriber = False
     
     choice = sched.choice((conn1, conn2), None)
     
     assert choice is conn1, "Expected reliable connection to be selected."
コード例 #8
0
ファイル: test_queue.py プロジェクト: LucaLanziani/coilmq
 def test_clear_transaction_frames(self):
     """ Test the clearing of transaction ACK frames. """
     dest = '/queue/tx'
     
     f = Frame('SEND', headers={'destination': dest, 'transaction': '1'}, body='Body-A')
     self.qm.send(f)
     
     print self.store.destinations()
     assert dest in self.store.destinations()
     
     conn1 = MockConnection()
     conn1.reliable_subscriber = True
     self.qm.subscribe(conn1, dest)
     
     assert len(conn1.frames) == 1
     
     self.qm.clear_transaction_frames(conn1, '1')
コード例 #9
0
ファイル: test_engine.py プロジェクト: LucaLanziani/coilmq
 def setUp(self):
     self.qm = MockQueueManager()
     self.tm = MockTopicManager()
     self.conn = MockConnection()
     self.auth = MockAuthenticator()
     self.engine = StompEngine(connection=self.conn,
                               queue_manager=self.qm,
                               topic_manager=self.tm,
                               authenticator=None)
コード例 #10
0
ファイル: test_queue.py プロジェクト: LucaLanziani/coilmq
 def test_disconnect_pending_frames(self):
     """ Test a queue disconnect when there are pending frames. """
     
     dest = '/queue/disconnect-pending-frames'
     conn1 = MockConnection()
     conn1.reliable_subscriber = True
     
     self.qm.subscribe(conn1, dest)
     
     m1 = Frame('MESSAGE', headers={'destination': dest}, body='Message body (1)')
     self.qm.send(m1)
     
     assert conn1.frames[0] == m1
     
     self.qm.disconnect(conn1)
     
     # Now we need to ensure that the frame we sent is re-queued.
     assert len(self.store.frames(dest)) == 1
コード例 #11
0
    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 = StompFrame('MESSAGE',
                       headers={
                           'destination': dest,
                           'message-id': uuid.uuid4()
                       },
                       body='Empty')
        self.qm.send(f)

        print conn1.frames
        print conn2.frames
        assert len(conn1.frames) == 1
        assert len(conn2.frames) == 0
コード例 #12
0
ファイル: test_scheduler.py プロジェクト: khoanx/vmcontroller
    def test_favorReliable(self):
        """ Test the favor reliable delivery scheduler. """

        sched = FavorReliableSubscriberScheduler()

        conn1 = MockConnection()
        conn1.reliable_subscriber = True

        conn2 = MockConnection()
        conn2.reliable_subscriber = False

        choice = sched.choice((conn1, conn2), None)

        assert choice is conn1, "Expected reliable connection to be selected."
コード例 #13
0
 def setUp(self):
     self.tm = TopicManager()
     self.conn = MockConnection()
コード例 #14
0
 def setUp(self):
     self.store = MemoryQueue()
     self.qm = QueueManager(self.store)
     self.conn = MockConnection()
コード例 #15
0
ファイル: test_engine.py プロジェクト: LucaLanziani/coilmq
class EngineTest(unittest.TestCase):
    
    def setUp(self):
        self.qm = MockQueueManager()
        self.tm = MockTopicManager()
        self.conn = MockConnection()
        self.auth = MockAuthenticator()
        self.engine = StompEngine(connection=self.conn,
                                  queue_manager=self.qm,
                                  topic_manager=self.tm,
                                  authenticator=None)
    def tearDown(self):
        self.conn.reset()
    
    def _connect(self):
        """ Call the engine connect() method so that we have a valid 'session'. """
        self.engine.connect(Frame('CONNECT'))
    
    def assertErrorFrame(self, frame, msgsub):
        """ Assert that the passed in frame is an error frame and that message contains specified
        string.
        """
        assert frame.command == 'ERROR'
        assert msgsub.lower() in frame.headers['message'].lower()
        
    def test_connect_no_auth(self):
        """ Test the CONNECT command with no auth required. """
        
        assert self.engine.connected == False
        self.engine.process_frame(Frame('CONNECT'))
        assert self.engine.connected == True
        
    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_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_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)        
        assert msg == self.qm.messages[-1]
        
        msg = Frame('SEND', headers={'destination': '/topic/foo'}, body='TOPICMSG-BODY')
        self.engine.process_frame(msg)
        assert 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 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]
        assert isinstance(rframe, ReceiptFrame)
        assert receipt_id == rframe.receipt_id
        
        receipt_id = 'FOOBAR2'
        self.engine.process_frame(Frame('SUBSCRIBE', headers={'destination': '/queue/bar', 'receipt': receipt_id}))
        rframe = self.conn.frames[-1]
        assert isinstance(rframe, ReceiptFrame)
        assert receipt_id == rframe.receipt_id
    
    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_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']
        
        print self.conn.frames
        
        self.engine.process_frame(Frame('UNSUBSCRIBE', headers={'destination': '/queue/bar'}))
        assert self.conn not in self.qm.queues['/queue/bar']
        
        print self.conn.frames
        
        self.engine.process_frame(Frame('UNSUBSCRIBE', headers={'destination': '/invalid'}))
        print self.conn.frames[-1]
    
    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_commit(self):
        """ Test transaction COMMIT. """
        self._connect()
         
        self.engine.process_frame(Frame('BEGIN', headers={'transaction': 'abc'}))
        self.engine.process_frame(Frame('BEGIN', headers={'transaction': '123'}))
        self.engine.process_frame(Frame('SEND', headers={'destination': '/dest', 'transaction': 'abc'}, body='ASDF'))
        self.engine.process_frame(Frame('SEND', headers={'destination': '/dest', 'transaction': 'abc'}, body='ASDF'))
        self.engine.process_frame(Frame('SEND', headers={'destination': '/dest', 'transaction': '123'}, body='ASDF'))
        
        assert len(self.tm.messages) == 0
        
        self.engine.process_frame(Frame('COMMIT', headers={'transaction': 'abc'}))
        
        print self.conn.frames
        
        assert len(self.tm.messages) == 2
        
        assert len(self.engine.transactions) == 1
        
        self.engine.process_frame(Frame('COMMIT', headers={'transaction': '123'}))
        assert len(self.tm.messages) == 3
        
        assert len(self.engine.transactions) == 0
        
    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 test_abort(self):
        """ Test transaction ABORT. """
        self._connect()
         
        self.engine.process_frame(Frame('BEGIN', headers={'transaction': 'abc'}))
        self.engine.process_frame(Frame('BEGIN', headers={'transaction': '123'}))
        
        f1 = Frame('SEND', headers={'destination': '/dest', 'transaction': 'abc'}, body='ASDF')
        self.engine.process_frame(f1)
        f2 = Frame('SEND', headers={'destination': '/dest', 'transaction': 'abc'}, body='ASDF')
        self.engine.process_frame(f2)
        f3 = Frame('SEND', headers={'destination': '/dest', 'transaction': '123'}, body='ASDF')
        self.engine.process_frame(f3)
        
        assert len(self.tm.messages) == 0
        
        self.engine.process_frame(Frame('ABORT', headers={'transaction': 'abc'}))
        assert len(self.tm.messages) == 0
        
        assert len(self.engine.transactions) == 1
        
    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')
        
コード例 #16
0
ファイル: test_queue.py プロジェクト: LucaLanziani/coilmq
 def setUp(self):
     self.store = self._queuestore()
     self.qm = QueueManager(self.store)
     self.conn = MockConnection()
コード例 #17
0
ファイル: test_engine.py プロジェクト: LucaLanziani/coilmq
class EngineTest(unittest.TestCase):
    def setUp(self):
        self.qm = MockQueueManager()
        self.tm = MockTopicManager()
        self.conn = MockConnection()
        self.auth = MockAuthenticator()
        self.engine = StompEngine(connection=self.conn,
                                  queue_manager=self.qm,
                                  topic_manager=self.tm,
                                  authenticator=None)

    def tearDown(self):
        self.conn.reset()

    def _connect(self):
        """ Call the engine connect() method so that we have a valid 'session'. """
        self.engine.connect(Frame('CONNECT'))

    def assertErrorFrame(self, frame, msgsub):
        """ Assert that the passed in frame is an error frame and that message contains specified
        string.
        """
        assert frame.command == 'ERROR'
        assert msgsub.lower() in frame.headers['message'].lower()

    def test_connect_no_auth(self):
        """ Test the CONNECT command with no auth required. """

        assert self.engine.connected == False
        self.engine.process_frame(Frame('CONNECT'))
        assert self.engine.connected == True

    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_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_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)
        assert msg == self.qm.messages[-1]

        msg = Frame('SEND',
                    headers={'destination': '/topic/foo'},
                    body='TOPICMSG-BODY')
        self.engine.process_frame(msg)
        assert 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 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]
        assert isinstance(rframe, ReceiptFrame)
        assert receipt_id == rframe.receipt_id

        receipt_id = 'FOOBAR2'
        self.engine.process_frame(
            Frame('SUBSCRIBE',
                  headers={
                      'destination': '/queue/bar',
                      'receipt': receipt_id
                  }))
        rframe = self.conn.frames[-1]
        assert isinstance(rframe, ReceiptFrame)
        assert receipt_id == rframe.receipt_id

    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_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']

        print self.conn.frames

        self.engine.process_frame(
            Frame('UNSUBSCRIBE', headers={'destination': '/queue/bar'}))
        assert self.conn not in self.qm.queues['/queue/bar']

        print self.conn.frames

        self.engine.process_frame(
            Frame('UNSUBSCRIBE', headers={'destination': '/invalid'}))
        print self.conn.frames[-1]

    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_commit(self):
        """ Test transaction COMMIT. """
        self._connect()

        self.engine.process_frame(
            Frame('BEGIN', headers={'transaction': 'abc'}))
        self.engine.process_frame(
            Frame('BEGIN', headers={'transaction': '123'}))
        self.engine.process_frame(
            Frame('SEND',
                  headers={
                      'destination': '/dest',
                      'transaction': 'abc'
                  },
                  body='ASDF'))
        self.engine.process_frame(
            Frame('SEND',
                  headers={
                      'destination': '/dest',
                      'transaction': 'abc'
                  },
                  body='ASDF'))
        self.engine.process_frame(
            Frame('SEND',
                  headers={
                      'destination': '/dest',
                      'transaction': '123'
                  },
                  body='ASDF'))

        assert len(self.tm.messages) == 0

        self.engine.process_frame(
            Frame('COMMIT', headers={'transaction': 'abc'}))

        print self.conn.frames

        assert len(self.tm.messages) == 2

        assert len(self.engine.transactions) == 1

        self.engine.process_frame(
            Frame('COMMIT', headers={'transaction': '123'}))
        assert len(self.tm.messages) == 3

        assert len(self.engine.transactions) == 0

    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 test_abort(self):
        """ Test transaction ABORT. """
        self._connect()

        self.engine.process_frame(
            Frame('BEGIN', headers={'transaction': 'abc'}))
        self.engine.process_frame(
            Frame('BEGIN', headers={'transaction': '123'}))

        f1 = Frame('SEND',
                   headers={
                       'destination': '/dest',
                       'transaction': 'abc'
                   },
                   body='ASDF')
        self.engine.process_frame(f1)
        f2 = Frame('SEND',
                   headers={
                       'destination': '/dest',
                       'transaction': 'abc'
                   },
                   body='ASDF')
        self.engine.process_frame(f2)
        f3 = Frame('SEND',
                   headers={
                       'destination': '/dest',
                       'transaction': '123'
                   },
                   body='ASDF')
        self.engine.process_frame(f3)

        assert len(self.tm.messages) == 0

        self.engine.process_frame(
            Frame('ABORT', headers={'transaction': 'abc'}))
        assert len(self.tm.messages) == 0

        assert len(self.engine.transactions) == 1

    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')