Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-azure-servicebus for openSUSE:Factory checked in at 2025-03-19 22:33:20 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-azure-servicebus (Old) and /work/SRC/openSUSE:Factory/.python-azure-servicebus.new.4956 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-azure-servicebus" Wed Mar 19 22:33:20 2025 rev:38 rq:1254235 version:7.14.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-azure-servicebus/python-azure-servicebus.changes 2025-02-20 17:40:12.912345049 +0100 +++ /work/SRC/openSUSE:Factory/.python-azure-servicebus.new.4956/python-azure-servicebus.changes 2025-03-19 22:33:36.633840018 +0100 @@ -1,0 +2,8 @@ +Tue Mar 18 09:43:59 UTC 2025 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- New upstream release + + Version 7.14.1 + + For detailed information about changes see the + CHANGELOG.md file provided with this package + +------------------------------------------------------------------- Old: ---- azure_servicebus-7.14.0.tar.gz New: ---- azure_servicebus-7.14.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-azure-servicebus.spec ++++++ --- /var/tmp/diff_new_pack.BtC8GK/_old 2025-03-19 22:33:37.553878750 +0100 +++ /var/tmp/diff_new_pack.BtC8GK/_new 2025-03-19 22:33:37.557878919 +0100 @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-azure-servicebus -Version: 7.14.0 +Version: 7.14.1 Release: 0 Summary: Microsoft Azure Service Bus Runtime Client Library License: Apache-2.0 ++++++ azure_servicebus-7.14.0.tar.gz -> azure_servicebus-7.14.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/CHANGELOG.md new/azure_servicebus-7.14.1/CHANGELOG.md --- old/azure_servicebus-7.14.0/CHANGELOG.md 2025-02-13 16:17:52.000000000 +0100 +++ new/azure_servicebus-7.14.1/CHANGELOG.md 2025-03-12 18:40:35.000000000 +0100 @@ -1,5 +1,12 @@ # Release History +## 7.14.1 (2025-03-12) + +### Bugs Fixed + +- Fixed a bug where service errors were incorrectly expected to have info/description fields set in all cases. +- Fixed a bug where the type in azure.servicebus.management.AuthorizationRule was not being correctly passed to the request. + ## 7.14.0 (2025-02-13) ### Features Added @@ -11,9 +18,7 @@ - Fixed a bug where async websocket disconnects were not being retried properly. ([#36280](https://github.com/Azure/azure-sdk-for-python/issues/36280)) - Fixed a bug where sending large messages with synchronous client caused a frame buffer offset error ([#37916](https://github.com/Azure/azure-sdk-for-python/issues/37916)) -- Fix to handle websocket disconnect/close on aiohttp, as aiohttp raises a `TypeError` while asserting bytes. ([#32061](https://github.com/Azure/azure-sdk-for-python/pull/32061)) -- Fixed a bug where pyAMQP was doubly retrying, causing latency on reconnect. ([#39037](https://github.com/Azure/azure-sdk-for-python/pull/39037)) -- Fix to handle large messages being sent twice due to incoming flow frames triggering a resend. ([#38067](https://github.com/Azure/azure-sdk-for-python/pull/38067)) +- Fixed a bug where pyAMQP was doubly retrying, causing higher latency on reconnect. ([#39037](https://github.com/Azure/azure-sdk-for-python/pull/39037)) - Missing await in sender async on pyAMQP. ([#39182](https://github.com/Azure/azure-sdk-for-python/pull/39182)) - Improved AutoLockRenewer to renew locks for more registered messages. ([#37340](https://github.com/Azure/azure-sdk-for-python/issues/37340)) - Fixed a bug where message IDs in management operation requests were not unique. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/PKG-INFO new/azure_servicebus-7.14.1/PKG-INFO --- old/azure_servicebus-7.14.0/PKG-INFO 2025-02-13 16:20:14.518781400 +0100 +++ new/azure_servicebus-7.14.1/PKG-INFO 2025-03-12 18:43:01.904153300 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: azure-servicebus -Version: 7.14.0 +Version: 7.14.1 Summary: Microsoft Azure Service Bus Client Library for Python Home-page: https://github.com/Azure/azure-sdk-for-python Author: Microsoft Corporation @@ -671,6 +671,13 @@ # Release History +## 7.14.1 (2025-03-12) + +### Bugs Fixed + +- Fixed a bug where service errors were incorrectly expected to have info/description fields set in all cases. +- Fixed a bug where the type in azure.servicebus.management.AuthorizationRule was not being correctly passed to the request. + ## 7.14.0 (2025-02-13) ### Features Added @@ -682,9 +689,7 @@ - Fixed a bug where async websocket disconnects were not being retried properly. ([#36280](https://github.com/Azure/azure-sdk-for-python/issues/36280)) - Fixed a bug where sending large messages with synchronous client caused a frame buffer offset error ([#37916](https://github.com/Azure/azure-sdk-for-python/issues/37916)) -- Fix to handle websocket disconnect/close on aiohttp, as aiohttp raises a `TypeError` while asserting bytes. ([#32061](https://github.com/Azure/azure-sdk-for-python/pull/32061)) -- Fixed a bug where pyAMQP was doubly retrying, causing latency on reconnect. ([#39037](https://github.com/Azure/azure-sdk-for-python/pull/39037)) -- Fix to handle large messages being sent twice due to incoming flow frames triggering a resend. ([#38067](https://github.com/Azure/azure-sdk-for-python/pull/38067)) +- Fixed a bug where pyAMQP was doubly retrying, causing higher latency on reconnect. ([#39037](https://github.com/Azure/azure-sdk-for-python/pull/39037)) - Missing await in sender async on pyAMQP. ([#39182](https://github.com/Azure/azure-sdk-for-python/pull/39182)) - Improved AutoLockRenewer to renew locks for more registered messages. ([#37340](https://github.com/Azure/azure-sdk-for-python/issues/37340)) - Fixed a bug where message IDs in management operation requests were not unique. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/azure/servicebus/_common/mgmt_handlers.py new/azure_servicebus-7.14.1/azure/servicebus/_common/mgmt_handlers.py --- old/azure_servicebus-7.14.0/azure/servicebus/_common/mgmt_handlers.py 2025-02-13 16:17:52.000000000 +0100 +++ new/azure_servicebus-7.14.1/azure/servicebus/_common/mgmt_handlers.py 2025-03-12 18:40:35.000000000 +0100 @@ -52,12 +52,14 @@ ): condition = message.application_properties.get(MGMT_RESPONSE_MESSAGE_ERROR_CONDITION) if status_code == 200: - return amqp_transport.parse_received_message( + parsed_messages = amqp_transport.parse_received_message( message, message_type=ServiceBusReceivedMessage, receiver=receiver, is_peeked_message=True ) + if parsed_messages: + receiver._last_received_sequenced_number = parsed_messages[-1].sequence_number # pylint: disable=protected-access + return parsed_messages if status_code in [202, 204]: return [] - amqp_transport.handle_amqp_mgmt_error( _LOGGER, "Message peek failed.", condition, description, status_code ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/azure/servicebus/_pyamqp/_transport.py new/azure_servicebus-7.14.1/azure/servicebus/_pyamqp/_transport.py --- old/azure_servicebus-7.14.0/azure/servicebus/_pyamqp/_transport.py 2025-02-13 16:17:52.000000000 +0100 +++ new/azure_servicebus-7.14.1/azure/servicebus/_pyamqp/_transport.py 2025-03-12 18:40:35.000000000 +0100 @@ -190,7 +190,11 @@ # are we already connected? if self.connected: return - self._connect(self.host, self.port, self.connect_timeout) + self.sock = socket.create_connection((self.host, self.port), self.connect_timeout) + try: + set_cloexec(self.sock, True) + except NotImplementedError: + pass self._init_socket( self.socket_settings, self.socket_timeout, @@ -257,56 +261,6 @@ if non_bocking_timeout != prev: sock.settimeout(prev) - def _connect(self, host, port, timeout): - e = None - - # Below we are trying to avoid additional DNS requests for AAAA if A - # succeeds. This helps a lot in case when a hostname has an IPv4 entry - # in /etc/hosts but not IPv6. Without the (arguably somewhat twisted) - # logic below, getaddrinfo would attempt to resolve the hostname for - # both IP versions, which would make the resolver talk to configured - # DNS servers. If those servers are for some reason not available - # during resolution attempt (either because of system misconfiguration, - # or network connectivity problem), resolution process locks the - # _connect call for extended time. - addr_types = (socket.AF_INET, socket.AF_INET6) - addr_types_num = len(addr_types) - for n, family in enumerate(addr_types): - # first, resolve the address for a single address family - try: - entries = socket.getaddrinfo(host, port, family, socket.SOCK_STREAM, SOL_TCP) - entries_num = len(entries) - except socket.gaierror as exc: - # we may have depleted all our options - if n + 1 >= addr_types_num: - # if getaddrinfo succeeded before for another address - # family, reraise the previous socket.error since it's more - # relevant to users - raise e if e is not None else socket.error("failed to resolve broker hostname") from exc - continue # pragma: no cover - - # now that we have address(es) for the hostname, connect to broker - for i, res in enumerate(entries): - af, socktype, proto, _, sa = res - try: - self.sock = socket.socket(af, socktype, proto) - try: - set_cloexec(self.sock, True) - except NotImplementedError: - pass - self.sock.settimeout(timeout) - self.sock.connect(sa) - except socket.error as ex: - e = ex - if self.sock is not None: - self.sock.close() - self.sock = None - # we may have depleted all our options - if i + 1 >= entries_num and n + 1 >= addr_types_num: - raise - else: - # hurray, we established connection - return def _init_socket(self, socket_settings, socket_timeout): self.sock.settimeout(None) # set socket back to blocking mode diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/azure/servicebus/_pyamqp/aio/_link_async.py new/azure_servicebus-7.14.1/azure/servicebus/_pyamqp/aio/_link_async.py --- old/azure_servicebus-7.14.0/azure/servicebus/_pyamqp/aio/_link_async.py 2025-02-13 16:17:52.000000000 +0100 +++ new/azure_servicebus-7.14.1/azure/servicebus/_pyamqp/aio/_link_async.py 2025-03-12 18:40:35.000000000 +0100 @@ -237,8 +237,13 @@ # TODO: on_detach_hook if frame[2]: # error # frame[2][0] is condition, frame[2][1] is description, frame[2][2] is info - error_cls = AMQPLinkRedirect if frame[2][0] == ErrorCondition.LinkRedirect else AMQPLinkError - self._error = error_cls(condition=frame[2][0], description=frame[2][1], info=frame[2][2]) + condition = frame[2][0] + error_cls = AMQPLinkRedirect if condition == ErrorCondition.LinkRedirect else AMQPLinkError + # description and info are optional fields, from the AMQP spec. + # https://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-transport-v1.0-os.html#type-error + description = None if len(frame[2]) < 2 else frame[2][1] + info = None if len(frame[2]) < 3 else frame[2][2] + self._error = error_cls(condition=condition, description=description, info=info) await self._set_state(LinkState.ERROR) else: if self.state != LinkState.DETACH_SENT: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/azure/servicebus/_pyamqp/link.py new/azure_servicebus-7.14.1/azure/servicebus/_pyamqp/link.py --- old/azure_servicebus-7.14.0/azure/servicebus/_pyamqp/link.py 2025-02-13 16:17:52.000000000 +0100 +++ new/azure_servicebus-7.14.1/azure/servicebus/_pyamqp/link.py 2025-03-12 18:40:35.000000000 +0100 @@ -232,8 +232,15 @@ # TODO: on_detach_hook if frame[2]: # error # frame[2][0] is condition, frame[2][1] is description, frame[2][2] is info - error_cls = AMQPLinkRedirect if frame[2][0] == ErrorCondition.LinkRedirect else AMQPLinkError - self._error = error_cls(condition=frame[2][0], description=frame[2][1], info=frame[2][2]) + condition = frame[2][0] + error_cls = AMQPLinkRedirect if condition == ErrorCondition.LinkRedirect else AMQPLinkError + + # description and info are optional fields, from the AMQP spec. + # https://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-transport-v1.0-os.html#type-error + description = None if len(frame[2]) < 2 else frame[2][1] + info = None if len(frame[2]) < 3 else frame[2][2] + + self._error = error_cls(condition=condition, description=description, info=info) self._set_state(LinkState.ERROR) else: if self.state != LinkState.DETACH_SENT: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/azure/servicebus/_servicebus_receiver.py new/azure_servicebus-7.14.1/azure/servicebus/_servicebus_receiver.py --- old/azure_servicebus-7.14.0/azure/servicebus/_servicebus_receiver.py 2025-02-13 16:17:52.000000000 +0100 +++ new/azure_servicebus-7.14.1/azure/servicebus/_servicebus_receiver.py 2025-03-12 18:40:35.000000000 +0100 @@ -72,7 +72,7 @@ _LOGGER = logging.getLogger(__name__) -class ServiceBusReceiver(BaseHandler, ReceiverMixin): +class ServiceBusReceiver(BaseHandler, ReceiverMixin): # pylint: disable=too-many-instance-attributes """The ServiceBusReceiver class defines a high level interface for receiving messages from the Azure Service Bus Queue or Topic Subscription. @@ -769,7 +769,11 @@ if timeout is not None and timeout <= 0: raise ValueError("The timeout must be greater than 0.") if not sequence_number: - sequence_number = self._last_received_sequenced_number or 1 + sequence_number = ( + self._last_received_sequenced_number + 1 + if self._last_received_sequenced_number + else 1 + ) if int(max_message_count) < 0: raise ValueError("max_message_count must be 1 or greater.") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/azure/servicebus/_version.py new/azure_servicebus-7.14.1/azure/servicebus/_version.py --- old/azure_servicebus-7.14.0/azure/servicebus/_version.py 2025-02-13 16:17:52.000000000 +0100 +++ new/azure_servicebus-7.14.1/azure/servicebus/_version.py 2025-03-12 18:40:35.000000000 +0100 @@ -3,4 +3,4 @@ # Licensed under the MIT License. # ------------------------------------ -VERSION = "7.14.0" +VERSION = "7.14.1" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/azure/servicebus/aio/_servicebus_receiver_async.py new/azure_servicebus-7.14.1/azure/servicebus/aio/_servicebus_receiver_async.py --- old/azure_servicebus-7.14.0/azure/servicebus/aio/_servicebus_receiver_async.py 2025-02-13 16:17:52.000000000 +0100 +++ new/azure_servicebus-7.14.1/azure/servicebus/aio/_servicebus_receiver_async.py 2025-03-12 18:40:35.000000000 +0100 @@ -748,7 +748,11 @@ if timeout is not None and timeout <= 0: raise ValueError("The timeout must be greater than 0.") if not sequence_number: - sequence_number = self._last_received_sequenced_number or 1 + sequence_number = ( + self._last_received_sequenced_number + 1 + if self._last_received_sequenced_number + else 1 + ) if int(max_message_count) < 0: raise ValueError("max_message_count must be 1 or greater.") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/azure/servicebus/management/_models.py new/azure_servicebus-7.14.1/azure/servicebus/management/_models.py --- old/azure_servicebus-7.14.0/azure/servicebus/management/_models.py 2025-02-13 16:17:52.000000000 +0100 +++ new/azure_servicebus-7.14.1/azure/servicebus/management/_models.py 2025-03-12 18:40:35.000000000 +0100 @@ -1452,6 +1452,7 @@ @classmethod def _from_internal_entity(cls, internal_authorization_rule: InternalAuthorizationRule) -> "AuthorizationRule": authorization_rule = cls() + authorization_rule.type = internal_authorization_rule.type authorization_rule.claim_type = internal_authorization_rule.claim_type authorization_rule.claim_value = internal_authorization_rule.claim_value authorization_rule.rights = internal_authorization_rule.rights @@ -1465,6 +1466,7 @@ def _to_internal_entity(self) -> InternalAuthorizationRule: internal_entity = InternalAuthorizationRule() + internal_entity.type = self.type internal_entity.claim_type = self.claim_type internal_entity.claim_value = self.claim_value internal_entity.rights = self.rights diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/azure_servicebus.egg-info/PKG-INFO new/azure_servicebus-7.14.1/azure_servicebus.egg-info/PKG-INFO --- old/azure_servicebus-7.14.0/azure_servicebus.egg-info/PKG-INFO 2025-02-13 16:20:14.000000000 +0100 +++ new/azure_servicebus-7.14.1/azure_servicebus.egg-info/PKG-INFO 2025-03-12 18:43:01.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: azure-servicebus -Version: 7.14.0 +Version: 7.14.1 Summary: Microsoft Azure Service Bus Client Library for Python Home-page: https://github.com/Azure/azure-sdk-for-python Author: Microsoft Corporation @@ -671,6 +671,13 @@ # Release History +## 7.14.1 (2025-03-12) + +### Bugs Fixed + +- Fixed a bug where service errors were incorrectly expected to have info/description fields set in all cases. +- Fixed a bug where the type in azure.servicebus.management.AuthorizationRule was not being correctly passed to the request. + ## 7.14.0 (2025-02-13) ### Features Added @@ -682,9 +689,7 @@ - Fixed a bug where async websocket disconnects were not being retried properly. ([#36280](https://github.com/Azure/azure-sdk-for-python/issues/36280)) - Fixed a bug where sending large messages with synchronous client caused a frame buffer offset error ([#37916](https://github.com/Azure/azure-sdk-for-python/issues/37916)) -- Fix to handle websocket disconnect/close on aiohttp, as aiohttp raises a `TypeError` while asserting bytes. ([#32061](https://github.com/Azure/azure-sdk-for-python/pull/32061)) -- Fixed a bug where pyAMQP was doubly retrying, causing latency on reconnect. ([#39037](https://github.com/Azure/azure-sdk-for-python/pull/39037)) -- Fix to handle large messages being sent twice due to incoming flow frames triggering a resend. ([#38067](https://github.com/Azure/azure-sdk-for-python/pull/38067)) +- Fixed a bug where pyAMQP was doubly retrying, causing higher latency on reconnect. ([#39037](https://github.com/Azure/azure-sdk-for-python/pull/39037)) - Missing await in sender async on pyAMQP. ([#39182](https://github.com/Azure/azure-sdk-for-python/pull/39182)) - Improved AutoLockRenewer to renew locks for more registered messages. ([#37340](https://github.com/Azure/azure-sdk-for-python/issues/37340)) - Fixed a bug where message IDs in management operation requests were not unique. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/tests/async_tests/test_queues_async.py new/azure_servicebus-7.14.1/tests/async_tests/test_queues_async.py --- old/azure_servicebus-7.14.0/tests/async_tests/test_queues_async.py 2025-02-13 16:17:52.000000000 +0100 +++ new/azure_servicebus-7.14.1/tests/async_tests/test_queues_async.py 2025-03-12 18:40:35.000000000 +0100 @@ -3682,3 +3682,117 @@ messages_in_queue = await receiver1.peek_messages() assert len(messages_in_queue) == 0 + + @pytest.mark.asyncio + @pytest.mark.liveTest + @pytest.mark.live_test_only + @CachedServiceBusResourceGroupPreparer(name_prefix="servicebustest") + @CachedServiceBusNamespacePreparer(name_prefix="servicebustest") + @ServiceBusQueuePreparer(name_prefix="servicebustest", dead_lettering_on_message_expiration=True) + @pytest.mark.parametrize("uamqp_transport", uamqp_transport_params, ids=uamqp_transport_ids) + @ArgPasserAsync() + async def test_queue_async_by_queue_client_peek_auto_increment( + self, uamqp_transport, *, servicebus_namespace=None, servicebus_queue=None, **kwargs + ): + fully_qualified_namespace = f"{servicebus_namespace.name}{SERVICEBUS_ENDPOINT_SUFFIX}" + credential = get_credential(is_async=True) + async with ServiceBusClient( + fully_qualified_namespace, credential, logging_enable=False, uamqp_transport=uamqp_transport + ) as sb_client: + + sender = sb_client.get_queue_sender(servicebus_queue.name) + async with sender: + messages = [] + for i in range(3): + message = ServiceBusMessage("Handler message no. {}".format(i), application_properties={"index": i}) + messages.append(message) + await sender.send_messages(messages) + + receiver = sb_client.get_queue_receiver(servicebus_queue.name, max_wait_time=5) + async with receiver: + peek_message = await receiver.peek_messages() + assert peek_message[0].application_properties[b"index"] == 0 + assert peek_message[0].sequence_number == 1 + peek_message = await receiver.peek_messages() + assert peek_message[0].application_properties[b"index"] == 1 + assert peek_message[0].sequence_number == 2 + peek_message = await receiver.peek_messages() + assert peek_message[0].application_properties[b"index"] == 2 + assert peek_message[0].sequence_number == 3 + + @pytest.mark.asyncio + @pytest.mark.liveTest + @pytest.mark.live_test_only + @CachedServiceBusResourceGroupPreparer(name_prefix="servicebustest") + @CachedServiceBusNamespacePreparer(name_prefix="servicebustest") + @ServiceBusQueuePreparer(name_prefix="servicebustest", dead_lettering_on_message_expiration=True) + @pytest.mark.parametrize("uamqp_transport", uamqp_transport_params, ids=uamqp_transport_ids) + @ArgPasserAsync() + async def test_queue_async_by_queue_client_peek_auto_increment_multiple( + self, uamqp_transport, *, servicebus_namespace=None, servicebus_queue=None, **kwargs + ): + fully_qualified_namespace = f"{servicebus_namespace.name}{SERVICEBUS_ENDPOINT_SUFFIX}" + credential = get_credential(is_async=True) + async with ServiceBusClient( + fully_qualified_namespace, credential, logging_enable=False, uamqp_transport=uamqp_transport + ) as sb_client: + + sender = sb_client.get_queue_sender(servicebus_queue.name) + async with sender: + messages = [] + for i in range(4): + message = ServiceBusMessage("Handler message no. {}".format(i), application_properties={"index": i}) + messages.append(message) + await sender.send_messages(messages) + + receiver = sb_client.get_queue_receiver(servicebus_queue.name, max_wait_time=5) + async with receiver: + peek_message = await receiver.peek_messages(max_message_count=2) + assert len(peek_message) == 2 + assert peek_message[0].application_properties[b"index"] == 0 + assert peek_message[0].sequence_number == 1 + assert peek_message[1].application_properties[b"index"] == 1 + assert peek_message[1].sequence_number == 2 + peek_message = await receiver.peek_messages(max_message_count=2) + assert len(peek_message) == 2 + assert peek_message[0].application_properties[b"index"] == 2 + assert peek_message[0].sequence_number == 3 + assert peek_message[1].application_properties[b"index"] == 3 + assert peek_message[1].sequence_number == 4 + + @pytest.mark.asyncio + @pytest.mark.liveTest + @pytest.mark.live_test_only + @CachedServiceBusResourceGroupPreparer(name_prefix="servicebustest") + @CachedServiceBusNamespacePreparer(name_prefix="servicebustest") + @ServiceBusQueuePreparer(name_prefix="servicebustest", dead_lettering_on_message_expiration=True) + @pytest.mark.parametrize("uamqp_transport", uamqp_transport_params, ids=uamqp_transport_ids) + @ArgPasserAsync() + async def test_queue_async_by_queue_client_peek_and_receive( + self, uamqp_transport, *, servicebus_namespace=None, servicebus_queue=None, **kwargs + ): + fully_qualified_namespace = f"{servicebus_namespace.name}{SERVICEBUS_ENDPOINT_SUFFIX}" + credential = get_credential(is_async=True) + async with ServiceBusClient( + fully_qualified_namespace, credential, logging_enable=False, uamqp_transport=uamqp_transport + ) as sb_client: + + sender = sb_client.get_queue_sender(servicebus_queue.name) + async with sender: + messages = [] + for i in range(4): + message = ServiceBusMessage("Handler message no. {}".format(i), application_properties={"index": i}) + messages.append(message) + await sender.send_messages(messages) + + receiver = sb_client.get_queue_receiver(servicebus_queue.name, max_wait_time=5) + async with receiver: + peeked_messages = await receiver.peek_messages(max_message_count=2) + + messages = await receiver.receive_messages(max_message_count=3) + last_received_sequnece_number = messages[-1].sequence_number + for message in messages: + await receiver.complete_message(message) + + peeked_messages = await receiver.peek_messages(max_message_count=2) + assert peeked_messages[0].sequence_number == last_received_sequnece_number + 1 \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/tests/mgmt_tests/async/test_mgmt_topics_async.py new/azure_servicebus-7.14.1/tests/mgmt_tests/async/test_mgmt_topics_async.py --- old/azure_servicebus-7.14.0/tests/mgmt_tests/async/test_mgmt_topics_async.py 2025-02-13 16:17:52.000000000 +0100 +++ new/azure_servicebus-7.14.1/tests/mgmt_tests/async/test_mgmt_topics_async.py 2025-03-12 18:40:35.000000000 +0100 @@ -6,9 +6,11 @@ import logging import pytest import datetime +import secrets +import base64 from azure.servicebus.aio.management import ServiceBusAdministrationClient -from azure.servicebus.management import TopicProperties +from azure.servicebus.management import TopicProperties, AccessRights, AuthorizationRule from azure.servicebus.aio._base_handler_async import ServiceBusSharedKeyCredential from azure.servicebus.management import ApiVersion from tests.utilities import get_logger @@ -54,6 +56,19 @@ topic_name = "iweidk" topic_name_2 = "dkozq" topic_name_3 = "famviq" + def generate_random_key(): + key256 = secrets.token_bytes(32) + return base64.b64encode(key256).decode('utf-8') + + auth_rule = AuthorizationRule( + type="SharedAccessAuthorizationRule", + key_name="test_key", + claim_type="SharedAccessKey", + claim_value="None", + rights=[AccessRights.MANAGE, AccessRights.LISTEN, AccessRights.SEND], + primary_key=generate_random_key(), + secondary_key=generate_random_key(), + ) try: await mgmt_service.create_topic( topic_name=topic_name, @@ -64,6 +79,7 @@ enable_express=True, enable_partitioning=True, max_size_in_megabytes=3072, + authorization_rules=[auth_rule], ) topic = await mgmt_service.get_topic(topic_name) assert topic.name == topic_name @@ -74,6 +90,8 @@ assert topic.enable_express assert topic.enable_partitioning assert topic.max_size_in_megabytes % 3072 == 0 + assert topic.authorization_rules[0].key_name == "test_key" + assert len(topic.authorization_rules[0].rights) == 3 await mgmt_service.create_topic( topic_name=topic_name_2, @@ -194,11 +212,25 @@ ) await clear_topics(mgmt_service) topic_name = "fjrui" + def generate_random_key(): + key256 = secrets.token_bytes(32) + return base64.b64encode(key256).decode('utf-8') + + auth_rule = AuthorizationRule( + type="SharedAccessAuthorizationRule", + key_name="test_key_listen", + claim_type="SharedAccessKey", + claim_value="None", + rights=[AccessRights.LISTEN], + primary_key=generate_random_key(), + secondary_key=generate_random_key(), + ) try: topic_description = await mgmt_service.create_topic(topic_name) # Try updating one setting. topic_description.default_message_time_to_live = datetime.timedelta(minutes=2) + topic_description.authorization_rules = [auth_rule] await mgmt_service.update_topic(topic_description) topic_description = await mgmt_service.get_topic(topic_name) assert topic_description.default_message_time_to_live == datetime.timedelta(minutes=2) @@ -214,6 +246,8 @@ # topic_description.requires_duplicate_detection = True # Read only # topic_description.requires_session = True # Cannot be changed after creation topic_description.support_ordering = True + assert topic_description.authorization_rules[0].key_name == "test_key_listen" + assert len(topic_description.authorization_rules[0].rights) == 1 await mgmt_service.update_topic(topic_description) topic_description = await mgmt_service.get_topic(topic_name) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/tests/mgmt_tests/test_mgmt_queues.py new/azure_servicebus-7.14.1/tests/mgmt_tests/test_mgmt_queues.py --- old/azure_servicebus-7.14.0/tests/mgmt_tests/test_mgmt_queues.py 2025-02-13 16:17:52.000000000 +0100 +++ new/azure_servicebus-7.14.1/tests/mgmt_tests/test_mgmt_queues.py 2025-03-12 18:40:35.000000000 +0100 @@ -9,8 +9,10 @@ import uuid import datetime import functools +import secrets +import base64 -from azure.servicebus.management import ServiceBusAdministrationClient, QueueProperties, ApiVersion +from azure.servicebus.management import ServiceBusAdministrationClient, QueueProperties, ApiVersion, AuthorizationRule, AccessRights from azure.servicebus._common.utils import utc_now from tests.utilities import get_logger from azure.core.exceptions import HttpResponseError, ResourceNotFoundError, ResourceExistsError @@ -270,6 +272,20 @@ queue_name_3 = "famviq" topic_name = "aghadh" + def generate_random_key(): + key256 = secrets.token_bytes(32) + return base64.b64encode(key256).decode('utf-8') + + auth_rule = AuthorizationRule( + type="SharedAccessAuthorizationRule", + key_name="test_key", + claim_type="SharedAccessKey", + claim_value="None", + rights=[AccessRights.MANAGE, AccessRights.LISTEN, AccessRights.SEND], + primary_key=generate_random_key(), + secondary_key=generate_random_key(), + ) + # TODO: Why don't we have an input model (queueOptions? as superclass of QueueProperties?) and output model to not show these params? # TODO: This fails with the following: E msrest.exceptions.DeserializationError: Find several XML 'prefix:DeadLetteringOnMessageExpiration' where it was not expected .tox\whl\lib\site-packages\msrest\serialization.py:1262: DeserializationError mgmt_service.create_topic(topic_name) @@ -289,6 +305,7 @@ max_size_in_megabytes=3072, # requires_duplicate_detection=True, requires_session=True, + authorization_rules=[auth_rule], ) mgmt_service.create_queue( @@ -335,6 +352,8 @@ # To know more visit https://aka.ms/sbResourceMgrExceptions. # assert queue.requires_duplicate_detection == True assert queue.requires_session == True + assert queue.authorization_rules[0].key_name == "test_key" + assert len(queue.authorization_rules[0].rights) == 3 queue2 = mgmt_service.get_queue(queue_name_2) assert queue2.name == queue_name_2 @@ -484,13 +503,30 @@ topic_name = "sagho" queue_description = mgmt_service.create_queue(queue_name) mgmt_service.create_topic(topic_name) + def generate_random_key(): + key256 = secrets.token_bytes(32) + return base64.b64encode(key256).decode('utf-8') + + auth_rule = AuthorizationRule( + type="SharedAccessAuthorizationRule", + key_name="test_key_listen", + claim_type="SharedAccessKey", + claim_value="None", + rights=[AccessRights.LISTEN], + primary_key=generate_random_key(), + secondary_key=generate_random_key(), + ) + try: # Try updating one setting. queue_description.lock_duration = datetime.timedelta(minutes=2) + queue_description.authorization_rules = [auth_rule] mgmt_service.update_queue(queue_description) queue_description = mgmt_service.get_queue(queue_name) assert queue_description.lock_duration == datetime.timedelta(minutes=2) + assert queue_description.authorization_rules[0].key_name == "test_key_listen" + assert len(queue_description.authorization_rules[0].rights) == 1 # Update forwarding settings with entity name. queue_description.forward_to = topic_name diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/tests/servicebus_preparer.py new/azure_servicebus-7.14.1/tests/servicebus_preparer.py --- old/azure_servicebus-7.14.0/tests/servicebus_preparer.py 2025-02-13 16:17:52.000000000 +0100 +++ new/azure_servicebus-7.14.1/tests/servicebus_preparer.py 2025-03-12 18:40:35.000000000 +0100 @@ -157,6 +157,9 @@ client_kwargs=client_kwargs, ) self.location = location + # Disable local auth if testing locally (without TME). + # We're running in the pipelines if AZURESUBSCRIPTION_SERVICE_CONNECTION_ID is set. + self.disable_local_auth = True if not os.environ.get("AZURESUBSCRIPTION_SERVICE_CONNECTION_ID") else False self.sku = sku self.resource_group_parameter_name = resource_group_parameter_name self.parameter_name = parameter_name @@ -181,6 +184,7 @@ { "sku": {"name": self.sku}, "location": self.location, + "disableLocalAuth": self.disable_local_auth, }, ) self.resource = namespace_async_operation.result() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_servicebus-7.14.0/tests/test_queues.py new/azure_servicebus-7.14.1/tests/test_queues.py --- old/azure_servicebus-7.14.0/tests/test_queues.py 2025-02-13 16:17:52.000000000 +0100 +++ new/azure_servicebus-7.14.1/tests/test_queues.py 2025-03-12 18:40:35.000000000 +0100 @@ -3720,3 +3720,117 @@ messages_in_queue = receiver1.peek_messages() assert len(messages_in_queue) == 0 + + @pytest.mark.liveTest + @pytest.mark.live_test_only + @CachedServiceBusResourceGroupPreparer(name_prefix="servicebustest") + @CachedServiceBusNamespacePreparer(name_prefix="servicebustest") + @ServiceBusQueuePreparer(name_prefix="servicebustest", dead_lettering_on_message_expiration=True) + @pytest.mark.parametrize("uamqp_transport", uamqp_transport_params, ids=uamqp_transport_ids) + @ArgPasser() + def test_queue_by_queue_client_peek_auto_increment( + self, uamqp_transport, *, servicebus_namespace=None, servicebus_queue=None, **kwargs + ): + fully_qualified_namespace = f"{servicebus_namespace.name}{SERVICEBUS_ENDPOINT_SUFFIX}" + credential = get_credential() + with ServiceBusClient( + fully_qualified_namespace, credential, logging_enable=False, uamqp_transport=uamqp_transport + ) as sb_client: + + sender = sb_client.get_queue_sender(servicebus_queue.name) + with sender: + messages = [] + for i in range(3): + message = ServiceBusMessage("Handler message no. {}".format(i), application_properties={"index": i}) + messages.append(message) + sender.send_messages(messages) + + receiver = sb_client.get_queue_receiver(servicebus_queue.name, max_wait_time=5) + with receiver: + peek_message = receiver.peek_messages() + assert peek_message[0].application_properties[b"index"] == 0 + assert peek_message[0].sequence_number == 1 + peek_message = receiver.peek_messages() + assert peek_message[0].application_properties[b"index"] == 1 + assert peek_message[0].sequence_number == 2 + peek_message = receiver.peek_messages() + assert peek_message[0].application_properties[b"index"] == 2 + assert peek_message[0].sequence_number == 3 + + @pytest.mark.liveTest + @pytest.mark.live_test_only + @CachedServiceBusResourceGroupPreparer(name_prefix="servicebustest") + @CachedServiceBusNamespacePreparer(name_prefix="servicebustest") + @ServiceBusQueuePreparer(name_prefix="servicebustest", dead_lettering_on_message_expiration=True) + @pytest.mark.parametrize("uamqp_transport", uamqp_transport_params, ids=uamqp_transport_ids) + @ArgPasser() + def test_queue_by_queue_client_peek_auto_increment_multiple( + self, uamqp_transport, *, servicebus_namespace=None, servicebus_queue=None, **kwargs + ): + fully_qualified_namespace = f"{servicebus_namespace.name}{SERVICEBUS_ENDPOINT_SUFFIX}" + credential = get_credential() + with ServiceBusClient( + fully_qualified_namespace, credential, logging_enable=False, uamqp_transport=uamqp_transport + ) as sb_client: + + sender = sb_client.get_queue_sender(servicebus_queue.name) + with sender: + messages = [] + for i in range(4): + message = ServiceBusMessage("Handler message no. {}".format(i), application_properties={"index": i}) + messages.append(message) + sender.send_messages(messages) + + receiver = sb_client.get_queue_receiver(servicebus_queue.name, max_wait_time=5) + with receiver: + peek_message = receiver.peek_messages(max_message_count=2) + assert len(peek_message) == 2 + assert peek_message[0].application_properties[b"index"] == 0 + assert peek_message[0].sequence_number == 1 + assert peek_message[1].application_properties[b"index"] == 1 + assert peek_message[1].sequence_number == 2 + peek_message = receiver.peek_messages(max_message_count=2) + assert len(peek_message) == 2 + assert peek_message[0].application_properties[b"index"] == 2 + assert peek_message[0].sequence_number == 3 + assert peek_message[1].application_properties[b"index"] == 3 + assert peek_message[1].sequence_number == 4 + + @pytest.mark.liveTest + @pytest.mark.live_test_only + @CachedServiceBusResourceGroupPreparer(name_prefix="servicebustest") + @CachedServiceBusNamespacePreparer(name_prefix="servicebustest") + @ServiceBusQueuePreparer(name_prefix="servicebustest", dead_lettering_on_message_expiration=True) + @pytest.mark.parametrize("uamqp_transport", uamqp_transport_params, ids=uamqp_transport_ids) + @ArgPasser() + def test_queue_by_queue_client_peek_and_receive( + self, uamqp_transport, *, servicebus_namespace=None, servicebus_queue=None, **kwargs + ): + fully_qualified_namespace = f"{servicebus_namespace.name}{SERVICEBUS_ENDPOINT_SUFFIX}" + credential = get_credential() + with ServiceBusClient( + fully_qualified_namespace, credential, logging_enable=False, uamqp_transport=uamqp_transport + ) as sb_client: + + sender = sb_client.get_queue_sender(servicebus_queue.name) + with sender: + messages = [] + for i in range(4): + message = ServiceBusMessage("Handler message no. {}".format(i), application_properties={"index": i}) + messages.append(message) + sender.send_messages(messages) + + receiver = sb_client.get_queue_receiver(servicebus_queue.name, max_wait_time=5) + with receiver: + receiver = sb_client.get_queue_receiver(servicebus_queue.name, max_wait_time=5) + peeked_messages = receiver.peek_messages(max_message_count=2) + + messages = receiver.receive_messages(max_message_count=3) + last_received_sequnece_number = messages[-1].sequence_number + for message in messages: + receiver.complete_message(message) + + peeked_messages = receiver.peek_messages(max_message_count=2) + assert peeked_messages[0].sequence_number == last_received_sequnece_number + 1 + + \ No newline at end of file