def test_consume_from_queue(self):
        """Verify RMQConsumer can consume from a queue."""
        msg_received = None
        event = threading.Event()

        def on_msg(msg):
            event.set()

            nonlocal msg_received
            msg_received = msg

        # Consume
        consume_key = self.consumer.consume(ConsumeParams(on_msg),
                                            queue_params=QueueParams("queue"))
        self.assertEqual(consume_key, "queue")

        # Wait for ConsumeOK
        event.wait(timeout=1.0)
        self.assertTrue(isinstance(msg_received, ConsumeOK))

        # Send a message and verify it is delivered OK
        event.clear()  # clear to re-use event
        self.producer.publish(b"body", queue_params=QueueParams("queue"))

        event.wait(timeout=1.0)
        self.assertEqual(msg_received, b"body")
Пример #2
0
    def test_consume_same_consume_key(self):
        """
        Verify that calling consume once more with the same queue name,
        exchange name and routing key will result in an exception.
        """
        self.consumer.consume(
            ConsumeParams(lambda _: ...), QueueParams("queue")
        )

        # Assertions
        with self.assertRaises(ValueError):
            self.consumer.consume(
                ConsumeParams(lambda _: ...), QueueParams("queue")
            )
Пример #3
0
    def test_on_msg(self):
        """
        Verify on_msg calls result in a call to the consumer's function as
        well as long as a matching consumer tag entry is found.
        """
        # Prep
        on_message_callback_called = False

        def on_message_callback(msg):
            if not msg == b'body' or isinstance(msg, ConsumeOK):
                return

            nonlocal on_message_callback_called
            on_message_callback_called = True

        queue_params = QueueParams("queue")
        self.consumer.consume(ConsumeParams(on_message_callback),
                              queue_params=queue_params)
        frame_mock = Mock()
        frame_mock.method.consumer_tag = "123"
        self.consumer.on_consume_ok(frame_mock, queue_params=queue_params)
        deliver_mock = Mock()
        deliver_mock.consumer_tag = "123"

        # Run test
        self.consumer.on_msg(Mock(), deliver_mock, Mock(), b"body")

        # Assertions
        self.assertTrue(on_message_callback_called)
Пример #4
0
    def test_on_consume_ok(self):
        """
        Verify that the correct actions follows a consume OK.
        """
        # Prep
        on_message_callback_called = False

        def on_message_callback(msg):
            if not isinstance(msg, ConsumeOK):
                return

            nonlocal on_message_callback_called
            on_message_callback_called = True

        consume_params = ConsumeParams(on_message_callback)
        queue_params = QueueParams("queue")
        frame = Mock()
        self.consumer.consume(consume_params, queue_params=queue_params)

        # Run test
        self.consumer.on_consume_ok(frame,
                                    queue_params=queue_params)

        # Assertions
        consume_instance = self.consumer._consumes[
            _gen_consume_key(queue=queue_params.queue)
        ]
        self.assertEqual(consume_instance.consumer_tag,
                         frame.method.consumer_tag)
        self.assertTrue(on_message_callback_called)  # Called with ConsumeOK
Пример #5
0
    def test_on_exchange_declared(self):
        """
        Verify that the correct action follows a successful exchange
        declaration.
        """
        # Prep
        self.consumer.bind_queue = Mock()
        exchange_params = ExchangeParams("exchange")
        consume_params = ConsumeParams(lambda _: ...)
        queue_params = QueueParams("queue")

        # Run test
        self.consumer.on_exchange_declared(exchange_params,
                                           None,
                                           consume_params=consume_params,
                                           queue_params=queue_params)

        # Assertions
        call_args = self.consumer.bind_queue.call_args
        queue_bind_params = call_args.args[0]
        self.consumer.bind_queue.assert_called_with(
            queue_bind_params, callback=ANY
        )
        self.assertEqual(queue_bind_params.queue, consume_params.queue)
        self.assertEqual(queue_bind_params.exchange, exchange_params.exchange)
        self.assertEqual(queue_bind_params.routing_key, None)
    def test_consume_from_exchange_and_queue(self):
        """
        Verify RMQConsumer can consume from an exchange, binding it to a
        specific queue.
        """
        msg_received = None
        event = threading.Event()

        def on_msg(msg):
            event.set()

            nonlocal msg_received
            msg_received = msg

        # Consume
        consume_key = self.consumer.consume(
            ConsumeParams(on_msg),
            exchange_params=ExchangeParams("exchange_fanout",
                                           exchange_type=ExchangeType.fanout),
            queue_params=QueueParams("queue_fanout_receiver"))
        self.assertEqual(consume_key, "queue_fanout_receiver|exchange_fanout")

        # Wait for ConsumeOK
        event.wait(timeout=1.0)
        self.assertTrue(isinstance(msg_received, ConsumeOK))

        # Send a message and verify it is delivered OK
        event.clear()
        self.producer.publish(b"body",
                              exchange_params=ExchangeParams(
                                  "exchange_fanout",
                                  exchange_type=ExchangeType.fanout))

        event.wait(timeout=1.0)
        self.assertEqual(msg_received, b"body")
Пример #7
0
    def test_consume_queue_exchange_and_routing_key(self):
        """
        Verify possibility to provide both an exchange, routing_key and a queue
        to the consume method.
        """
        # Prep
        def on_msg(): pass
        consume = ConsumeParams(on_msg)
        queue = QueueParams("queue")
        exchange = ExchangeParams("exchange")

        # Run test
        self.consumer.consume(consume,
                              queue_params=queue,
                              exchange_params=exchange,
                              routing_key="routing_key")

        # Assertions
        consume_key = _gen_consume_key(queue=queue.queue,
                                       exchange=exchange.exchange,
                                       routing_key="routing_key")
        consume_instance = self.consumer._consumes[consume_key]
        self.assertEqual(consume_instance.consume_params, consume)
        self.assertEqual(consume_instance.queue_params, queue)
        self.assertEqual(consume_instance.exchange_params, exchange)
        self.assertEqual(consume_instance.routing_key, "routing_key")
        self.consumer.declare_queue.assert_called_with(queue, callback=ANY)
Пример #8
0
    def set_up_confirmed_consume(self) -> str:
        """Helper that sets up queue-only confirmed consume."""
        queue_params = QueueParams("queue")
        self.consumer.consume(ConsumeParams(lambda _: ...),
                              queue_params=queue_params)
        frame_mock = Mock()
        frame_mock.method.consumer_tag = "123"
        self.consumer.on_consume_ok(frame_mock, queue_params=queue_params)

        return "123"
Пример #9
0
def unpair(hume_uuid):
    """
    Issues an unpairing command to the target HUME. This will lead to the HUME
    being factory reset, and any device information is lost on the HUME end.
    """
    payload = {
        "type": MessageType.UNPAIR
    }
    global _producer
    _producer.publish(json.dumps(payload).encode('utf-8'),
                      queue_params=QueueParams(hume_uuid, durable=True))
Пример #10
0
def detach(hume_uuid, device_uuid):
    """
    Issues a detach command to the a hume for a device.
    """
    payload = {
        "type": MessageType.DETACH,
        "device_uuid": device_uuid
    }
    global _producer
    _producer.publish(json.dumps(payload).encode('utf-8'),
                      queue_params=QueueParams(hume_uuid, durable=True))
Пример #11
0
    def test_on_msg_callback_raises_exception(self):
        """
        Verify that exceptions raised from the consumer callback as a result of
        an on_msg invocation does not lead to an exception in RMQConsumer.
        """
        # Prep
        def on_message_callback(msg):
            if isinstance(msg, ConsumeOK):
                return

            raise ValueError

        self.consumer.consume(ConsumeParams(on_message_callback),
                              queue_params=QueueParams("queue"))
        frame_mock = Mock()
        frame_mock.method.consumer_tag = "123"
        self.consumer.on_consume_ok(frame_mock,
                                    queue_params=QueueParams("queue"))
        deliver_mock = Mock()
        deliver_mock.consumer_tag = "123"

        # Run test, assertion is that no exception is uncaught
        self.consumer.on_msg(Mock(), deliver_mock, Mock(), b"body")
    def test_publish_using_both_queue_params_and_exchange_params(self):
        """
        Verify that a ValueError is raised if both queue and exchange
        parameters are provided to publish.
        """
        # Prep
        queue_params = QueueParams("queue")
        exchange_params = ExchangeParams("exchange")

        # Run test + assertions
        with self.assertRaises(ValueError):
            self.producer.publish(b"body",
                                  exchange_params=exchange_params,
                                  queue_params=queue_params)
Пример #13
0
def discover_devices(hume_uuid: str, message_content: str):
    """
    Issue a Discover devices command to a HUME.

    :param hume_uuid: UUID of the HUME to send the Discover devices message to.
    :param message_content: discover devices message content.
    """
    global _producer
    _producer.publish(
        json.dumps(
            {
                "type": MessageType.DISCOVER_DEVICES,
                "content": message_content
            }
        ).encode('utf-8'),
        queue_params=QueueParams(hume_uuid, durable=True)
    )
Пример #14
0
def attach(hume_uuid: str, identifier: str):
    """
    Issue an attach command for a device to a HUME.

    :param hume_uuid: UUID of the HUME that discovered the device.
    :param identifier: identifier of the device to attach.
    """
    global _producer
    _producer.publish(
        json.dumps(
            {
                "type": MessageType.ATTACH_DEVICE,
                "identifier": identifier
            }
        ).encode('utf-8'),
        queue_params=QueueParams(hume_uuid, durable=True)
    )
Пример #15
0
    def test_consume_queue_only(self):
        """Verify possibility to consume from a queue."""
        # Prep
        def on_msg(): pass
        consume = ConsumeParams(on_msg)
        queue = QueueParams("queue")

        # Run test
        self.consumer.consume(consume, queue_params=queue)

        #
        # Assertions
        consume_key = _gen_consume_key(queue=queue.queue)
        consume_instance = self.consumer._consumes[consume_key]
        self.assertEqual(consume_instance.consume_params, consume)
        self.assertEqual(consume_instance.queue_params, queue)
        self.assertEqual(consume_instance.exchange_params, None)
        self.consumer.declare_queue.assert_called_with(queue, callback=ANY)
Пример #16
0
    def test_on_consume_ok_callback_raises_exception(self):
        """
        Verify that an exception raised from the consume OK notification does
        not crash the consumer.
        """
        # Prep
        def crappy_callback(msg):
            # Random exception chosen, ANY exception shall be possible to
            # handle.
            raise ValueError

        queue_params = QueueParams("queue")

        self.consumer.consume(ConsumeParams(crappy_callback),
                              queue_params=queue_params)

        # Run test
        # Assertion is that no unhandled exception happens :-)
        self.consumer.on_consume_ok(Mock(), queue_params=queue_params)
    def test_publish_using_queue_params(self):
        """Verify possibility to publish providing only queue parameters."""
        # Prep
        queue_params = QueueParams("queue")
        frame_mock = Mock()
        frame_mock.method.queue = "queue"

        # Run test + assertions
        self.producer.publish(b"body", queue_params=queue_params)
        self.producer.declare_queue.assert_called_with(queue_params,
                                                       callback=ANY)

        self.producer.on_queue_declared(b"body",
                                        frame_mock,
                                        publish_params=None)
        self.producer.basic_publish.assert_called_with(
            b"body",
            exchange=DEFAULT_EXCHANGE,
            routing_key=queue_params.queue,
            publish_params=None)
Пример #18
0
    def test_on_queue_declared_no_exchange(self):
        """
        Verify that the correct action follows a successful queue declare.
        """
        # Prep
        self.consumer.basic_consume = Mock()
        frame = Mock()
        consume_params = ConsumeParams(lambda _: ...)
        queue_params = QueueParams("queue")

        # Run test
        self.consumer.on_queue_declared(frame,
                                        consume_params=consume_params,
                                        queue_params=queue_params)

        # Assertions
        self.consumer.basic_consume.assert_called_with(
            consume_params,
            on_message_callback_override=self.consumer.on_msg,
            callback=ANY)
    def test_declare_queue(self):
        """
        Verify declaring a queue.
        """
        # Prep
        queue_params = QueueParams("queue")

        def on_queue_declared():
            ...

        # Test
        self.conn_imp.declare_queue(queue_params, callback=on_queue_declared)

        # Assert
        self.conn_imp._channel.queue_declare.assert_called_with(
            queue_params.queue,
            durable=queue_params.durable,
            exclusive=queue_params.exclusive,
            auto_delete=queue_params.auto_delete,
            arguments=queue_params.arguments,
            callback=on_queue_declared)
Пример #20
0
    def test_on_queue_declared_exchange(self):
        """
        Verify that the correct action follows a successful queue declare when
        exchange is specified.
        """
        # Prep
        self.consumer.declare_exchange = Mock()
        frame = Mock()
        consume_params = ConsumeParams(lambda _: ...)
        queue_params = QueueParams("queue")
        exchange_params = ExchangeParams("exchange")

        # Run test
        self.consumer.on_queue_declared(frame,
                                        consume_params=consume_params,
                                        queue_params=queue_params,
                                        exchange_params=exchange_params)

        # Assertions
        self.assertTrue(isinstance(consume_params.queue, Mock))
        self.consumer.declare_exchange.assert_called_with(
            exchange_params, callback=ANY)
Пример #21
0
    def test_on_close_marks_consumes_stopped(self):
        """Verify a call to on_close marks all consumes as stopped."""
        queue_consume = ConsumeParams(lambda _: ...)
        queue = QueueParams("queue")
        self.consumer.consume(queue_consume, queue_params=queue)

        exchange_consume = ConsumeParams(lambda _: ...)
        exchange = ExchangeParams("exchange")
        self.consumer.consume(exchange_consume, exchange_params=exchange)

        # Fake having all consumes started
        for _, consume in self.consumer._consumes.items():
            consume.consumer_tag = "some tag"

        # Run test
        self.consumer.on_close()

        # Checks
        for _, consume in self.consumer._consumes.items():
            if consume.consumer_tag == "some tag":
                self.fail(
                    "a consume did not have its consumer tag cleared when "
                    "on_close was called"
                )
Пример #22
0
def send_device_action(hume_uuid: str,
                       device_uuid: str,
                       **kwargs):
    """
    Issues a device action command to a HUME for a specific device.

    :param hume_uuid: HUME to receive the action.
    :param device_uuid: device to receive the action.

    Possible kwargs:

        For a STATEFUL action, both of these parameters must be provided:

        group_id: group ID of a pointed out new device state.
        state_id: new device state.
    """
    payload = {
        "type": MessageType.ACTION_STATEFUL,
        "device_uuid": device_uuid,
    }
    payload.update(kwargs)
    global _producer
    _producer.publish(json.dumps(payload).encode('utf-8'),
                      queue_params=QueueParams(hume_uuid, durable=True))
Пример #23
0
    def test_on_queue_bound(self):
        """
        Verify that the correct action follows a successful queue bind
        operation.
        """
        # Prep
        self.consumer.basic_consume = Mock()
        frame = Mock()
        consume_params = ConsumeParams(lambda _: ...)
        queue_params = QueueParams("queue")

        # Run test
        self.consumer.on_queue_bound(frame,
                                     consume_params=consume_params,
                                     queue_params=queue_params,
                                     exchange="exchange",
                                     routing_key=None)

        # Assertions
        self.consumer.basic_consume.assert_called_with(
            consume_params,
            on_message_callback_override=self.consumer.on_msg,
            callback=ANY
        )
Пример #24
0
    def test_on_ready_starts_consumes(self):
        """
        Verify that a call to on_ready results in re-issuing of all active
        consumes.
        """
        # Prep
        self.consumer._handle_consume = Mock()

        queue_params = QueueParams("queue")
        exchange_params = ExchangeParams("exchange")

        self.consumer.consume(ConsumeParams(lambda _: ...),
                              queue_params=queue_params)
        self.consumer.consume(ConsumeParams(lambda _: ...),
                              exchange_params=exchange_params)

        # Run test
        self.consumer.on_ready()

        # Assertions
        self.consumer._handle_consume.assert_has_calls(
            (call(ANY, queue_params, None, None),
             call(ANY, None, exchange_params, None),)
        )
    def test_publish_is_delayed_until_producer_connection_ready(self):
        """
        Verify that the producer buffers messages that are to be sent when the
        producer connection is not in a ready state, and that the buffered
        messages are sent upon the producer becoming ready.
        """
        # Prep
        exchange_params = ExchangeParams("exchange")
        frame_mock = Mock()
        frame_mock.method.queue = "queue"
        queue_params = QueueParams("queue")

        # Run test + assertions
        self.producer.on_close()
        self.producer.publish(b"body", exchange_params=exchange_params)
        self.producer.publish(b"body", queue_params=queue_params)

        self.assertEqual(2, len(self.producer._buffered_messages))

        self.producer.on_ready()
        self.producer.declare_exchange.assert_called_with(exchange_params,
                                                          callback=ANY)
        self.producer.declare_queue.assert_called_with(queue_params,
                                                       callback=ANY)
Пример #26
0
    def ready(self):
        """
        Called once the application is ready.

        https://docs.djangoproject.com/en/3.1/ref/applications/
        """
        # Development specific, due to Django code reload ...
        # DEBUG indicates development, RUN_MAIN indicates it's not the
        # reloader reaching this block.
        if settings.DEBUG and not os.environ.get("RUN_MAIN"):
            return

        if BrokerConfig.has_started:
            return
        BrokerConfig.has_started = True

        # Set up and start the RabbitMQ client
        rmq_client_log_level = logging.INFO
        logger = logging.getLogger("rabbitmq_client")
        logger.setLevel(rmq_client_log_level)

        # Create handler to actually print something
        stream_handler = logging.StreamHandler()
        logger.addHandler(stream_handler)

        formatter = logging.Formatter(fmt="{asctime} {levelname:^8} "
                                      "{name} - {message}",
                                      style="{",
                                      datefmt="%d/%m/%Y %H:%M:%S")
        stream_handler.setFormatter(formatter)
        stream_handler.setLevel(rmq_client_log_level)

        credentials = pika.PlainCredentials(settings.HUME_BROKER_USERNAME,
                                            settings.HUME_BROKER_PASSWORD)
        connection_params = pika.ConnectionParameters(
            host=settings.HUME_BROKER_IP,
            port=settings.HUME_BROKER_PORT,
            virtual_host='/',
            credentials=credentials)

        hint_master_queue_parameters = QueueParams(
            settings.MASTER_COMMAND_QUEUE_NAME, durable=True)

        consumer = RMQConsumer(connection_parameters=connection_params)
        consumer.consume(ConsumeParams(incoming_message),
                         queue_params=hint_master_queue_parameters)

        producer = RMQProducer(connection_parameters=connection_params)
        producer_module.init(producer)

        consumer.start()
        producer.start()

        def stop_func(_s, _f, consumer=None, producer=None):
            """
            :param _s: signal leading to stop
            :param _f: frame when stop was called
            :param consumer: rabbitmq_client.RMQConsumer
            :param producer: rabbitmq_client.RMQProducer
            """
            consumer.stop()
            producer.stop()

        stop_callback = functools.partial(stop_func,
                                          consumer=consumer,
                                          producer=producer)

        signal.signal(signal.SIGINT, stop_callback)
        signal.signal(signal.SIGTERM, stop_callback)
handler = logging.StreamHandler()
handler.setLevel(logging.INFO)
logger.addHandler(handler)

producer = RMQProducer()
producer.start()


def stop(*args):
    producer.stop()
    sys.exit(0)


signal.signal(signal.SIGINT, stop)

producer.publish(b"queue publish 1", queue_params=QueueParams("queue"))
producer.publish(b"queue publish 2", queue_params=QueueParams("queue"))
producer.publish(b"queue publish 3", queue_params=QueueParams("queue"))
producer.publish(b"exchange publish 1",
                 exchange_params=ExchangeParams("direct"),
                 routing_key="rkey")
producer.publish(b"exchange publish 2",
                 exchange_params=ExchangeParams(
                     "fanout", exchange_type=ExchangeType.fanout))

time.sleep(0.3)
producer.activate_confirm_mode(lambda x: print(x))
producer.publish(b"exchange publish 2",
                 exchange_params=ExchangeParams(
                     "fanout", exchange_type=ExchangeType.fanout))
producer.publish(b"exchange publish 2",