def parse_raw_message(self, consumer, raw_message): """ Create an `SQSMessage` from SQS data. """ message_id = self.parse_message_id(raw_message) receipt_handle = self.parse_receipt_handle(raw_message) attributes = raw_message.get("Attributes", {}) approximate_receive_count = int( attributes.get("ApproximateReceiveCount", 1)) body = self.parse_body(raw_message) if self.should_validate_md5: self.validate_md5(raw_message, body) message = self.parse_message(body) media_type, content = self.parse_media_type_and_content(message) return SQSMessage( consumer=consumer, content=content, media_type=media_type, message_id=message_id, receipt_handle=receipt_handle, approximate_receive_count=approximate_receive_count, )
def test_nack_with_visibility_timeout_via_exception(): """ Consumer raises Nack; calls nack with visibility timeout """ visibility_timeout_seconds = 2 graph = ExampleDaemon.create_for_testing().graph message = SQSMessage( consumer=graph.sqs_consumer, content=None, media_type=DerivedSchema.MEDIA_TYPE, message_id=MESSAGE_ID, receipt_handle=RECEIPT_HANDLE, ) with patch.object(graph.sqs_consumer.backoff_policy, "visibility_timeout_seconds", visibility_timeout_seconds): try: with message: raise Nack(visibility_timeout_seconds) except Nack: pass graph.sqs_consumer.sqs_client.change_message_visibility.assert_called_with( QueueUrl="queue", ReceiptHandle=RECEIPT_HANDLE, VisibilityTimeout=visibility_timeout_seconds, )
def test_handle_with_no_context(): """ Test that when no context is added the dispatcher behaves sanely. """ daemon = ExampleDaemon.create_for_testing() graph = daemon.graph # remove the sqs_message_context from the graph so we can test the dispatcher # defaulting logic graph._registry.entry_points.pop("sqs_message_context") content = dict(bar="baz") result = graph.sqs_message_dispatcher.handle_message( message=SQSMessage( consumer=None, content=content, media_type=DerivedSchema.MEDIA_TYPE, message_id=MESSAGE_ID, receipt_handle=None, ), bound_handlers=daemon.bound_handlers, ) assert_that(result, is_(equal_to(True))) assert_that(graph.sqs_message_dispatcher.sqs_message_context(content), is_(equal_to(dict())))
def test_ack(): """ Consumer delegates to SQS client. """ def loader(metadata): return dict( sqs_consumer=dict( sqs_queue_url=FOO_QUEUE_URL, visibility_timeout_seconds=None, ), pubsub_message_codecs=dict(default=FooSchema, ), ) graph = create_object_graph("example", testing=True, loader=loader) message = SQSMessage( consumer=graph.sqs_consumer, content=None, media_type=FooSchema.MEDIA_TYPE, message_id=MESSAGE_ID, receipt_handle=RECEIPT_HANDLE, ) message.ack() graph.sqs_consumer.sqs_client.delete_message.assert_called_with( QueueUrl='foo-queue-url', ReceiptHandle=RECEIPT_HANDLE, )
def test_nack_with_visibility_timeout_via_exception(): """ Consumer raises Nack; calls nack with visibility timeout """ visibility_timeout_seconds = 2 def loader(metadata): return dict( sqs_consumer=dict( sqs_queue_url=FOO_QUEUE_URL, visibility_timeout_seconds=visibility_timeout_seconds, ), pubsub_message_codecs=dict(default=FooSchema, ), ) graph = create_object_graph("example", testing=True, loader=loader) message = SQSMessage( consumer=graph.sqs_consumer, content=None, media_type=FooSchema.MEDIA_TYPE, message_id=MESSAGE_ID, receipt_handle=RECEIPT_HANDLE, ) try: with message: raise Nack(visibility_timeout_seconds) except Nack: pass graph.sqs_consumer.sqs_client.change_message_visibility.assert_called_with( QueueUrl='foo-queue-url', ReceiptHandle=RECEIPT_HANDLE, VisibilityTimeout=visibility_timeout_seconds, )
def setup(self): self.graph = ExampleDaemon.create_for_testing().graph self.opaque = self.graph.opaque self.message = SQSMessage( consumer=self.graph.sqs_consumer, content=None, media_type=DerivedSchema.MEDIA_TYPE, message_id=MESSAGE_ID, receipt_handle=RECEIPT_HANDLE, ) self.graph.sqs_consumer.sqs_client.reset_mock()
def setup(self): self.graph = ExampleDaemon.create_for_testing().graph self.message = SQSMessage( consumer=self.graph.sqs_consumer, content=dict( opaque_data=dict(foo="bar", ), uri=MESSAGE_URI, ), media_type=None, message_id=MESSAGE_ID, receipt_handle=None, )
def test_nack_without_visibility_timeout(): """ Consumer passes """ graph = ExampleDaemon.create_for_testing().graph message = SQSMessage( consumer=graph.sqs_consumer, content=None, media_type=DerivedSchema.MEDIA_TYPE, message_id=MESSAGE_ID, receipt_handle=RECEIPT_HANDLE, ) message.nack() graph.sqs_consumer.sqs_client.change_message_visibility.assert_not_called()
def test_exponential_timeout(): message = SQSMessage( None, None, None, None, None, approximate_receive_count=1, ) backoff_policy = ExponentialBackoffPolicy() assert_that( backoff_policy.compute_backoff_timeout(message, None), is_(equal_to(1)), )
def test_message_timeout(): message = SQSMessage( None, None, None, None, None, approximate_receive_count=1, ) backoff_policy = NaiveBackoffPolicy(42) assert_that( backoff_policy.compute_backoff_timeout(message, 77), is_(equal_to(77)), )
def test_trace_message_dispatch(): daemon = ExampleDaemon.create_for_testing() graph = daemon.graph dispatcher = graph.sqs_message_dispatcher content = dict(bar="baz", uri="http://example.com", opaque_data={ "X-Request-Id": "req-id-5678", "x-dynatrace": "tag-5678", }) message = SQSMessage( approximate_receive_count=0, consumer=graph.sqs_consumer, content=content, media_type=DerivedSchema.MEDIA_TYPE, message_id="message-id-5678", receipt_handle=None, ) graph.sqs_consumer.sqs_client.reset_mock() with patch.object(tracing, "oneagent") as oneagent, \ patch.object(tracing, "ChannelType"), \ patch.object(tracing, "Channel") as channel, \ patch.object(tracing, "MessagingDestinationType") as messagingdestinationtype: result = dispatcher.handle_message( message=message, bound_handlers=daemon.bound_handlers, ) assert_that(result.result, equal_to(MessageHandlingResultType.SUCCEEDED)) sdk = oneagent.get_sdk.return_value sdk.create_messaging_system_info.assert_called_once_with( "SQS", "queue", messagingdestinationtype.QUEUE, channel.return_value) sdk.trace_incoming_message_process.assert_called_once_with( sdk.create_messaging_system_info.return_value, str_tag="tag-5678", ) tracer_manager = sdk.trace_incoming_message_process.return_value tracer_manager.__enter__.assert_called_once_with() tracer_obj = tracer_manager.__enter__.return_value tracer_obj.set_vendor_message_id.assert_called_once_with( "message-id-5678") tracer_obj.set_correlation_id.assert_called_once_with("req-id-5678") tracer_manager.__exit__.assert_called_once_with(None, None, None)
def setup(self): self.daemon = ExampleDaemon.create_for_testing() self.graph = self.daemon.graph self.dispatcher = self.graph.sqs_message_dispatcher self.content = dict(bar="baz", uri="http://example.com") self.message = SQSMessage( approximate_receive_count=0, consumer=self.graph.sqs_consumer, content=self.content, media_type=DerivedSchema.MEDIA_TYPE, message_id=MESSAGE_ID, receipt_handle=None, ) self.graph.sqs_consumer.sqs_client.reset_mock()
def test_ack(): """ Consumer delegates to SQS client. """ graph = ExampleDaemon.create_for_testing().graph message = SQSMessage( consumer=graph.sqs_consumer, content=None, media_type=DerivedSchema.MEDIA_TYPE, message_id=MESSAGE_ID, receipt_handle=RECEIPT_HANDLE, ) message.ack() graph.sqs_consumer.sqs_client.delete_message.assert_called_with( QueueUrl="queue", ReceiptHandle=RECEIPT_HANDLE, )
def test_scaled_exponential_timeout(): message = SQSMessage( None, None, None, None, None, approximate_receive_count=2, ) backoff_policy = ExponentialBackoffPolicy() with patch.object(backoff_policy, "randint") as mocked: mocked.return_value = 2 assert_that( backoff_policy.compute_backoff_timeout(message, None), is_(equal_to(2)), ) mocked.assert_called_with(1, 3)
def test_handle_with_skipping(): """ Test that skipping works """ daemon = ExampleDaemon.create_for_testing() graph = daemon.graph content = dict(bar="baz") result = graph.sqs_message_dispatcher.handle_message( message=SQSMessage( consumer=None, content=content, media_type=created("bar"), message_id=MESSAGE_ID, receipt_handle=None, ), bound_handlers=daemon.bound_handlers, ) assert_that(result, is_(equal_to(False)))
def test_handle_existing_opaque_message_id(self): self.message = SQSMessage( consumer=self.graph.sqs_consumer, content=dict( opaque_data=dict( foo="bar", message_id="opaque_message_id", ), uri=MESSAGE_URI, ), media_type=None, message_id=MESSAGE_ID, receipt_handle=None, ) with self.graph.opaque.initialize(self.graph.sqs_message_context, self.message): assert_that( self.graph.opaque.as_dict(), has_entries(message_id=MESSAGE_ID, ), )
def test_handle(): """ Test that the dispatcher handles a message and assigns context. """ daemon = ExampleDaemon.create_for_testing() graph = daemon.graph content = dict(bar="baz") sqs_message_context = Mock(return_value=dict()) with graph.opaque.initialize(sqs_message_context, content): result = graph.sqs_message_dispatcher.handle_message( message=SQSMessage( consumer=None, content=content, media_type=DerivedSchema.MEDIA_TYPE, message_id=MESSAGE_ID, receipt_handle=None, ), bound_handlers=daemon.bound_handlers, ) assert_that(result, is_(equal_to(True))) sqs_message_context.assert_called_once_with(content)