async def _mgmt_request_response(
        self,
        mgmt_operation,
        message,
        callback,
        keep_alive_associated_link=True,
        timeout=None,
        **kwargs
    ):
        # type: (bytes, uamqp.Message, Callable, bool, Optional[float], Any) -> uamqp.Message
        """
        Execute an amqp management operation.

        :param bytes mgmt_operation: The type of operation to be performed. This value will
         be service-specific, but common values include READ, CREATE and UPDATE.
         This value will be added as an application property on the message.
        :param message: The message to send in the management request.
        :paramtype message: ~uamqp.message.Message
        :param callback: The callback which is used to parse the returning message.
        :paramtype callback: Callable[int, ~uamqp.message.Message, str]
        :param keep_alive_associated_link: A boolean flag for keeping associated amqp sender/receiver link alive when
         executing operation on mgmt links.
        :param timeout: timeout in seconds for executing the mgmt operation.
        :rtype: None
        """
        await self._open()

        application_properties = {}
        # Some mgmt calls do not support an associated link name (such as list_sessions).  Most do, so on by default.
        if keep_alive_associated_link:
            try:
                application_properties = {
                    ASSOCIATEDLINKPROPERTYNAME: self._handler.message_handler.name
                }
            except AttributeError:
                pass

        mgmt_msg = uamqp.Message(
            body=message,
            properties=MessageProperties(
                reply_to=self._mgmt_target, encoding=self._config.encoding, **kwargs
            ),
            application_properties=application_properties,
        )
        try:
            return await self._handler.mgmt_request_async(
                mgmt_msg,
                mgmt_operation,
                op_type=MGMT_REQUEST_OP_TYPE_ENTITY_MGMT,
                node=self._mgmt_target.encode(self._config.encoding),
                timeout=timeout * 1000 if timeout else None,
                callback=callback,
            )
        except Exception as exp:  # pylint: disable=broad-except
            if isinstance(exp, compat.TimeoutException):
                raise OperationTimeoutError(error=exp)
            raise
Beispiel #2
0
    def test_parse_message_should_succeed(
        self,
        device_id,
        encoding,
        content_type,
        interface_name,
        payload,
        properties,
        app_properties,
        module_id,
    ):
        # setup
        properties = MessageProperties(content_encoding=encoding,
                                       content_type=content_type)
        message = Message(
            body=json.dumps(payload).encode(),
            properties=properties,
            annotations={
                common_parser.DEVICE_ID_IDENTIFIER: device_id.encode(),
                common_parser.INTERFACE_NAME_IDENTIFIER:
                interface_name.encode(),
                common_parser.MODULE_ID_IDENTIFIER: module_id.encode(),
            },
            application_properties=_encode_app_props(app_properties),
        )
        args = CommonParserArguments(properties=["all"],
                                     content_type=content_type)
        parser = common_parser.CommonParser(message=message,
                                            common_parser_args=args)

        # act
        parsed_msg = parser.parse_message()

        # verify
        assert parsed_msg["event"]["payload"] == payload
        assert parsed_msg["event"]["origin"] == device_id
        device_identifier = str(common_parser.DEVICE_ID_IDENTIFIER, "utf8")
        assert parsed_msg["event"]["annotations"][
            device_identifier] == device_id
        module_identifier = str(common_parser.MODULE_ID_IDENTIFIER, "utf8")
        if module_id:
            assert parsed_msg["event"]["annotations"][
                module_identifier] == module_id
        else:
            assert not parsed_msg["event"]["annotations"].get(
                module_identifier)
        properties = parsed_msg["event"]["properties"]
        assert properties["system"]["content_encoding"] == encoding
        assert properties["system"]["content_type"] == content_type
        assert properties["application"] == app_properties

        assert len(parser.issues_handler.get_all_issues()) == 0
Beispiel #3
0
    def test_validate_invalid_telmetry_component_template_should_fail(self):
        # setup
        device_template = Template(
            load_json(FileNames.central_property_validation_template_file))

        properties = MessageProperties(content_encoding=self.encoding,
                                       content_type=self.content_type)
        message = Message(
            body=json.dumps(self.bad_dcm_payload).encode(),
            properties=properties,
            annotations={
                common_parser.DEVICE_ID_IDENTIFIER:
                self.device_id.encode(),
                common_parser.COMPONENT_NAME_IDENTIFIER:
                list(device_template.components.keys())[1].encode(),
            },
            application_properties=_encode_app_props(self.app_properties),
        )
        args = CommonParserArguments(properties=["all"])
        parser = self._create_parser(device_template=device_template,
                                     message=message,
                                     args=args)

        # act
        parsed_msg = parser.parse_message()

        # verify
        assert parsed_msg["event"]["payload"] == self.bad_dcm_payload
        assert parsed_msg["event"]["origin"] == self.device_id
        device_identifier = str(common_parser.DEVICE_ID_IDENTIFIER, "utf8")
        assert parsed_msg["event"]["annotations"][
            device_identifier] == self.device_id
        component_identifier = str(common_parser.COMPONENT_NAME_IDENTIFIER,
                                   "utf8")
        assert (
            parsed_msg["event"]["annotations"][component_identifier] == list(
                device_template.components.keys())[1])
        properties = parsed_msg["event"]["properties"]
        assert properties["system"]["content_encoding"] == self.encoding
        assert properties["system"]["content_type"] == self.content_type
        assert properties["application"] == self.app_properties

        expected_details = strings.invalid_field_name_component_mismatch_template(
            list(self.bad_dcm_payload.keys()),
            device_template.component_schema_names,
        )

        _validate_issues(parser, Severity.warning, 1, 1, [expected_details])
Beispiel #4
0
    def xtest_validate_against_template_should_fail(self):
        # setup
        device_template = self._get_template()

        properties = MessageProperties(content_encoding=self.encoding,
                                       content_type=self.content_type)
        message = Message(
            body=json.dumps(self.bad_dcm_payload).encode(),
            properties=properties,
            annotations={
                common_parser.DEVICE_ID_IDENTIFIER: self.device_id.encode()
            },
            application_properties=_encode_app_props(self.app_properties),
        )
        args = CommonParserArguments(properties=["all"])
        parser = self._create_parser(device_template=device_template,
                                     message=message,
                                     args=args)

        # act
        parsed_msg = parser.parse_message()
        schema = parser._extract_template_schemas_from_template(
            device_template)

        schema = parser._extract_template_schemas_from_template(
            device_template)

        # verify
        assert parsed_msg["event"]["payload"] == self.bad_dcm_payload
        assert parsed_msg["event"]["origin"] == self.device_id
        device_identifier = str(common_parser.DEVICE_ID_IDENTIFIER, "utf8")
        assert parsed_msg["event"]["annotations"][
            device_identifier] == self.device_id

        properties = parsed_msg["event"]["properties"]
        assert properties["system"]["content_encoding"] == self.encoding
        assert properties["system"]["content_type"] == self.content_type
        assert properties["application"] == self.app_properties

        expected_details = strings.invalid_field_name_mismatch_template(
            list(self.bad_dcm_payload.keys()), list(schema.keys()))

        _validate_issues(parser, Severity.warning, 1, 1, [expected_details])
Beispiel #5
0
    def test_parse_message_should_succeed(self):
        # setup
        app_prop_type = "some_app_prop"
        app_prop_value = "some_app_value"
        properties = MessageProperties(content_encoding=self.encoding,
                                       content_type=self.content_type)
        message = Message(
            body=json.dumps(self.payload).encode(),
            properties=properties,
            annotations={
                _parser.DEVICE_ID_IDENTIFIER: self.device_id.encode()
            },
            application_properties={
                app_prop_type.encode(): app_prop_value.encode()
            },
        )
        parser = _parser.Event3Parser()

        # act
        parsed_msg = parser.parse_message(
            message=message,
            pnp_context=False,
            interface_name=None,
            properties={"all"},
            content_type_hint=None,
            simulate_errors=False,
        )

        # verify
        assert parsed_msg["event"]["payload"] == self.payload
        assert parsed_msg["event"]["origin"] == self.device_id
        device_identifier = str(_parser.DEVICE_ID_IDENTIFIER, "utf8")
        assert parsed_msg["event"]["annotations"][
            device_identifier] == self.device_id

        properties = parsed_msg["event"]["properties"]
        assert properties["system"]["content_encoding"] == self.encoding
        assert properties["system"]["content_type"] == self.content_type
        assert properties["application"][app_prop_type] == app_prop_value

        assert len(parser._errors) == 0
        assert len(parser._warnings) == 0
        assert len(parser._info) == 0
Beispiel #6
0
    def test_parse_message_bad_encoding_should_warn(self):
        # setup
        properties = MessageProperties(content_encoding=self.bad_encoding,
                                       content_type=self.content_type)
        message = Message(
            body=json.dumps(self.payload).encode(self.bad_encoding),
            properties=properties,
            annotations={
                common_parser.DEVICE_ID_IDENTIFIER: self.device_id.encode()
            },
        )
        args = CommonParserArguments()
        parser = common_parser.CommonParser(message=message,
                                            common_parser_args=args)

        # act
        parser.parse_message()

        expected_details = strings.invalid_encoding(self.bad_encoding)
        _validate_issues(parser, Severity.warning, 1, 1, [expected_details])
Beispiel #7
0
    def _mgmt_request_response(self, operation, message, callback, **kwargs):
        if not self.running:
            raise InvalidHandlerState("Client connection is closed.")

        mgmt_msg = Message(body=message,
                           properties=MessageProperties(
                               reply_to=self.mgmt_target,
                               encoding=self.encoding,
                               **kwargs))
        try:
            return self._handler.mgmt_request(mgmt_msg,
                                              operation,
                                              op_type=b"entity-mgmt",
                                              node=self.mgmt_target.encode(
                                                  self.encoding),
                                              timeout=5000,
                                              callback=callback)
        except Exception as exp:  # pylint: disable=broad-except
            raise ServiceBusError("Management request failed: {}".format(exp),
                                  exp)
Beispiel #8
0
    def test_parse_message_pnp_should_fail(self):
        # setup
        actual_interface_name = "actual_interface_name"
        expected_interface_name = "expected_interface_name"
        properties = MessageProperties(content_encoding=self.encoding,
                                       content_type=self.content_type)
        message = Message(
            body=json.dumps(self.payload).encode(),
            properties=properties,
            annotations={
                _parser.DEVICE_ID_IDENTIFIER: self.device_id.encode(),
                _parser.INTERFACE_NAME_IDENTIFIER:
                actual_interface_name.encode(),
            },
        )
        parser = _parser.Event3Parser()

        # act
        parsed_msg = parser.parse_message(
            message=message,
            pnp_context=True,
            interface_name=expected_interface_name,
            properties=None,
            content_type_hint=None,
            simulate_errors=False,
        )

        # verify
        # all the items should still be parsed and available, but we should have an error
        assert parsed_msg["event"]["payload"] == self.payload
        assert parsed_msg["event"]["origin"] == self.device_id
        assert parsed_msg["event"]["interface"] == actual_interface_name

        assert len(parser._errors) == 1
        assert len(parser._warnings) == 0
        assert len(parser._info) == 0

        actual_error = parser._errors[0]
        expected_error = "Inteface name mismatch. {}. Expected: {}, Actual: {}".format(
            self.device_id, expected_interface_name, actual_interface_name)
        assert actual_error == expected_error
    async def _mgmt_request_response(self, mgmt_operation, message, callback, **kwargs):
        await self._open()
        if not self._running:
            raise InvalidHandlerState("Client connection is closed.")

        mgmt_msg = uamqp.Message(
            body=message,
            properties=MessageProperties(
                reply_to=self._mgmt_target,
                encoding=self._config.encoding,
                **kwargs))
        try:
            return await self._handler.mgmt_request_async(
                mgmt_msg,
                mgmt_operation,
                op_type=MGMT_REQUEST_OP_TYPE_ENTITY_MGMT,
                node=self._mgmt_target.encode(self._config.encoding),
                timeout=5000,
                callback=callback)
        except Exception as exp:  # pylint: disable=broad-except
            raise ServiceBusError("Management request failed: {}".format(exp), exp)
Beispiel #10
0
    async def _mgmt_request_response(self,
                                     mgmt_operation,
                                     message,
                                     callback,
                                     keep_alive_associated_link=True,
                                     **kwargs):
        await self._open()
        if not self._running:
            raise InvalidHandlerState("Client connection is closed.")

        application_properties = {}
        # Some mgmt calls do not support an associated link name (such as list_sessions).  Most do, so on by default.
        if keep_alive_associated_link:
            try:
                application_properties = {
                    ASSOCIATEDLINKPROPERTYNAME:
                    self._handler.message_handler.name
                }
            except AttributeError:
                pass

        mgmt_msg = uamqp.Message(body=message,
                                 properties=MessageProperties(
                                     reply_to=self._mgmt_target,
                                     encoding=self._config.encoding,
                                     **kwargs),
                                 application_properties=application_properties)
        try:
            return await self._handler.mgmt_request_async(
                mgmt_msg,
                mgmt_operation,
                op_type=MGMT_REQUEST_OP_TYPE_ENTITY_MGMT,
                node=self._mgmt_target.encode(self._config.encoding),
                timeout=5000,
                callback=callback)
        except Exception as exp:  # pylint: disable=broad-except
            raise ServiceBusError("Management request failed: {}".format(exp),
                                  exp)
Beispiel #11
0
    def __init__(self, body=None, batch=None, to_device=None, message=None):
        """
        Initialize EventData.

        :param body: The data to send in a single message.
        :type body: str, bytes or list
        :param batch: A data generator to send batched messages.
        :type batch: Generator
        :param to_device: An IoT device to route to.
        :type to_device: str
        :param message: The received message.
        :type message: ~uamqp.message.Message
        """
        self._partition_key = types.AMQPSymbol(EventData.PROP_PARTITION_KEY)
        self._annotations = {}
        self._app_properties = {}
        self.msg_properties = MessageProperties()
        if to_device:
            self.msg_properties.to = '/devices/{}/messages/devicebound'.format(
                to_device)
        if batch:
            self.message = BatchMessage(data=batch,
                                        multi_messages=True,
                                        properties=self.msg_properties)
        elif message:
            self.message = message
            self.msg_properties = message.properties
            self._annotations = message.annotations
            self._app_properties = message.application_properties
        else:
            if isinstance(body, list) and body:
                self.message = Message(body[0], properties=self.msg_properties)
                for more in body[1:]:
                    self.message._body.append(more)  # pylint: disable=protected-access
            elif body is None:
                raise ValueError("EventData cannot be None.")
            else:
                self.message = Message(body, properties=self.msg_properties)
Beispiel #12
0
    def test_parse_message_bad_encoding_should_fail(self):
        # setup
        properties = MessageProperties(content_encoding=self.bad_encoding,
                                       content_type=self.content_type)
        message = Message(
            body=json.dumps(self.payload).encode(self.bad_encoding),
            properties=properties,
            annotations={
                _parser.DEVICE_ID_IDENTIFIER: self.device_id.encode()
            },
        )
        parser = _parser.Event3Parser()

        # act
        parser.parse_message(message, None, None, None, None, False)

        assert len(parser._errors) == 1
        assert len(parser._warnings) == 0
        assert len(parser._info) == 0

        errors = parser._errors[0]
        assert "Unsupported encoding detected: '{}'".format(
            self.bad_encoding) in errors
    def _mgmt_request_response(self,
                               operation,
                               message,
                               callback,
                               keep_alive_associated_link=True,
                               **kwargs):
        if not self.running:
            raise InvalidHandlerState("Client connection is closed.")

        application_properties = {}
        # Some mgmt calls do not support an associated link name.  Most do, however, so on by default.
        if keep_alive_associated_link:
            try:
                application_properties = {
                    ASSOCIATEDLINKPROPERTYNAME:
                    self._handler.message_handler.name
                }
            except AttributeError:
                pass

        mgmt_msg = Message(body=message,
                           properties=MessageProperties(
                               reply_to=self.mgmt_target,
                               encoding=self.encoding,
                               **kwargs),
                           application_properties=application_properties)
        try:
            return self._handler.mgmt_request(mgmt_msg,
                                              operation,
                                              op_type=b"entity-mgmt",
                                              node=self.mgmt_target.encode(
                                                  self.encoding),
                                              timeout=5000,
                                              callback=callback)
        except Exception as exp:  # pylint: disable=broad-except
            raise ServiceBusError("Management request failed: {}".format(exp),
                                  exp)
Beispiel #14
0
    def test_parse_message_bad_json_should_fail(self):
        # setup
        properties = MessageProperties(content_encoding=self.encoding,
                                       content_type=self.content_type)
        message = Message(
            body=self.bad_payload.encode(),
            properties=properties,
            annotations={
                common_parser.DEVICE_ID_IDENTIFIER: self.device_id.encode()
            },
        )
        args = CommonParserArguments()
        parser = common_parser.CommonParser(message=message,
                                            common_parser_args=args)

        # act
        parsed_msg = parser.parse_message()

        # verify
        # parsing should attempt to place raw payload into result even if parsing fails
        assert parsed_msg["event"]["payload"] == self.bad_payload

        expected_details = strings.invalid_json()
        _validate_issues(parser, Severity.error, 1, 1, [expected_details])
Beispiel #15
0
    def __init__(self, body=None, to_device=None):
        """
        Initialize EventData.

        :param body: The data to send in a single message.
        :type body: str, bytes or list
        :param to_device: An IoT device to route to.
        :type to_device: str
        """

        self._annotations = {}
        self._app_properties = {}
        self._msg_properties = MessageProperties()
        if to_device:
            self._msg_properties.to = '/devices/{}/messages/devicebound'.format(
                to_device)
        if body and isinstance(body, list):
            self.message = Message(body[0], properties=self._msg_properties)
            for more in body[1:]:
                self.message._body.append(more)  # pylint: disable=protected-access
        elif body is None:
            raise ValueError("EventData cannot be None.")
        else:
            self.message = Message(body, properties=self._msg_properties)
def test_message_pickle():
    properties = MessageProperties()
    properties.message_id = '2'
    properties.user_id = '1'
    properties.to = 'dkfj'
    properties.subject = 'dsljv'
    properties.reply_to = "kdjfk"
    properties.correlation_id = 'ienag'
    properties.content_type = 'b'
    properties.content_encoding = '39ru'
    properties.absolute_expiry_time = 24
    properties.creation_time = 10
    properties.group_id = '3irow'
    properties.group_sequence = 39
    properties.reply_to_group_id = '39rud'

    header = MessageHeader()
    header.delivery_count = 3
    header.time_to_live = 5
    header.first_acquirer = 'dkfj'
    header.durable = True
    header.priority = 4

    data_message = Message(body=[b'testmessage1', b'testmessage2'])
    pickled = pickle.loads(pickle.dumps(data_message))
    body = list(pickled.get_data())
    assert len(body) == 2
    assert body == [b'testmessage1', b'testmessage2']

    sequence_message = Message(body=[[1234.56, b'testmessage2', True],
                                     [-1234.56, {
                                         b'key': b'value'
                                     }, False]],
                               body_type=MessageBodyType.Sequence)
    pickled = pickle.loads(pickle.dumps(sequence_message))
    body = list(pickled.get_data())
    assert len(body) == 2
    assert body == [[1234.56, b'testmessage2', True],
                    [-1234.56, {
                        b'key': b'value'
                    }, False]]

    value_message = Message(body={b'key': [1, b'str', False]},
                            body_type=MessageBodyType.Value)
    pickled = pickle.loads(pickle.dumps(value_message))
    body = pickled.get_data()
    assert body == {b'key': [1, b'str', False]}

    error = errors.MessageModified(False, False, {b'key': b'value'})
    pickled_error = pickle.loads(pickle.dumps(error))
    assert pickled_error._annotations == {b'key': b'value'}  # pylint: disable=protected-access

    message = Message(body="test", properties=properties, header=header)
    message.on_send_complete = send_complete_callback
    message.footer = {'a': 2}
    message.state = constants.MessageState.ReceivedSettled

    pickled = pickle.loads(pickle.dumps(message))
    assert list(message.get_data()) == [b"test"]
    assert message.footer == pickled.footer
    assert message.state == pickled.state
    assert message.application_properties == pickled.application_properties
    assert message.annotations == pickled.annotations
    assert message.delivery_annotations == pickled.delivery_annotations
    assert message.settled == pickled.settled
    assert message.properties.message_id == pickled.properties.message_id
    assert message.properties.user_id == pickled.properties.user_id
    assert message.properties.to == pickled.properties.to
    assert message.properties.subject == pickled.properties.subject
    assert message.properties.reply_to == pickled.properties.reply_to
    assert message.properties.correlation_id == pickled.properties.correlation_id
    assert message.properties.content_type == pickled.properties.content_type
    assert message.properties.content_encoding == pickled.properties.content_encoding
    assert message.properties.absolute_expiry_time == pickled.properties.absolute_expiry_time
    assert message.properties.creation_time == pickled.properties.creation_time
    assert message.properties.group_id == pickled.properties.group_id
    assert message.properties.group_sequence == pickled.properties.group_sequence
    assert message.properties.reply_to_group_id == pickled.properties.reply_to_group_id
    assert message.header.delivery_count == pickled.header.delivery_count
    assert message.header.time_to_live == pickled.header.time_to_live
    assert message.header.first_acquirer == pickled.header.first_acquirer
    assert message.header.durable == pickled.header.durable
    assert message.header.priority == pickled.header.priority

    # send with message param
    settler = errors.MessageAlreadySettled
    internal_message = c_uamqp.create_message()
    internal_message.add_body_data(b"hi")
    message_w_message_param = Message(message=internal_message,
                                      settler=settler,
                                      delivery_no=1)
    pickled = pickle.loads(pickle.dumps(message_w_message_param))
    message_data = str(message_w_message_param.get_data())
    pickled_data = str(pickled.get_data())

    assert message_data == pickled_data
    assert message_w_message_param.footer == pickled.footer
    assert message_w_message_param.state == pickled.state
    assert message_w_message_param.application_properties == pickled.application_properties
    assert message_w_message_param.annotations == pickled.annotations
    assert message_w_message_param.delivery_annotations == pickled.delivery_annotations
    assert message_w_message_param.settled == pickled.settled
    assert pickled.delivery_no == 1
    assert type(pickled._settler()) == type(settler())  # pylint: disable=protected-access
def test_message_properties():

    properties = MessageProperties()
    assert properties.user_id is None

    properties = MessageProperties()
    properties.user_id = b''
    assert properties.user_id == b''

    properties = MessageProperties()
    properties.user_id = '1'
    assert properties.user_id == b'1'

    properties = MessageProperties()
    properties.user_id = 'short'
    assert properties.user_id == b'short'

    properties = MessageProperties()
    properties.user_id = 'longuseridstring'
    assert properties.user_id == b'longuseridstring'

    properties = MessageProperties()
    properties.user_id = '!@#$%^&*()_+1234567890'
    assert properties.user_id == b'!@#$%^&*()_+1234567890'

    properties = MessageProperties()
    properties.user_id = 'werid/0\0\1\t\n'
    assert properties.user_id == b'werid/0\0\1\t\n'
def test_deepcopy_batch_message():
    ## DEEPCOPY WITH MESSAGES IN BATCH THAT HAVE HEADER/PROPERTIES
    properties = MessageProperties()
    properties.message_id = '2'
    properties.user_id = '1'
    properties.to = 'dkfj'
    properties.subject = 'dsljv'
    properties.reply_to = "kdjfk"
    properties.correlation_id = 'ienag'
    properties.content_type = 'b'
    properties.content_encoding = '39ru'
    properties.absolute_expiry_time = 24
    properties.creation_time = 10
    properties.group_id = '3irow'
    properties.group_sequence = 39
    properties.reply_to_group_id = '39rud'

    header = MessageHeader()
    header.delivery_count = 3
    header.time_to_live = 5
    header.first_acquirer = 'dkfj'
    header.durable = True
    header.priority = 4

    message = Message(body="test", properties=properties, header=header)
    message.on_send_complete = send_complete_callback
    message.footer = {'a': 2}
    message.state = constants.MessageState.ReceivedSettled

    message_batch = BatchMessage(data=[],
                                 multi_messages=False,
                                 properties=None)
    message_batch._body_gen.append(message)
    message_batch_copy = copy.deepcopy(message_batch)
    batch_message = list(message_batch._body_gen)[0]
    batch_copy_message = list(message_batch_copy._body_gen)[0]
    assert len(list(message_batch._body_gen)) == len(
        list(message_batch_copy._body_gen))

    # check message attributes are equal to deepcopied message attributes
    assert list(batch_message.get_data()) == list(
        batch_copy_message.get_data())
    assert batch_message.footer == batch_copy_message.footer
    assert batch_message.state == batch_copy_message.state
    assert batch_message.application_properties == batch_copy_message.application_properties
    assert batch_message.annotations == batch_copy_message.annotations
    assert batch_message.delivery_annotations == batch_copy_message.delivery_annotations
    assert batch_message.settled == batch_copy_message.settled
    assert batch_message.properties.message_id == batch_copy_message.properties.message_id
    assert batch_message.properties.user_id == batch_copy_message.properties.user_id
    assert batch_message.properties.to == batch_copy_message.properties.to
    assert batch_message.properties.subject == batch_copy_message.properties.subject
    assert batch_message.properties.reply_to == batch_copy_message.properties.reply_to
    assert batch_message.properties.correlation_id == batch_copy_message.properties.correlation_id
    assert batch_message.properties.content_type == batch_copy_message.properties.content_type
    assert batch_message.properties.content_encoding == batch_copy_message.properties.content_encoding
    assert batch_message.properties.absolute_expiry_time == batch_copy_message.properties.absolute_expiry_time
    assert batch_message.properties.creation_time == batch_copy_message.properties.creation_time
    assert batch_message.properties.group_id == batch_copy_message.properties.group_id
    assert batch_message.properties.group_sequence == batch_copy_message.properties.group_sequence
    assert batch_message.properties.reply_to_group_id == batch_copy_message.properties.reply_to_group_id
    assert batch_message.header.delivery_count == batch_copy_message.header.delivery_count
    assert batch_message.header.time_to_live == batch_copy_message.header.time_to_live
    assert batch_message.header.first_acquirer == batch_copy_message.header.first_acquirer
    assert batch_message.header.durable == batch_copy_message.header.durable
    assert batch_message.header.priority == batch_copy_message.header.priority