def _test_nack(self, version):
        if version not in commands.versions(VERSION):
            print 'Skipping test case (version %s is not configured)' % VERSION
            defer.returnValue(None)

        config = self.getConfig(version)
        client = async.Stomp(config)
        try:
            client = yield client.connect(host=VIRTUALHOST, versions=[version])

        except StompProtocolError as e:
            print 'Broker does not support STOMP protocol %s. Skipping this test case. [%s]' % (version, e)
            defer.returnValue(None)

        client.subscribe(self.queue, {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL, StompSpec.ID_HEADER: '4711'}, listener=SubscriptionListener(self._nackFrame, ack=False))
        client.send(self.queue, self.frame)
        while not self.framesHandled:
            yield task.deferLater(reactor, 0.01, lambda: None)

        client.disconnect()
        yield client.disconnected

        if BROKER == 'activemq':
            print 'Broker %s by default does not redeliver messages. Will not try and harvest the NACKed message.' % BROKER
            return

        self.framesHandled = 0
        client = yield client.connect(host=VIRTUALHOST)
        client.subscribe(self.queue, {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL, StompSpec.ID_HEADER: '4711'}, listener=SubscriptionListener(self._eatFrame, ack=True))
        while self.framesHandled != 1:
            yield task.deferLater(reactor, 0.01, lambda: None)

        client.disconnect()
        yield client.disconnected
    def test_4_integration_stomp_1_1(self):
        if StompSpec.VERSION_1_1 not in commands.versions(VERSION):
            print 'This broker does not support STOMP protocol version 1.1'
            return

        client = Stomp(self.getConfig(StompSpec.VERSION_1_1))
        client.connect(host=VIRTUALHOST)

        client.send(self.DESTINATION, 'test message 1')
        client.send(self.DESTINATION, 'test message 2')
        self.assertFalse(client.canRead(self.TIMEOUT))
        token = client.subscribe(self.DESTINATION, {StompSpec.ID_HEADER: 4711, StompSpec.ACK_HEADER: 'client-individual'})
        self.assertTrue(client.canRead(self.TIMEOUT))
        client.ack(client.receiveFrame())
        self.assertTrue(client.canRead(self.TIMEOUT))
        client.ack(client.receiveFrame())
        self.assertFalse(client.canRead(self.TIMEOUT))
        client.unsubscribe(token)
        client.send(self.DESTINATION, 'test message 3', receipt='4711')
        self.assertTrue(client.canRead(self.TIMEOUT))
        self.assertEquals(client.receiveFrame(), StompFrame(StompSpec.RECEIPT, {'receipt-id': '4711'}))
        self.assertFalse(client.canRead(self.TIMEOUT))
        client.subscribe(self.DESTINATION, {StompSpec.ID_HEADER: 4711, StompSpec.ACK_HEADER: 'client-individual'})
        self.assertTrue(client.canRead(self.TIMEOUT))
        client.ack(client.receiveFrame())
        self.assertFalse(client.canRead(self.TIMEOUT))
        client.disconnect(receipt='4712')
        self.assertEquals(client.receiveFrame(), StompFrame(StompSpec.RECEIPT, {'receipt-id': '4712'}))
        self.assertRaises(StompConnectionError, client.receiveFrame)
        client.connect(host=VIRTUALHOST)
        client.disconnect(receipt='4711')
        self.assertEquals(client.receiveFrame(), StompFrame(StompSpec.RECEIPT, {'receipt-id': '4711'}))
        client.close()
        self.assertRaises(StompConnectionError, client.canRead, 0)
    def test_5_integration_stomp_1_1_heartbeat(self):
        if BROKER == 'apollo':
            print "Broker %s doesn't properly support heart-beating. Skipping test." % BROKER
            return

        if StompSpec.VERSION_1_1 not in commands.versions(VERSION):
            print 'This broker does not support STOMP protocol version 1.1'
            return

        port = 61612 if (BROKER == 'activemq') else PORT # stomp+nio on 61613 does not work properly, so use stomp on 61612
        client = Stomp(self.getConfig(StompSpec.VERSION_1_1, port))
        self.assertEquals(client.lastReceived, None)
        self.assertEquals(client.lastSent, None)

        heartBeatPeriod = 100
        client.connect(host=VIRTUALHOST, heartBeats=(heartBeatPeriod, heartBeatPeriod))
        self.assertTrue((time.time() - client.lastReceived) < 0.1)
        if not (client.serverHeartBeat and client.clientHeartBeat):
            print 'broker does not support heart-beating. disconnecting ...'
            client.disconnect()
            client.close()
            return

        serverHeartBeatInSeconds = client.serverHeartBeat / 1000.0
        clientHeartBeatInSeconds = client.clientHeartBeat / 1000.0

        start = time.time()
        while (time.time() - start) < (2.5 * max(serverHeartBeatInSeconds, clientHeartBeatInSeconds)):
            time.sleep(0.5 * min(serverHeartBeatInSeconds, clientHeartBeatInSeconds))
            client.canRead(0)
            self.assertTrue((time.time() - client.lastReceived) < (1.5 * serverHeartBeatInSeconds))
            if (time.time() - client.lastSent) > (0.5 * clientHeartBeatInSeconds):
                client.beat()
                self.assertTrue((time.time() - client.lastSent) < 0.1)

        start = time.time()
        try:
            while not client.canRead(0.5 * clientHeartBeatInSeconds):
                pass
        except StompConnectionError:
            self.assertTrue((time.time() - start) < (3.0 * clientHeartBeatInSeconds))
            self.assertTrue((time.time() - client.lastReceived) < (1.5 * serverHeartBeatInSeconds))
            self.assertTrue((time.time() - client.lastSent) > clientHeartBeatInSeconds)
        else:
            raise
        client.close()
    def _test_onhandlerException_ackMessage_filterReservedHdrs_send2ErrorQ_and_disconnect(self, version):
        if version not in commands.versions(VERSION):
            print 'This broker does not support STOMP protocol version 1.1'
            return

        config = self.getConfig(StompSpec.VERSION_1_1)
        client = async.Stomp(config)

        try:
            client = yield client.connect(host=VIRTUALHOST)
            if client.session.version == '1.0':
                yield client.disconnect()
                raise StompProtocolError('Broker chose STOMP protocol 1.0')

        except StompProtocolError as e:
            print 'Broker does not support STOMP protocol 1.1. Skipping this test case. [%s]' % e
            defer.returnValue(None)

        if client.session.version != version:
            print 'Broker does not support STOMP protocol %s. Skipping this test case.' % version
            yield client.disconnect()
            defer.returnValue(None)

        # enqueue two messages
        client.send(self.queue, self.frame1, self.msg1Hdrs)
        client.send(self.queue, self.frame2)

        defaultHeaders = {StompSpec.ACK_HEADER: 'client-individual'}
        if version != '1.0':
            defaultHeaders.update(self.headers)

        # barf on first message so it will get put in error queue
        # use selector to guarantee message order.  AMQ doesn't guarantee order by default
        headers = {'selector': "food = 'barf'"}
        headers.update(defaultHeaders)
        client.subscribe(self.queue, self._saveFrameAndBarf, headers, errorDestination=self.errorQueue, onMessageFailed=self._onMessageFailedSendToErrorDestinationAndRaise)

        # client disconnected and returned error
        try:
            yield client.disconnected
        except StompestTestError:
            pass
        else:
            raise

        client = async.Stomp(config) # take a fresh client to prevent replay (we were disconnected by an error)

        # reconnect and subscribe again - consuming second message then disconnecting
        client = yield client.connect(host=VIRTUALHOST)
        headers.pop('selector')
        client.subscribe(self.queue, self._eatOneFrameAndDisconnect, headers, errorDestination=self.errorQueue)

        # client disconnects without error
        yield client.disconnected

        # reconnect and subscribe to error queue
        client = yield client.connect(host=VIRTUALHOST)
        client.subscribe(self.errorQueue, self._saveErrorFrameAndDisconnect, defaultHeaders)

        # wait for disconnect
        yield client.disconnected

        # verify that first message was in error queue
        self.assertEquals(self.frame1, self.errorQueueFrame.body)
        self.assertEquals(self.msg1Hdrs['food'], self.errorQueueFrame.headers['food'])
        self.assertNotEquals(self.unhandledFrame.headers['message-id'], self.errorQueueFrame.headers['message-id'])

        # verify that second message was consumed
        self.assertEquals(self.frame2, self.consumedFrame.body)
    def _test_onhandlerException_ackMessage_filterReservedHdrs_send2ErrorQ_and_disconnect(self, version):
        if version not in commands.versions(VERSION):
            print("Skipping test case (version %s is not configured)" % VERSION)
            defer.returnValue(None)

        if BROKER == "rabbitmq":
            print("RabbitMQ does not support selector header")
            defer.returnValue(None)

        config = self.getConfig(version)
        client = async.Stomp(config)

        try:
            yield client.connect(host=VIRTUALHOST, versions=[version])
        except StompProtocolError as e:
            print("Broker does not support STOMP protocol %s. Skipping this test case. [%s]" % (e, version))
            defer.returnValue(None)

        # enqueue two messages
        messageHeaders = dict(self.msg1Hdrs)
        defaultHeaders = {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}
        specialCharactersHeader = b"fen\xc3\xaatre".decode("utf-8")
        if version != StompSpec.VERSION_1_0:
            defaultHeaders.update(self.headers)
            messageHeaders[specialCharactersHeader] = b"\xc2\xbfqu\xc3\xa9 tal?".decode("utf-8")

        client.send(self.queue, self.frame1, messageHeaders)
        client.send(self.queue, self.frame2)

        client.disconnect()
        yield client.disconnected

        # barf on first message so it will get put in error queue
        # use selector to guarantee message order (order not necessarily guaranteed)
        headers = {StompSpec.SELECTOR_HEADER: "food='barf'"}
        headers.update(defaultHeaders)

        yield client.connect(host=VIRTUALHOST, versions=[version])
        client.subscribe(
            self.queue,
            headers,
            listener=SubscriptionListener(
                self._saveFrameAndBarf,
                errorDestination=self.errorQueue,
                onMessageFailed=self._onMessageFailedSendToErrorDestinationAndRaise,
            ),
        )

        # client disconnected and returned error
        try:
            yield client.disconnected
        except StompestTestError:
            pass
        else:
            raise

        client = async.Stomp(config)  # take a fresh client to prevent replay (we were disconnected by an error)

        # reconnect and subscribe again - consuming second message then disconnecting
        yield client.connect(host=VIRTUALHOST)
        headers.pop("selector")

        client.subscribe(
            self.queue,
            headers,
            listener=SubscriptionListener(self._eatOneFrameAndDisconnect, errorDestination=self.errorQueue),
        )

        # client disconnects without error
        yield client.disconnected

        # reconnect and subscribe to error queue
        yield client.connect(host=VIRTUALHOST)
        client.subscribe(
            self.errorQueue, defaultHeaders, listener=SubscriptionListener(self._saveErrorFrameAndDisconnect)
        )

        # wait for disconnect
        yield client.disconnected

        # verify that first message was in error queue
        self.assertEquals(self.frame1, self.errorQueueFrame.body)
        self.assertEquals(messageHeaders["food"], self.errorQueueFrame.headers["food"])
        if version != StompSpec.VERSION_1_0:
            self.assertEquals(
                messageHeaders[specialCharactersHeader], self.errorQueueFrame.headers[specialCharactersHeader]
            )
        self.assertNotEquals(
            self.unhandledFrame.headers[StompSpec.MESSAGE_ID_HEADER],
            self.errorQueueFrame.headers[StompSpec.MESSAGE_ID_HEADER],
        )

        # verify that second message was consumed
        self.assertEquals(self.frame2, self.consumedFrame.body)
    def _test_onhandlerException_ackMessage_filterReservedHdrs_send2ErrorQ_and_disconnect(self, version):
        if version not in commands.versions(VERSION):
            print 'Skipping test case (version %s is not configured)' % VERSION
            defer.returnValue(None)

        if BROKER == 'rabbitmq':
            print 'RabbitMQ does not support selector header'
            defer.returnValue(None)

        config = self.getConfig(version)
        client = async.Stomp(config)

        try:
            yield client.connect(host=VIRTUALHOST, versions=[version])
        except StompProtocolError as e:
            print 'Broker does not support STOMP protocol %s. Skipping this test case. [%s]' % (e, version)
            defer.returnValue(None)

        # enqueue two messages
        messageHeaders = dict(self.msg1Hdrs)
        defaultHeaders = {StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL}
        specialCharactersHeader = u'fen\xeatre:\r\n'
        if version != StompSpec.VERSION_1_0:
            defaultHeaders.update(self.headers)
            messageHeaders[specialCharactersHeader] = u'\xbfqu\xe9 tal?, s\xfc\xdf'

        client.send(self.queue, self.frame1, messageHeaders)
        client.send(self.queue, self.frame2)

        client.disconnect()
        yield client.disconnected

        # barf on first message so it will get put in error queue
        # use selector to guarantee message order (order not necessarily guaranteed)
        headers = {StompSpec.SELECTOR_HEADER: u"food='barf'"}
        headers.update(defaultHeaders)

        yield client.connect(host=VIRTUALHOST, versions=[version])
        client.subscribe(self.queue, headers, listener=SubscriptionListener(self._saveFrameAndBarf, errorDestination=self.errorQueue, onMessageFailed=self._onMessageFailedSendToErrorDestinationAndRaise))

        # client disconnected and returned error
        try:
            yield client.disconnected
        except StompestTestError:
            pass
        else:
            raise

        client = async.Stomp(config) # take a fresh client to prevent replay (we were disconnected by an error)

        # reconnect and subscribe again - consuming second message then disconnecting
        client = yield client.connect(host=VIRTUALHOST)
        headers.pop('selector')

        client.subscribe(self.queue, headers, listener=SubscriptionListener(self._eatOneFrameAndDisconnect, errorDestination=self.errorQueue))

        # client disconnects without error
        yield client.disconnected

        # reconnect and subscribe to error queue
        client = yield client.connect(host=VIRTUALHOST)
        client.subscribe(self.errorQueue, defaultHeaders, listener=SubscriptionListener(self._saveErrorFrameAndDisconnect))

        # wait for disconnect
        yield client.disconnected

        # verify that first message was in error queue
        self.assertEquals(self.frame1, self.errorQueueFrame.body)
        self.assertEquals(messageHeaders[u'food'], self.errorQueueFrame.headers['food'])
        if version != StompSpec.VERSION_1_0:
            self.assertEquals(messageHeaders[specialCharactersHeader], self.errorQueueFrame.headers[specialCharactersHeader])
        self.assertNotEquals(self.unhandledFrame.headers[StompSpec.MESSAGE_ID_HEADER], self.errorQueueFrame.headers[StompSpec.MESSAGE_ID_HEADER])

        # verify that second message was consumed
        self.assertEquals(self.frame2, self.consumedFrame.body)