From b824c9ec49ffabc2481ed95651d7e6de0b1a22c5 Mon Sep 17 00:00:00 2001 From: JonNesvold Date: Fri, 4 Jul 2025 18:27:12 +0200 Subject: [PATCH 1/7] bugmaster --- reports/coverage/.coverage => .coverage | Bin 53248 -> 53248 bytes mrsal/amqp/subclass.py | 8 +- mrsal/superclass.py | 4 +- reports/coverage/coverage.xml | 1283 ----------------------- reports/junit/junit.xml | 1 - 5 files changed, 8 insertions(+), 1288 deletions(-) rename reports/coverage/.coverage => .coverage (95%) delete mode 100644 reports/coverage/coverage.xml delete mode 100644 reports/junit/junit.xml diff --git a/reports/coverage/.coverage b/.coverage similarity index 95% rename from reports/coverage/.coverage rename to .coverage index 12e46cb62817f93bc6e44fc30c245368608460a0..bc5d6665e95be136d3fcddff20a5f3c15c7f0217 100644 GIT binary patch delta 840 zcmZozz}&Eac|sCXm%zr9+4_t|n+#Y4L^${a8Te20PvZ~d=j1!W*T`qjC%9Qq;3uz- z4hJ(synaT0ZmND(ex81Aj&5pRdS+f~YEfohx_)j^abk{sUVcSdW=^VJL8Svb3qvC- zF6EO8{Us*n`SQp)vH_K`<5jlamsif26{w6GpEBK~oc!c$piAOQa*BcWyRiUu2;$Q* z+0;)+&Y78j!RkTAOw0_qxD0~&yCk)^q*y;WKQ9f$0$Oj(h)2`p7ydH9fEHrl6XHL^ zKb=2_pNsD(UlX4LFra_&dh0UBGZL^55zZWrERC!}~#xWa1li+C9YA$I=b4E#U&-}67` zzt4Z2|2+S3U?^|o*I;93VdUgv*JEP?(QJHdtRR{-j*SIGv(&LMgJ@>H$?y9`freaU c;Q!74h5s%8GoUdy_%8wt+0DQC;(UDr0OukR%K!iX delta 1825 zcma)+eQXnD9LJyQbA7q??w&DYoYGm625@0;+dADKW``J^GlueqBL9rKm)ltSa-%P> z7wNUe7)gws*&kB}mc)<{BSUQrf504sKVaxA0|J^Mo0^qnbIxU@Qflwo-8@Z#Ak0Je zhj*5gwK}?NZo%vBR_N^pg;wXM*O%_lD+HCFDCy^|l-cX>DA``16c!a`i=_%31nqgC zhlXkqU2PrhO5SQM1mbEG9$%;6ZgDhuGTl^ba;l^U_x4XLbhQYb-VV`~m8o;emaCeZ zJc3hf6|$q(kP!G*(_&M(bAKo2@iqU~<_=hB!J>8Jt|}D-_QJWng2(IOG7HN@%J5Z0 zeog<3)u{Iaa|cJ?V{BL6b^wuc%7&w`Zcmy{ZkA^0Jfi z%S(&T9uCJs-q}z*Vcm8&6px3lr;~4951T&Si{omYPT`7mvFXS6XftC}X#e8oz!d&7 zf|u}HN4G9U!%>7sZb?d#Ug=b)$oV<7Z&<*eF{>>A=U*@^YA@(nX9yQWv2%r>-qj?lVljsLDjxM7M l=q&mg4JqIAePqrwOVD)oG8nR#UZ1@vDtqa4k?}BB@i)k?w9o(m diff --git a/mrsal/amqp/subclass.py b/mrsal/amqp/subclass.py index 0690498..b6928bd 100644 --- a/mrsal/amqp/subclass.py +++ b/mrsal/amqp/subclass.py @@ -252,6 +252,7 @@ def publish_message( exchange_type: str, queue_name: str, auto_declare: bool = True, + passive: bool = True, prop: pika.BasicProperties | None = None, ) -> None: """Publish message to the exchange specifying routing key and properties. @@ -281,7 +282,8 @@ def publish_message( exchange_name=exchange_name, queue_name=queue_name, exchange_type=exchange_type, - routing_key=routing_key + routing_key=routing_key, + passive=passive ) try: # Publish the message by serializing it in json dump @@ -311,6 +313,7 @@ def publish_messages( self, mrsal_protocol_collection: dict[str, dict[str, str | bytes]], prop: pika.BasicProperties | None = None, + passive: bool = True ) -> None: """Publish message to the exchange specifying routing key and properties. @@ -339,7 +342,8 @@ def publish_messages( exchange_name=protocol.exchange_name, queue_name=protocol.queue_name, exchange_type=protocol.exchange_type, - routing_key=protocol.routing_key + routing_key=protocol.routing_key, + passive=passive ) try: # Publish the message by serializing it in json dump diff --git a/mrsal/superclass.py b/mrsal/superclass.py index b6bd013..c66134c 100644 --- a/mrsal/superclass.py +++ b/mrsal/superclass.py @@ -82,7 +82,7 @@ def _setup_exchange_and_queue(self, exchange_type=exchange_type, arguments=None, durable=exch_durable, - passive=False, + passive=passive, internal=internal, auto_delete=auto_delete ) @@ -177,7 +177,7 @@ async def _async_setup_exchange_and_queue(self, exchange_type=exchange_type, arguments=None, durable=exch_durable, - passive=False, + passive=passive, internal=internal, auto_delete=auto_delete ) diff --git a/reports/coverage/coverage.xml b/reports/coverage/coverage.xml deleted file mode 100644 index 9f79c59..0000000 --- a/reports/coverage/coverage.xml +++ /dev/null @@ -1,1283 +0,0 @@ - - - - - - /home/runner/work/mrsal/mrsal - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/reports/junit/junit.xml b/reports/junit/junit.xml deleted file mode 100644 index 106fc0b..0000000 --- a/reports/junit/junit.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file From 70af322dfb17bb31ff3aef0bd71c8544e3f21299 Mon Sep 17 00:00:00 2001 From: JonNesvold Date: Fri, 4 Jul 2025 18:27:25 +0200 Subject: [PATCH 2/7] king --- .coverage | Bin 53248 -> 53248 bytes reports/junit/junit.xml | 64 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 reports/junit/junit.xml diff --git a/.coverage b/.coverage index bc5d6665e95be136d3fcddff20a5f3c15c7f0217..5418558959d7561b5cd5adf026c98b683d78064e 100644 GIT binary patch delta 1061 zcmZvbT};zZ6vyvqyRUv+AsA56nJk)+2vZgXjZ!csghWAoP@h1=p$i`!Y-A{rZa(RY z)huy|Uo$ZzY6O+V>_KrD9|RRAYCwYWp>Y}%i82OtuGe;AB1#{6?m54n|GEF$T-RmH zbs4*b7p$Nu1mF{R7Vd&+%qVk>X<%4-hVGy_I*UU7Gtcqf4 zZG*j{##G7GRapHC4rW!#{~6bA z!0HoVA>*2V;5_5%f8adh#74}SkX^vIe@A&>Wd_9*11Q2t_!2h5255y463koXIdh&V zmVIY3{7#Bc>D()+Y+oQ0MfH1ruvgK8`~h^8Z9_(T{N)Q&bj&LiwU0y$JyDcby;=;3 zyFYjta%Wm=k zWZ+^$+fi;yY^Waz1BR+NZ?2714n;#rq+aey*AIURbv7rh*2zhUu0@*qw)vzlEI7u6 zNVIg*v=E61ui_$jMFH{P!_}w)gD|Kwg#85`;Di8@^no~h;{YyFM?oy>>`)jy!_~+yOMkj zS_a+DEuibW*91BxAse_b0D_+ppL1I*?am{+GAEqF9fQ@MI;EmCgLx??PuPIvOX6(n zv3|$imaL(#k6DxQ;yjbW;tUG50~mu5I03_O1iprS@G*P{@4-8;UH+e^pi$YZilP#M UBojfePXwJV5wu!=pU<@R7u_76xc~qF delta 272 zcmZozz}&Eac>{}s2nU}a1OI9MY5alwoP0<48u{$`1UCx`{N!cQ;h4M-@ zk!^CJuM;aP3qvFK53aYhHeQNzPamqp_consumer = MrsalBlockingAMQP(host='localhost', port=5672, credentials=('user', 'password'), virtual_host='testboi', ssl=False, ve... prefetch_count=1, heartbeat=60, dlx_enable=True, max_retries=3, use_quorum_queues=True, blocked_connection_timeout=60) + + def test_publish_message(amqp_consumer): + """Test that the message is correctly published to the exchange.""" + amqp_consumer._setup_exchange_and_queue = Mock() + + message = b'{"data": "test_message"}' + exchange_name = 'test_x' + routing_key = 'test_route' + + amqp_consumer.publish_message( + exchange_name=exchange_name, + routing_key=routing_key, + message=message, + exchange_type='direct', + queue_name='test_q', + auto_declare=True + ) + +> amqp_consumer._setup_exchange_and_queue.assert_called_once_with( + exchange_name=exchange_name, + queue_name='test_q', + exchange_type='direct', + routing_key=routing_key + ) + +tests/test_mrsal_blocking_no_tls.py:187: +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ +/usr/local/lib/python3.12/unittest/mock.py:956: in assert_called_once_with + return self.assert_called_with(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + +self = <Mock id='140203246558032'>, args = () +kwargs = {'exchange_name': 'test_x', 'exchange_type': 'direct', 'queue_name': 'test_q', 'routing_key': 'test_route'} +expected = call(exchange_name='test_x', queue_name='test_q', exchange_type='direct', routing_key='test_route') +actual = call(exchange_name='test_x', queue_name='test_q', exchange_type='direct', routing_key='test_route', passive=True) +_error_message = <function NonCallableMock.assert_called_with.<locals>._error_message at 0x7f839ccdce00>, cause = None + + def assert_called_with(self, /, *args, **kwargs): + """assert that the last call was made with the specified arguments. + + Raises an AssertionError if the args and keyword args passed in are + different to the last call to the mock.""" + if self.call_args is None: + expected = self._format_mock_call_signature(args, kwargs) + actual = 'not called.' + error_message = ('expected call not found.\nExpected: %s\nActual: %s' + % (expected, actual)) + raise AssertionError(error_message) + + def _error_message(): + msg = self._format_mock_failure_message(args, kwargs) + return msg + expected = self._call_matcher(_Call((args, kwargs), two=True)) + actual = self._call_matcher(self.call_args) + if actual != expected: + cause = expected if isinstance(expected, Exception) else None +> raise AssertionError(_error_message()) from cause +E AssertionError: expected call not found. +E Expected: mock(exchange_name='test_x', queue_name='test_q', exchange_type='direct', routing_key='test_route') +E Actual: mock(exchange_name='test_x', queue_name='test_q', exchange_type='direct', routing_key='test_route', passive=True) + +/usr/local/lib/python3.12/unittest/mock.py:944: AssertionError \ No newline at end of file From fbeba50d297fd7bd57bf2a0cbc4a2d50593f3675 Mon Sep 17 00:00:00 2001 From: JonNesvold Date: Fri, 4 Jul 2025 18:27:33 +0200 Subject: [PATCH 3/7] ugh --- reports/junit/junit.xml | 64 ----------------------------------------- 1 file changed, 64 deletions(-) delete mode 100644 reports/junit/junit.xml diff --git a/reports/junit/junit.xml b/reports/junit/junit.xml deleted file mode 100644 index 47fff87..0000000 --- a/reports/junit/junit.xml +++ /dev/null @@ -1,64 +0,0 @@ -amqp_consumer = MrsalBlockingAMQP(host='localhost', port=5672, credentials=('user', 'password'), virtual_host='testboi', ssl=False, ve... prefetch_count=1, heartbeat=60, dlx_enable=True, max_retries=3, use_quorum_queues=True, blocked_connection_timeout=60) - - def test_publish_message(amqp_consumer): - """Test that the message is correctly published to the exchange.""" - amqp_consumer._setup_exchange_and_queue = Mock() - - message = b'{"data": "test_message"}' - exchange_name = 'test_x' - routing_key = 'test_route' - - amqp_consumer.publish_message( - exchange_name=exchange_name, - routing_key=routing_key, - message=message, - exchange_type='direct', - queue_name='test_q', - auto_declare=True - ) - -> amqp_consumer._setup_exchange_and_queue.assert_called_once_with( - exchange_name=exchange_name, - queue_name='test_q', - exchange_type='direct', - routing_key=routing_key - ) - -tests/test_mrsal_blocking_no_tls.py:187: -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ -/usr/local/lib/python3.12/unittest/mock.py:956: in assert_called_once_with - return self.assert_called_with(*args, **kwargs) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - -self = <Mock id='140203246558032'>, args = () -kwargs = {'exchange_name': 'test_x', 'exchange_type': 'direct', 'queue_name': 'test_q', 'routing_key': 'test_route'} -expected = call(exchange_name='test_x', queue_name='test_q', exchange_type='direct', routing_key='test_route') -actual = call(exchange_name='test_x', queue_name='test_q', exchange_type='direct', routing_key='test_route', passive=True) -_error_message = <function NonCallableMock.assert_called_with.<locals>._error_message at 0x7f839ccdce00>, cause = None - - def assert_called_with(self, /, *args, **kwargs): - """assert that the last call was made with the specified arguments. - - Raises an AssertionError if the args and keyword args passed in are - different to the last call to the mock.""" - if self.call_args is None: - expected = self._format_mock_call_signature(args, kwargs) - actual = 'not called.' - error_message = ('expected call not found.\nExpected: %s\nActual: %s' - % (expected, actual)) - raise AssertionError(error_message) - - def _error_message(): - msg = self._format_mock_failure_message(args, kwargs) - return msg - expected = self._call_matcher(_Call((args, kwargs), two=True)) - actual = self._call_matcher(self.call_args) - if actual != expected: - cause = expected if isinstance(expected, Exception) else None -> raise AssertionError(_error_message()) from cause -E AssertionError: expected call not found. -E Expected: mock(exchange_name='test_x', queue_name='test_q', exchange_type='direct', routing_key='test_route') -E Actual: mock(exchange_name='test_x', queue_name='test_q', exchange_type='direct', routing_key='test_route', passive=True) - -/usr/local/lib/python3.12/unittest/mock.py:944: AssertionError \ No newline at end of file From 34eb76fbd561d11b2ae60b1a9c4437531ccc8e3e Mon Sep 17 00:00:00 2001 From: JonNesvold Date: Fri, 4 Jul 2025 18:49:38 +0200 Subject: [PATCH 4/7] okay --- mrsal/superclass.py | 219 ++++++++++++++++++++++++-------------------- 1 file changed, 119 insertions(+), 100 deletions(-) diff --git a/mrsal/superclass.py b/mrsal/superclass.py index 89308ce..ecc1e32 100644 --- a/mrsal/superclass.py +++ b/mrsal/superclass.py @@ -89,66 +89,71 @@ def _setup_exchange_and_queue(self, if queue_args is None: queue_args = {} + if not passive: + if dlx_enable: + dlx_name = dlx_exchange_name or f"{exchange_name}.dlx" + dlx_routing = dlx_routing_key or routing_key + try: + self._declare_exchange( + exchange=dlx_name, + exchange_type=exchange_type, + arguments=None, + durable=exch_durable, + passive=passive, + internal=internal, + auto_delete=auto_delete + ) + if self.verbose: + log.info(f"Dead letter exchange {dlx_name} declared successfully") + + except MrsalSetupError as e: + log.warning(f"DLX {dlx_name} might already exist or failed to create: {e}") + + queue_args.update({ + 'x-dead-letter-exchange': dlx_name, + 'x-dead-letter-routing-key': dlx_routing + }) + + if use_quorum_queues: + queue_args.update({ + 'x-queue-type': 'quorum', + 'x-quorum-initial-group-size': 3 + }) - if dlx_enable: - dlx_name = dlx_exchange_name or f"{exchange_name}.dlx" - dlx_routing = dlx_routing_key or routing_key - try: - self._declare_exchange( - exchange=dlx_name, - exchange_type=exchange_type, - arguments=None, - durable=exch_durable, - passive=passive, - internal=internal, - auto_delete=auto_delete - ) if self.verbose: - log.info(f"Dead letter exchange {dlx_name} declared successfully") - - except MrsalSetupError as e: - log.warning(f"DLX {dlx_name} might already exist or failed to create: {e}") - - queue_args.update({ - 'x-dead-letter-exchange': dlx_name, - 'x-dead-letter-routing-key': dlx_routing - }) - - if use_quorum_queues: - queue_args.update({ - 'x-queue-type': 'quorum', - 'x-quorum-initial-group-size': 3 - }) + log.info(f"Queue {queue_name} configured as quorum queue for enhanced reliability") - if self.verbose: - log.info(f"Queue {queue_name} configured as quorum queue for enhanced reliability") + # Add max length settings + if max_queue_length and max_queue_length > 0: + queue_args['x-max-length'] = max_queue_length + + if max_queue_length_bytes and max_queue_length_bytes > 0: + queue_args['x-max-length-bytes'] = max_queue_length_bytes - # Add max length settings - if max_queue_length and max_queue_length > 0: - queue_args['x-max-length'] = max_queue_length - - if max_queue_length_bytes and max_queue_length_bytes > 0: - queue_args['x-max-length-bytes'] = max_queue_length_bytes + # Add overflow behavior + if queue_overflow in ["drop-head", "reject-publish"]: + queue_args['x-overflow'] = queue_overflow - # Add overflow behavior - if queue_overflow in ["drop-head", "reject-publish"]: - queue_args['x-overflow'] = queue_overflow + # Add single active consumer + if single_active_consumer: + queue_args['x-single-active-consumer'] = True - # Add single active consumer - if single_active_consumer: - queue_args['x-single-active-consumer'] = True + # Add lazy queue setting + if lazy_queue: + queue_args['x-queue-mode'] = 'lazy' - # Add lazy queue setting - if lazy_queue: - queue_args['x-queue-mode'] = 'lazy' + if self.verbose and queue_args: + log.info(f"Queue {queue_name} configured with arguments: {queue_args}") + else: + queue_args = {} + if self.verbose: + log.info(f"Passive mode: checking existence of queue {queue_name} without configuration") - if self.verbose and queue_args: - log.info(f"Queue {queue_name} configured with arguments: {queue_args}") declare_exhange_dict = { 'exchange': exchange_name, 'exchange_type': exchange_type, - 'arguments': exch_args, + 'arguments': exch_args if not passive else None, 'durable': exch_durable, 'passive': passive, 'internal': internal, @@ -174,9 +179,13 @@ def _setup_exchange_and_queue(self, try: self._declare_exchange(**declare_exhange_dict) self._declare_queue(**declare_queue_dict) - self._declare_queue_binding(**declare_queue_binding_dict) + if not passive: + self._declare_queue_binding(**declare_queue_binding_dict) self.auto_declare_ok = True - log.info(f"Exchange {exchange_name} and Queue {queue_name} set up successfully.") + if not passive: + log.info(f"Exchange {exchange_name} and Queue {queue_name} set up successfully.") + else: + log.info(f"Exchange {exchange_name} and Queue {queue_name} set up successfully.") except MrsalSetupError as e: log.error(f'Splæt! I failed the declaration setup with {e}', exc_info=True) self.auto_declare_ok = False @@ -207,66 +216,72 @@ async def _async_setup_exchange_and_queue(self, if queue_args is None: queue_args = {} - if dlx_enable: - dlx_name = dlx_exchange_name or f"{exchange_name}.dlx" - dlx_routing = dlx_routing_key or routing_key - - try: - await self._async_declare_exchange( - exchange=dlx_name, - exchange_type=exchange_type, - arguments=None, - durable=exch_durable, - passive=passive, - internal=internal, - auto_delete=auto_delete - ) + if not passive: + if dlx_enable: + dlx_name = dlx_exchange_name or f"{exchange_name}.dlx" + dlx_routing = dlx_routing_key or routing_key + + try: + await self._async_declare_exchange( + exchange=dlx_name, + exchange_type=exchange_type, + arguments=None, + durable=exch_durable, + passive=passive, + internal=internal, + auto_delete=auto_delete + ) + + if self.verbose: + log.info(f"Dead letter exchange {dlx_name} declared successfully") + + except MrsalSetupError as e: + log.warning(f"DLX {dlx_name} might already exist or failed to create: {e}") + + queue_args.update({ + 'x-dead-letter-exchange': dlx_name, + 'x-dead-letter-routing-key': dlx_routing + }) + + if use_quorum_queues: + queue_args.update({ + 'x-queue-type': 'quorum', + 'x-quorum-initial-group-size': 3 # Good default for 3+ node clusters + }) if self.verbose: - log.info(f"Dead letter exchange {dlx_name} declared successfully") + log.info(f"Queue {queue_name} configured as quorum queue for enhanced reliability") - except MrsalSetupError as e: - log.warning(f"DLX {dlx_name} might already exist or failed to create: {e}") + if max_queue_length and max_queue_length > 0: + queue_args['x-max-length'] = max_queue_length + + if max_queue_length_bytes and max_queue_length_bytes > 0: + queue_args['x-max-length-bytes'] = max_queue_length_bytes - queue_args.update({ - 'x-dead-letter-exchange': dlx_name, - 'x-dead-letter-routing-key': dlx_routing - }) + # Add overflow behavior + if queue_overflow and queue_overflow in ["drop-head", "reject-publish"]: + queue_args['x-overflow'] = queue_overflow - if use_quorum_queues: - queue_args.update({ - 'x-queue-type': 'quorum', - 'x-quorum-initial-group-size': 3 # Good default for 3+ node clusters - }) - - if self.verbose: - log.info(f"Queue {queue_name} configured as quorum queue for enhanced reliability") + # Add single active consumer + if single_active_consumer: + queue_args['x-single-active-consumer'] = True - if max_queue_length and max_queue_length > 0: - queue_args['x-max-length'] = max_queue_length - - if max_queue_length_bytes and max_queue_length_bytes > 0: - queue_args['x-max-length-bytes'] = max_queue_length_bytes + # Add lazy queue setting + if lazy_queue: + queue_args['x-queue-mode'] = 'lazy' - # Add overflow behavior - if queue_overflow and queue_overflow in ["drop-head", "reject-publish"]: - queue_args['x-overflow'] = queue_overflow - - # Add single active consumer - if single_active_consumer: - queue_args['x-single-active-consumer'] = True - - # Add lazy queue setting - if lazy_queue: - queue_args['x-queue-mode'] = 'lazy' + if self.verbose and queue_args: + log.info(f"Queue {queue_name} configured with arguments: {queue_args}") + else: + queue_args = {} + if self.verbose: + log.info(f"Passive mode: checking existence of queue {queue_name} without configuration") - if self.verbose and queue_args: - log.info(f"Queue {queue_name} configured with arguments: {queue_args}") async_declare_exhange_dict = { 'exchange': exchange_name, 'exchange_type': exchange_type, - 'arguments': exch_args, + 'arguments': exch_args if not passive else None, 'durable': exch_durable, 'passive': passive, 'internal': internal, @@ -292,9 +307,13 @@ async def _async_setup_exchange_and_queue(self, # Declare exchange and queue exchange = await self._async_declare_exchange(**async_declare_exhange_dict) queue = await self._async_declare_queue(**async_declare_queue_dict) - await self._async_declare_queue_binding(queue=queue, exchange=exchange, **async_declare_queue_binding_dict) + if not passive: + await self._async_declare_queue_binding(queue=queue, exchange=exchange, **async_declare_queue_binding_dict) self.auto_declare_ok = True - log.info(f"Exchange {exchange_name} and Queue {queue_name} set up successfully.") + if not passive: + log.info(f"Exchange {exchange_name} and Queue {queue_name} set up successfully.") + else: + log.info(f"Exchange {exchange_name} and Queue {queue_name} set up successfully.") if dlx_enable: log.info(f"You have a dead letter exhange {dlx_name} for fault tolerance -- use it well young grasshopper!") return queue From 8e56c1c2be506c65f7e05d8d894cc3b8574470bd Mon Sep 17 00:00:00 2001 From: JonNesvold Date: Fri, 4 Jul 2025 18:56:21 +0200 Subject: [PATCH 5/7] added some testeroonies --- tests/test_mrsal_with_full_queue_config.py | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/test_mrsal_with_full_queue_config.py b/tests/test_mrsal_with_full_queue_config.py index 5789834..181776d 100644 --- a/tests/test_mrsal_with_full_queue_config.py +++ b/tests/test_mrsal_with_full_queue_config.py @@ -1,6 +1,7 @@ import pytest from unittest.mock import MagicMock from mrsal.amqp.subclass import MrsalBlockingAMQP +from pika.exceptions import ChannelClosedByBroker class TestPassiveDeclarationAndQueueSettings: @@ -112,3 +113,43 @@ def test_consumer_passive_declaration_default(self, mock_consumer): single_active_consumer=None, lazy_queue=None ) + + + def test_publisher_passive_false_with_queue_mismatch(self, mock_consumer): + """Test that publisher with passive=False can cause configuration conflicts""" + # Mock a RabbitMQ error when queue config doesn't match + mock_consumer._setup_exchange_and_queue.side_effect = ChannelClosedByBroker( + 406, "PRECONDITION_FAILED - inequivalent arg 'x-max-length'" + ) + + with pytest.raises(Exception): # Should fail with config mismatch + mock_consumer.publish_message( + exchange_name="test_exch", + routing_key="test_key", + message="test_message", + exchange_type="direct", + queue_name="test_queue", + passive=False, # This should cause problems! + # Publisher trying to configure queue = bad idea + ) + + def test_publisher_passive_true_no_conflicts(self, mock_consumer): + """Test that publisher with passive=True avoids configuration conflicts""" + # This should work fine - no config arguments sent + mock_consumer.publish_message( + exchange_name="test_exch", + routing_key="test_key", + message="test_message", + exchange_type="direct", + queue_name="test_queue", + passive=True # Safe mode - just check existence + ) + + # Should succeed without issues + mock_consumer._setup_exchange_and_queue.assert_called_with( + exchange_name="test_exch", + queue_name="test_queue", + exchange_type="direct", + routing_key="test_key", + passive=True + ) From 95184913c3b1ec4246326663356ece2cf809847e Mon Sep 17 00:00:00 2001 From: JonNesvold Date: Fri, 4 Jul 2025 18:57:22 +0200 Subject: [PATCH 6/7] vbump --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 240a393..0b4317b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ license = "GPL-3.0-or-later" maintainers = ["Jon E Nesvold "] name = "mrsal" readme = "README.md" -version = "2.1.0" +version = "2.1.1" homepage = "https://github.com/NeoMedSys/mrsal" repository = "https://github.com/NeoMedSys/mrsal" documentation = "https://neomedsys.github.io/mrsal/" From c9dd6f0358ac680de7ff3d3ed1d1872d68e67552 Mon Sep 17 00:00:00 2001 From: JonNesvold Date: Fri, 4 Jul 2025 16:58:48 +0000 Subject: [PATCH 7/7] Apply automatic changes --- README.md | 2 +- reports/coverage/.coverage | Bin 0 -> 53248 bytes reports/coverage/coverage.xml | 1361 +++++++++++++++++++++++++++++++++ reports/junit/junit.xml | 1 + 4 files changed, 1363 insertions(+), 1 deletion(-) create mode 100644 reports/coverage/.coverage create mode 100644 reports/coverage/coverage.xml create mode 100644 reports/junit/junit.xml diff --git a/README.md b/README.md index a405c26..8142a87 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # MRSAL AMQP -[![Release](https://img.shields.io/badge/release-2.1.0-blue.svg)](https://pypi.org/project/mrsal/) +[![Release](https://img.shields.io/badge/release-2.1.1-blue.svg)](https://pypi.org/project/mrsal/) [![Python 3.10+](https://img.shields.io/badge/python-3.10%7C3.11%7C3.12-blue.svg)](https://www.python.org/downloads/) [![Mrsal Workflow](https://github.com/NeoMedSys/mrsal/actions/workflows/mrsal.yaml/badge.svg?branch=main)](https://github.com/NeoMedSys/mrsal/actions/workflows/mrsal.yaml) [![Coverage](https://neomedsys.github.io/mrsal/reports/badges/coverage-badge.svg)](https://neomedsys.github.io/mrsal/reports/coverage/htmlcov/) diff --git a/reports/coverage/.coverage b/reports/coverage/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..b4bab4b578fa22dae8c074b38ec29c6961d08fdb GIT binary patch literal 53248 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 literal 0 HcmV?d00001 diff --git a/reports/coverage/coverage.xml b/reports/coverage/coverage.xml new file mode 100644 index 0000000..12bd931 --- /dev/null +++ b/reports/coverage/coverage.xml @@ -0,0 +1,1361 @@ + + + + + + /home/runner/work/mrsal/mrsal + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/reports/junit/junit.xml b/reports/junit/junit.xml new file mode 100644 index 0000000..6388327 --- /dev/null +++ b/reports/junit/junit.xml @@ -0,0 +1 @@ + \ No newline at end of file