From ebdab81bda1d848851ddf1d45ec59c0c74e07ce0 Mon Sep 17 00:00:00 2001 From: Madalyn Redding <66138537+m-redding@users.noreply.github.com> Date: Sat, 11 May 2024 21:40:33 -0400 Subject: [PATCH] [Event Hubs] Geo DR - Preview v2 (#43973) * primary changes * fix build * run scripts * fix unit tests * additional test tweaks * changelog * Update sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/BlobCheckpointStore/BlobCheckpointStoreInternal.cs Co-authored-by: Jesse Squire * Update sdk/eventhub/Azure.Messaging.EventHubs/CHANGELOG.md Co-authored-by: Jesse Squire * Update sdk/eventhub/Azure.Messaging.EventHubs/src/Azure.Messaging.EventHubs.csproj Co-authored-by: Jesse Squire * Update sdk/eventhub/Azure.Messaging.EventHubs/src/Processor/CheckpointPosition.cs Co-authored-by: Jesse Squire * Update sdk/eventhub/Azure.Messaging.EventHubs/src/Processor/CheckpointPosition.cs Co-authored-by: Jesse Squire * forgot to bring some things from the other preview pr --------- Co-authored-by: Jesse Squire --- ...ging.EventHubs.Processor.netstandard2.0.cs | 6 +- .../samples/Sample08_MockingClientTypes.md | 4 +- ...Azure.Messaging.EventHubs.Processor.csproj | 9 +- ...BlobCheckpointStoreInternal.Diagnostics.cs | 12 +- .../Diagnostics/BlobEventStoreEventSource.cs | 18 +-- .../EventProcessorClientEventSource.cs | 94 +++++++++++++-- .../src/EventProcessorClient.cs | 40 ++++-- .../src/Primitives/BlobCheckpointStore.cs | 3 +- ...CheckpointStoreInternalDiagnosticsTests.cs | 26 ++-- .../DiagnosticsActivitySourceTests.cs | 50 ++++++-- .../tests/Diagnostics/DiagnosticsTests.cs | 14 +-- .../Primitives/BlobCheckpointStoreTests.cs | 2 +- .../EventProcessorClientLiveTests.cs | 2 +- .../Processor/EventProcessorClientTests.cs | 53 ++++---- .../Sample08_MockingClientTypesLiveTests.cs | 4 +- .../BlobCheckpointStoreInternal.cs | 74 ++++++------ .../src/Resources.Designer.cs | 11 ++ .../src/Resources.resx | 3 + .../src/Testing/MockEventData.cs | 2 +- .../BlobsCheckpointStoreInternalLiveTests.cs | 12 +- .../BlobsCheckpointStoreInternalTests.cs | 114 ++++++------------ ...lobsCheckpointStoreInternal.Diagnostics.cs | 12 +- .../tests/Infrastructure/IBlobEventLogger.cs | 6 - .../tests/Testing/EventDataExtensionsTests.cs | 32 ++--- ...zure.Messaging.EventHubs.netstandard2.0.cs | 41 ++++--- .../samples/Sample11_MockingClientTypes.md | 12 +- .../Amqp/AmqpAnnotatedMessageExtensions.cs | 24 ++-- .../src/Amqp/AmqpConnectionScope.cs | 6 + .../src/Amqp/AmqpConsumer.cs | 2 +- .../src/Amqp/AmqpFilter.cs | 2 +- .../src/Amqp/AmqpManagement.cs | 6 + .../src/Amqp/AmqpMessageConverter.cs | 13 +- .../src/Amqp/AmqpProperty.cs | 6 + .../src/Consumer/EventPosition.cs | 4 +- .../Consumer/LastEnqueuedEventProperties.cs | 4 +- .../src/EventData.cs | 14 +-- .../src/EventHubProperties.cs | 11 +- .../src/EventHubsModelFactory.cs | 6 +- .../src/PartitionProperties.cs | 4 +- .../src/Primitives/CheckpointStore.cs | 3 +- .../src/Primitives/EventProcessor.cs | 30 ++--- .../PluggableCheckpointStoreEventProcessor.cs | 3 +- .../src/Processor/CheckpointPosition.cs | 36 +++++- .../AmqpAnnotatedMessageExtensionsTests.cs | 26 ++-- .../tests/Amqp/AmqpConnectionScopeTests.cs | 6 +- .../tests/Amqp/AmqpConsumerTests.cs | 18 +-- .../tests/Amqp/AmqpFilterTests.cs | 6 +- .../tests/Amqp/AmqpMessageConverterTests.cs | 18 +-- .../Connection/EventHubConnectionTests.cs | 2 +- .../Consumer/EventHubConsumerClientTests.cs | 32 ++--- .../tests/Consumer/EventPositionTests.cs | 14 +-- .../LastEnqueuedEventPropertiesTests.cs | 26 ++-- .../tests/Consumer/PartitionContextTests.cs | 2 +- .../tests/Core/EventDataTests.cs | 20 +-- .../tests/Core/EventHubsModelFactoryTests.cs | 8 +- .../Primitives/EventProcessorOptionsTests.cs | 2 +- .../EventProcessorTests.Infrastructure.cs | 12 +- .../EventProcessorTests.MainProcessingLoop.cs | 94 ++++++++++----- ...EventProcessorTests.PartitionProcessing.cs | 40 +++--- .../EventProcessorTests.StartStop.cs | 30 +++-- .../Primitives/PartitionReceiverLiveTests.cs | 2 +- .../Primitives/PartitionReceiverTests.cs | 14 +-- ...gableCheckpointStoreEventProcessorTests.cs | 4 +- .../Processor/CheckpointPositionTests.cs | 58 ++++++++- .../EventHubBufferedProducerClientTests.cs | 2 +- .../Sample11_MockingClientTypesLiveTests.cs | 12 +- 66 files changed, 771 insertions(+), 507 deletions(-) diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/api/Azure.Messaging.EventHubs.Processor.netstandard2.0.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/api/Azure.Messaging.EventHubs.Processor.netstandard2.0.cs index 681137633b6d8..a52a75a3d49a0 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/api/Azure.Messaging.EventHubs.Processor.netstandard2.0.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/api/Azure.Messaging.EventHubs.Processor.netstandard2.0.cs @@ -38,7 +38,8 @@ public partial class EventProcessorClient : Azure.Messaging.EventHubs.Primitives [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public override string ToString() { throw null; } protected override System.Threading.Tasks.Task UpdateCheckpointAsync(string partitionId, Azure.Messaging.EventHubs.Processor.CheckpointPosition startingPosition, System.Threading.CancellationToken cancellationToken) { throw null; } - protected override System.Threading.Tasks.Task UpdateCheckpointAsync(string partitionId, long offset, long? sequenceNumber, System.Threading.CancellationToken cancellationToken) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + protected override System.Threading.Tasks.Task UpdateCheckpointAsync(string partitionId, string offset, long? sequenceNumber, System.Threading.CancellationToken cancellationToken) { throw null; } protected override System.Threading.Tasks.Task ValidateProcessingPreconditions(System.Threading.CancellationToken cancellationToken) { throw null; } } public partial class EventProcessorClientOptions @@ -71,7 +72,8 @@ public partial class BlobCheckpointStore : Azure.Messaging.EventHubs.Primitives. public override System.Threading.Tasks.Task> ClaimOwnershipAsync(System.Collections.Generic.IEnumerable desiredOwnership, System.Threading.CancellationToken cancellationToken) { throw null; } public override System.Threading.Tasks.Task GetCheckpointAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, System.Threading.CancellationToken cancellationToken) { throw null; } public override System.Threading.Tasks.Task> ListOwnershipAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, System.Threading.CancellationToken cancellationToken) { throw null; } - public override System.Threading.Tasks.Task UpdateCheckpointAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, long offset, long? sequenceNumber, System.Threading.CancellationToken cancellationToken) { throw null; } public override System.Threading.Tasks.Task UpdateCheckpointAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, string clientIdentifier, Azure.Messaging.EventHubs.Processor.CheckpointPosition startingPosition, System.Threading.CancellationToken cancellationToken) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override System.Threading.Tasks.Task UpdateCheckpointAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, string offset, long? sequenceNumber, System.Threading.CancellationToken cancellationToken) { throw null; } } } diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/samples/Sample08_MockingClientTypes.md b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/samples/Sample08_MockingClientTypes.md index 8207da4d3aedd..3f81b21037c20 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/samples/Sample08_MockingClientTypes.md +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/samples/Sample08_MockingClientTypes.md @@ -49,7 +49,7 @@ EventData eventData = EventHubsModelFactory.EventData( systemProperties: new Dictionary(), //arbitrary value partitionKey: "sample-key", sequenceNumber: 1000, - offset: 1500, + offset: "1500", enqueuedTime: DateTimeOffset.Parse("11:36 PM")); // This creates a new instance of ProcessEventArgs to pass into the handler directly. @@ -110,7 +110,7 @@ TimerCallback dispatchEvent = async _ => systemProperties: new Dictionary(), //arbitrary value partitionKey: "sample-key", sequenceNumber: 1000, - offset: 1500, + offset: "1500", enqueuedTime: DateTimeOffset.Parse("11:36 PM")); ProcessEventArgs eventArgs = new( diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Azure.Messaging.EventHubs.Processor.csproj b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Azure.Messaging.EventHubs.Processor.csproj index bdfb4b7b61f6d..9e01e14f32204 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Azure.Messaging.EventHubs.Processor.csproj +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Azure.Messaging.EventHubs.Processor.csproj @@ -1,4 +1,4 @@ - + Azure Event Hubs is a highly scalable publish-subscribe service that can ingest millions of events per second and stream them to multiple consumers. This library extends its Event Processor with durable storage for checkpoint information using Azure Blob storage. For more information about Event Hubs, see https://azure.microsoft.com/en-us/services/event-hubs/ 5.12.0-beta.1 @@ -9,12 +9,17 @@ true + + + + + - + diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Diagnostics/BlobCheckpointStoreInternal.Diagnostics.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Diagnostics/BlobCheckpointStoreInternal.Diagnostics.cs index 189c5246e500b..f5c8d5d88804f 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Diagnostics/BlobCheckpointStoreInternal.Diagnostics.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Diagnostics/BlobCheckpointStoreInternal.Diagnostics.cs @@ -96,7 +96,6 @@ static BlobCheckpointStoreInternal() /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the client that authored this checkpoint. /// The sequence number associated with the checkpoint. - /// The replication segment associated with the checkpoint. /// The offset associated with the checkpoint. /// The exception that occurred. /// @@ -106,10 +105,9 @@ static BlobCheckpointStoreInternal() string consumerGroup, string clientIdentifier, string sequenceNumber, - string replicationSegment, string offset, Exception exception) => - Logger.UpdateCheckpointError(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, exception.Message, sequenceNumber, replicationSegment, offset); + Logger.UpdateCheckpointError(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, exception.Message, sequenceNumber, offset); /// /// Indicates that an attempt to update a checkpoint has completed. @@ -121,7 +119,6 @@ static BlobCheckpointStoreInternal() /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the client that authored this checkpoint. /// The sequence number associated with this checkpoint. - /// The replication segment associated with this checkpoint. /// The offset associated with this checkpoint. /// partial void UpdateCheckpointComplete(string partitionId, @@ -130,9 +127,8 @@ static BlobCheckpointStoreInternal() string consumerGroup, string clientIdentifier, string sequenceNumber, - string replicationSegment, string offset) => - Logger.UpdateCheckpointComplete(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber, replicationSegment, offset); + Logger.UpdateCheckpointComplete(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber, offset); /// /// Indicates that an attempt to create/update a checkpoint has started. @@ -144,7 +140,6 @@ static BlobCheckpointStoreInternal() /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the client that authored this checkpoint. /// The sequence number associated with this checkpoint. - /// The replication segment associated with this checkpoint. /// The offset associated with this checkpoint. /// partial void UpdateCheckpointStart(string partitionId, @@ -153,9 +148,8 @@ static BlobCheckpointStoreInternal() string consumerGroup, string clientIdentifier, string sequenceNumber, - string replicationSegment, string offset) => - Logger.UpdateCheckpointStart(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber, replicationSegment, offset); + Logger.UpdateCheckpointStart(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber, offset); /// /// Indicates that an attempt to retrieve claim partition ownership has completed. diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Diagnostics/BlobEventStoreEventSource.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Diagnostics/BlobEventStoreEventSource.cs index 2598b3656ac9c..03eb5ab6a3377 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Diagnostics/BlobEventStoreEventSource.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Diagnostics/BlobEventStoreEventSource.cs @@ -252,22 +252,20 @@ protected BlobEventStoreEventSource() : base(EventSourceName) /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the client that authored this checkpoint. /// The sequence number associated with this checkpoint. - /// The replication segment associated with this checkpoint. /// The offset associated with this checkpoint. /// - [Event(32, Level = EventLevel.Verbose, Message = "Starting to create/update a checkpoint for partition: `{0}` of FullyQualifiedNamespace: '{1}'; EventHubName: '{2}'; ConsumerGroup: '{3}'; ClientIdentifier: '{4}'; at SequenceNumber: '{5}' ReplicationSegment: '{6}' Offset: '{7}'.")] + [Event(32, Level = EventLevel.Verbose, Message = "Starting to create/update a checkpoint for partition: `{0}` of FullyQualifiedNamespace: '{1}'; EventHubName: '{2}'; ConsumerGroup: '{3}'; ClientIdentifier: '{4}'; at SequenceNumber: '{5}' Offset: '{6}'.")] public virtual void UpdateCheckpointStart(string partitionId, string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string clientIdentifier, string sequenceNumber, - string replicationSegment, string offset) { if (IsEnabled()) { - WriteEvent(32, partitionId ?? string.Empty, fullyQualifiedNamespace ?? string.Empty, eventHubName ?? string.Empty, consumerGroup ?? string.Empty, clientIdentifier ?? string.Empty, sequenceNumber ?? string.Empty, replicationSegment ?? string.Empty, offset ?? string.Empty); + WriteEvent(32, partitionId ?? string.Empty, fullyQualifiedNamespace ?? string.Empty, eventHubName ?? string.Empty, consumerGroup ?? string.Empty, clientIdentifier ?? string.Empty, sequenceNumber ?? string.Empty, offset ?? string.Empty); } } @@ -281,22 +279,20 @@ protected BlobEventStoreEventSource() : base(EventSourceName) /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the client that authored this checkpoint. /// The sequence number associated with this checkpoint. - /// The replication segment associated with this checkpoint. /// The offset associated with this checkpoint. /// - [Event(33, Level = EventLevel.Verbose, Message = "Completed the attempt to create/update a checkpoint for partition: `{0}` of FullyQualifiedNamespace: '{1}'; EventHubName: '{2}'; ConsumerGroup: '{3}'; ClientIdentifier: '{4}'; at SequenceNumber: '{5}' ReplicationSegment: '{6}' Offset: '{7}'.")] + [Event(33, Level = EventLevel.Verbose, Message = "Completed the attempt to create/update a checkpoint for partition: `{0}` of FullyQualifiedNamespace: '{1}'; EventHubName: '{2}'; ConsumerGroup: '{3}'; ClientIdentifier: '{4}'; at SequenceNumber: '{5}' Offset: '{6}'.")] public virtual void UpdateCheckpointComplete(string partitionId, string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string clientIdentifier, string sequenceNumber, - string replicationSegment, string offset) { if (IsEnabled()) { - WriteEvent(33, partitionId ?? string.Empty, fullyQualifiedNamespace ?? string.Empty, eventHubName ?? string.Empty, consumerGroup ?? string.Empty, clientIdentifier ?? string.Empty, sequenceNumber ?? string.Empty, replicationSegment ?? string.Empty, offset ?? string.Empty); + WriteEvent(33, partitionId ?? string.Empty, fullyQualifiedNamespace ?? string.Empty, eventHubName ?? string.Empty, consumerGroup ?? string.Empty, clientIdentifier ?? string.Empty, sequenceNumber ?? string.Empty, offset ?? string.Empty); } } @@ -310,11 +306,10 @@ protected BlobEventStoreEventSource() : base(EventSourceName) /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the processor that authored this checkpoint. /// The sequence number associated with this checkpoint. - /// The replication segment associated with this checkpoint. /// The offset associated with this checkpoint. /// The message for the exception that occurred. /// - [Event(34, Level = EventLevel.Error, Message = "An exception occurred when creating/updating a checkpoint for partition: `{0}` of FullyQualifiedNamespace: '{1}'; EventHubName: '{2}'; ConsumerGroup: '{3}'; ClientIdentifier: '{5}'; at SequenceNumber: '{6}' ReplicationSegment '{7}' Offset '{8}'. ErrorMessage: '{4}'.")] + [Event(34, Level = EventLevel.Error, Message = "An exception occurred when creating/updating a checkpoint for partition: `{0}` of FullyQualifiedNamespace: '{1}'; EventHubName: '{2}'; ConsumerGroup: '{3}'; ErrorMessage: '{4}'; ClientIdentifier: '{5}'; at SequenceNumber: '{6}' Offset '{7}'.")] public virtual void UpdateCheckpointError(string partitionId, string fullyQualifiedNamespace, string eventHubName, @@ -322,12 +317,11 @@ protected BlobEventStoreEventSource() : base(EventSourceName) string clientIdentifier, string errorMessage, string sequenceNumber, - string replicationSegment, string offset) { if (IsEnabled()) { - WriteEvent(34, partitionId ?? string.Empty, fullyQualifiedNamespace ?? string.Empty, eventHubName ?? string.Empty, consumerGroup ?? string.Empty, errorMessage ?? string.Empty, clientIdentifier ?? string.Empty, sequenceNumber ?? string.Empty, replicationSegment ?? string.Empty, offset ?? string.Empty); + WriteEvent(34, partitionId ?? string.Empty, fullyQualifiedNamespace ?? string.Empty, eventHubName ?? string.Empty, consumerGroup ?? string.Empty, errorMessage ?? string.Empty, clientIdentifier ?? string.Empty, sequenceNumber ?? string.Empty, offset ?? string.Empty); } } diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Diagnostics/EventProcessorClientEventSource.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Diagnostics/EventProcessorClientEventSource.cs index c9f480105ef2e..6f2a4e8b397b7 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Diagnostics/EventProcessorClientEventSource.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Diagnostics/EventProcessorClientEventSource.cs @@ -119,16 +119,20 @@ protected EventProcessorClientEventSource() : base(EventSourceName) /// A unique name used to identify the event processor. /// The name of the Event Hub that the processor is associated with. /// The name of the consumer group that the processor is associated with. + /// The sequence number associated with the checkpoint being written. + /// The offset associated with the checkpoint being written. /// - [Event(23, Level = EventLevel.Verbose, Message = "Starting to perform a checkpoint update for partition '{0}' by processor instance with identifier '{1}' for Event Hub: {2} and Consumer Group: {3}.")] + [Event(23, Level = EventLevel.Verbose, Message = "Starting to perform a checkpoint update for partition '{0}' by processor instance with identifier '{1}' for Event Hub: {2} and Consumer Group: {3} Sequence Number: {4} Offset {5}.")] public virtual void UpdateCheckpointStart(string partitionId, string identifier, string eventHubName, - string consumerGroup) + string consumerGroup, + string sequenceNumber, + string offset) { if (IsEnabled()) { - WriteEvent(23, partitionId ?? string.Empty, identifier ?? string.Empty, eventHubName ?? string.Empty, consumerGroup ?? string.Empty); + WriteEvent(23, partitionId ?? string.Empty, identifier ?? string.Empty, eventHubName ?? string.Empty, consumerGroup ?? string.Empty, sequenceNumber ?? string.Empty, offset ?? string.Empty); } } @@ -140,16 +144,20 @@ protected EventProcessorClientEventSource() : base(EventSourceName) /// A unique name used to identify the event processor. /// The name of the Event Hub that the processor is associated with. /// The name of the consumer group that the processor is associated with. + /// The sequence number associated with the checkpoint being written. + /// The offset associated with the checkpoint being written. /// - [Event(24, Level = EventLevel.Verbose, Message = "Completed performing a checkpoint update for partition '{0}' by processor instance with identifier '{1}' for Event Hub: {2} and Consumer Group: {3}.")] + [Event(24, Level = EventLevel.Verbose, Message = "Completed performing a checkpoint update for partition '{0}' by processor instance with identifier '{1}' for Event Hub: {2} and Consumer Group: {3} Sequence Number: {4} Offset: {5}.")] public virtual void UpdateCheckpointComplete(string partitionId, string identifier, string eventHubName, - string consumerGroup) + string consumerGroup, + string sequenceNumber, + string offset) { if (IsEnabled()) { - WriteEvent(24, partitionId ?? string.Empty, identifier ?? string.Empty, eventHubName ?? string.Empty, consumerGroup ?? string.Empty); + WriteEvent(24, partitionId ?? string.Empty, identifier ?? string.Empty, eventHubName ?? string.Empty, consumerGroup ?? string.Empty, sequenceNumber ?? string.Empty, offset ?? string.Empty); } } @@ -162,17 +170,21 @@ protected EventProcessorClientEventSource() : base(EventSourceName) /// The name of the Event Hub that the processor is associated with. /// The name of the consumer group that the processor is associated with. /// The message for the exception that occurred. + /// The sequence number associated with the checkpoint being written. + /// The offset associated with the checkpoint being written. /// - [Event(25, Level = EventLevel.Error, Message = "An exception occurred while attempting to perform a checkpoint update for partition '{0}' by processor instance with identifier '{1}' for Event Hub: {2} and Consumer Group: {3}. Error Message: '{4}'")] + [Event(25, Level = EventLevel.Error, Message = "An exception occurred while attempting to perform a checkpoint update for partition '{0}' by processor instance with identifier '{1}' for Event Hub: {2} and Consumer Group: {3}. Error Message: '{4}. Sequence Number: {5} Offset: {6}'")] public virtual void UpdateCheckpointError(string partitionId, string identifier, string eventHubName, string consumerGroup, - string errorMessage) + string errorMessage, + string sequenceNumber, + string offset) { if (IsEnabled()) { - WriteEvent(25, partitionId ?? string.Empty, identifier ?? string.Empty, eventHubName ?? string.Empty, consumerGroup ?? string.Empty, errorMessage ?? string.Empty); + WriteEvent(25, partitionId ?? string.Empty, identifier ?? string.Empty, eventHubName ?? string.Empty, consumerGroup ?? string.Empty, errorMessage ?? string.Empty, sequenceNumber ?? string.Empty, offset ?? string.Empty); } } @@ -359,11 +371,71 @@ protected EventProcessorClientEventSource() : base(EventSourceName) eventPayload[4].Size = (arg5.Length + 1) * sizeof(char); eventPayload[4].DataPointer = (IntPtr)arg5Ptr; - eventPayload[5].Size = (arg5.Length + 1) * sizeof(char); - eventPayload[5].DataPointer = (IntPtr)arg5Ptr; + eventPayload[5].Size = (arg6.Length + 1) * sizeof(char); + eventPayload[5].DataPointer = (IntPtr)arg6Ptr; WriteEventCore(eventId, 6, eventPayload); } } + + /// + /// Writes an event with five string arguments into a stack allocated + /// struct to avoid the parameter array allocation on the WriteEvent methods. + /// + /// + /// The identifier of the event. + /// The first argument. + /// The second argument. + /// The third argument. + /// The fourth argument. + /// The fifth argument. + /// The sixth argument. + /// The seventh argument. + /// + [NonEvent] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe void WriteEvent(int eventId, + string arg1, + string arg2, + string arg3, + string arg4, + string arg5, + string arg6, + string arg7) + { + fixed (char* arg1Ptr = arg1) + fixed (char* arg2Ptr = arg2) + fixed (char* arg3Ptr = arg3) + fixed (char* arg4Ptr = arg4) + fixed (char* arg5Ptr = arg5) + fixed (char* arg6Ptr = arg6) + fixed (char* arg7Ptr = arg7) + { + var eventPayload = stackalloc EventData[7]; + + eventPayload[0].Size = (arg1.Length + 1) * sizeof(char); + eventPayload[0].DataPointer = (IntPtr)arg1Ptr; + + eventPayload[1].Size = (arg2.Length + 1) * sizeof(char); + eventPayload[1].DataPointer = (IntPtr)arg2Ptr; + + eventPayload[2].Size = (arg3.Length + 1) * sizeof(char); + eventPayload[2].DataPointer = (IntPtr)arg3Ptr; + + eventPayload[3].Size = (arg4.Length + 1) * sizeof(char); + eventPayload[3].DataPointer = (IntPtr)arg4Ptr; + + eventPayload[4].Size = (arg5.Length + 1) * sizeof(char); + eventPayload[4].DataPointer = (IntPtr)arg5Ptr; + + eventPayload[5].Size = (arg6.Length + 1) * sizeof(char); + eventPayload[5].DataPointer = (IntPtr)arg6Ptr; + + eventPayload[6].Size = (arg7.Length + 1) * sizeof(char); + eventPayload[6].DataPointer = (IntPtr)arg7Ptr; + + WriteEventCore(eventId, 7, eventPayload); + } + } } } diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/EventProcessorClient.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/EventProcessorClient.cs index a26fd56f277c3..269ec4cf21854 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/EventProcessorClient.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/EventProcessorClient.cs @@ -911,15 +911,16 @@ protected override async Task ValidateProcessingPreconditions(CancellationToken /// The sequence number to associate with the checkpoint, indicating that a processor should begin reading from the next event in the stream. /// A instance to signal a request to cancel the operation. /// + [EditorBrowsable(EditorBrowsableState.Never)] protected override Task UpdateCheckpointAsync(string partitionId, - long offset, + string offset, long? sequenceNumber, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); Argument.AssertNotNull(partitionId, nameof(partitionId)); - Logger.UpdateCheckpointStart(partitionId, Identifier, EventHubName, ConsumerGroup); + Logger.UpdateCheckpointStart(partitionId, Identifier, EventHubName, ConsumerGroup, sequenceNumber?.ToString(), offset); using var scope = ClientDiagnostics.CreateScope(DiagnosticProperty.EventProcessorCheckpointActivityName, ActivityKind.Internal); scope.Start(); @@ -934,13 +935,13 @@ protected override async Task ValidateProcessingPreconditions(CancellationToken // be thrown directly to the caller here. scope.Failed(ex); - Logger.UpdateCheckpointError(partitionId, Identifier, EventHubName, ConsumerGroup, ex.Message); + Logger.UpdateCheckpointError(partitionId, Identifier, EventHubName, ConsumerGroup, ex.Message, sequenceNumber?.ToString(), offset); throw; } finally { - Logger.UpdateCheckpointComplete(partitionId, Identifier, EventHubName, ConsumerGroup); + Logger.UpdateCheckpointComplete(partitionId, Identifier, EventHubName, ConsumerGroup, sequenceNumber?.ToString(), offset); } } @@ -960,9 +961,19 @@ protected override async Task ValidateProcessingPreconditions(CancellationToken cancellationToken.ThrowIfCancellationRequested(); Argument.AssertNotNull(partitionId, nameof(partitionId)); - Argument.AssertAtLeast(startingPosition.SequenceNumber, 0, nameof(startingPosition.SequenceNumber)); + if (string.IsNullOrEmpty(startingPosition.Offset)) + { + if (EventHubProperties?.IsGeoReplicationEnabled ?? false) + { + var message = string.Format(CultureInfo.InvariantCulture, Resources.ProcessorAttemptingToWriteCheckpointWithoutOffset); + var updateCheckpointException = new EventHubsException(true, EventHubName, message, EventHubsException.FailureReason.GeneralError); + _ = InvokeOnProcessingErrorAsync(updateCheckpointException, Resources.OperationEventProcessingLoop, CancellationToken.None); + } - Logger.UpdateCheckpointStart(partitionId, Identifier, EventHubName, ConsumerGroup); + Argument.AssertAtLeast(startingPosition.SequenceNumber, 0, nameof(startingPosition.SequenceNumber)); + } + + Logger.UpdateCheckpointStart(partitionId, Identifier, EventHubName, ConsumerGroup, startingPosition.SequenceNumber.ToString(), startingPosition.Offset); using var scope = ClientDiagnostics.CreateScope(DiagnosticProperty.EventProcessorCheckpointActivityName, ActivityKind.Internal); scope.Start(); @@ -977,16 +988,29 @@ protected override async Task ValidateProcessingPreconditions(CancellationToken // be thrown directly to the caller here. scope.Failed(ex); - Logger.UpdateCheckpointError(partitionId, Identifier, EventHubName, ConsumerGroup, ex.Message); + Logger.UpdateCheckpointError(partitionId, Identifier, EventHubName, ConsumerGroup, ex.Message, startingPosition.SequenceNumber.ToString(), startingPosition.Offset); throw; } finally { - Logger.UpdateCheckpointComplete(partitionId, Identifier, EventHubName, ConsumerGroup); + Logger.UpdateCheckpointComplete(partitionId, Identifier, EventHubName, ConsumerGroup, startingPosition.SequenceNumber.ToString(), startingPosition.Offset); } } + /// + /// Performs the tasks needed invoke the method in the background, + /// as it is intended to be a fire-and-forget operation. + /// + /// + /// The exception that occurred during operation of the event processor. + /// A short textual description of the operation during which the exception occurred; intended to be informational only. + /// A instance to signal the request to cancel the processing. + /// + private Task InvokeOnProcessingErrorAsync(Exception exception, + string operationDescription, + CancellationToken cancellationToken) => Task.Run(() => OnProcessingErrorAsync(exception, null, operationDescription, cancellationToken), CancellationToken.None); + /// /// Creates an to use for communicating with the Event Hubs service. /// diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Primitives/BlobCheckpointStore.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Primitives/BlobCheckpointStore.cs index 78ae93f7f05df..7d07c43a25cf1 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Primitives/BlobCheckpointStore.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/src/Primitives/BlobCheckpointStore.cs @@ -107,11 +107,12 @@ public BlobCheckpointStore(BlobContainerClient blobContainerClient) : this(new B /// The sequence number to associate with the checkpoint, indicating that a processor should begin reading from the next event in the stream. /// A instance to signal a request to cancel the operation. /// + [EditorBrowsable(EditorBrowsableState.Never)] public override Task UpdateCheckpointAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, - long offset, + string offset, long? sequenceNumber, CancellationToken cancellationToken) => _checkpointStoreImplementation.UpdateCheckpointAsync(fullyQualifiedNamespace, eventHubName, consumerGroup, partitionId, offset, sequenceNumber, cancellationToken); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Diagnostics/BlobCheckpointStoreInternalDiagnosticsTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Diagnostics/BlobCheckpointStoreInternalDiagnosticsTests.cs index 5a2af1d26d755..efafc51d526b2 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Diagnostics/BlobCheckpointStoreInternalDiagnosticsTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Diagnostics/BlobCheckpointStoreInternalDiagnosticsTests.cs @@ -268,9 +268,10 @@ public async Task UpdateCheckpointLogsStartAndCompleteWhenTheBlobExists() target.Logger = mockLog.Object; var expectedSequenceNumber = 0; - await target.UpdateCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, PartitionId, Identifier, new CheckpointPosition(expectedSequenceNumber), CancellationToken.None); - mockLog.Verify(log => log.UpdateCheckpointStart(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, expectedSequenceNumber.ToString(), "-1", string.Empty)); - mockLog.Verify(log => log.UpdateCheckpointComplete(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, expectedSequenceNumber.ToString(), "-1", string.Empty)); + var expectedOffset = "10"; + await target.UpdateCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, PartitionId, Identifier, new CheckpointPosition(expectedOffset, expectedSequenceNumber), CancellationToken.None); + mockLog.Verify(log => log.UpdateCheckpointStart(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, expectedSequenceNumber.ToString(), expectedOffset)); + mockLog.Verify(log => log.UpdateCheckpointComplete(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, expectedSequenceNumber.ToString(), expectedOffset)); } /// @@ -299,8 +300,8 @@ public async Task UpdateCheckpointLogsStartAndCompleteWhenTheBlobDoesNotExist() var expectedSequenceNumber = 0; await target.UpdateCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, PartitionId, Identifier, new CheckpointPosition(expectedSequenceNumber), CancellationToken.None); - mockLog.Verify(log => log.UpdateCheckpointStart(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, expectedSequenceNumber.ToString(), "-1", string.Empty)); - mockLog.Verify(log => log.UpdateCheckpointComplete(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, expectedSequenceNumber.ToString(), "-1", string.Empty)); + mockLog.Verify(log => log.UpdateCheckpointStart(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, expectedSequenceNumber.ToString(), null)); + mockLog.Verify(log => log.UpdateCheckpointComplete(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, expectedSequenceNumber.ToString(), null)); } /// @@ -324,8 +325,9 @@ public void UpdateCheckpointLogsErrorsWhenTheBlobExists() target.Logger = mockLog.Object; var expectedSequenceNumber = 456; - Assert.That(async () => await target.UpdateCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, PartitionId, Identifier, new CheckpointPosition(expectedSequenceNumber), CancellationToken.None), Throws.Exception.EqualTo(expectedException)); - mockLog.Verify(log => log.UpdateCheckpointError(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, expectedException.Message, expectedSequenceNumber.ToString(), "-1", string.Empty)); + var expectedOffset = "404"; + Assert.That(async () => await target.UpdateCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, PartitionId, Identifier, new CheckpointPosition(expectedOffset, expectedSequenceNumber), CancellationToken.None), Throws.Exception.EqualTo(expectedException)); + mockLog.Verify(log => log.UpdateCheckpointError(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, expectedException.Message, expectedSequenceNumber.ToString(), expectedOffset)); } /// @@ -348,8 +350,9 @@ public void UpdateCheckpointLogsErrorsWhenTheBlobDoesNotExist() target.Logger = mockLog.Object; var expectedSequenceNumber = 6; - Assert.That(async () => await target.UpdateCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, PartitionId, Identifier, new CheckpointPosition(expectedSequenceNumber), CancellationToken.None), Throws.Exception.EqualTo(expectedException)); - mockLog.Verify(log => log.UpdateCheckpointError(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, expectedException.Message, expectedSequenceNumber.ToString(), "-1", string.Empty)); + var expectedOffset = "9"; + Assert.That(async () => await target.UpdateCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, PartitionId, Identifier, new CheckpointPosition(expectedOffset, expectedSequenceNumber), CancellationToken.None), Throws.Exception.EqualTo(expectedException)); + mockLog.Verify(log => log.UpdateCheckpointError(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, expectedException.Message, expectedSequenceNumber.ToString(), expectedOffset)); } /// @@ -367,8 +370,9 @@ public void UpdateCheckpointForMissingContainerLogsCheckpointUpdateError() target.Logger = mockLog.Object; var expectedSequenceNumber = 999; - Assert.That(async () => await target.UpdateCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, PartitionId, Identifier, new CheckpointPosition(expectedSequenceNumber), CancellationToken.None), Throws.InstanceOf()); - mockLog.Verify(m => m.UpdateCheckpointError(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, ex.Message, expectedSequenceNumber.ToString(), "-1", string.Empty)); + var expectedOffset = "777"; + Assert.That(async () => await target.UpdateCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, PartitionId, Identifier, new CheckpointPosition(expectedOffset, expectedSequenceNumber), CancellationToken.None), Throws.InstanceOf()); + mockLog.Verify(m => m.UpdateCheckpointError(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, ex.Message, expectedSequenceNumber.ToString(), expectedOffset)); } /// diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Diagnostics/DiagnosticsActivitySourceTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Diagnostics/DiagnosticsActivitySourceTests.cs index f7e8023731650..593e336f2bf7b 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Diagnostics/DiagnosticsActivitySourceTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Diagnostics/DiagnosticsActivitySourceTests.cs @@ -73,13 +73,14 @@ public async Task CheckpointStoreActivitySourceDisabled() var mockLogger = new Mock(); mockLogger - .Setup(log => log.UpdateCheckpointComplete(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Setup(log => log.UpdateCheckpointComplete(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback(() => completionSource.TrySetResult(true)); mockProcessor.Object.Logger = mockLogger.Object; using var listener = new TestActivitySourceListener(source => source.Name.StartsWith(DiagnosticProperty.DiagnosticNamespace)); await InvokeUpdateCheckpointAsync(mockProcessor.Object, mockContext.Object.PartitionId, 998, default); + await InvokeOldUpdateCheckpointAsync(mockProcessor.Object, mockContext.Object.PartitionId, "998", 774, default); Assert.IsEmpty(listener.Activities); } @@ -90,7 +91,9 @@ public async Task CheckpointStoreActivitySourceDisabled() /// /// [Test] - public async Task UpdateCheckpointAsyncCreatesScope() + [TestCase(true)] + [TestCase(false)] + public async Task UpdateCheckpointAsyncCreatesScope(bool useOldCheckpoint) { using var cancellationSource = new CancellationTokenSource(); cancellationSource.CancelAfter(TimeSpan.FromSeconds(30)); @@ -106,7 +109,7 @@ public async Task UpdateCheckpointAsyncCreatesScope() .Returns(Mock.Of()); mockLogger - .Setup(log => log.UpdateCheckpointComplete(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Setup(log => log.UpdateCheckpointComplete(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback(() => completionSource.TrySetResult(true)); mockProcessor.Object.Logger = mockLogger.Object; @@ -114,7 +117,14 @@ public async Task UpdateCheckpointAsyncCreatesScope() using var _ = SetAppConfigSwitch(); using var listener = new TestActivitySourceListener(source => source.Name.StartsWith(DiagnosticProperty.DiagnosticNamespace)); - await InvokeUpdateCheckpointAsync(mockProcessor.Object, mockContext.Object.PartitionId, 998, default); + if (useOldCheckpoint) + { + await InvokeOldUpdateCheckpointAsync(mockProcessor.Object, mockContext.Object.PartitionId, "998", 778, default); + } + else + { + await InvokeUpdateCheckpointAsync(mockProcessor.Object, mockContext.Object.PartitionId, 998, default); + } await Task.WhenAny(completionSource.Task, Task.Delay(Timeout.Infinite, cancellationSource.Token)); Assert.That(cancellationSource.IsCancellationRequested, Is.False, "The cancellation token should not have been signaled."); @@ -141,8 +151,8 @@ public async Task EventProcessorClientCreatesScopeForEachEventProcessing() var enqueuedTime = DateTimeOffset.UtcNow; var eventBatch = new[] { - new MockEventData(new byte[] { 0x11 }, offset: 123, sequenceNumber: 123, enqueuedTime: enqueuedTime), - new MockEventData(new byte[] { 0x22 }, offset: 456, sequenceNumber: 456, enqueuedTime: enqueuedTime) + new MockEventData(new byte[] { 0x11 }, offset: "123", sequenceNumber: 123, enqueuedTime: enqueuedTime), + new MockEventData(new byte[] { 0x22 }, offset: "456", sequenceNumber: 456, enqueuedTime: enqueuedTime) }; for (int i = 0; i < eventBatch.Length; i++) @@ -199,8 +209,8 @@ public async Task EventProcessorClientCreatesScopeError() using var listener = new TestActivitySourceListener(source => source.Name.StartsWith(DiagnosticProperty.DiagnosticNamespace)); var eventBatch = new[] { - new MockEventData(new byte[] { 0x11 }, offset: 123, sequenceNumber: 123), - new MockEventData(new byte[] { 0x22 }, offset: 456, sequenceNumber: 456) + new MockEventData(new byte[] { 0x11 }, offset: "123", sequenceNumber: 123), + new MockEventData(new byte[] { 0x22 }, offset: "456", sequenceNumber: 456) }; var mockLogger = new Mock(); @@ -252,8 +262,8 @@ public async Task EventProcessorClientCreatesScopeForEachEventProcessingWithoutR var enqueuedTime = DateTimeOffset.UtcNow; var eventBatch = new[] { - new MockEventData(new byte[] { 0x11 }, offset: 123, sequenceNumber: 123, enqueuedTime: enqueuedTime), - new MockEventData(new byte[] { 0x22 }, offset: 456, sequenceNumber: 456, enqueuedTime: enqueuedTime) + new MockEventData(new byte[] { 0x11 }, offset: "123", sequenceNumber: 123, enqueuedTime: enqueuedTime), + new MockEventData(new byte[] { 0x22 }, offset: "456", sequenceNumber: 456, enqueuedTime: enqueuedTime) }; var mockLogger = new Mock(); @@ -309,6 +319,26 @@ public async Task EventProcessorClientCreatesScopeForEachEventProcessingWithoutR .GetMethod("UpdateCheckpointAsync", BindingFlags.Instance | BindingFlags.NonPublic, new Type[] { typeof(string), typeof(CheckpointPosition), typeof(CancellationToken) }) .Invoke(target, new object[] { partitionId, new CheckpointPosition(sequenceNumber), cancellationToken }); + /// + /// Invokes the protected UpdateCheckpointAsync method on the processor client. + /// + /// + /// The client whose method to invoke. + /// The identifier of the partition the checkpoint is for. + /// The offset to associate with the checkpoint, indicating that a processor should begin reading form the next event in the stream. + /// An optional sequence number to associate with the checkpoint, intended as informational metadata. The will be used for positioning when events are read. + /// A instance to signal a request to cancel the operation. + /// + private static Task InvokeOldUpdateCheckpointAsync(EventProcessorClient target, + string partitionId, + string offset, + long sequenceNumber, + CancellationToken cancellationToken) => + (Task) + typeof(EventProcessorClient) + .GetMethod("UpdateCheckpointAsync", BindingFlags.Instance | BindingFlags.NonPublic, new Type[] { typeof(string), typeof(string), typeof(long), typeof(CancellationToken) }) + .Invoke(target, new object[] { partitionId, offset, sequenceNumber, cancellationToken }); + /// /// Sets and returns the app config switch to enable Activity Source. The switch must be disposed at the end of the test. /// diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Diagnostics/DiagnosticsTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Diagnostics/DiagnosticsTests.cs index 371ff6910b0f8..dc9166053f2aa 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Diagnostics/DiagnosticsTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Diagnostics/DiagnosticsTests.cs @@ -62,7 +62,7 @@ public async Task UpdateCheckpointAsyncCreatesScope() .Returns(Mock.Of()); mockLogger - .Setup(log => log.UpdateCheckpointComplete(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Setup(log => log.UpdateCheckpointComplete(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Callback(() => completionSource.TrySetResult(true)); mockProcessor.Object.Logger = mockLogger.Object; @@ -93,8 +93,8 @@ public async Task EventProcessorClientCreatesScopeForEachEventProcessing() var enqueuedTime = DateTimeOffset.UtcNow; var eventBatch = new[] { - new MockEventData(new byte[] { 0x11 }, offset: 123, sequenceNumber: 123, enqueuedTime: enqueuedTime), - new MockEventData(new byte[] { 0x22 }, offset: 456, sequenceNumber: 456, enqueuedTime: enqueuedTime) + new MockEventData(new byte[] { 0x11 }, offset: "123", sequenceNumber: 123, enqueuedTime: enqueuedTime), + new MockEventData(new byte[] { 0x22 }, offset: "456", sequenceNumber: 456, enqueuedTime: enqueuedTime) }; for (int i = 0; i < eventBatch.Length; i++) @@ -150,8 +150,8 @@ public async Task EventProcessorClientCreatesScopeError() using var listener = new ClientDiagnosticListener(DiagnosticProperty.DiagnosticNamespace); var eventBatch = new[] { - new MockEventData(new byte[] { 0x11 }, offset: 123, sequenceNumber: 123), - new MockEventData(new byte[] { 0x22 }, offset: 456, sequenceNumber: 456) + new MockEventData(new byte[] { 0x11 }, offset: "123", sequenceNumber: 123), + new MockEventData(new byte[] { 0x22 }, offset: "456", sequenceNumber: 456) }; var mockLogger = new Mock(); @@ -199,8 +199,8 @@ public async Task EventProcessorClientCreatesScopeForEachEventProcessingWithoutR var enqueuedTime = DateTimeOffset.UtcNow; var eventBatch = new[] { - new MockEventData(new byte[] { 0x11 }, offset: 123, sequenceNumber: 123, enqueuedTime: enqueuedTime), - new MockEventData(new byte[] { 0x22 }, offset: 456, sequenceNumber: 456, enqueuedTime: enqueuedTime) + new MockEventData(new byte[] { 0x11 }, offset: "123", sequenceNumber: 123, enqueuedTime: enqueuedTime), + new MockEventData(new byte[] { 0x22 }, offset: "456", sequenceNumber: 456, enqueuedTime: enqueuedTime) }; var mockLogger = new Mock(); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Primitives/BlobCheckpointStoreTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Primitives/BlobCheckpointStoreTests.cs index e2b474a339942..7b6e2fc172fba 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Primitives/BlobCheckpointStoreTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Primitives/BlobCheckpointStoreTests.cs @@ -151,7 +151,7 @@ public async Task UpdateCheckpointAsyncOldOverloadDelegatesTheCall() var expectedHub = "fakeHub"; var expectedConsumerGroup = "fakeGroup"; var expectedPartition = "fakePart"; - var expectedOffset = 123; + var expectedOffset = "123"; var expectedSequence = 999; var mockCheckpointStore = new Mock(); var blobCheckpointStore = new BlobCheckpointStore(mockCheckpointStore.Object); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Processor/EventProcessorClientLiveTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Processor/EventProcessorClientLiveTests.cs index e794c4108d0d9..446ac2a75c500 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Processor/EventProcessorClientLiveTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Processor/EventProcessorClientLiveTests.cs @@ -394,7 +394,7 @@ public async Task ProcessorClientCanStartFromAnInitialPosition() // Read the initial set back, marking the offset and sequence number of the last event in the initial set. - var startingOffset = 0L; + string startingOffset = null; await using (var consumer = new EventHubConsumerClient(scope.ConsumerGroups.First(), connectionString)) { diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Processor/EventProcessorClientTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Processor/EventProcessorClientTests.cs index 3d31e9674b210..25f0164b0c23e 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Processor/EventProcessorClientTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Processor/EventProcessorClientTests.cs @@ -793,7 +793,7 @@ public async Task ProcessorRaisesInitializeEventHandlerWhenPartitionIsInitialize var capturedEventArgs = default(PartitionInitializingEventArgs); var partitionId = "0"; - var startingPosition = EventPosition.FromOffset(433); + var startingPosition = EventPosition.FromOffset("433"); var options = new EventProcessorOptions { DefaultStartingPosition = startingPosition }; var processorClient = new TestEventProcessorClient(Mock.Of(), "consumerGroup", "namespace", "eventHub", Mock.Of(), Mock.Of(), options); @@ -925,8 +925,8 @@ public async Task ProcessorRaisesProcessEventHandlerWhenEventsAreRead() var eventBatch = new[] { - new MockEventData(new byte[] { 0x11 }, offset: 123, sequenceNumber: 123), - new MockEventData(new byte[] { 0x22 }, offset: 456, sequenceNumber: 456) + new MockEventData(new byte[] { 0x11 }, offset: "123", sequenceNumber: 123), + new MockEventData(new byte[] { 0x22 }, offset: "456", sequenceNumber: 456) }; var capturedEventArgs = new List(); @@ -1043,8 +1043,8 @@ public void EventProcessingToleratesAndSurfacesAnException() var eventBatch = new[] { - new MockEventData(new byte[] { 0x11 }, offset: 123, sequenceNumber: 123), - new MockEventData(new byte[] { 0x22 }, offset: 456, sequenceNumber: 456) + new MockEventData(new byte[] { 0x11 }, offset: "123", sequenceNumber: 123), + new MockEventData(new byte[] { 0x22 }, offset: "456", sequenceNumber: 456) }; var invokeCount = 0; @@ -1089,7 +1089,7 @@ public async Task EventProcessingToleratesAndSurfacesMultipleExceptions() var eventBatch = Enumerable .Range(0, eventCount) - .Select(index => new MockEventData(Array.Empty(), offset: 1000 + index, sequenceNumber: 2000 + index)) + .Select(index => new MockEventData(Array.Empty(), offset: (1000 + index).ToString(), sequenceNumber: 2000 + index)) .ToList(); processorClient.ProcessEventAsync += eventArgs => @@ -1133,8 +1133,8 @@ public async Task EventProcessingLogsExecution() var eventBatch = new[] { - new MockEventData(new byte[] { 0x11 }, offset: 123, sequenceNumber: 123), - new MockEventData(new byte[] { 0x22 }, offset: 456, sequenceNumber: 456) + new MockEventData(new byte[] { 0x11 }, offset: "123", sequenceNumber: 123), + new MockEventData(new byte[] { 0x22 }, offset: "456", sequenceNumber: 456) }; var partitionId = "3"; @@ -1179,8 +1179,8 @@ public async Task EventProcessingLogsExceptions() var eventBatch = new[] { - new MockEventData(new byte[] { 0x11 }, offset: 123, sequenceNumber: 123), - new MockEventData(new byte[] { 0x22 }, offset: 456, sequenceNumber: 456) + new MockEventData(new byte[] { 0x11 }, offset: "123", sequenceNumber: 123), + new MockEventData(new byte[] { 0x22 }, offset: "456", sequenceNumber: 456) }; var partitionId = "3"; @@ -1218,10 +1218,10 @@ public async Task EventProcessingRespectsCancellation() var eventBatch = new[] { - new MockEventData(new byte[] { 0x11 }, offset: 123, sequenceNumber: 123), - new MockEventData(new byte[] { 0x22 }, offset: 456, sequenceNumber: 456), - new MockEventData(new byte[] { 0x33 }, offset: 789, sequenceNumber: 789), - new MockEventData(new byte[] { 0x44 }, offset: 000, sequenceNumber: 000) + new MockEventData(new byte[] { 0x11 }, offset: "123", sequenceNumber: 123), + new MockEventData(new byte[] { 0x22 }, offset: "456", sequenceNumber: 456), + new MockEventData(new byte[] { 0x33 }, offset: "789", sequenceNumber: 789), + new MockEventData(new byte[] { 0x44 }, offset: "000", sequenceNumber: 000) }; var processedEventsCount = 0; @@ -1291,7 +1291,7 @@ public async Task GetCheckpointIncludesInitializeEventHandlerStartingPositionWhe cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partitionId = "0"; - var startingPosition = EventPosition.FromOffset(433); + var startingPosition = EventPosition.FromOffset("433"); var options = new EventProcessorOptions { DefaultStartingPosition = EventPosition.Latest }; var mockCheckpointStore = new Mock(); var processorClient = new TestEventProcessorClient(mockCheckpointStore.Object, "consumerGroup", "namespace", "eventHub", Mock.Of(), Mock.Of(), options); @@ -1330,7 +1330,7 @@ public async Task GetCheckpointPrefersNaturalCheckpointOverInitializeEventHandle cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partitionId = "0"; - var startingPosition = EventPosition.FromOffset(433); + var startingPosition = EventPosition.FromOffset("433"); var checkpointStartingPosition = EventPosition.FromSequenceNumber(999); var options = new EventProcessorOptions { DefaultStartingPosition = EventPosition.Latest }; var mockCheckpointStore = new Mock(); @@ -1498,7 +1498,7 @@ public async Task PreviousUpdateCheckpointCallsTheOldUpdateCheckpoint() cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partitionId = "3"; - var offset = 456; + var offset = "456"; var sequenceNumber = 789; var checkpointPosition = new CheckpointPosition(sequenceNumber); var mockStorage = new Mock(); @@ -1548,7 +1548,8 @@ public async Task UpdateCheckpointLogsExecution() var partitionId = "3"; var sequenceNumber = 789; - var checkpointStartingPosition = new CheckpointPosition(sequenceNumber); + var offset = "135"; + var checkpointStartingPosition = new CheckpointPosition(offset, sequenceNumber); var mockLogger = new Mock(); var processorClient = new TestEventProcessorClient(Mock.Of(), "consumerGroup", "namespace", "eventHub", Mock.Of(), Mock.Of(), default); @@ -1560,7 +1561,9 @@ public async Task UpdateCheckpointLogsExecution() partitionId, processorClient.Identifier, processorClient.EventHubName, - processorClient.ConsumerGroup), + processorClient.ConsumerGroup, + sequenceNumber.ToString(), + offset), Times.Once); mockLogger @@ -1568,7 +1571,9 @@ public async Task UpdateCheckpointLogsExecution() partitionId, processorClient.Identifier, processorClient.EventHubName, - processorClient.ConsumerGroup), + processorClient.ConsumerGroup, + sequenceNumber.ToString(), + offset), Times.Once); cancellationSource.Cancel(); @@ -1587,7 +1592,7 @@ public void UpdateCheckpointLogsExceptions() var expectedException = new NotImplementedException("This didn't work."); var partitionId = "3"; - var checkpointStartingPosition = new CheckpointPosition(789); + var checkpointStartingPosition = new CheckpointPosition("44", 789); var mockLogger = new Mock(); var mockStorage = new Mock(); var processorClient = new TestEventProcessorClient(mockStorage.Object, "consumerGroup", "namespace", "eventHub", Mock.Of(), Mock.Of(), default); @@ -1612,7 +1617,9 @@ public void UpdateCheckpointLogsExceptions() processorClient.Identifier, processorClient.EventHubName, processorClient.ConsumerGroup, - expectedException.Message), + expectedException.Message, + "789", + "44"), Times.Once); cancellationSource.Cancel(); @@ -1726,7 +1733,7 @@ public class TestEventProcessorClient : EventProcessorClient public Task InvokeGetCheckpointAsync(string partitionId, CancellationToken cancellationToken) => base.GetCheckpointAsync(partitionId, cancellationToken); public Task> InvokeListOwnershipAsync(CancellationToken cancellationToken) => base.ListOwnershipAsync(cancellationToken); public Task> InvokeClaimOwnershipAsync(IEnumerable desiredOwnership, CancellationToken cancellationToken) => base.ClaimOwnershipAsync(desiredOwnership, cancellationToken); - public Task InvokeOldUpdateCheckpointAsync(string partitionId, long offset, long sequenceNumber, CancellationToken cancellationToken) => base.UpdateCheckpointAsync(partitionId, offset, sequenceNumber, cancellationToken); + public Task InvokeOldUpdateCheckpointAsync(string partitionId, string offset, long sequenceNumber, CancellationToken cancellationToken) => base.UpdateCheckpointAsync(partitionId, offset, sequenceNumber, cancellationToken); public Task InvokeUpdateCheckpointAsync(string partitionId, CheckpointPosition checkpointStartingPosition, CancellationToken cancellationToken) => base.UpdateCheckpointAsync(partitionId, checkpointStartingPosition, cancellationToken); protected override EventHubConnection CreateConnection() => InjectedConnection; protected override Task ValidateProcessingPreconditions(CancellationToken cancellationToken = default) => Task.CompletedTask; diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Snippets/Sample08_MockingClientTypesLiveTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Snippets/Sample08_MockingClientTypesLiveTests.cs index fb002cd6c66c6..468943a157a79 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Snippets/Sample08_MockingClientTypesLiveTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Processor/tests/Snippets/Sample08_MockingClientTypesLiveTests.cs @@ -64,7 +64,7 @@ Task processErrorHandler(ProcessErrorEventArgs args) systemProperties: new Dictionary(), //arbitrary value partitionKey: "sample-key", sequenceNumber: 1000, - offset: 1500, + offset: "1500", enqueuedTime: DateTimeOffset.Parse("11:36 PM")); // This creates a new instance of ProcessEventArgs to pass into the handler directly. @@ -130,7 +130,7 @@ Task processEventHandler(ProcessEventArgs args) systemProperties: new Dictionary(), //arbitrary value partitionKey: "sample-key", sequenceNumber: 1000, - offset: 1500, + offset: "1500", enqueuedTime: DateTimeOffset.Parse("11:36 PM")); ProcessEventArgs eventArgs = new( diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/BlobCheckpointStore/BlobCheckpointStoreInternal.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/BlobCheckpointStore/BlobCheckpointStoreInternal.cs index 6915a4f70983e..30bd5a6f4fddd 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/BlobCheckpointStore/BlobCheckpointStoreInternal.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/BlobCheckpointStore/BlobCheckpointStoreInternal.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Globalization; using System.IO; using System.Text.Json; @@ -366,11 +367,12 @@ await foreach (BlobItem blob in ContainerClient.GetBlobsAsync(traits: BlobTraits /// The sequence number to associate with the checkpoint, indicating that a processor should begin reading from the next event in the stream. /// A instance to signal a request to cancel the operation. /// + [EditorBrowsable(EditorBrowsableState.Never)] public override async Task UpdateCheckpointAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, - long offset, + string offset, long? sequenceNumber, CancellationToken cancellationToken) => await UpdateCheckpointInternalAsync(fullyQualifiedNamespace, eventHubName, consumerGroup, partitionId, string.Empty, offset, sequenceNumber, cancellationToken).ConfigureAwait(false); @@ -395,7 +397,7 @@ await foreach (BlobItem blob in ContainerClient.GetBlobsAsync(traits: BlobTraits string clientIdentifier, CheckpointPosition startingPosition, CancellationToken cancellationToken) - => await UpdateCheckpointInternalAsync(fullyQualifiedNamespace, eventHubName, consumerGroup, partitionId, clientIdentifier, null, startingPosition.SequenceNumber, cancellationToken).ConfigureAwait(false); + => await UpdateCheckpointInternalAsync(fullyQualifiedNamespace, eventHubName, consumerGroup, partitionId, clientIdentifier, startingPosition.Offset, startingPosition.SequenceNumber, cancellationToken).ConfigureAwait(false); /// /// Gets the name of the Storage Blob representing the checkpoint for a given partition. @@ -428,14 +430,22 @@ await foreach (BlobItem blob in ContainerClient.GetBlobsAsync(traits: BlobTraits /// The sequence number to associate with the checkpoint, indicating that a processor should begin reading from the next event in the stream. /// A instance to signal a request to cancel the operation. /// - private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, string clientIdentifier, long? offset, long? sequenceNumber, CancellationToken cancellationToken) + private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, string clientIdentifier, string offset, long? sequenceNumber, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - UpdateCheckpointStart(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber.ToString(), "-1", offset.ToString()); + UpdateCheckpointStart(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber?.ToString(), offset); var blobName = GetCheckpointBlobName(fullyQualifiedNamespace, eventHubName, consumerGroup, partitionId); var blobClient = ContainerClient.GetBlobClient(blobName); + if (sequenceNumber == long.MinValue) + { + // We don't want to set the sequence number in the checkpoint to long.MinValue. This can break in-process upgrade since old SDKs don't have + // the long.MinValue check. Since CheckpointPosition.SequenceNumber is not nullable, the default value is long.MinValue. If we get + // the default, just set it to null. + sequenceNumber = null; + } + // Because the checkpoint format changed and offset is no longer populated by the EventProcessor, we need to ensure that a value is present for // the Functions scale controller which uses a null check on the offset to determine if a checkpoint is in the legacy format or current. Because // GetCheckpointAsync will only populate the offset if a long.TryParse is successful, adding a nonsense string value to satisfy the null check @@ -443,7 +453,7 @@ private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, var metadata = new Dictionary() { - { BlobMetadataKey.Offset, offset.HasValue ? offset.Value.ToString(CultureInfo.InvariantCulture) : "no offset" }, + { BlobMetadataKey.Offset, offset ?? ""}, { BlobMetadataKey.SequenceNumber, sequenceNumber.HasValue ? sequenceNumber.Value.ToString(CultureInfo.InvariantCulture) : "" }, { BlobMetadataKey.ClientIdentifier, clientIdentifier } }; @@ -466,17 +476,17 @@ private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, } catch (RequestFailedException ex) when (ex.ErrorCode == BlobErrorCode.ContainerNotFound) { - UpdateCheckpointError(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber.ToString(), "-1", offset.ToString(), ex); + UpdateCheckpointError(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber?.ToString(), offset, ex); throw new RequestFailedException(BlobsResourceDoesNotExist, ex); } catch (Exception ex) { - UpdateCheckpointError(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber.ToString(), "-1", offset.ToString(), ex); + UpdateCheckpointError(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber?.ToString(), offset, ex); throw; } finally { - UpdateCheckpointComplete(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber.ToString(), "-1", offset.ToString()); + UpdateCheckpointComplete(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber?.ToString(), offset); } } @@ -501,24 +511,21 @@ private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, DateTimeOffset modifiedDate) { var startingPosition = default(EventPosition?); - var offset = default(long?); + var offset = default(string); var sequenceNumber = default(long?); var clientIdentifier = default(string); + if (metadata.TryGetValue(BlobMetadataKey.Offset, out var offsetStr) && !string.IsNullOrEmpty(offsetStr)) + { + offset = offsetStr; + startingPosition = EventPosition.FromOffset(offsetStr, false); + } if (metadata.TryGetValue(BlobMetadataKey.SequenceNumber, out var sequenceStr) && long.TryParse(sequenceStr, NumberStyles.Integer, CultureInfo.InvariantCulture, out var sequenceResult)) { sequenceNumber = sequenceResult; if (sequenceNumber != long.MinValue) // If the sequence number is not equal to the default (long.MinValue), then a value was passed in. { - startingPosition = EventPosition.FromSequenceNumber(sequenceResult, false); - } - } - if (metadata.TryGetValue(BlobMetadataKey.Offset, out var offsetStr) && long.TryParse(offsetStr, NumberStyles.Integer, CultureInfo.InvariantCulture, out var offsetResult)) - { - offset = offsetResult; - if (offset != long.MinValue) // If the offset is not equal to the default (long.MinValue), then a value was passed in. - { - startingPosition ??= EventPosition.FromOffset(offsetResult, false); + startingPosition ??= EventPosition.FromSequenceNumber(sequenceResult, false); } } if (metadata.TryGetValue(BlobMetadataKey.ClientIdentifier, out var idStr)) @@ -577,16 +584,16 @@ private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, if (TryReadLegacyCheckpoint( memoryStream.GetBuffer().AsSpan(0, (int)memoryStream.Length), - out long? offset, + out string offset, out long? sequenceNumber)) { - if (sequenceNumber.HasValue && sequenceNumber.Value != long.MinValue) + if (!string.IsNullOrEmpty(offset)) { - startingPosition = EventPosition.FromSequenceNumber(sequenceNumber.Value, false); + startingPosition ??= EventPosition.FromOffset(offset, false); } - else if (offset.HasValue) + else if (sequenceNumber.HasValue && sequenceNumber.Value != long.MinValue) { - startingPosition ??= EventPosition.FromOffset(offset.Value, false); + startingPosition = EventPosition.FromSequenceNumber(sequenceNumber.Value, false); } else { @@ -616,7 +623,7 @@ private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, } /// - /// Attempts to read a legacy checkpoint JSON format and extract an offset and a sequence number + /// Attempts to read a legacy checkpoint JSON format and extract an offset and a sequence number. /// /// /// The binary representation of the checkpoint JSON. @@ -636,7 +643,7 @@ private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, /// /// private static bool TryReadLegacyCheckpoint(Span data, - out long? offset, + out string offset, out long? sequenceNumber) { offset = null; @@ -666,14 +673,7 @@ private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, var offsetString = jsonReader.GetString(); if (!string.IsNullOrEmpty(offsetString)) { - if (long.TryParse(offsetString, out long offsetValue)) - { - offset = offsetValue; - } - else - { - return false; - } + offset = offsetString; } break; @@ -814,7 +814,6 @@ private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the client that authored the checkpoint. /// The sequence number associated with the checkpoint. - /// The replication segment associated with the checkpoint. /// The offset associated with the checkpoint. /// The message for the exception that occurred. /// @@ -824,7 +823,6 @@ private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, string consumerGroup, string clientIdentifier, string sequenceNumber, - string replicationSegment, string offset, Exception exception); @@ -838,7 +836,6 @@ private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the client that authored the checkpoint. /// The sequence number associated with the checkpoint. - /// The replication segment associated with the checkpoint. /// The offset associated with the checkpoint. /// partial void UpdateCheckpointComplete(string partitionId, @@ -847,7 +844,6 @@ private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, string consumerGroup, string clientIdentifier, string sequenceNumber, - string replicationSegment, string offset); /// @@ -860,7 +856,6 @@ private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the client that authored this checkpoint. /// The sequence number associated with the checkpoint. - /// The replication segment associated with the checkpoint. /// The offset associated with the checkpoint. /// partial void UpdateCheckpointStart(string partitionId, @@ -869,7 +864,6 @@ private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, string consumerGroup, string clientIdentifier, string sequenceNumber, - string replicationSegment, string offset); /// @@ -975,7 +969,7 @@ private async Task UpdateCheckpointInternalAsync(string fullyQualifiedNamespace, /// internal class BlobStorageCheckpoint : EventProcessorCheckpoint { - public long? Offset { get; set; } + public string Offset { get; set; } public long? SequenceNumber { get; set; } } } diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Resources.Designer.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Resources.Designer.cs index 889f5675c93d6..b4742d4341be7 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Resources.Designer.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Resources.Designer.cs @@ -847,6 +847,17 @@ internal static string ProcessorLoadBalancingCycleSlowMask } } + /// + /// Looks up a localized string similar to WARNING: A processor for a geo-replication-enabled Event Hub is trying to write a checkpoint without an offset. Readers of geo-replicated Event Hubs cannot be positioned without an offset.. + /// + internal static string ProcessorAttemptingToWriteCheckpointWithoutOffset + { + get + { + return ResourceManager.GetString("ProcessorLoadBalancingCycleSlowMask", resourceCulture); + } + } + /// /// Looks up a localized string similar to WARNING: The 'PartitionOwnershipExpirationInterval' and 'LoadBalancingUpdateInterval' are configured for intervals that may cause stability issues with partition ownership. It is recommended that the 'PartitionOwnershipExpirationInterval' be at least 3 times greater than the 'LoadBalancingUpdateInterval' and very strongly advised that it should be no less than twice as long. It is advised to adjust the intervals in the processor options. Load Balancing Interval '{1:0:00}' seconds. Partition Ownership Interval '{1:0:00}' seconds.. /// diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Resources.resx b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Resources.resx index 11f9364633207..3172f6e1194da 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Resources.resx +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Resources.resx @@ -351,4 +351,7 @@ FATAL: The processor has experienced a fatal error in its load balancing and health check task. Recovery is NOT possible; the processor is shutting down. Error message: {0} + + WARNING: A processor for a geo-replication-enabled Event Hub is trying to write a checkpoint without an offset. Readers of geo-replicated Event Hubs cannot be positioned without an offset. + \ No newline at end of file diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Testing/MockEventData.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Testing/MockEventData.cs index b1b2d59c1ac80..88f38ab751ab9 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Testing/MockEventData.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/src/Testing/MockEventData.cs @@ -29,7 +29,7 @@ internal class MockEventData : EventData IDictionary properties = null, IReadOnlyDictionary systemProperties = null, long sequenceNumber = long.MinValue, - long offset = long.MinValue, + string offset = null, DateTimeOffset enqueuedTime = default, string partitionKey = null) : base(eventBody, properties, systemProperties, sequenceNumber, offset, enqueuedTime, partitionKey) { diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/BlobCheckpointStore/BlobsCheckpointStoreInternalLiveTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/BlobCheckpointStore/BlobsCheckpointStoreInternalLiveTests.cs index 7d9a94dce1c36..9722ff42ff7ae 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/BlobCheckpointStore/BlobsCheckpointStoreInternalLiveTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/BlobCheckpointStore/BlobsCheckpointStoreInternalLiveTests.cs @@ -131,8 +131,8 @@ await using (StorageScope storageScope = await StorageScope.CreateAsync()) }; await checkpointStore.ClaimOwnershipAsync(ownershipList, default); - Assert.That(async () => await checkpointStore.UpdateCheckpointAsync("namespace", "eventHubName", "consumerGroup", "partitionId", "Id", new CheckpointPosition(10), default), Throws.Nothing); - Assert.That(async () => await checkpointStore.UpdateCheckpointAsync("namespace", "eventHubName", "consumerGroup", "partitionId", 0, 10, default), Throws.Nothing); + Assert.That(async () => await checkpointStore.UpdateCheckpointAsync("namespace", "eventHubName", "consumerGroup", "partitionId", "Id", new CheckpointPosition("0", 10), default), Throws.Nothing); + Assert.That(async () => await checkpointStore.UpdateCheckpointAsync("namespace", "eventHubName", "consumerGroup", "partitionId", "0", 10, default), Throws.Nothing); } } @@ -736,7 +736,7 @@ await using (StorageScope storageScope = await StorageScope.CreateAsync()) var mockEvent = new MockEventData( eventBody: Array.Empty(), - offset: 10, + offset: "10", sequenceNumber: 20); // There should be no blobs or checkpoints before the first call. @@ -805,7 +805,7 @@ await using (StorageScope storageScope = await StorageScope.CreateAsync()) var mockEvent = new MockEventData( eventBody: Array.Empty(), - offset: 10, + offset: "10", sequenceNumber: 20); // Calling update should create the checkpoint. @@ -862,7 +862,7 @@ await using (StorageScope storageScope = await StorageScope.CreateAsync()) var mockEvent = new MockEventData( eventBody: Array.Empty(), - offset: 10, + offset: "10", sequenceNumber: 20); // Calling update should create the checkpoint. @@ -891,7 +891,7 @@ await foreach (var blob in containerClient.GetBlobsAsync()) mockEvent = new MockEventData( eventBody: Array.Empty(), - offset: 50, + offset: "50", sequenceNumber: 60); await checkpointStore.UpdateCheckpointAsync(checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.PartitionId, checkpoint.ClientIdentifier, new CheckpointPosition(mockEvent.SequenceNumber), default); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/BlobCheckpointStore/BlobsCheckpointStoreInternalTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/BlobCheckpointStore/BlobsCheckpointStoreInternalTests.cs index 3e9dd64c74c89..e8da6192c28ad 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/BlobCheckpointStore/BlobsCheckpointStoreInternalTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/BlobCheckpointStore/BlobsCheckpointStoreInternalTests.cs @@ -362,7 +362,7 @@ public async Task GetCheckpointLogsStartAndComplete() [Test] public async Task GetCheckpointUsesOffsetAsTheStartingPositionWhenNoSequenceNumberIsPresent() { - var expectedOffset = 13; + var expectedOffset = "13"; var expectedStartingPosition = EventPosition.FromOffset(expectedOffset, false); var partition = Guid.NewGuid().ToString(); @@ -428,48 +428,10 @@ public async Task GetCheckpointUsesSequenceNumberAsTheStartingPositionWhenNoOffs /// /// [Test] - public async Task GetCheckpointUsesSequenceNumberAsTheStartingPositionWhenOffsetIsMinValue() + public async Task GetCheckpointUsesOffsetAsTheStartingPosition() { - var expectedSequence = 133; - var expectedStartingPosition = EventPosition.FromSequenceNumber(expectedSequence, false); - var partition = Guid.NewGuid().ToString(); - - var blobList = new List - { - BlobsModelFactory.BlobItem($"{FullyQualifiedNamespaceLowercase}/{EventHubNameLowercase}/{ConsumerGroupLowercase}/checkpoint/{partition}", - false, - BlobsModelFactory.BlobItemProperties(true, lastModified: DateTime.UtcNow, eTag: new ETag(MatchingEtag)), - "snapshot", - new Dictionary - { - {BlobMetadataKey.OwnerIdentifier, Guid.NewGuid().ToString()}, - {BlobMetadataKey.Offset, long.MinValue.ToString()}, - {BlobMetadataKey.SequenceNumber, expectedSequence.ToString()} - }) - }; - - var target = new BlobCheckpointStoreInternal(new MockBlobContainerClient() { Blobs = blobList }); - var checkpoint = await target.GetCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, partition, CancellationToken.None); - - Assert.That(checkpoint, Is.Not.Null, "A checkpoint should have been returned."); - Assert.That(checkpoint.StartingPosition, Is.EqualTo(expectedStartingPosition)); - - Assert.That(checkpoint, Is.InstanceOf(), "Checkpoint instance was not the expected type."); - var blobCheckpoint = (BlobCheckpointStoreInternal.BlobStorageCheckpoint)checkpoint; - Assert.That(blobCheckpoint.Offset, Is.EqualTo(long.MinValue), "The offset should have been long.MinValue."); - Assert.That(expectedSequence, Is.EqualTo(blobCheckpoint.SequenceNumber), "Checkpoint sequence number did not have the correct value."); - } - - /// - /// Verifies basic functionality of GetCheckpointAsync and ensures the starting position is set correctly. - /// - /// - [Test] - public async Task GetCheckpointUsesSequenceNumberAsTheStartingPositionWhenInvalidOffsetIsPresent() - { - var expectedSequence = 133; - var expectedOffset = "invalid offset"; - var expectedStartingPosition = EventPosition.FromSequenceNumber(expectedSequence, false); + var expectedOffset = "133"; + var expectedStartingPosition = EventPosition.FromOffset(expectedOffset, false); var partition = Guid.NewGuid().ToString(); var blobList = new List @@ -482,7 +444,7 @@ public async Task GetCheckpointUsesSequenceNumberAsTheStartingPositionWhenInvali { {BlobMetadataKey.OwnerIdentifier, Guid.NewGuid().ToString()}, {BlobMetadataKey.Offset, expectedOffset}, - {BlobMetadataKey.SequenceNumber, expectedSequence.ToString()} + {BlobMetadataKey.SequenceNumber, long.MinValue.ToString()} }) }; @@ -494,8 +456,8 @@ public async Task GetCheckpointUsesSequenceNumberAsTheStartingPositionWhenInvali Assert.That(checkpoint, Is.InstanceOf(), "Checkpoint instance was not the expected type."); var blobCheckpoint = (BlobCheckpointStoreInternal.BlobStorageCheckpoint)checkpoint; - Assert.That(blobCheckpoint.Offset, Is.Null, $"The offset should not have been populated, as it was an invalid number."); - Assert.That(expectedSequence, Is.EqualTo(blobCheckpoint.SequenceNumber), "Checkpoint sequence number did not have the correct value."); + Assert.That(blobCheckpoint.SequenceNumber, Is.EqualTo(long.MinValue), "The offset should have been long.MinValue."); + Assert.That(expectedOffset, Is.EqualTo(blobCheckpoint.Offset), "Checkpoint sequence number did not have the correct value."); } /// @@ -503,11 +465,11 @@ public async Task GetCheckpointUsesSequenceNumberAsTheStartingPositionWhenInvali /// /// [Test] - public async Task GetCheckpointPrefersSequenceNumberAsTheStartingPosition() + public async Task GetCheckpointPrefersOffsetAsTheStartingPosition() { - var offset = 13; + var offset = "13"; var sequenceNumber = 7777; - var expectedStartingPosition = EventPosition.FromSequenceNumber(sequenceNumber, false); + var expectedStartingPosition = EventPosition.FromOffset(offset, false); var partition = Guid.NewGuid().ToString(); var blobList = new List @@ -519,7 +481,7 @@ public async Task GetCheckpointPrefersSequenceNumberAsTheStartingPosition() new Dictionary { {BlobMetadataKey.OwnerIdentifier, Guid.NewGuid().ToString()}, - {BlobMetadataKey.Offset, offset.ToString()}, + {BlobMetadataKey.Offset, offset}, {BlobMetadataKey.SequenceNumber, sequenceNumber.ToString()} }) }; @@ -548,7 +510,7 @@ public async Task GetCheckpointConsidersDataInvalidWithNoOffsetOrSequenceNumber( new Dictionary { {BlobMetadataKey.OwnerIdentifier, Guid.NewGuid().ToString()}, - {BlobMetadataKey.Offset, "invalid"}, + {BlobMetadataKey.Offset, ""}, {BlobMetadataKey.SequenceNumber, long.MinValue.ToString()} }) }; @@ -569,7 +531,7 @@ public async Task GetCheckpointConsidersDataInvalidWithNoOffsetOrSequenceNumber( /// /// [Test] - public async Task GetCheckpointUsesSequenceNumberAsTheStartingPositionWhenPresentInLegacyCheckpoint() + public async Task GetCheckpointUsesOffsetAsTheStartingPositionWhenPresentInLegacyCheckpoint() { var blobList = new List { @@ -596,7 +558,7 @@ public async Task GetCheckpointUsesSequenceNumberAsTheStartingPositionWhenPresen var checkpoint = await target.GetCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, "0", CancellationToken.None); Assert.That(checkpoint, Is.Not.Null, "A checkpoints should have been returned."); - Assert.That(checkpoint.StartingPosition, Is.EqualTo(EventPosition.FromSequenceNumber(960180, false))); + Assert.That(checkpoint.StartingPosition, Is.EqualTo(EventPosition.FromOffset("13", false))); Assert.That(checkpoint.PartitionId, Is.EqualTo("0")); } @@ -676,14 +638,14 @@ public async Task UpdateCheckpointLogsStartAndCompleteWhenTheBlobExists(bool use if (useCheckpointPositionOverload) { await target.UpdateCheckpointAsync(checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.PartitionId, checkpoint.ClientIdentifier, new CheckpointPosition(sequenceNumber), CancellationToken.None); - mockLog.Verify(log => log.UpdateCheckpointStart(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.ClientIdentifier, sequenceNumber.ToString(), "-1", string.Empty)); - mockLog.Verify(log => log.UpdateCheckpointComplete(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.ClientIdentifier, sequenceNumber.ToString(), "-1", string.Empty)); + mockLog.Verify(log => log.UpdateCheckpointStart(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.ClientIdentifier, sequenceNumber.ToString(), null)); + mockLog.Verify(log => log.UpdateCheckpointComplete(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.ClientIdentifier, sequenceNumber.ToString(), null)); } else { - await target.UpdateCheckpointAsync(checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.PartitionId, 123, null, CancellationToken.None); - mockLog.Verify(log => log.UpdateCheckpointStart(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, string.Empty, string.Empty, "-1", "123")); - mockLog.Verify(log => log.UpdateCheckpointComplete(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, string.Empty, string.Empty, "-1", "123")); + await target.UpdateCheckpointAsync(checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.PartitionId, "123", null, CancellationToken.None); + mockLog.Verify(log => log.UpdateCheckpointStart(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, string.Empty, null, "123")); + mockLog.Verify(log => log.UpdateCheckpointComplete(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, string.Empty, null, "123")); } } @@ -697,7 +659,7 @@ public async Task UpdateCheckpointLogsStartAndCompleteWhenTheBlobExists(bool use public async Task UpdateCheckpointLogsStartAndCompleteWhenTheBlobDoesNotExist(bool useCheckpointPositionOverload) { var sequenceNumber = 1234; - var offset = 5678; + var offset = "5678"; var checkpoint = new EventProcessorCheckpoint { @@ -728,15 +690,15 @@ public async Task UpdateCheckpointLogsStartAndCompleteWhenTheBlobDoesNotExist(bo if (useCheckpointPositionOverload) { - await target.UpdateCheckpointAsync(checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.PartitionId, checkpoint.ClientIdentifier, new CheckpointPosition(sequenceNumber), CancellationToken.None); - mockLog.Verify(log => log.UpdateCheckpointStart(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.ClientIdentifier, sequenceNumber.ToString(), "-1", string.Empty)); - mockLog.Verify(log => log.UpdateCheckpointComplete(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.ClientIdentifier, sequenceNumber.ToString(), "-1", string.Empty)); + await target.UpdateCheckpointAsync(checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.PartitionId, checkpoint.ClientIdentifier, new CheckpointPosition(offset, sequenceNumber), CancellationToken.None); + mockLog.Verify(log => log.UpdateCheckpointStart(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.ClientIdentifier, sequenceNumber.ToString(), offset)); + mockLog.Verify(log => log.UpdateCheckpointComplete(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.ClientIdentifier, sequenceNumber.ToString(), offset)); } else { await target.UpdateCheckpointAsync(checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.PartitionId, offset, sequenceNumber, CancellationToken.None); - mockLog.Verify(log => log.UpdateCheckpointStart(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, string.Empty, sequenceNumber.ToString(), "-1", offset.ToString())); - mockLog.Verify(log => log.UpdateCheckpointComplete(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, string.Empty, sequenceNumber.ToString(), "-1", offset.ToString())); + mockLog.Verify(log => log.UpdateCheckpointStart(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, string.Empty, sequenceNumber.ToString(), offset.ToString())); + mockLog.Verify(log => log.UpdateCheckpointComplete(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, string.Empty, sequenceNumber.ToString(), offset.ToString())); } } @@ -751,7 +713,7 @@ public async Task UpdateCheckpointLogsStartAndCompleteWhenTheBlobDoesNotExist(bo public void UpdateCheckpointLogsErrorsWhenTheBlobExists(bool useCheckpointPositionOverload) { var sequenceNumber = 456; - var offset = 789; + var offset = "789"; var checkpoint = new EventProcessorCheckpoint { @@ -777,13 +739,13 @@ public void UpdateCheckpointLogsErrorsWhenTheBlobExists(bool useCheckpointPositi if (useCheckpointPositionOverload) { - Assert.That(async () => await target.UpdateCheckpointAsync(checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.PartitionId, checkpoint.ClientIdentifier, new CheckpointPosition(sequenceNumber), CancellationToken.None), Throws.Exception.EqualTo(expectedException)); - mockLog.Verify(log => log.UpdateCheckpointError(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.ClientIdentifier, sequenceNumber.ToString(), "-1", string.Empty, expectedException.Message)); + Assert.That(async () => await target.UpdateCheckpointAsync(checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.PartitionId, checkpoint.ClientIdentifier, new CheckpointPosition(offset, sequenceNumber), CancellationToken.None), Throws.Exception.EqualTo(expectedException)); + mockLog.Verify(log => log.UpdateCheckpointError(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.ClientIdentifier, sequenceNumber.ToString(), offset.ToString(), expectedException.Message)); } else { Assert.That(async () => await target.UpdateCheckpointAsync(checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.PartitionId, offset, sequenceNumber, CancellationToken.None), Throws.Exception.EqualTo(expectedException)); - mockLog.Verify(log => log.UpdateCheckpointError(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, string.Empty, sequenceNumber.ToString(), "-1", offset.ToString(), expectedException.Message)); + mockLog.Verify(log => log.UpdateCheckpointError(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, string.Empty, sequenceNumber.ToString(), offset.ToString(), expectedException.Message)); } } @@ -819,13 +781,13 @@ public void UpdateCheckpointLogsErrorsWhenTheBlobDoesNotExist(bool useCheckpoint if (useCheckpointPositionOverload) { - Assert.That(async () => await target.UpdateCheckpointAsync(checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.PartitionId, checkpoint.ClientIdentifier, new CheckpointPosition(0), CancellationToken.None), Throws.Exception.EqualTo(expectedException)); - mockLog.Verify(log => log.UpdateCheckpointError(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.ClientIdentifier, "0", "-1", string.Empty, expectedException.Message)); + Assert.That(async () => await target.UpdateCheckpointAsync(checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.PartitionId, checkpoint.ClientIdentifier, new CheckpointPosition("0", 0), CancellationToken.None), Throws.Exception.EqualTo(expectedException)); + mockLog.Verify(log => log.UpdateCheckpointError(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.ClientIdentifier, "0", "0", expectedException.Message)); } else { - Assert.That(async () => await target.UpdateCheckpointAsync(checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.PartitionId, 0, 0, CancellationToken.None), Throws.Exception.EqualTo(expectedException)); - mockLog.Verify(log => log.UpdateCheckpointError(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, string.Empty, "0", "-1", "0", expectedException.Message)); + Assert.That(async () => await target.UpdateCheckpointAsync(checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, checkpoint.PartitionId, "0", 0, CancellationToken.None), Throws.Exception.EqualTo(expectedException)); + mockLog.Verify(log => log.UpdateCheckpointError(checkpoint.PartitionId, checkpoint.FullyQualifiedNamespace, checkpoint.EventHubName, checkpoint.ConsumerGroup, string.Empty, "0", "0", expectedException.Message)); } } @@ -844,7 +806,7 @@ public void UpdateCheckpointForMissingContainerThrowsAndLogsCheckpointUpdateErro target.Logger = mockLog.Object; Assert.That(async () => await target.UpdateCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, PartitionId, Identifier, new CheckpointPosition(0), CancellationToken.None), Throws.InstanceOf()); - mockLog.Verify(m => m.UpdateCheckpointError(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, "0", "-1", string.Empty, ex.Message)); + mockLog.Verify(m => m.UpdateCheckpointError(PartitionId, FullyQualifiedNamespace, EventHubName, ConsumerGroup, Identifier, "0", null, ex.Message)); } /// @@ -1283,7 +1245,7 @@ public async Task UpdateCheckpointAsyncDelegatesTheCancellationTokenWhenTheBlobE } else { - await checkpointStore.UpdateCheckpointAsync(FullyQualifiedNamespaceLowercase, EventHubNameLowercase, ConsumerGroupLowercase, partition, 0, 10, cancellationSource.Token); + await checkpointStore.UpdateCheckpointAsync(FullyQualifiedNamespaceLowercase, EventHubNameLowercase, ConsumerGroupLowercase, partition, "0", 10, cancellationSource.Token); } Assert.That(stateBeforeCancellation.HasValue, Is.True, "State before cancellation should have been captured."); @@ -1388,12 +1350,12 @@ public async Task GetCheckpointPreferredNewCheckpointOverLegacy() var checkpoint = await target.GetCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, "0", CancellationToken.None); Assert.That(checkpoint, Is.Not.Null, "A single checkpoint should have been returned."); - Assert.That(checkpoint.StartingPosition, Is.EqualTo(EventPosition.FromSequenceNumber(960182, false))); + Assert.That(checkpoint.StartingPosition, Is.EqualTo(EventPosition.FromOffset("14", false))); Assert.That(checkpoint.PartitionId, Is.EqualTo("0")); Assert.That(checkpoint, Is.InstanceOf(), "Checkpoint instance was not the expected type."); var blobCheckpoint = (BlobCheckpointStoreInternal.BlobStorageCheckpoint)checkpoint; - Assert.That(14, Is.EqualTo(blobCheckpoint.Offset), "Checkpoint offset did not have the correct value."); + Assert.That("14", Is.EqualTo(blobCheckpoint.Offset), "Checkpoint offset did not have the correct value."); Assert.That(960182, Is.EqualTo(blobCheckpoint.SequenceNumber), "Checkpoint sequence number did not have the correct value."); } @@ -1430,7 +1392,7 @@ public async Task GetCheckpointsUsesOffsetAsTheStartingPositionWhenPresentInLega var checkpoint = await target.GetCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, "0", CancellationToken.None); Assert.That(checkpoint, Is.Not.Null, "A set of checkpoints should have been returned."); - Assert.That(checkpoint.StartingPosition, Is.EqualTo(EventPosition.FromSequenceNumber(960180, false))); + Assert.That(checkpoint.StartingPosition, Is.EqualTo(EventPosition.FromOffset("13", false))); Assert.That(checkpoint.PartitionId, Is.EqualTo("0")); } diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/Infrastructure/BlobsCheckpointStoreInternal.Diagnostics.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/Infrastructure/BlobsCheckpointStoreInternal.Diagnostics.cs index aaa66f163bce3..23d19e1c51c47 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/Infrastructure/BlobsCheckpointStoreInternal.Diagnostics.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/Infrastructure/BlobsCheckpointStoreInternal.Diagnostics.cs @@ -87,7 +87,6 @@ internal sealed partial class BlobCheckpointStoreInternal /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the client that authored this checkpoint. /// The sequence number associated with this checkpoint. - /// The replication segment associated with this checkpoint. /// The offset associated with this checkpoint. /// The exception that occurred. /// @@ -97,10 +96,9 @@ internal sealed partial class BlobCheckpointStoreInternal string consumerGroup, string clientIdentifier, string sequenceNumber, - string replicationSegment, string offset, Exception exception) => - Logger.UpdateCheckpointError(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber, replicationSegment, offset, exception.Message); + Logger.UpdateCheckpointError(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber, offset, exception.Message); /// /// Indicates that an attempt to update a checkpoint has completed. @@ -112,7 +110,6 @@ internal sealed partial class BlobCheckpointStoreInternal /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the client that authored this checkpoint. /// The sequence number associated with this checkpoint. - /// The replication segment associated with this checkpoint. /// The offset associated with this checkpoint. /// partial void UpdateCheckpointComplete(string partitionId, @@ -121,9 +118,8 @@ internal sealed partial class BlobCheckpointStoreInternal string consumerGroup, string clientIdentifier, string sequenceNumber, - string replicationSegment, string offset) => - Logger.UpdateCheckpointComplete(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber, replicationSegment, offset); + Logger.UpdateCheckpointComplete(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber, offset); /// /// Indicates that an attempt to create/update a checkpoint has started. @@ -135,7 +131,6 @@ internal sealed partial class BlobCheckpointStoreInternal /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the client that authored this checkpoint. /// The sequence number associated with this checkpoint. - /// The replication segment associated with this checkpoint. /// The offset associated with this checkpoint. /// partial void UpdateCheckpointStart(string partitionId, @@ -144,9 +139,8 @@ internal sealed partial class BlobCheckpointStoreInternal string consumerGroup, string clientIdentifier, string sequenceNumber, - string replicationSegment, string offset) => - Logger.UpdateCheckpointStart(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber, replicationSegment, offset); + Logger.UpdateCheckpointStart(partitionId, fullyQualifiedNamespace, eventHubName, consumerGroup, clientIdentifier, sequenceNumber, offset); /// /// Indicates that an attempt to retrieve claim partition ownership has completed. diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/Infrastructure/IBlobEventLogger.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/Infrastructure/IBlobEventLogger.cs index 9f37487c033cb..e6ca8eaf158ae 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/Infrastructure/IBlobEventLogger.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/Infrastructure/IBlobEventLogger.cs @@ -116,7 +116,6 @@ public interface IBlobEventLogger /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the client that authored this checkpoint. /// The sequence number associated with this checkpoint. - /// The replication segment associated with this checkpoint. /// The offset associated with this checkpoint. /// The exception that occurred. /// @@ -126,7 +125,6 @@ public interface IBlobEventLogger string consumerGroup, string clientIdentifier, string sequenceNumber, - string replicationSegment, string offset, string exception); @@ -140,7 +138,6 @@ public interface IBlobEventLogger /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the client that authored this checkpoint. /// The sequence number associated with this checkpoint. - /// The replication segment associated with this checkpoint. /// The offset associated with this checkpoint. /// void UpdateCheckpointComplete(string partitionId, @@ -149,7 +146,6 @@ public interface IBlobEventLogger string consumerGroup, string clientIdentifier, string sequenceNumber, - string replicationSegment, string offset); /// @@ -162,7 +158,6 @@ public interface IBlobEventLogger /// The name of the consumer group the checkpoint is associated with. /// The unique identifier of the client that authored this checkpoint. /// The sequence number associated with this checkpoint. - /// The replication segment associated with this checkpoint. /// The offset associated with this checkpoint. /// void UpdateCheckpointStart(string partitionId, @@ -171,7 +166,6 @@ public interface IBlobEventLogger string consumerGroup, string clientIdentifier, string sequenceNumber, - string replicationSegment, string offset); /// diff --git a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/Testing/EventDataExtensionsTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/Testing/EventDataExtensionsTests.cs index 0efbbccdc3cec..8819e5c40fb5d 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/Testing/EventDataExtensionsTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs.Shared/tests/Testing/EventDataExtensionsTests.cs @@ -39,13 +39,13 @@ public void IsEquivalentToDetectsDifferentDifferentOffset() { var firstEvent = new MockEventData( eventBody: new byte[] { 0x22, 0x44 }, - offset: 1, + offset: "1", partitionKey: "hello", systemProperties: new Dictionary { { "test", new object() } }); var secondEvent = new MockEventData( eventBody: new byte[] { 0x22, 0x44 }, - offset: 111, + offset: "111", partitionKey: "hello", systemProperties: new Dictionary { { "test", new object() } }); @@ -62,13 +62,13 @@ public void IsEquivalentToDetectsDifferentDifferentSequenceNumbers() { var firstEvent = new MockEventData( eventBody: new byte[] { 0x22, 0x44 }, - offset: 1, + offset: "1", partitionKey: "hello", systemProperties: new Dictionary { { "test", new object() } }); var secondEvent = new MockEventData( eventBody: new byte[] { 0x22, 0x44 }, - offset: 1, + offset: "1", partitionKey: "hello", systemProperties: new Dictionary { { "test", new object() } }); @@ -85,13 +85,13 @@ public void IsEquivalentToDetectsDifferentDifferentPartitionKey() { var firstEvent = new MockEventData( eventBody: new byte[] { 0x22, 0x44 }, - offset: 1, + offset: "1", partitionKey: "hello", systemProperties: new Dictionary { { "test", new object() } }); var secondEvent = new MockEventData( eventBody: new byte[] { 0x22, 0x44 }, - offset: 1, + offset: "1", partitionKey: "goodbye", systemProperties: new Dictionary { { "test", new object() } }); @@ -285,8 +285,8 @@ public void IsEquivalentToIgnoresMappedSystemPropertiesByDefault() public void IsEquivalentToDetectsDifferentTypedSystemProperties() { var body = new byte[] { 0x22, 0x44, 0x88 }; - var firstEvent = new MockEventData((byte[])body.Clone(), offset: 1); - var secondEvent = new MockEventData((byte[])body.Clone(), offset: 2); + var firstEvent = new MockEventData((byte[])body.Clone(), offset: "1"); + var secondEvent = new MockEventData((byte[])body.Clone(), offset: "2"); Assert.That(firstEvent.IsEquivalentTo(secondEvent, true), Is.False); } @@ -380,13 +380,13 @@ public void IsEquivalentToDetectsEqualEventsWithPartitionMetrics() var firstEvent = new MockEventData( eventBody: (byte[])body.Clone(), - offset: 1, + offset: "1", partitionKey: "hello", systemProperties: new Dictionary { { "test", new object() } }); var secondEvent = new MockEventData( eventBody: (byte[])body.Clone(), - offset: 1, + offset: "1", partitionKey: "hello", systemProperties: new Dictionary { { "test", new object() } }); @@ -405,13 +405,13 @@ public void IsEquivalentToDetectsEqualEventsWithoutPartitionMetrics() var firstEvent = new MockEventData( eventBody: (byte[])body.Clone(), - offset: 1, + offset: "1", partitionKey: "hello", systemProperties: new Dictionary { { "test", new object() } }); var secondEvent = new MockEventData( eventBody: (byte[])body.Clone(), - offset: 1, + offset: "1", partitionKey: "hello", systemProperties: new Dictionary { { "test", new object() } }); @@ -428,7 +428,7 @@ public void IsEquivalentToDetectsSameInstance() { var firstEvent = new MockEventData( eventBody: new byte[] { 0x22, 0x44, 0x88 }, - offset: 1, + offset: "1", partitionKey: "hello", systemProperties: new Dictionary { { "test", new object() } }); @@ -456,7 +456,7 @@ public void IsEquivalentToDetectsNullInstance() { var firstEvent = new MockEventData( eventBody: new byte[] { 0x22, 0x44, 0x88 }, - offset: 1, + offset: "1", partitionKey: "hello", systemProperties: new Dictionary { { "test", new object() } }); @@ -473,7 +473,7 @@ public void IsEquivalentToDetectsNullArgument() { var firstEvent = new MockEventData( eventBody: new byte[] { 0x22, 0x44, 0x88 }, - offset: 1, + offset: "1", partitionKey: "hello", systemProperties: new Dictionary { { "test", new object() } }); @@ -493,7 +493,7 @@ private class MockEventData : EventData IDictionary properties = null, IReadOnlyDictionary systemProperties = null, long sequenceNumber = long.MinValue, - long offset = long.MinValue, + string offset = null, DateTimeOffset enqueuedTime = default, string partitionKey = null) : base(eventBody, properties, systemProperties, sequenceNumber, offset, enqueuedTime, partitionKey) { diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/api/Azure.Messaging.EventHubs.netstandard2.0.cs b/sdk/eventhub/Azure.Messaging.EventHubs/api/Azure.Messaging.EventHubs.netstandard2.0.cs index 7d23614281bcd..bf44cadc5aca6 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/api/Azure.Messaging.EventHubs.netstandard2.0.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/api/Azure.Messaging.EventHubs.netstandard2.0.cs @@ -6,10 +6,10 @@ public partial class EventData : Azure.Messaging.MessageContent public EventData(Azure.Core.Amqp.AmqpAnnotatedMessage amqpMessage) { } public EventData(System.BinaryData eventBody) { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - protected EventData(System.BinaryData eventBody, System.Collections.Generic.IDictionary properties = null, System.Collections.Generic.IReadOnlyDictionary systemProperties = null, long sequenceNumber = (long)-9223372036854775808, long offset = (long)-9223372036854775808, System.DateTimeOffset enqueuedTime = default(System.DateTimeOffset), string partitionKey = null) { } + protected EventData(System.BinaryData eventBody, System.Collections.Generic.IDictionary properties = null, System.Collections.Generic.IReadOnlyDictionary systemProperties = null, long sequenceNumber = (long)-9223372036854775808, string offset = null, System.DateTimeOffset enqueuedTime = default(System.DateTimeOffset), string partitionKey = null) { } public EventData(System.ReadOnlyMemory eventBody) { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - protected EventData(System.ReadOnlyMemory eventBody, System.Collections.Generic.IDictionary properties = null, System.Collections.Generic.IReadOnlyDictionary systemProperties = null, long sequenceNumber = (long)-9223372036854775808, long offset = (long)-9223372036854775808, System.DateTimeOffset enqueuedTime = default(System.DateTimeOffset), string partitionKey = null) { } + protected EventData(System.ReadOnlyMemory eventBody, System.Collections.Generic.IDictionary properties = null, System.Collections.Generic.IReadOnlyDictionary systemProperties = null, long sequenceNumber = (long)-9223372036854775808, string offset = null, System.DateTimeOffset enqueuedTime = default(System.DateTimeOffset), string partitionKey = null) { } public EventData(string eventBody) { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public System.ReadOnlyMemory Body { get { throw null; } } @@ -26,7 +26,7 @@ public partial class EventData : Azure.Messaging.MessageContent [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public override bool IsReadOnly { get { throw null; } } public string MessageId { get { throw null; } set { } } - public long Offset { get { throw null; } } + public string Offset { get { throw null; } } public string PartitionKey { get { throw null; } } public System.Collections.Generic.IDictionary Properties { get { throw null; } } public long SequenceNumber { get { throw null; } } @@ -80,8 +80,9 @@ public partial class EventHubConnectionOptions } public partial class EventHubProperties { - protected internal EventHubProperties(string name, System.DateTimeOffset createdOn, string[] partitionIds) { } + protected internal EventHubProperties(string name, System.DateTimeOffset createdOn, string[] partitionIds, bool isGeoReplicationEnabled = false) { } public System.DateTimeOffset CreatedOn { get { throw null; } } + public bool IsGeoReplicationEnabled { get { throw null; } } public string Name { get { throw null; } } public string[] PartitionIds { get { throw null; } } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] @@ -139,14 +140,14 @@ public enum FailureReason } public static partial class EventHubsModelFactory { - public static Azure.Messaging.EventHubs.EventData EventData(System.BinaryData eventBody, System.Collections.Generic.IDictionary properties = null, System.Collections.Generic.IReadOnlyDictionary systemProperties = null, string partitionKey = null, long sequenceNumber = (long)-9223372036854775808, long offset = (long)-9223372036854775808, System.DateTimeOffset enqueuedTime = default(System.DateTimeOffset)) { throw null; } + public static Azure.Messaging.EventHubs.EventData EventData(System.BinaryData eventBody, System.Collections.Generic.IDictionary properties = null, System.Collections.Generic.IReadOnlyDictionary systemProperties = null, string partitionKey = null, long sequenceNumber = (long)-9223372036854775808, string offset = null, System.DateTimeOffset enqueuedTime = default(System.DateTimeOffset)) { throw null; } public static Azure.Messaging.EventHubs.Producer.EventDataBatch EventDataBatch(long batchSizeBytes, System.Collections.Generic.IList batchEventStore, Azure.Messaging.EventHubs.Producer.CreateBatchOptions batchOptions = null, System.Func tryAddCallback = null) { throw null; } public static Azure.Messaging.EventHubs.EventHubProperties EventHubProperties(string name, System.DateTimeOffset createdOn, string[] partitionIds) { throw null; } - public static Azure.Messaging.EventHubs.Consumer.LastEnqueuedEventProperties LastEnqueuedEventProperties(long? lastSequenceNumber, long? lastOffset, System.DateTimeOffset? lastEnqueuedTime, System.DateTimeOffset? lastReceivedTime) { throw null; } + public static Azure.Messaging.EventHubs.Consumer.LastEnqueuedEventProperties LastEnqueuedEventProperties(long? lastSequenceNumber, string lastOffset, System.DateTimeOffset? lastEnqueuedTime, System.DateTimeOffset? lastReceivedTime) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static Azure.Messaging.EventHubs.Consumer.PartitionContext PartitionContext(string partitionId, Azure.Messaging.EventHubs.Consumer.LastEnqueuedEventProperties lastEnqueuedEventProperties = default(Azure.Messaging.EventHubs.Consumer.LastEnqueuedEventProperties)) { throw null; } public static Azure.Messaging.EventHubs.Consumer.PartitionContext PartitionContext(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, Azure.Messaging.EventHubs.Consumer.LastEnqueuedEventProperties lastEnqueuedEventProperties = default(Azure.Messaging.EventHubs.Consumer.LastEnqueuedEventProperties)) { throw null; } - public static Azure.Messaging.EventHubs.PartitionProperties PartitionProperties(string eventHubName, string partitionId, bool isEmpty, long beginningSequenceNumber, long lastSequenceNumber, long lastOffset, System.DateTimeOffset lastEnqueuedTime) { throw null; } + public static Azure.Messaging.EventHubs.PartitionProperties PartitionProperties(string eventHubName, string partitionId, bool isEmpty, long beginningSequenceNumber, long lastSequenceNumber, string lastOffset, System.DateTimeOffset lastEnqueuedTime) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static Azure.Messaging.EventHubs.Producer.PartitionPublishingProperties PartitionPublishingProperties(bool isIdempotentPublishingEnabled, long? producerGroupId, short? ownerLevel, int? lastPublishedSequenceNumber) { throw null; } } @@ -184,12 +185,12 @@ public enum EventHubsTransportType } public partial class PartitionProperties { - protected internal PartitionProperties(string eventHubName, string partitionId, bool isEmpty, long beginningSequenceNumber, long lastSequenceNumber, long lastOffset, System.DateTimeOffset lastEnqueuedTime) { } + protected internal PartitionProperties(string eventHubName, string partitionId, bool isEmpty, long beginningSequenceNumber, long lastSequenceNumber, string lastOffset, System.DateTimeOffset lastEnqueuedTime) { } public long BeginningSequenceNumber { get { throw null; } } public string EventHubName { get { throw null; } } public string Id { get { throw null; } } public bool IsEmpty { get { throw null; } } - public long LastEnqueuedOffset { get { throw null; } } + public string LastEnqueuedOffset { get { throw null; } } public long LastEnqueuedSequenceNumber { get { throw null; } } public System.DateTimeOffset LastEnqueuedTime { get { throw null; } } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] @@ -260,7 +261,7 @@ public partial struct EventPosition : System.IEquatable { - public LastEnqueuedEventProperties(long? lastSequenceNumber, long? lastOffset, System.DateTimeOffset? lastEnqueuedTime, System.DateTimeOffset? lastReceivedTime) { throw null; } + private object _dummy; + private int _dummyPrimitive; + public LastEnqueuedEventProperties(long? lastSequenceNumber, string lastOffset, System.DateTimeOffset? lastEnqueuedTime, System.DateTimeOffset? lastReceivedTime) { throw null; } public System.DateTimeOffset? EnqueuedTime { get { throw null; } } public System.DateTimeOffset? LastReceivedTime { get { throw null; } } - public long? Offset { get { throw null; } } + public string Offset { get { throw null; } } public long? SequenceNumber { get { throw null; } } public bool Equals(Azure.Messaging.EventHubs.Consumer.LastEnqueuedEventProperties other) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] @@ -331,8 +334,9 @@ public abstract partial class CheckpointStore public abstract System.Threading.Tasks.Task> ClaimOwnershipAsync(System.Collections.Generic.IEnumerable desiredOwnership, System.Threading.CancellationToken cancellationToken); public abstract System.Threading.Tasks.Task GetCheckpointAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, System.Threading.CancellationToken cancellationToken); public abstract System.Threading.Tasks.Task> ListOwnershipAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, System.Threading.CancellationToken cancellationToken); - public virtual System.Threading.Tasks.Task UpdateCheckpointAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, long offset, long? sequenceNumber, System.Threading.CancellationToken cancellationToken) { throw null; } public virtual System.Threading.Tasks.Task UpdateCheckpointAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, string clientIdentifier, Azure.Messaging.EventHubs.Processor.CheckpointPosition startingPosition, System.Threading.CancellationToken cancellationToken) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual System.Threading.Tasks.Task UpdateCheckpointAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, string offset, long? sequenceNumber, System.Threading.CancellationToken cancellationToken) { throw null; } } public partial class EventProcessorCheckpoint { @@ -393,6 +397,7 @@ public abstract partial class EventProcessor where TPartition : Azur public string ConsumerGroup { get { throw null; } } protected bool EnableBatchTracing { get { throw null; } set { } } public string EventHubName { get { throw null; } } + protected Azure.Messaging.EventHubs.EventHubProperties EventHubProperties { get { throw null; } } public string FullyQualifiedNamespace { get { throw null; } } public string Identifier { get { throw null; } } public bool IsRunning { get { throw null; } protected set { } } @@ -420,7 +425,8 @@ public abstract partial class EventProcessor where TPartition : Azur [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public override string ToString() { throw null; } protected virtual System.Threading.Tasks.Task UpdateCheckpointAsync(string partitionId, Azure.Messaging.EventHubs.Processor.CheckpointPosition startingPosition, System.Threading.CancellationToken cancellationToken) { throw null; } - protected virtual System.Threading.Tasks.Task UpdateCheckpointAsync(string partitionId, long offset, long? sequenceNumber, System.Threading.CancellationToken cancellationToken) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + protected virtual System.Threading.Tasks.Task UpdateCheckpointAsync(string partitionId, string offset, long? sequenceNumber, System.Threading.CancellationToken cancellationToken) { throw null; } protected internal virtual System.Threading.Tasks.Task ValidateProcessingPreconditions(System.Threading.CancellationToken cancellationToken) { throw null; } } public partial class PartitionReceiver : System.IAsyncDisposable @@ -482,7 +488,8 @@ public abstract partial class PluggableCheckpointStoreEventProcessor protected override System.Threading.Tasks.Task GetCheckpointAsync(string partitionId, System.Threading.CancellationToken cancellationToken) { throw null; } protected override System.Threading.Tasks.Task> ListOwnershipAsync(System.Threading.CancellationToken cancellationToken) { throw null; } protected override System.Threading.Tasks.Task UpdateCheckpointAsync(string partitionId, Azure.Messaging.EventHubs.Processor.CheckpointPosition startingPosition, System.Threading.CancellationToken cancellationToken) { throw null; } - protected override System.Threading.Tasks.Task UpdateCheckpointAsync(string partitionId, long offset, long? sequenceNumber, System.Threading.CancellationToken cancellationToken) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + protected override System.Threading.Tasks.Task UpdateCheckpointAsync(string partitionId, string offset, long? sequenceNumber, System.Threading.CancellationToken cancellationToken) { throw null; } } } namespace Azure.Messaging.EventHubs.Processor @@ -490,8 +497,12 @@ namespace Azure.Messaging.EventHubs.Processor [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] public partial struct CheckpointPosition : System.IEquatable { + private object _dummy; private int _dummyPrimitive; + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public CheckpointPosition(long sequenceNumber) { throw null; } + public CheckpointPosition(string offset, long sequenceNumber = (long)-9223372036854775808) { throw null; } + public string Offset { get { throw null; } } public long SequenceNumber { get { throw null; } } public bool Equals(Azure.Messaging.EventHubs.Processor.CheckpointPosition other) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/samples/Sample11_MockingClientTypes.md b/sdk/eventhub/Azure.Messaging.EventHubs/samples/Sample11_MockingClientTypes.md index 261fe72ca2432..3a6613477e639 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/samples/Sample11_MockingClientTypes.md +++ b/sdk/eventhub/Azure.Messaging.EventHubs/samples/Sample11_MockingClientTypes.md @@ -220,7 +220,7 @@ Mock mockConsumer = new(); LastEnqueuedEventProperties lastEnqueueEventProperties = EventHubsModelFactory.LastEnqueuedEventProperties( lastSequenceNumber : 1234, - lastOffset : 234, + lastOffset : "234", lastEnqueuedTime : DateTimeOffset.Parse("1:24 AM"), lastReceivedTime : DateTimeOffset.Parse("1:26 AM")); @@ -246,7 +246,7 @@ async IAsyncEnumerable mockReturn() systemProperties: new Dictionary(), //arbitrary value partitionKey: "sample-key", sequenceNumber: 1000, - offset: 1500, + offset: "1500", enqueuedTime: DateTimeOffset.Parse("11:36 PM")); EventData eventData2 = EventHubsModelFactory.EventData( @@ -254,7 +254,7 @@ async IAsyncEnumerable mockReturn() systemProperties: new Dictionary(), //arbitrary value partitionKey: "sample-key", sequenceNumber: 1000, - offset: 1500, + offset: "1500", enqueuedTime: DateTimeOffset.Parse("11:36 PM")); // This creates a mock PartitionEvent to return from the consumer client. @@ -341,7 +341,7 @@ for (int index = 0; index < 10; index++) systemProperties: new Dictionary(), //arbitrary value partitionKey: $"sample-key-{index}", sequenceNumber: 1234, - offset: 234, + offset: "234", enqueuedTime: DateTimeOffset.Parse("9:25 AM")); receivedEvents.Add(eventData); @@ -431,7 +431,7 @@ Dictionary partitionProperties = new() isEmpty : true, beginningSequenceNumber: 1000, lastSequenceNumber : 1100, - lastOffset : 500, + lastOffset : "500", lastEnqueuedTime : DateTime.UtcNow) }, // Empty partition @@ -441,7 +441,7 @@ Dictionary partitionProperties = new() isEmpty : false, beginningSequenceNumber : 2000, lastSequenceNumber : 2000, - lastOffset : 760, + lastOffset : "760", lastEnqueuedTime : DateTime.UtcNow) } }; diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpAnnotatedMessageExtensions.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpAnnotatedMessageExtensions.cs index c42a363462a87..cd64f1480e620 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpAnnotatedMessageExtensions.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpAnnotatedMessageExtensions.cs @@ -33,11 +33,11 @@ internal static class AmqpAnnotatedMessageExtensions public static void PopulateFromEventProperties(this AmqpAnnotatedMessage instance, IDictionary properties = null, long? sequenceNumber = null, - long? offset = null, + string offset = null, DateTimeOffset? enqueuedTime = null, string partitionKey = null, long? lastPartitionSequenceNumber = null, - long? lastPartitionOffset = null, + string lastPartitionOffset = null, DateTimeOffset? lastPartitionEnqueuedTime = null, DateTimeOffset? lastPartitionPropertiesRetrievalTime = null) { @@ -51,9 +51,9 @@ internal static class AmqpAnnotatedMessageExtensions instance.MessageAnnotations[AmqpProperty.SequenceNumber.ToString()] = sequenceNumber.Value; } - if (offset.HasValue) + if (!string.IsNullOrEmpty(offset)) { - instance.MessageAnnotations[AmqpProperty.Offset.ToString()] = offset.Value; + instance.MessageAnnotations[AmqpProperty.Offset.ToString()] = offset; } if (enqueuedTime.HasValue) @@ -71,9 +71,9 @@ internal static class AmqpAnnotatedMessageExtensions instance.DeliveryAnnotations[AmqpProperty.PartitionLastEnqueuedSequenceNumber.ToString()] = lastPartitionSequenceNumber.Value; } - if (lastPartitionOffset.HasValue) + if (!string.IsNullOrEmpty(lastPartitionOffset)) { - instance.DeliveryAnnotations[AmqpProperty.PartitionLastEnqueuedOffset.ToString()] = lastPartitionOffset.Value; + instance.DeliveryAnnotations[AmqpProperty.PartitionLastEnqueuedOffset.ToString()] = lastPartitionOffset; } if (lastPartitionEnqueuedTime.HasValue) @@ -188,13 +188,13 @@ public static BinaryData GetEventBody(this AmqpAnnotatedMessage instance) /// /// The offset, if represented in the ; otherwise, . /// - public static long GetOffset(this AmqpAnnotatedMessage instance, - long defaultValue = long.MinValue) + public static string GetOffset(this AmqpAnnotatedMessage instance, + string defaultValue = default) { if ((instance.HasSection(AmqpMessageSection.MessageAnnotations)) && (instance.MessageAnnotations.TryGetValue(AmqpProperty.Offset.ToString(), out var value))) { - return (long)value; + return (string)value; } return defaultValue; @@ -298,13 +298,13 @@ public static BinaryData GetEventBody(this AmqpAnnotatedMessage instance) /// /// The offset of the last event published to the partition, if represented in the ; otherwise, . /// - public static long? GetLastPartitionOffset(this AmqpAnnotatedMessage instance, - long? defaultValue = default) + public static string GetLastPartitionOffset(this AmqpAnnotatedMessage instance, + string defaultValue = default) { if ((instance.HasSection(AmqpMessageSection.DeliveryAnnotations)) && (instance.DeliveryAnnotations.TryGetValue(AmqpProperty.PartitionLastEnqueuedOffset.ToString(), out var value))) { - return (long)value; + return (string)value; } return defaultValue; diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpConnectionScope.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpConnectionScope.cs index e643ee6a405a9..ffc0a68e4414d 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpConnectionScope.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpConnectionScope.cs @@ -702,6 +702,9 @@ public void Dispose() linkSettings.AddProperty(AmqpProperty.ConsumerIdentifier, linkIdentifier); } + linkSettings.DesiredCapabilities ??= new Multiple(); + linkSettings.DesiredCapabilities.Add(AmqpProperty.GeoReplication); + if (trackLastEnqueuedEventProperties) { linkSettings.DesiredCapabilities ??= new Multiple(); @@ -807,6 +810,9 @@ public void Dispose() linkSettings.AddProperty(AmqpProperty.Timeout, (uint)linkTimeout.CalculateRemaining(stopWatch.GetElapsedTime()).TotalMilliseconds); linkSettings.AddProperty(AmqpProperty.EntityType, (int)AmqpProperty.Entity.EventHub); + linkSettings.DesiredCapabilities ??= new Multiple(); + linkSettings.DesiredCapabilities.Add(AmqpProperty.GeoReplication); + if ((features & TransportProducerFeatures.IdempotentPublishing) != 0) { linkSettings.DesiredCapabilities ??= new Multiple(); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpConsumer.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpConsumer.cs index 927134ece9fe0..83bc43a141ad9 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpConsumer.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpConsumer.cs @@ -297,7 +297,7 @@ internal class AmqpConsumer : TransportConsumer firstReceivedEvent = receivedEvents[0]; lastReceivedEvent = receivedEvents[receivedEventCount - 1]; - if (lastReceivedEvent.Offset > long.MinValue) + if (!string.IsNullOrEmpty(lastReceivedEvent.Offset)) { CurrentEventPosition = EventPosition.FromOffset(lastReceivedEvent.Offset, false); } diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpFilter.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpFilter.cs index a9fb19fd33c64..bbfcf3dabaeda 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpFilter.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpFilter.cs @@ -72,7 +72,7 @@ public static string BuildFilterExpression(EventPosition eventPosition) return $"{ EnqueuedTimeName } > { eventPosition.EnqueuedTime.Value.ToUnixTimeMilliseconds() }"; } - // If no filter was built, than the event position is not valid for filtering. + // If no filter was built, then the event position is not valid for filtering. throw new ArgumentException(Resources.InvalidEventPositionForFilter, nameof(eventPosition)); } diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpManagement.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpManagement.cs index 682fa3be3b393..7d8c65603d34b 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpManagement.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpManagement.cs @@ -74,6 +74,12 @@ public static class ResponseMap /// public static MapKey PartitionIdentifiers { get; } = new MapKey("partition_ids"); + /// + /// The message property that identifies whether this Event Hub has geo-replication enabled. + /// + /// + public static MapKey GeoReplicationFactor { get; } = new MapKey("georeplication_factor"); + /// /// The message property that identifies the beginning sequence number in a partition. /// diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpMessageConverter.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpMessageConverter.cs index c24eb13643348..d6c879b296a15 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpMessageConverter.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpMessageConverter.cs @@ -39,9 +39,7 @@ internal class AmqpMessageConverter private static readonly HashSet SystemPropertyLongKeys = new() { AmqpProperty.SequenceNumber.ToString(), - AmqpProperty.Offset.ToString(), AmqpProperty.PartitionLastEnqueuedSequenceNumber.ToString(), - AmqpProperty.PartitionLastEnqueuedOffset.ToString() }; /// @@ -181,10 +179,17 @@ public virtual EventHubProperties CreateEventHubPropertiesFromResponse(AmqpMessa throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resources.InvalidMessageBody, typeof(AmqpMap).Name)); } + var geoReplicationEnabled = responseData[AmqpManagement.ResponseMap.GeoReplicationFactor] switch + { + int count when count > 1 => true, + _ => false + }; + return new EventHubProperties( (string)responseData[AmqpManagement.ResponseMap.Name], new DateTimeOffset((DateTime)responseData[AmqpManagement.ResponseMap.CreatedAt], TimeSpan.Zero), - (string[])responseData[AmqpManagement.ResponseMap.PartitionIdentifiers]); + (string[])responseData[AmqpManagement.ResponseMap.PartitionIdentifiers], + geoReplicationEnabled); } /// @@ -250,7 +255,7 @@ public virtual PartitionProperties CreatePartitionPropertiesFromResponse(AmqpMes (bool)responseData[AmqpManagement.ResponseMap.PartitionRuntimeInfoPartitionIsEmpty], (long)responseData[AmqpManagement.ResponseMap.PartitionBeginSequenceNumber], (long)responseData[AmqpManagement.ResponseMap.PartitionLastEnqueuedSequenceNumber], - long.Parse((string)responseData[AmqpManagement.ResponseMap.PartitionLastEnqueuedOffset], NumberStyles.Integer, CultureInfo.InvariantCulture), + (string)responseData[AmqpManagement.ResponseMap.PartitionLastEnqueuedOffset], new DateTimeOffset((DateTime)responseData[AmqpManagement.ResponseMap.PartitionLastEnqueuedTimeUtc], TimeSpan.Zero)); } diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpProperty.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpProperty.cs index 5ac1bb58d36cb..6906dd509084a 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpProperty.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Amqp/AmqpProperty.cs @@ -43,6 +43,12 @@ internal static class AmqpProperty /// public static AmqpSymbol TrackLastEnqueuedEventProperties { get; } = AmqpConstants.Vendor + ":enable-receiver-runtime-metric"; + /// + /// The capability for geo replication in a namespace, to associate with a link. + /// + /// + public static AmqpSymbol GeoReplication { get; } = AmqpConstants.Vendor + ":georeplication"; + /// /// The capability for opting-into idempotent publishing. /// diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Consumer/EventPosition.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/Consumer/EventPosition.cs index fe0d8731e57a7..810f3b7c82e81 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Consumer/EventPosition.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Consumer/EventPosition.cs @@ -81,12 +81,12 @@ public struct EventPosition : IEquatable /// /// The specified position of an event in the partition. /// - public static EventPosition FromOffset(long offset, + public static EventPosition FromOffset(string offset, bool isInclusive = true) { return new EventPosition { - Offset = offset.ToString(CultureInfo.InvariantCulture), + Offset = offset, IsInclusive = isInclusive }; } diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Consumer/LastEnqueuedEventProperties.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/Consumer/LastEnqueuedEventProperties.cs index 8736b79f1761d..1b20862cc781b 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Consumer/LastEnqueuedEventProperties.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Consumer/LastEnqueuedEventProperties.cs @@ -23,7 +23,7 @@ public struct LastEnqueuedEventProperties : IEquatable /// - public long? Offset { get; } + public string Offset { get; } /// /// The date and time, in UTC, that the last observed event was enqueued in the partition. @@ -47,7 +47,7 @@ public struct LastEnqueuedEventProperties : IEquatableThe date and time, in UTC, that the information was last received. /// public LastEnqueuedEventProperties(long? lastSequenceNumber, - long? lastOffset, + string lastOffset, DateTimeOffset? lastEnqueuedTime, DateTimeOffset? lastReceivedTime) { diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/EventData.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/EventData.cs index 69bf941fca6cb..2e6029682bb55 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/EventData.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/EventData.cs @@ -289,10 +289,10 @@ public string CorrelationId /// /// /// This value is read-only and will only be populated for events that have been read from Event Hubs. The default value - /// when not populated is . + /// when not populated is null. /// /// - public long Offset => _amqpMessage.GetOffset(long.MinValue); + public string Offset => _amqpMessage.GetOffset(null); /// /// The date and time, in UTC, of when the event was enqueued in the Event Hub partition. @@ -383,7 +383,7 @@ public string CorrelationId /// populated is null. /// /// - internal long? LastPartitionOffset => _amqpMessage.GetLastPartitionOffset(); + internal string LastPartitionOffset => _amqpMessage.GetLastPartitionOffset(); /// /// The date and time, in UTC, that the last event was enqueued into the Event Hub partition from @@ -553,11 +553,11 @@ public EventData(AmqpAnnotatedMessage amqpMessage) IDictionary properties = null, IReadOnlyDictionary systemProperties = null, long? sequenceNumber = null, - long? offset = null, + string offset = null, DateTimeOffset? enqueuedTime = null, string partitionKey = null, long? lastPartitionSequenceNumber = null, - long? lastPartitionOffset = null, + string lastPartitionOffset = null, DateTimeOffset? lastPartitionEnqueuedTime = null, DateTimeOffset? lastPartitionPropertiesRetrievalTime = null, int? publishedSequenceNumber = null, @@ -621,7 +621,7 @@ public EventData(AmqpAnnotatedMessage amqpMessage) IDictionary properties = null, IReadOnlyDictionary systemProperties = null, long sequenceNumber = long.MinValue, - long offset = long.MinValue, + string offset = null, DateTimeOffset enqueuedTime = default, string partitionKey = null) : this(eventBody, properties, systemProperties, sequenceNumber, offset, enqueuedTime, partitionKey, lastPartitionSequenceNumber: null) { @@ -653,7 +653,7 @@ public EventData(AmqpAnnotatedMessage amqpMessage) IDictionary properties = null, IReadOnlyDictionary systemProperties = null, long sequenceNumber = long.MinValue, - long offset = long.MinValue, + string offset = null, DateTimeOffset enqueuedTime = default, string partitionKey = null) : this(new BinaryData(eventBody), properties, systemProperties, sequenceNumber, offset, enqueuedTime, partitionKey, lastPartitionSequenceNumber: null) { diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/EventHubProperties.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/EventHubProperties.cs index 14a132c29a27e..9ad67f85bdb4e 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/EventHubProperties.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/EventHubProperties.cs @@ -31,6 +31,12 @@ public class EventHubProperties /// public string[] PartitionIds { get; } + /// + /// A flag indicating whether or not the Event Hub has geo-replication enabled. + /// + /// + public bool IsGeoReplicationEnabled { get; } + /// /// Initializes a new instance of the class. /// @@ -38,14 +44,17 @@ public class EventHubProperties /// The name of the Event Hub. /// The date and time at which the Event Hub was created. /// The set of unique identifiers for each partition. + /// A flag indicating whether or not the Event Hub has geo-replication enabled. /// protected internal EventHubProperties(string name, DateTimeOffset createdOn, - string[] partitionIds) + string[] partitionIds, + bool isGeoReplicationEnabled = false) { Name = name; CreatedOn = createdOn; PartitionIds = partitionIds; + IsGeoReplicationEnabled = isGeoReplicationEnabled; } /// diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/EventHubsModelFactory.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/EventHubsModelFactory.cs index b4abe69e6b1fc..5626be93e2b30 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/EventHubsModelFactory.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/EventHubsModelFactory.cs @@ -51,7 +51,7 @@ public static class EventHubsModelFactory bool isEmpty, long beginningSequenceNumber, long lastSequenceNumber, - long lastOffset, + string lastOffset, DateTimeOffset lastEnqueuedTime) => new PartitionProperties(eventHubName, partitionId, isEmpty, beginningSequenceNumber, lastSequenceNumber, lastOffset, lastEnqueuedTime); @@ -81,7 +81,7 @@ public static class EventHubsModelFactory /// The date and time, in UTC, that the information was last received. /// public static LastEnqueuedEventProperties LastEnqueuedEventProperties(long? lastSequenceNumber, - long? lastOffset, + string lastOffset, DateTimeOffset? lastEnqueuedTime, DateTimeOffset? lastReceivedTime) => new LastEnqueuedEventProperties(lastSequenceNumber, lastOffset, lastEnqueuedTime, lastReceivedTime); @@ -132,7 +132,7 @@ public static class EventHubsModelFactory IReadOnlyDictionary systemProperties = null, string partitionKey = null, long sequenceNumber = long.MinValue, - long offset = long.MinValue, + string offset = default, DateTimeOffset enqueuedTime = default) => new EventData(eventBody, properties, systemProperties, sequenceNumber, offset, enqueuedTime, partitionKey); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/PartitionProperties.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/PartitionProperties.cs index 122cd4d023dde..450044d8ada81 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/PartitionProperties.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/PartitionProperties.cs @@ -41,7 +41,7 @@ public class PartitionProperties /// The offset of the last observed event to be enqueued in the partition. /// /// - public long LastEnqueuedOffset { get; } + public string LastEnqueuedOffset { get; } /// /// The date and time, in UTC, that the last observed event was enqueued in the partition. @@ -74,7 +74,7 @@ public class PartitionProperties bool isEmpty, long beginningSequenceNumber, long lastSequenceNumber, - long lastOffset, + string lastOffset, DateTimeOffset lastEnqueuedTime) { EventHubName = eventHubName; diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Primitives/CheckpointStore.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/Primitives/CheckpointStore.cs index bdfb33b061e6c..77a97a59851ed 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Primitives/CheckpointStore.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Primitives/CheckpointStore.cs @@ -82,11 +82,12 @@ public abstract class CheckpointStore /// The sequence number to associate with the checkpoint, indicating that a processor should begin reading from the next event in the stream. /// A instance to signal a request to cancel the operation. /// + [EditorBrowsable(EditorBrowsableState.Never)] public virtual Task UpdateCheckpointAsync(string fullyQualifiedNamespace, string eventHubName, string consumerGroup, string partitionId, - long offset, + string offset, long? sequenceNumber, CancellationToken cancellationToken) => throw new NotImplementedException(); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Primitives/EventProcessor.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/Primitives/EventProcessor.cs index 2a5e5edd17e64..eb5551d9718f8 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Primitives/EventProcessor.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Primitives/EventProcessor.cs @@ -206,6 +206,12 @@ internal EventProcessorStatus Status /// protected EventHubsRetryPolicy RetryPolicy { get; } + /// + /// The properties associated with the Event Hub being read from. This value is updated in each load balancing cycle. + /// + /// + protected EventHubProperties EventHubProperties { get; private set; } + /// /// Indicates whether or not this event processor should instrument batch event processing calls with distributed tracing. /// Implementations that instrument event processing themselves should set this to false. @@ -815,7 +821,7 @@ async Task performProcessing() lastEvent = (eventBatch != null && eventBatch.Count > 0) ? eventBatch[eventBatch.Count - 1] : null; - if ((lastEvent != null) && (lastEvent.Offset != long.MinValue)) + if (!string.IsNullOrEmpty(lastEvent?.Offset)) { startingPosition = EventPosition.FromOffset(lastEvent.Offset, false); } @@ -1088,18 +1094,11 @@ protected internal virtual async Task ValidateProcessingPreconditions(Cancellati /// be called instead. /// /// + [EditorBrowsable(EditorBrowsableState.Never)] protected virtual Task UpdateCheckpointAsync(string partitionId, - long offset, + string offset, long? sequenceNumber, - CancellationToken cancellationToken) - { - if (sequenceNumber.HasValue) - { - return UpdateCheckpointAsync(partitionId, new CheckpointPosition(sequenceNumber.Value), cancellationToken); - } - - throw new NotImplementedException(); - } + CancellationToken cancellationToken) => UpdateCheckpointAsync(partitionId, new CheckpointPosition(offset, sequenceNumber.Value), cancellationToken); /// /// Creates or updates a checkpoint for a specific partition, identifying a position in the partition's event stream @@ -1295,9 +1294,11 @@ protected virtual LastEnqueuedEventProperties ReadLastEnqueuedEventProperties(st /// /// The set of identifiers for the Event Hub partitions. /// - protected virtual async Task ListPartitionIdsAsync(EventHubConnection connection, - CancellationToken cancellationToken) => - await connection.GetPartitionIdsAsync(RetryPolicy, cancellationToken).ConfigureAwait(false); + protected virtual Task ListPartitionIdsAsync(EventHubConnection connection, + CancellationToken cancellationToken) + { + return Task.FromResult(EventHubProperties.PartitionIds); + } /// /// Allows reporting that a partition was stolen by another event consumer causing ownership @@ -1634,6 +1635,7 @@ private async Task RunProcessingAsync(CancellationToken cancellationToken) try { + EventHubProperties = await connection.GetPropertiesAsync(RetryPolicy, cancellationToken).ConfigureAwait(false); partitionIds = await ListPartitionIdsAsync(connection, cancellationToken).ConfigureAwait(false); } catch (Exception ex) when (ex.IsNotType()) diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Primitives/PluggableCheckpointStoreEventProcessor.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/Primitives/PluggableCheckpointStoreEventProcessor.cs index b3110143dcdc2..80621f41264e2 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Primitives/PluggableCheckpointStoreEventProcessor.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Primitives/PluggableCheckpointStoreEventProcessor.cs @@ -224,8 +224,9 @@ protected PluggableCheckpointStoreEventProcessor() /// The sequence number to associate with the checkpoint, indicating that a processor should begin reading from the next event in the stream. /// A instance to signal a request to cancel the operation. /// + [EditorBrowsable(EditorBrowsableState.Never)] protected override Task UpdateCheckpointAsync(string partitionId, - long offset, + string offset, long? sequenceNumber, CancellationToken cancellationToken) => _checkpointStore.UpdateCheckpointAsync(FullyQualifiedNamespace, EventHubName, ConsumerGroup, partitionId, offset, sequenceNumber, cancellationToken); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/src/Processor/CheckpointPosition.cs b/sdk/eventhub/Azure.Messaging.EventHubs/src/Processor/CheckpointPosition.cs index 43dbfe0b4a277..5c0b71d416300 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/src/Processor/CheckpointPosition.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/src/Processor/CheckpointPosition.cs @@ -16,22 +16,48 @@ namespace Azure.Messaging.EventHubs.Processor public struct CheckpointPosition : IEquatable { /// - /// The sequence number to associate with the checkpoint. This indicates that a processor should begin reading from the next event in the stream. + /// The sequence number to associate with the checkpoint. The sequence number is intended to be informational, and will only be used for + /// positioning if no is set. /// /// public long SequenceNumber { get; } + /// + /// The offset to associate with the checkpoint. This indicates that a processor should begin reading from the next event in the stream. + /// + /// + public string Offset { get; } + /// /// Initializes a new instance of the struct. /// /// /// The sequence number to associate with the checkpoint. This indicates that a processor should begin reading from the next event in the stream. /// + /// + /// This constructor is not compatible when processing a geo-replicated Event Hub. Use or + /// instead. + /// + /// + [EditorBrowsable(EditorBrowsableState.Never)] public CheckpointPosition(long sequenceNumber) { SequenceNumber = sequenceNumber; } + /// + /// Initializes a new instance of the struct. + /// + /// The offset to associate with the checkpoint. This indicates that a processor should begin reading from the next event in the stream. + /// The sequence number to associate with the checkpoint. This is used as informational metadata. + /// + public CheckpointPosition(string offset, + long sequenceNumber = long.MinValue) + { + SequenceNumber = sequenceNumber; + Offset = offset; + } + /// /// Initializes a new instance of the from an instance. /// @@ -40,7 +66,7 @@ public CheckpointPosition(long sequenceNumber) /// public static CheckpointPosition FromEvent(EventData eventData) { - return new CheckpointPosition(eventData.SequenceNumber); + return new CheckpointPosition(eventData.Offset, eventData.SequenceNumber); } /// @@ -53,7 +79,8 @@ public static CheckpointPosition FromEvent(EventData eventData) /// public bool Equals(CheckpointPosition other) { - return (SequenceNumber == other.SequenceNumber); + return ((SequenceNumber == other.SequenceNumber) + && (Offset == other.Offset)); } /// @@ -83,6 +110,7 @@ public override int GetHashCode() { var hashCode = new HashCodeBuilder(); hashCode.Add(SequenceNumber); + hashCode.Add(Offset); return hashCode.ToHashCode(); } @@ -95,7 +123,7 @@ public override int GetHashCode() /// public override string ToString() { - return $"Sequence Number: [{SequenceNumber}]"; + return $"Offset: [{Offset}] Sequence Number: [{SequenceNumber}]"; } /// diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpAnnotatedMessageExtensionsTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpAnnotatedMessageExtensionsTests.cs index 9c64cadd26b88..8dc0d83bd4456 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpAnnotatedMessageExtensionsTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpAnnotatedMessageExtensionsTests.cs @@ -295,11 +295,11 @@ public void GetEventBodyDoesNotAllowNonDataBodyTypes(AmqpMessageBodyType bodyTyp public void SystemPropertiesCanBeRead() { var sequenceNumber = 123L; - var offset = 456L; + var offset = "456L"; var enqueueTime = new DateTimeOffset(2015, 10, 27, 00, 00, 00, TimeSpan.Zero); var partitionKey = "fake-key"; var lastSequence = 321L; - var lastOffset = 654L; + var lastOffset = "654L"; var lastEnqueue = new DateTimeOffset(2012, 03, 04, 08, 00, 00, TimeSpan.Zero); var lastRetrieve = new DateTimeOffset(2020, 01, 01, 05, 15, 37, TimeSpan.Zero); var message = CreateDataBodyMessageWithSystemProperties(sequenceNumber, lastSequence, offset, lastOffset, partitionKey, enqueueTime, lastEnqueue, lastRetrieve); @@ -330,11 +330,11 @@ public void MessageIsPopulatedFromEventHubProperties() }; var sequenceNumber = 123L; - var offset = 456L; + var offset = "456L"; var enqueueTime = new DateTimeOffset(2015, 10, 27, 00, 00, 00, TimeSpan.Zero); var partitionKey = "fake-key"; var lastSequence = 321L; - var lastOffset = 654L; + var lastOffset = "654L"; var lastEnqueue = new DateTimeOffset(2012, 03, 04, 08, 00, 00, TimeSpan.Zero); var lastRetrieve = new DateTimeOffset(2020, 01, 01, 05, 15, 37, TimeSpan.Zero); @@ -361,11 +361,11 @@ public void MessageIsPopulatedFromEventHubProperties() public void SystemPropertiesReturnCustomDefaultValuesWhenNotInTheMessage() { var sequenceNumber = 123L; - var offset = 456L; + var offset = "456L"; var enqueueTime = new DateTimeOffset(2015, 10, 27, 00, 00, 00, TimeSpan.Zero); var partitionKey = "fake-key"; var lastSequence = 321L; - var lastOffset = 654L; + var lastOffset = "654L"; var lastEnqueue = new DateTimeOffset(2012, 03, 04, 08, 00, 00, TimeSpan.Zero); var lastRetrieve = new DateTimeOffset(2020, 01, 01, 05, 15, 37, TimeSpan.Zero); var message = CreateDataBodyMessageWithSystemProperties(default, default, default, default, default, default, default, default); @@ -391,7 +391,7 @@ public void SystemPropertiesReturnExpectedDefaultValuesWhenNotInTheMessageAndNoC var message = CreateDataBodyMessageWithSystemProperties(default, default, default, default, default, default, default, default); Assert.That(message.GetSequenceNumber(), Is.EqualTo(long.MinValue), "The sequence number should match."); - Assert.That(message.GetOffset(), Is.EqualTo(long.MinValue), "The offset should match."); + Assert.That(message.GetOffset(), Is.EqualTo(null), "The offset should match."); Assert.That(message.GetEnqueuedTime(), Is.EqualTo(default(DateTimeOffset)), "The enqueue time should match."); Assert.That(message.GetPartitionKey(), Is.EqualTo(null), "The partition key should match."); Assert.That(message.GetLastPartitionSequenceNumber(), Is.EqualTo(null), "The last sequence number should match."); @@ -510,8 +510,8 @@ private static AmqpAnnotatedMessage CreateFullyPopulatedDataBodyMessage() /// private static AmqpAnnotatedMessage CreateDataBodyMessageWithSystemProperties(long? sequenceNumber, long? lastSequenceNumber, - long? offset, - long? lastOffset, + string offset, + string lastOffset, string partitionKey, DateTimeOffset? enqueueTime, DateTimeOffset? lastEnqueueTime, @@ -526,9 +526,9 @@ private static AmqpAnnotatedMessage CreateFullyPopulatedDataBodyMessage() message.MessageAnnotations.Add(AmqpProperty.SequenceNumber.ToString(), sequenceNumber.Value); } - if (offset.HasValue) + if (!string.IsNullOrEmpty(offset)) { - message.MessageAnnotations.Add(AmqpProperty.Offset.ToString(), offset.Value); + message.MessageAnnotations.Add(AmqpProperty.Offset.ToString(), offset); } if (enqueueTime.HasValue) @@ -550,9 +550,9 @@ private static AmqpAnnotatedMessage CreateFullyPopulatedDataBodyMessage() message.DeliveryAnnotations.Add(AmqpProperty.PartitionLastEnqueuedSequenceNumber.ToString(), lastSequenceNumber.Value); } - if (lastOffset.HasValue) + if (!string.IsNullOrEmpty(lastOffset)) { - message.DeliveryAnnotations.Add(AmqpProperty.PartitionLastEnqueuedOffset.ToString(), lastOffset.Value); + message.DeliveryAnnotations.Add(AmqpProperty.PartitionLastEnqueuedOffset.ToString(), lastOffset); } if (lastEnqueueTime.HasValue) diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpConnectionScopeTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpConnectionScopeTests.cs index db35d7d46db88..07aeb49314fbc 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpConnectionScopeTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpConnectionScopeTests.cs @@ -778,7 +778,7 @@ public async Task OpenConsumerLinkAsyncRespectsTheTrackLastEventOption() var link = await mockScope.Object.OpenConsumerLinkAsync(consumerGroup, partitionId, position, TimeSpan.FromDays(1), TimeSpan.FromDays(1), prefetchCount, prefetchSizeInBytes, ownerLevel, trackLastEvent, identifier, cancellationSource.Token); Assert.That(link, Is.Not.Null, "The link produced was null"); - Assert.That(link.Settings.DesiredCapabilities, Is.Null, "There should have not have been a set of desired capabilities created, as we're not tracking the last event."); + Assert.That(link.Settings.DesiredCapabilities.Contains(AmqpProperty.GeoReplication), Is.True, "Geo replication should always be requested."); } /// @@ -1292,6 +1292,7 @@ public async Task OpenProducerLinkAsyncConfiguresTheLink() Assert.That(link.Settings.Properties.Any(item => item.Key.Key.ToString() == AmqpProperty.EntityType.ToString()), Is.True, "There should be an entity type specified."); Assert.That(link.Settings.Properties[AmqpProperty.ProducerGroupId], Is.EqualTo(options.ProducerGroupId), "The producer group should have been set."); Assert.That(link.Settings.Properties[AmqpProperty.ProducerOwnerLevel], Is.EqualTo(options.OwnerLevel), "The owner level should have been set."); + Assert.That(link.Settings.DesiredCapabilities.Contains(AmqpProperty.GeoReplication), Is.True, "Geo replication should always be requested."); Assert.That(link.Settings.Properties[AmqpProperty.ProducerSequenceNumber], Is.EqualTo(options.StartingSequenceNumber), "The published sequence number should have been set."); } @@ -1435,6 +1436,7 @@ public async Task OpenProducerLinkAsyncConfiguresTheLinkWhenOptionsAreEmpty(obje var linkTarget = (Target)link.Settings.Target; Assert.That(linkTarget.Address.ToString(), Contains.Substring($"/{ partitionId }"), "The partition identifier should have been part of the link address."); Assert.That(link.Settings.DesiredCapabilities.Contains(AmqpProperty.EnableIdempotentPublishing), Is.True, "The idempotent publishing capability should have been set."); + Assert.That(link.Settings.DesiredCapabilities.Contains(AmqpProperty.GeoReplication), Is.True, "Geo replication should always be requested."); Assert.That(link.Settings.Properties.Any(item => item.Key.Key.ToString() == AmqpProperty.EntityType.ToString()), Is.True, "There should be an entity type specified."); Assert.That(link.Settings.Properties.Any(item => item.Key.Key.ToString() == AmqpProperty.ProducerGroupId.ToString()), Is.True, "The producer group should have been set."); Assert.That(link.Settings.Properties.Any(item => item.Key.Key.ToString() == AmqpProperty.ProducerOwnerLevel.ToString()), Is.True, "The owner level should have been set."); @@ -1513,7 +1515,7 @@ public async Task OpenProducerLinkAsyncConfiguresTheLinkWhenNoFeaturesAreActive( var linkTarget = (Target)link.Settings.Target; Assert.That(linkTarget.Address.ToString(), Contains.Substring($"/{ partitionId }"), "The partition identifier should have been part of the link address."); - Assert.That(link.Settings.DesiredCapabilities, Is.Null, "The idempotent publishing capability should not have been set."); + Assert.That(link.Settings.DesiredCapabilities.Contains(AmqpProperty.GeoReplication), Is.True, "Geo replication should always be requested."); Assert.That(link.Settings.Properties.Any(item => item.Key.Key.ToString() == AmqpProperty.EntityType.ToString()), Is.True, "There should be an entity type specified."); Assert.That(link.Settings.Properties[AmqpProperty.ProducerGroupId], Is.EqualTo(options.ProducerGroupId), "The producer group should have been set."); Assert.That(link.Settings.Properties[AmqpProperty.ProducerOwnerLevel], Is.EqualTo(options.OwnerLevel), "The owner level should have been set."); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpConsumerTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpConsumerTests.cs index c32237bdfdcba..8128f95cbe332 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpConsumerTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpConsumerTests.cs @@ -162,7 +162,7 @@ public void ReceiveAsyncValidatesTheMaximumMessageCount(int count) var consumerGroup = "$DEFAULT"; var partition = "3"; var identifier = "cusTOM-1D"; - var eventPosition = EventPosition.FromOffset(123); + var eventPosition = EventPosition.FromOffset("123"); var retryPolicy = new BasicRetryPolicy(new EventHubsRetryOptions()); var retriableException = new EventHubsException(true, "Test"); var mockConverter = new Mock(); @@ -187,7 +187,7 @@ public void ReceiveAsyncRespectsTheCancellationTokenIfSetWhenCalled() var consumerGroup = "$DEFAULT"; var partition = "3"; var identifier = "cusTOM-1D"; - var eventPosition = EventPosition.FromOffset(123); + var eventPosition = EventPosition.FromOffset("123"); var retryPolicy = new BasicRetryPolicy(new EventHubsRetryOptions()); var retriableException = new EventHubsException(true, "Test"); var mockConverter = new Mock(); @@ -215,7 +215,7 @@ public void ReceiveAsyncAppliesTheRetryPolicy(EventHubsRetryOptions retryOptions var consumerGroup = "$DEFAULT"; var partition = "3"; var identifier = "cusTOM-1D"; - var eventPosition = EventPosition.FromOffset(123); + var eventPosition = EventPosition.FromOffset("123"); var trackLastEnqueued = false; var invalidateOnSteal = true; var ownerLevel = 123L; @@ -279,7 +279,7 @@ public void ReceiveAsyncConsidersOperationCanceledExceptionAsRetriable(EventHubs var consumerGroup = "$DEFAULT"; var partition = "3"; var identifier = "cusTOM-1D"; - var eventPosition = EventPosition.FromOffset(123); + var eventPosition = EventPosition.FromOffset("123"); var trackLastEnqueued = false; var invalidateOnSteal = true; var ownerLevel = 123L; @@ -344,7 +344,7 @@ public void ReceiveAsyncAppliesTheRetryPolicyForAmqpErrors(EventHubsRetryOptions var consumerGroup = "$DEFAULT"; var partition = "3"; var identifier = "cusTOM-1D"; - var eventPosition = EventPosition.FromOffset(123); + var eventPosition = EventPosition.FromOffset("123"); var trackLastEnqueued = false; var invalidateOnSteal = true; var ownerLevel = 123L; @@ -407,7 +407,7 @@ public void ReceiveAsyncDetectsAnEmbeddedErrorForOperationCanceled() var consumerGroup = "$DEFAULT"; var partition = "3"; var identifier = "cusTOM-1D"; - var eventPosition = EventPosition.FromOffset(123); + var eventPosition = EventPosition.FromOffset("123"); var trackLastEnqueued = false; var invalidateOnSteal = true; var ownerLevel = 123L; @@ -470,7 +470,7 @@ public void ReceiveAsyncDetectsAnEmbeddedAmqpErrorForOperationCanceled() var consumerGroup = "$DEFAULT"; var partition = "3"; var identifier = "cusTOM-1D"; - var eventPosition = EventPosition.FromOffset(123); + var eventPosition = EventPosition.FromOffset("123"); var trackLastEnqueued = false; var invalidateOnSteal = true; var ownerLevel = 123L; @@ -533,7 +533,7 @@ public async Task ReceiveAsyncValidatesClosed() var consumerGroup = "$DEFAULT"; var partition = "3"; var identifier = "cusTOM-1D"; - var eventPosition = EventPosition.FromOffset(123); + var eventPosition = EventPosition.FromOffset("123"); var options = new EventHubConsumerClientOptions(); var retryPolicy = new BasicRetryPolicy(new EventHubsRetryOptions()); var retriableException = new EventHubsException(true, "Test"); @@ -562,7 +562,7 @@ public void ReceiveAsyncValidatesConnectionClosed() var consumerGroup = "$DEFAULT"; var partition = "3"; var identifier = "cusTOM-1D"; - var eventPosition = EventPosition.FromOffset(123); + var eventPosition = EventPosition.FromOffset("123"); var options = new EventHubConsumerClientOptions(); var retryPolicy = new BasicRetryPolicy(new EventHubsRetryOptions()); var mockCredential = new EventHubTokenCredential(Mock.Of()); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpFilterTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpFilterTests.cs index 1d7223e9aaf2b..280b7654c96f9 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpFilterTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpFilterTests.cs @@ -26,7 +26,7 @@ public void BuildFilterExpressionEnsuresAnEventPositionIsFilterable() { // Unset all properties for the event position. - var position = EventPosition.FromOffset(1); + var position = EventPosition.FromOffset("1"); position.Offset = null; Assert.That(() => AmqpFilter.BuildFilterExpression(position), Throws.ArgumentException); @@ -42,7 +42,7 @@ public void BuildFilterExpressionPrefersOffset() { // Set all properties for the event position. - var offset = 1; + var offset = "1"; var position = EventPosition.FromOffset(offset); position.SequenceNumber = "222"; position.EnqueuedTime = DateTimeOffset.Parse("2015-10-27T12:00:00Z"); @@ -122,7 +122,7 @@ public void BuildFilterExpressionAllowsLatest() public void BuildFilterExpressionHonorsInclusiveFlagForOffset(bool inclusive) { var comparison = (inclusive) ? ">=" : ">"; - var position = EventPosition.FromOffset(1); + var position = EventPosition.FromOffset("1"); position.IsInclusive = inclusive; var filter = AmqpFilter.BuildFilterExpression(position); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpMessageConverterTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpMessageConverterTests.cs index 6acfccfec21f8..9e29a2d3a1fc5 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpMessageConverterTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Amqp/AmqpMessageConverterTests.cs @@ -1214,7 +1214,7 @@ public void CreateEventFromMessageDoesNotIncludeUnknownApplicationPropertyType() [Test] public void CreateEventFromMessagePopulatesTypedSystemProperties() { - var offset = 123; + var offset = "123"; var sequenceNumber = (long.MaxValue - 10); var enqueuedTime = DateTimeOffset.Parse("2015-10-27T12:00:00Z"); var partitionKey = "OMG! partition!"; @@ -1225,7 +1225,7 @@ public void CreateEventFromMessagePopulatesTypedSystemProperties() message.ApplicationProperties.Map.Add("First", 1); message.ApplicationProperties.Map.Add("Second", "2"); - message.MessageAnnotations.Map.Add(AmqpProperty.Offset, offset.ToString()); + message.MessageAnnotations.Map.Add(AmqpProperty.Offset, offset); message.MessageAnnotations.Map.Add(AmqpProperty.SequenceNumber, sequenceNumber); message.MessageAnnotations.Map.Add(AmqpProperty.EnqueuedTime, enqueuedTime.Ticks); message.MessageAnnotations.Map.Add(AmqpProperty.PartitionKey, partitionKey); @@ -1240,7 +1240,7 @@ public void CreateEventFromMessagePopulatesTypedSystemProperties() Assert.That(eventData.SequenceNumber, Is.EqualTo(sequenceNumber), "The sequence number should match."); Assert.That(eventData.EnqueuedTime, Is.EqualTo(enqueuedTime), "The enqueue time should match."); Assert.That(eventData.PartitionKey, Is.EqualTo(partitionKey), "The partition key should match."); - Assert.That(eventData.LastPartitionOffset.HasValue, Is.False, "The last offset should not be set."); + Assert.That(eventData.LastPartitionOffset, Is.Null, "The last offset should not be set."); Assert.That(eventData.LastPartitionSequenceNumber.HasValue, Is.False, "The last sequence number should not be set."); Assert.That(eventData.LastPartitionEnqueuedTime.HasValue, Is.False, "The last enqueued time should not be set."); Assert.That(eventData.LastPartitionPropertiesRetrievalTime.HasValue, Is.False, "The last retrieval time should not be set."); @@ -1291,8 +1291,8 @@ public void CreateEventFromMessagePopulatesMappedSystemProperties() [Test] public void CreateEventFromMessagePopulatesTypedSystemPropertiesAndMetrics() { - var offset = 123; - var lastOffset = 987; + string offset = "123"; + var lastOffset = "987"; var sequenceNumber = (long.MaxValue - 10); var lastSequenceNumber = (long.MaxValue - 100); var enqueuedTime = DateTimeOffset.Parse("2015-10-27T12:00:00Z"); @@ -1564,11 +1564,11 @@ void validateMap(AmqpMap expected, IDictionary dictionary, strin [Test] public void CreateEventFromMessageAllowsAnEmptyMessageWithProperties() { - var propertyValue = 1; + var propertyValue = "1"; using var message = AmqpMessage.Create(); message.ApplicationProperties.Map.Add("Test", propertyValue); - message.MessageAnnotations.Map.Add(AmqpProperty.Offset, propertyValue.ToString()); + message.MessageAnnotations.Map.Add(AmqpProperty.Offset, propertyValue); var eventData = new AmqpMessageConverter().CreateEventFromMessage(message); Assert.That(eventData, Is.Not.Null, "The event should have been created."); @@ -2046,7 +2046,7 @@ public void CreatePartitionPropertiesFromResponseCreatesTheProperties() var partition = "55"; var beginSequenceNumber = 555L; var lastSequenceNumber = 666L; - var lastOffset = 777L; + var lastOffset = "777L"; var lastEnqueueTime = DateTimeOffset.Parse("2015-10-27T00:00:00z"); var isEmpty = false; var converter = new AmqpMessageConverter(); @@ -2056,7 +2056,7 @@ public void CreatePartitionPropertiesFromResponseCreatesTheProperties() { AmqpManagement.ResponseMap.PartitionIdentifier, partition }, { AmqpManagement.ResponseMap.PartitionBeginSequenceNumber, beginSequenceNumber }, { AmqpManagement.ResponseMap.PartitionLastEnqueuedSequenceNumber, lastSequenceNumber }, - { AmqpManagement.ResponseMap.PartitionLastEnqueuedOffset, lastOffset.ToString() }, + { AmqpManagement.ResponseMap.PartitionLastEnqueuedOffset, lastOffset }, { AmqpManagement.ResponseMap.PartitionLastEnqueuedTimeUtc, lastEnqueueTime.UtcDateTime }, { AmqpManagement.ResponseMap.PartitionRuntimeInfoPartitionIsEmpty, isEmpty } }; diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Connection/EventHubConnectionTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Connection/EventHubConnectionTests.cs index c8560b0aa7e6c..7bab1af03fc8b 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Connection/EventHubConnectionTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Connection/EventHubConnectionTests.cs @@ -835,7 +835,7 @@ public void CreateConsumerInvokesTheTransportClient() { var transportClient = new ObservableTransportClientMock(); var connection = new InjectableTransportClientMock(transportClient, "Endpoint=sb://not-real.servicebus.windows.net/;SharedAccessKeyName=DummyKey;SharedAccessKey=[not_real];EntityPath=fake"); - var expectedPosition = EventPosition.FromOffset(65); + var expectedPosition = EventPosition.FromOffset("65"); var expectedPartition = "2123"; var expectedIdentifier = "OMG-ID"; var expectedConsumerGroup = EventHubConsumerClient.DefaultConsumerGroupName; diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/EventHubConsumerClientTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/EventHubConsumerClientTests.cs index d9600187c2e8b..99116681f3627 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/EventHubConsumerClientTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/EventHubConsumerClientTests.cs @@ -684,7 +684,7 @@ public async Task ReadEventsFromPartitionAsyncWithNoOptionsReturnsAnEnumerable() var mockConnection = new MockConnection(() => transportConsumer); var consumer = new EventHubConsumerClient(EventHubConsumerClient.DefaultConsumerGroupName, mockConnection); - IAsyncEnumerable enumerable = consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset(12)); + IAsyncEnumerable enumerable = consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset("12")); Assert.That(enumerable, Is.Not.Null, "An enumerable should have been returned."); Assert.That(enumerable, Is.InstanceOf>(), "The enumerable should be of the correct type."); @@ -709,7 +709,7 @@ public async Task ReadEventsFromPartitionAsyncWithOptionsReturnsAnEnumerable() var consumer = new EventHubConsumerClient(EventHubConsumerClient.DefaultConsumerGroupName, mockConnection); var options = new ReadEventOptions { MaximumWaitTime = TimeSpan.FromMilliseconds(25) }; - var enumerable = consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset(12), options); + var enumerable = consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset("12"), options); Assert.That(enumerable, Is.Not.Null, "An enumerable should have been returned."); Assert.That(enumerable, Is.InstanceOf>(), "The enumerable should be of the correct type."); @@ -734,7 +734,7 @@ public async Task ReadEventsFromPartitionAsyncRespectsTheCacheEventCount() var consumer = new EventHubConsumerClient(EventHubConsumerClient.DefaultConsumerGroupName, mockConnection); var options = new ReadEventOptions { MaximumWaitTime = TimeSpan.FromMilliseconds(25), CacheEventCount = 999 }; - await using var enumerator = consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset(12), options).GetAsyncEnumerator(); + await using var enumerator = consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset("12"), options).GetAsyncEnumerator(); for (var index = 0; index < 5; ++index) { @@ -776,7 +776,7 @@ public async Task ReadEventsFromPartitionAsyncRespectsThePrefetchCount() It.IsAny())) .Returns(transportConsumer); - await using var enumerator = consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset(12), options).GetAsyncEnumerator(); + await using var enumerator = consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset("12"), options).GetAsyncEnumerator(); await enumerator.MoveNextAsync(); mockConnection @@ -824,7 +824,7 @@ public void ReadEventsFromPartitionAsyncThrowsIfConsumerClosedBeforeRead() { await consumer.CloseAsync(cancellationSource.Token); - await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset(12), cancellationSource.Token)) + await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset("12"), cancellationSource.Token)) { receivedEvents = true; break; @@ -862,7 +862,7 @@ public void ReadEventsFromPartitionAsyncThrowsIfCanceledBeforeRead() Assert.That(async () => { - await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset(12), cancellation.Token)) + await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset("12"), cancellation.Token)) { if (partitionEvent.Data == null) { @@ -905,7 +905,7 @@ public void ReadEventsFromPartitionAsyncThrowsIfCanceledDuringRead() Assert.That(async () => { - await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset(12), cancellation.Token)) + await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset("12"), cancellation.Token)) { if (++receivedEvents >= expectedEvents) { @@ -946,7 +946,7 @@ public void ReadEventsFromPartitionAsyncDoesNotThrowIfNotCanceled() Assert.That(async () => { - await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset(12), cancellation.Token)) + await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset("12"), cancellation.Token)) { if (++receivedEvents >= expectedEvents) { @@ -983,7 +983,7 @@ public async Task ReadEventsFromPartitionAsyncStopsReceivingWhenCanceled() try { - await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset(12), cancellation.Token)) + await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset("12"), cancellation.Token)) { if (++receivedEvents >= expectedEvents) { @@ -1024,7 +1024,7 @@ public async Task ReadEventsFromPartitionAsyncStopsReceivingWhenIterationStops() try { - await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset(12), cancellation.Token)) + await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset("12"), cancellation.Token)) { if (++receivedEvents >= expectedEvents) { @@ -1075,7 +1075,7 @@ public async Task ReadEventsFromPartitionAsyncStopsReceivingOnException() try { - await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset(12), cancellation.Token)) + await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset("12"), cancellation.Token)) { ++receivedEvents; } @@ -1114,7 +1114,7 @@ public async Task ReadEventsFromPartitionAsyncEmitsEventsToOneIteratorIteratorAn using var cancellation = new CancellationTokenSource(); cancellation.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); - await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset(12), cancellation.Token)) + await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset("12"), cancellation.Token)) { receivedEvents.Add(partitionEvent.Data); @@ -1147,7 +1147,7 @@ public async Task ReadEventsFromPartitionAsyncEmitsEventsWithMultipleIteratorsAn var options = new ReadEventOptions { MaximumWaitTime = TimeSpan.FromMilliseconds(5) }; var partition = "0"; - var position = EventPosition.FromOffset(22); + var position = EventPosition.FromOffset("22"); var mockConnection = new MockConnection(() => new PublishingTransportConsumerMock(events)); var consumer = new EventHubConsumerClient(EventHubConsumerClient.DefaultConsumerGroupName, mockConnection); var firstSubscriberEvents = new List(); @@ -1337,7 +1337,7 @@ public async Task ReadEventsFromPartitionAsyncRespectsWaitTimeWhenEmittingEvents using var cancellation = new CancellationTokenSource(); cancellation.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); - await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset(12), options, cancellation.Token)) + await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset("12"), options, cancellation.Token)) { receivedEvents.Add(partitionEvent.Data); consecutiveEmptyCount = (partitionEvent.Data == null) ? consecutiveEmptyCount + 1 : 0; @@ -1377,7 +1377,7 @@ public void ReadEventsFromPartitionAsyncPropagatesExceptions(Type exceptionType) Assert.That(async () => { - await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset(2), cancellation.Token)) + await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync("0", EventPosition.FromOffset("2"), cancellation.Token)) { ++receivedEvents; break; @@ -1445,7 +1445,7 @@ public async Task ReadEventsFromPartitionAsyncSetsThePartitionContext() using var cancellation = new CancellationTokenSource(); cancellation.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); - await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync(expectedPartition, EventPosition.FromOffset(12), cancellation.Token)) + await foreach (PartitionEvent partitionEvent in consumer.ReadEventsFromPartitionAsync(expectedPartition, EventPosition.FromOffset("12"), cancellation.Token)) { Assert.That(partitionEvent.Partition.PartitionId, Is.EqualTo(expectedPartition), $"The event in position: { actualCount } was not associated with the expected partition."); Assert.That(partitionEvent.Partition.FullyQualifiedNamespace, Is.EqualTo(mockConnection.FullyQualifiedNamespace), $"The event in position: { actualCount } was not associated with the expected namespace."); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/EventPositionTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/EventPositionTests.cs index 0eb31ffdd8ccb..830cebb61a1ae 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/EventPositionTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/EventPositionTests.cs @@ -40,8 +40,8 @@ public void EarliestAndLatestAreNotEqual() [Test] public void TheSameOffsetAreEqual() { - var first = EventPosition.FromOffset(12); - var second = EventPosition.FromOffset(12); + var first = EventPosition.FromOffset("12"); + var second = EventPosition.FromOffset("12"); Assert.That(first.Equals((object)second), Is.True, "The default Equals comparison is incorrect."); Assert.That(first.Equals(second), Is.True, "The IEquatable comparison is incorrect."); @@ -57,8 +57,8 @@ public void TheSameOffsetAreEqual() [Test] public void DifferentOffsetsAreNotEqual() { - var first = EventPosition.FromOffset(12); - var second = EventPosition.FromOffset(34); + var first = EventPosition.FromOffset("12"); + var second = EventPosition.FromOffset("34"); Assert.That(first.Equals((object)second), Is.False, "The default Equals comparison is incorrect."); Assert.That(first.Equals(second), Is.False, "The IEquatable comparison is incorrect."); @@ -179,7 +179,7 @@ public void DifferentInclusiveFlagsAreNotEqual() public void DifferentMembersAreNotEqual() { var first = EventPosition.FromSequenceNumber(234234); - var second = EventPosition.FromOffset(12); + var second = EventPosition.FromOffset("12"); Assert.That(first.Equals((object)second), Is.False, "The default Equals comparison is incorrect."); Assert.That(first.Equals(second), Is.False, "The IEquatable comparison is incorrect."); @@ -195,7 +195,7 @@ public void DifferentMembersAreNotEqual() [Test] public void GetHashCodeReturnsDifferentValuesForDifferentMembers() { - var first = EventPosition.FromOffset(12); + var first = EventPosition.FromOffset("12"); var second = EventPosition.FromSequenceNumber(123); Assert.That(first.GetHashCode(), Is.Not.EqualTo(second.GetHashCode())); @@ -210,7 +210,7 @@ public void GetHashCodeReturnsDifferentValuesForDifferentMembers() public void ToStringReflectsTheState() { var inclusive = true; - var offset = 123; + var offset = "123"; var sequence = 778; var enqueued = DateTimeOffset.Now.AddHours(1); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/LastEnqueuedEventPropertiesTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/LastEnqueuedEventPropertiesTests.cs index 8a3b638b46c8e..bf6d165612790 100755 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/LastEnqueuedEventPropertiesTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/LastEnqueuedEventPropertiesTests.cs @@ -24,8 +24,8 @@ public class LastEnqueuedEventPropertiesTests public void TheSameValuesAreEqual() { var now = DateTimeOffset.UtcNow; - var first = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: 887, lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); - var second = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: 887, lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); + var first = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: "887", lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); + var second = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: "887", lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); Assert.That(first.Equals((object)second), Is.True, "The default Equals comparison is incorrect."); Assert.That(first.Equals(second), Is.True, "The IEquatable comparison is incorrect."); @@ -42,8 +42,8 @@ public void TheSameValuesAreEqual() public void DifferentOffsetsAreNotEqual() { var now = DateTimeOffset.UtcNow; - var first = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: 999, lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); - var second = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: 888, lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); + var first = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: "999", lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); + var second = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: "888", lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); Assert.That(first.Equals((object)second), Is.False, "The default Equals comparison is incorrect."); Assert.That(first.Equals(second), Is.False, "The IEquatable comparison is incorrect."); @@ -60,8 +60,8 @@ public void DifferentOffsetsAreNotEqual() public void DifferentEnqueueTimesAreNotEqual() { var now = DateTimeOffset.UtcNow; - var first = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: 887, lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); - var second = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: 887, lastEnqueuedTime: DateTimeOffset.Parse("1974-12-09T21:30:00Z"), lastReceivedTime: now); + var first = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: "887", lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); + var second = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: "887", lastEnqueuedTime: DateTimeOffset.Parse("1974-12-09T21:30:00Z"), lastReceivedTime: now); Assert.That(first.Equals((object)second), Is.False, "The default Equals comparison is incorrect."); Assert.That(first.Equals(second), Is.False, "The IEquatable comparison is incorrect."); @@ -78,8 +78,8 @@ public void DifferentEnqueueTimesAreNotEqual() public void DifferentSequenceNumbersAreNotEqual() { var now = DateTimeOffset.UtcNow; - var first = new LastEnqueuedEventProperties(lastSequenceNumber: 333, lastOffset: 887, lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); - var second = new LastEnqueuedEventProperties(lastSequenceNumber: 444, lastOffset: 887, lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); + var first = new LastEnqueuedEventProperties(lastSequenceNumber: 333, lastOffset: "887", lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); + var second = new LastEnqueuedEventProperties(lastSequenceNumber: 444, lastOffset: "887", lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); Assert.That(first.Equals((object)second), Is.False, "The default Equals comparison is incorrect."); Assert.That(first.Equals(second), Is.False, "The IEquatable comparison is incorrect."); @@ -96,8 +96,8 @@ public void DifferentSequenceNumbersAreNotEqual() public void DifferentLastReceiveTimesAreNotEqual() { var now = DateTimeOffset.UtcNow; - var first = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: 887, lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); - var second = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: 887, lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now.AddHours(1)); + var first = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: "887", lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); + var second = new LastEnqueuedEventProperties(lastSequenceNumber: 123, lastOffset: "887", lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now.AddHours(1)); Assert.That(first.Equals((object)second), Is.False, "The default Equals comparison is incorrect."); Assert.That(first.Equals(second), Is.False, "The IEquatable comparison is incorrect."); @@ -114,8 +114,8 @@ public void DifferentLastReceiveTimesAreNotEqual() public void GetHashCodeReturnsDifferentValuesForDifferentMembers() { var now = DateTimeOffset.UtcNow; - var first = new LastEnqueuedEventProperties(lastSequenceNumber: 333, lastOffset: 888, lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); - var second = new LastEnqueuedEventProperties(lastSequenceNumber: 555, lastOffset: 777, lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); + var first = new LastEnqueuedEventProperties(lastSequenceNumber: 333, lastOffset: "888", lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); + var second = new LastEnqueuedEventProperties(lastSequenceNumber: 555, lastOffset: "777", lastEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastReceivedTime: now); Assert.That(first.GetHashCode(), Is.Not.EqualTo(second.GetHashCode())); } @@ -128,7 +128,7 @@ public void GetHashCodeReturnsDifferentValuesForDifferentMembers() [Test] public void ToStringReflectsTheState() { - var offset = 123; + var offset = "123"; var sequence = 778; var enqueued = DateTimeOffset.Now.AddHours(1); var received = DateTimeOffset.Now.AddHours(7); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/PartitionContextTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/PartitionContextTests.cs index dd54b8c35fa93..0d93cd30bc415 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/PartitionContextTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Consumer/PartitionContextTests.cs @@ -89,7 +89,7 @@ public void ReadLastEnqueuedEventPropertiesDelegatesToTheConsumer() ( eventBody: new BinaryData(Array.Empty()), lastPartitionSequenceNumber: 1234, - lastPartitionOffset: 42, + lastPartitionOffset: "42", lastPartitionEnqueuedTime: DateTimeOffset.Parse("2015-10-27T00:00:00Z"), lastPartitionPropertiesRetrievalTime: DateTimeOffset.Parse("2012-03-04T08:42Z") ); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Core/EventDataTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Core/EventDataTests.cs index f2265ad863b7a..78b8530410a0a 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Core/EventDataTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Core/EventDataTests.cs @@ -145,11 +145,11 @@ public void MutablePropertySettersPopulateTheAmqpMessage() public void NonIdempotentStatePropertyAcessorsDeferToTheAmqpMessage() { var sequenceNumber = 123L; - var offset = 456L; + var offset = "456L"; var enqueueTime = new DateTimeOffset(2015, 10, 27, 00, 00, 00, TimeSpan.Zero); var partitionKey = "fake-key"; var lastSequence = 321L; - var lastOffset = 654L; + var lastOffset = "654L"; var lastEnqueue = new DateTimeOffset(2012, 03, 04, 08, 00, 00, TimeSpan.Zero); var lastRetrieve = new DateTimeOffset(2020, 01, 01, 05, 15, 37, TimeSpan.Zero); var message = CreateFullyPopulatedAmqpMessage(sequenceNumber, lastSequence, offset, lastOffset, partitionKey, enqueueTime, lastEnqueue, lastRetrieve); @@ -245,11 +245,11 @@ public void CloneProducesACopyWhenPropertyDictionariesAreSet() new Dictionary { { "Test", 123 } }, new Dictionary { { "System", "Hello" } }, 33334444, - 666777, + "666777", DateTimeOffset.Parse("2015-10-27T00:00:00Z"), "TestKey", 111222, - 999888, + "999888", DateTimeOffset.Parse("2012-03-04T09:00:00Z"), DateTimeOffset.Parse("2003-09-27T15:00:00Z"), 787878, @@ -275,11 +275,11 @@ public void CloneProducesACopyWhenPropertyDictionariesAreNotSet() null, null, 33334444, - 666777, + "666777", DateTimeOffset.Parse("2015-10-27T00:00:00Z"), "TestKey", 111222, - 999888, + "999888", DateTimeOffset.Parse("2012-03-04T09:00:00Z"), DateTimeOffset.Parse("2003-09-27T15:00:00Z"), 787878, @@ -304,11 +304,11 @@ public void CloneIsolatesPropertyChanges() new Dictionary { { "Test", 123 } }, new Dictionary { { "System", "Hello" } }, 33334444, - 666777, + "666777", DateTimeOffset.Parse("2015-10-27T00:00:00Z"), "TestKey", 111222, - 999888, + "999888", DateTimeOffset.Parse("2012-03-04T09:00:00Z"), DateTimeOffset.Parse("2003-09-27T15:00:00Z"), 787878, @@ -341,8 +341,8 @@ public void CloneIsolatesPropertyChanges() /// private static AmqpAnnotatedMessage CreateFullyPopulatedAmqpMessage(long sequenceNumber, long lastSequenceNumber, - long offset, - long lastOffset, + string offset, + string lastOffset, string partitionKey, DateTimeOffset enqueueTime, DateTimeOffset lastEnqueueTime, diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Core/EventHubsModelFactoryTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Core/EventHubsModelFactoryTests.cs index 737cf9b0c6826..a5ddcdf8f2f1b 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Core/EventHubsModelFactoryTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Core/EventHubsModelFactoryTests.cs @@ -52,7 +52,7 @@ public void PartitionPropertiesInitializesProperties() var isEmpty = false; var beginningSequenceNumber = 123; var lastSequenceNumber = 9999; - var lastOffset = 767; + var lastOffset = "767"; var lastEnqueuedTime = new DateTimeOffset(2015, 10, 27, 12, 0, 0, TimeSpan.Zero); var properties = EventHubsModelFactory.PartitionProperties(eventHubName, partitionId, isEmpty, beginningSequenceNumber, lastSequenceNumber, lastOffset, lastEnqueuedTime); @@ -96,7 +96,7 @@ public void PartitionPublishingPropertiesInitializesProperties() public void LastEnqueuedEventPropertiesInitializesProperties() { var lastSequence = long.MaxValue - 100; - var lastOffset = long.MaxValue - 10; + var lastOffset = (long.MaxValue - 10).ToString(); var lastEnqueued = new DateTimeOffset(2015, 10, 27, 12, 0, 0, TimeSpan.Zero); var lastReceived = new DateTimeOffset(2012, 03, 04, 08, 0, 0, TimeSpan.Zero); var properties = EventHubsModelFactory.LastEnqueuedEventProperties(lastSequence, lastOffset, lastEnqueued, lastReceived); @@ -121,7 +121,7 @@ public void PartitionContextInitializesProperties() var eventHubName = "fakeHub"; var consumerGroup = "fakeConsumerGroup"; var partition = "0"; - var properties = EventHubsModelFactory.LastEnqueuedEventProperties(465, 988, fakeDate, fakeDate); + var properties = EventHubsModelFactory.LastEnqueuedEventProperties(465, "988", fakeDate, fakeDate); var context = EventHubsModelFactory.PartitionContext(fullyQualifiedNamespace, eventHubName, consumerGroup, partition, properties); Assert.That(context, Is.Not.Null, "The context should have been created."); @@ -166,7 +166,7 @@ public void EventDataInitializesProperties() var properties = new Dictionary { { "id", 12 } }; var systemProperties = new Dictionary { { "custom", "sys-value" } }; var sequenceNumber = long.MaxValue - 512; - var offset = long.MaxValue - 1024; + string offset = (long.MaxValue - 1024).ToString(); var enqueueTime = new DateTimeOffset(2015, 10, 27, 12, 0, 0, TimeSpan.Zero); var partitionKey = "omghai!"; var eventData = EventHubsModelFactory.EventData(body, properties, systemProperties, partitionKey, sequenceNumber, offset, enqueueTime); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorOptionsTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorOptionsTests.cs index 01734cdf07e8d..4859885cac3ed 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorOptionsTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorOptionsTests.cs @@ -35,7 +35,7 @@ public void CloneProducesACopy() PartitionOwnershipExpirationInterval = TimeSpan.FromHours(16), Identifier = "Rick Springfield is a bad friend", TrackLastEnqueuedEventProperties = false, - DefaultStartingPosition = EventPosition.FromOffset(555) + DefaultStartingPosition = EventPosition.FromOffset("555") }; EventProcessorOptions clone = options.Clone(); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.Infrastructure.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.Infrastructure.cs index 9516f4e8d4375..3a63625422ed1 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.Infrastructure.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.Infrastructure.cs @@ -42,7 +42,7 @@ public async Task ReadLastEnqueuedEventPropertiesReadsPropertiesWhenThePartition var partitionId = "27"; var partitionIds = new[] { "0", partitionId }; var ownedPartitions = new List(); - var lastEventProperties = new LastEnqueuedEventProperties(1234, 9876, DateTimeOffset.Parse("2015-10-27T00:00:00Z"), DateTimeOffset.Parse("2012-03-04T08:30:00Z")); + var lastEventProperties = new LastEnqueuedEventProperties(1234, "9876", DateTimeOffset.Parse("2015-10-27T00:00:00Z"), DateTimeOffset.Parse("2012-03-04T08:30:00Z")); var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var options = new EventProcessorOptions { LoadBalancingUpdateInterval = TimeSpan.FromMinutes(5), TrackLastEnqueuedEventProperties = true }; var mockLoadBalancer = new Mock(); @@ -72,8 +72,8 @@ public async Task ReadLastEnqueuedEventPropertiesReadsPropertiesWhenThePartition .Returns(() => default); mockConnection - .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(partitionIds); + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("", DateTime.Now, partitionIds, false)); mockProcessor .Setup(processor => processor.CreateConnection()) @@ -112,7 +112,7 @@ public async Task ReadLastEnqueuedEventPropertiesThrowsWhenThePartitionIsNotOwne var partitionId = "27"; var partitionIds = new[] { "0", partitionId }; - var lastEventProperties = new LastEnqueuedEventProperties(1234, 9876, DateTimeOffset.Parse("2015-10-27T00:00:00Z"), DateTimeOffset.Parse("2012-03-04T08:30:00Z")); + var lastEventProperties = new LastEnqueuedEventProperties(1234, "9876", DateTimeOffset.Parse("2015-10-27T00:00:00Z"), DateTimeOffset.Parse("2012-03-04T08:30:00Z")); var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var options = new EventProcessorOptions { LoadBalancingUpdateInterval = TimeSpan.FromMinutes(5), TrackLastEnqueuedEventProperties = true }; var mockLoadBalancer = new Mock(); @@ -129,8 +129,8 @@ public async Task ReadLastEnqueuedEventPropertiesThrowsWhenThePartitionIsNotOwne .Callback(() => completionSource.TrySetResult(true)); mockConnection - .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(partitionIds); + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("", DateTime.Now, partitionIds, false)); mockProcessor .Setup(processor => processor.CreateConnection()) diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.MainProcessingLoop.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.MainProcessingLoop.cs index 4bcfd5f5acf5a..8ad26f0f6b608 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.MainProcessingLoop.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.MainProcessingLoop.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -142,11 +143,16 @@ public async Task BackgroundProcessingToleratesPartitionIdQueryFailure() var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockConnection = new Mock(); var mockProcessor = new Mock(65, "consumerGroup", "namespace", "eventHub", Mock.Of(), default(EventProcessorOptions)) { CallBase = true }; + var partitionIds = new[] { "0", "1" }; mockConnection - .SetupSequence(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) + .SetupSequence(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) .Throws(expectedException) - .ReturnsAsync(new[] { "0", "1" }); + .ReturnsAsync(new EventHubProperties("", DateTime.Now, partitionIds, false)); + + mockConnection + .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(partitionIds); mockProcessor .Setup(processor => processor.CreateConnection()) @@ -217,6 +223,10 @@ public async Task BackgroundProcessingToleratesALoadBalancingRunFailure() .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(partitionIds); + mockConnection + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("", DateTime.Now, partitionIds, false)); + mockProcessor.Object.Logger = mockLogger.Object; mockProcessor @@ -301,8 +311,8 @@ public async Task BackgroundProcessingToleratesAnOwnershipClaimFailureWhenThePar .Throws(expectedException); mockConnection - .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(partitionIds); + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("", DateTime.Now, partitionIds, false)); mockProcessor.Object.Logger = mockLogger.Object; @@ -387,8 +397,8 @@ public async Task BackgroundProcessingToleratesAnOwnershipClaimFailureWhenThePar .Throws(expectedException); mockConnection - .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(partitionIds); + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("", DateTime.Now, partitionIds, false)); mockProcessor.Object.Logger = mockLogger.Object; @@ -486,8 +496,8 @@ public async Task BackgroundProcessingToleratesAnOwnershipClaimFailureWhenThePar .Returns(Mock.Of()); mockConnection - .Setup(connection => connection.GetPropertiesAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds)); + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds, false)); mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) @@ -604,8 +614,8 @@ public async Task BackgroundProcessingStartsProcessingForClaimedPartitions() .Returns(mockConsumer.Object); mockConnection - .Setup(connection => connection.GetPropertiesAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds)); + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds, false)); mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) @@ -744,7 +754,7 @@ public async Task BackgroundProcessingStopsProcessingAllPartitionsWhenShutdown() mockConnection .Setup(connection => connection.GetPropertiesAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds)); + .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds, false)); mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) @@ -875,7 +885,7 @@ public async Task BackgroundProcessingLogsHandlerErrorWhenPartitionProcessingSto mockConnection .Setup(connection => connection.GetPropertiesAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds)); + .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds, false)); mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) @@ -1000,7 +1010,7 @@ public async Task BackgroundProcessingStopsProcessingForPartitionsWithLostOwners mockConnection .Setup(connection => connection.GetPropertiesAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds)); + .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds, false)); mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) @@ -1090,6 +1100,10 @@ public async Task BackgroundProcessingRestartsProcessingForFaultedPartitions() .Returns(new ValueTask(new EventProcessorPartitionOwnership { PartitionId = partitionId })) .Returns(() => default); + mockConnection + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("eventHub", DateTimeOffset.Now, partitionIds, false)); + mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(partitionIds); @@ -1149,7 +1163,7 @@ public async Task BackgroundProcessingUsesCheckpointsWhenProcessingPartitions() cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var createConsumerCalls = 0; - var expectedStartingPosition = EventPosition.FromOffset(775, true); + var expectedStartingPosition = EventPosition.FromOffset("775", true); var partitionId = "27"; var partitionIds = new[] { "0", partitionId, "11" }; var ownedPartitions = new List { partitionId }; @@ -1174,7 +1188,7 @@ public async Task BackgroundProcessingUsesCheckpointsWhenProcessingPartitions() mockConnection .Setup(connection => connection.GetPropertiesAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds)); + .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds, false)); mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) @@ -1253,7 +1267,7 @@ public async Task BackgroundProcessingDelegatesInitializationWhenProcessingClaim mockConnection .Setup(connection => connection.GetPropertiesAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds)); + .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds, false)); mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) @@ -1372,7 +1386,7 @@ public async Task BackgroundProcessingLogsWhenStartingToProcessClaimedPartitions mockConnection .Setup(connection => connection.GetPropertiesAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds)); + .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds, false)); mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) @@ -1484,6 +1498,10 @@ public async Task BackgroundProcessingLogsWhenStartingToProcessClaimedPartitions .Returns(new ValueTask(new EventProcessorPartitionOwnership { PartitionId = partitionId })) .Returns(() => default); + mockConnection + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("eventHub", DateTimeOffset.Now, partitionIds, false)); + mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(partitionIds); @@ -1582,6 +1600,10 @@ public async Task BackgroundProcessingDispatchesExceptionsWhenStartingToProcessC .Returns(new ValueTask(new EventProcessorPartitionOwnership { PartitionId = partitionId })) .Returns(() => default); + mockConnection + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("eventHub", DateTimeOffset.Now, partitionIds, false)); + mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(partitionIds); @@ -1701,7 +1723,7 @@ public async Task BackgroundProcessingLogsWhenSurrenderingClaimedPartitions() mockConnection .Setup(connection => connection.GetPropertiesAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds)); + .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds, false)); mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) @@ -1814,7 +1836,7 @@ public async Task BackgroundProcessingDelegatesStopNotificationWhenSurrenderingC mockConnection .Setup(connection => connection.GetPropertiesAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds)); + .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds, false)); mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) @@ -1877,7 +1899,7 @@ public async Task BackgroundProcessingLogsWhenLoadBalancingIsSlow() var partitionId = "27"; var partitionIds = new[] { "0", partitionId, "111" }; var ownedPartitions = new List { partitionId }; - var options = new EventProcessorOptions { LoadBalancingUpdateInterval = TimeSpan.FromMilliseconds(250), PartitionOwnershipExpirationInterval = TimeSpan.FromMilliseconds(750), LoadBalancingStrategy = LoadBalancingStrategy.Balanced }; + var options = new EventProcessorOptions { LoadBalancingUpdateInterval = TimeSpan.FromMilliseconds(250), PartitionOwnershipExpirationInterval = TimeSpan.FromMilliseconds(750), LoadBalancingStrategy = LoadBalancingStrategy.Balanced }; var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockLogger = new Mock(); var mockLoadBalancer = new Mock(); @@ -1902,6 +1924,10 @@ public async Task BackgroundProcessingLogsWhenLoadBalancingIsSlow() return default; }); + mockConnection + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("eventHub", DateTimeOffset.Now, partitionIds, false)); + mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(partitionIds); @@ -1959,7 +1985,7 @@ public async Task BackgroundProcessingEmitsAnErrorWhenLoadBalancingIsSlow() var partitionId = "27"; var partitionIds = new[] { "0", partitionId, "111" }; var ownedPartitions = new List { partitionId }; - var options = new EventProcessorOptions { LoadBalancingUpdateInterval = TimeSpan.FromMilliseconds(250), PartitionOwnershipExpirationInterval = TimeSpan.FromMilliseconds(750), LoadBalancingStrategy = LoadBalancingStrategy.Balanced }; + var options = new EventProcessorOptions { LoadBalancingUpdateInterval = TimeSpan.FromMilliseconds(250), PartitionOwnershipExpirationInterval = TimeSpan.FromMilliseconds(750), LoadBalancingStrategy = LoadBalancingStrategy.Balanced }; var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockLogger = new Mock(); var mockLoadBalancer = new Mock(); @@ -2000,7 +2026,7 @@ public async Task BackgroundProcessingEmitsAnErrorWhenLoadBalancingIsSlow() mockConnection .Setup(connection => connection.GetPropertiesAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds)); + .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds, false)); mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) @@ -2100,8 +2126,8 @@ public async Task BackgroundProcessingLogsWhenLargeNumberOfOwnedPartitions() .Returns(new ValueTask(default(EventProcessorPartitionOwnership))); mockConnection - .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(partitionIds); + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("", DateTime.Now, partitionIds, false)); mockConsumer .Setup(consumer => consumer.ReceiveAsync(It.IsAny(), It.IsAny(), It.IsAny())) @@ -2187,6 +2213,10 @@ public async Task BackgroundProcessingDoesNotLogWarningWhenOwnedCountIsStable() } }); + mockConnection + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("eventHub", DateTimeOffset.Now, partitionIds, false)); + mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(partitionIds); @@ -2282,11 +2312,11 @@ public async Task LoadBalancingAppliesTheGreedyStrategy() }); mockConnection - .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) .Returns(async () => { await Task.Yield(); - return partitionIds; + return new EventHubProperties("", DateTime.Now, partitionIds, false); }); mockConsumer @@ -2377,8 +2407,8 @@ public async Task LoadBalancingWhenGreedyAppliesTheTimeoutAfterBalance() }); mockConnection - .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(partitionIds); + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("", DateTime.Now, partitionIds, false)); mockConsumer .Setup(consumer => consumer.ReceiveAsync(It.IsAny(), It.IsAny(), It.IsAny())) @@ -2475,8 +2505,8 @@ public async Task LoadBalancingAppliesTheBalancedStrategy() }); mockConnection - .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(partitionIds); + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("", DateTime.Now, partitionIds, false)); mockConsumer .Setup(consumer => consumer.ReceiveAsync(It.IsAny(), It.IsAny(), It.IsAny())) @@ -2584,7 +2614,7 @@ public async Task LoadBalancingIsNotBlockedByLostPartitionOwnership() mockConnection .Setup(connection => connection.GetPropertiesAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds)); + .ReturnsAsync(new EventHubProperties(mockProcessor.Object.EventHubName, new DateTimeOffset(2015, 10, 27, 12, 0, 0, 0, TimeSpan.Zero), partitionIds, false)); mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) @@ -2617,7 +2647,7 @@ public async Task LoadBalancingIsNotBlockedByLostPartitionOwnership() ItExpr.IsAny>(), ItExpr.Is(part => part.PartitionId == firstPartiton), ItExpr.IsAny()) - .Callback (() => + .Callback(() => { if (loadBalancingCountAtDelay == 0) { diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.PartitionProcessing.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.PartitionProcessing.cs index e3d4a3e920b51..f0b7f217c27a1 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.PartitionProcessing.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.PartitionProcessing.cs @@ -364,7 +364,7 @@ public async Task CreatePartitionProcessorCanReadLastEventProperties() cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = true }; - var lastEvent = new EventData(new BinaryData(Array.Empty()), lastPartitionSequenceNumber: 123, lastPartitionOffset: 887, lastPartitionEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastPartitionPropertiesRetrievalTime: DateTimeOffset.Parse("2021-03-04T08:30:00Z")); + var lastEvent = new EventData(new BinaryData(Array.Empty()), lastPartitionSequenceNumber: 123, lastPartitionOffset: "887", lastPartitionEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastPartitionPropertiesRetrievalTime: DateTimeOffset.Parse("2021-03-04T08:30:00Z")); var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockConnection = Mock.Of(); var mockConsumer = new Mock(); @@ -413,7 +413,7 @@ public async Task CreatePartitionProcessorCanReadLastEventPropertiesWhenTheConsu var retryOptions = new EventHubsRetryOptions { MaximumRetries = 0, MaximumDelay = TimeSpan.FromMilliseconds(5) }; var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = true, RetryOptions = retryOptions }; - var lastEvent = new EventData(new BinaryData(Array.Empty()), lastPartitionSequenceNumber: 123, lastPartitionOffset: 887, lastPartitionEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastPartitionPropertiesRetrievalTime: DateTimeOffset.Parse("2021-03-04T08:30:00Z")); + var lastEvent = new EventData(new BinaryData(Array.Empty()), lastPartitionSequenceNumber: 123, lastPartitionOffset: "887", lastPartitionEnqueuedTime: DateTimeOffset.Parse("2015-10-27T12:00:00Z"), lastPartitionPropertiesRetrievalTime: DateTimeOffset.Parse("2021-03-04T08:30:00Z")); var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockConnection = Mock.Of(); var mockConsumer = new Mock(); @@ -482,7 +482,7 @@ public async Task CreatePartitionProcessorCreatesTheTransportConsumer() cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var options = new EventProcessorOptions { Identifier = "fake", TrackLastEnqueuedEventProperties = false, PrefetchCount = 37, PrefetchSizeInBytes = 44, LoadBalancingUpdateInterval = TimeSpan.FromMinutes(1) }; var expectedOwnerLevel = 0; var expectedInvalidationOnSteal = true; @@ -542,7 +542,7 @@ public async Task CreatePartitionProcessorStartsTheProcessingTask() cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false }; var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockConnection = Mock.Of(); @@ -596,7 +596,7 @@ public async Task CreatePartitionProcessorProcessingTaskRespectsCancellation() cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false }; var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockConnection = Mock.Of(); @@ -644,7 +644,7 @@ public async Task CreatePartitionProcessorProcessingTaskClosesTheConsumerOnCance cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false }; var receiveCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var closeCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -754,7 +754,7 @@ public async Task CreatePartitionProcessorProcessingTaskDoesNotInvokeTheErrorHan cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false }; var receiveCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var closeCompletionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -846,7 +846,7 @@ public async Task CreatePartitionProcessorProcessingTaskDispatchesEvents() cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var retryOptions = new EventHubsRetryOptions { MaximumRetries = 0, MaximumDelay = TimeSpan.FromMilliseconds(5) }; var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false, RetryOptions = retryOptions }; var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -903,7 +903,7 @@ public async Task CreatePartitionProcessorProcessingLogsEachCycle() var startSequenceNumber = "4444"; var endSequenceNumber = "8888"; var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var retryOptions = new EventHubsRetryOptions { MaximumRetries = 0, MaximumDelay = TimeSpan.FromMilliseconds(5) }; var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false, RetryOptions = retryOptions }; var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -914,8 +914,8 @@ public async Task CreatePartitionProcessorProcessingLogsEachCycle() var eventBatch = new List { - EventHubsModelFactory.EventData(new BinaryData(Array.Empty()), offset: 0, sequenceNumber: long.Parse(startSequenceNumber)), - EventHubsModelFactory.EventData(new BinaryData(Array.Empty()), offset: 1, sequenceNumber: long.Parse(endSequenceNumber)) + EventHubsModelFactory.EventData(new BinaryData(Array.Empty()), offset: "0", sequenceNumber: long.Parse(startSequenceNumber)), + EventHubsModelFactory.EventData(new BinaryData(Array.Empty()), offset: "1", sequenceNumber: long.Parse(endSequenceNumber)) }; mockConsumer @@ -994,7 +994,7 @@ public async Task CreatePartitionProcessorProcessingTaskDispatchesExceptionsWhen var expectedException = new DivideByZeroException(); var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var retryOptions = new EventHubsRetryOptions { MaximumRetries = 0, MaximumDelay = TimeSpan.FromMilliseconds(5) }; var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false, RetryOptions = retryOptions }; var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -1048,7 +1048,7 @@ public async Task CreatePartitionProcessorProcessingTaskDispatchesExceptions() var expectedException = new DivideByZeroException(); var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var retryOptions = new EventHubsRetryOptions { MaximumRetries = 0, MaximumDelay = TimeSpan.FromMilliseconds(5) }; var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false, RetryOptions = retryOptions }; var receiveCompletion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -1111,7 +1111,7 @@ public async Task CreatePartitionProcessorProcessingTaskLogsExceptions() var expectedException = new DivideByZeroException("OMG FAIL!"); var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var retryOptions = new EventHubsRetryOptions { MaximumRetries = 0, MaximumDelay = TimeSpan.FromMilliseconds(5) }; var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false, RetryOptions = retryOptions }; var receiveCompletion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -1176,7 +1176,7 @@ public async Task CreatePartitionProcessorProcessingTaskSurfacesExceptions() var expectedException = new DivideByZeroException("I'm special!"); var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var retryOptions = new EventHubsRetryOptions { MaximumRetries = 0, MaximumDelay = TimeSpan.FromMilliseconds(5) }; var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false, RetryOptions = retryOptions }; var receiveCompletion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -1232,7 +1232,7 @@ public async Task CreatePartitionProcessorProcessingTaskWarnsForDeveloperCodeExc var expectedException = new DeveloperCodeException(new DivideByZeroException()); var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var retryOptions = new EventHubsRetryOptions { MaximumRetries = 1, MaximumDelay = TimeSpan.FromMilliseconds(5) }; var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false, RetryOptions = retryOptions }; var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -1293,7 +1293,7 @@ public async Task CreatePartitionProcessorProcessingTaskLogsDeveloperCodeExcepti var expectedException = new DeveloperCodeException(new DivideByZeroException("Yay, I'm on the inside!")); var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var retryOptions = new EventHubsRetryOptions { MaximumRetries = 1, MaximumDelay = TimeSpan.FromMilliseconds(5) }; var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false, RetryOptions = retryOptions }; var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -1356,7 +1356,7 @@ public async Task CreatePartitionProcessorProcessingTaskSurfacesDeveloperCodeExc var expectedException = new InvalidOperationException("BOOM!"); var developerException = new DeveloperCodeException(expectedException); var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var retryOptions = new EventHubsRetryOptions { MaximumRetries = 1, MaximumDelay = TimeSpan.FromMilliseconds(5) }; var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false, RetryOptions = retryOptions }; var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -1403,7 +1403,7 @@ public async Task CreatePartitionProcessorProcessingTaskHonorsTheRetryPolicy() var expectedException = new EventHubsException(true, "frank", "BOOM!", EventHubsException.FailureReason.GeneralError); var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var retryOptions = new EventHubsRetryOptions { MaximumRetries = 2, MaximumDelay = TimeSpan.FromMilliseconds(15) }; var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false, RetryOptions = retryOptions }; var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -1658,7 +1658,7 @@ public async Task CreatePartitionProcessorProcessingTaskStartsTheConsumerAtTheCo var retryOptions = new EventHubsRetryOptions { MaximumRetries = 0, MaximumDelay = TimeSpan.FromMilliseconds(5) }; var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false, RetryOptions = retryOptions }; var partition = new EventProcessorPartition { PartitionId = "4" }; - var lastEventBatch = new List { new EventData(new BinaryData(Array.Empty())), new EventData(new BinaryData(Array.Empty()), offset: 9987) }; + var lastEventBatch = new List { new EventData(new BinaryData(Array.Empty())), new EventData(new BinaryData(Array.Empty()), offset: "9987") }; var initialStartingPosition = EventPosition.FromSequenceNumber(332); var completionSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockConnection = Mock.Of(); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.StartStop.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.StartStop.cs index a22005b0c94cd..02925a96af0d1 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.StartStop.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/EventProcessorTests.StartStop.cs @@ -132,6 +132,10 @@ public async Task StartProcessingStartsTheLoadBalancer(bool async) .Callback(() => completionSource.TrySetResult(true)) .ReturnsAsync(default(EventProcessorPartitionOwnership)); + mockConnection + .Setup(connection => connection.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("eventHub", DateTimeOffset.Now, partitions, false)); + mockConnection .Setup(connection => connection.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(partitions); @@ -429,9 +433,9 @@ public async Task StartProcessingSurfacesMultipleValidationFailures(bool async) var mockConnection = new Mock(); var mockProcessor = new Mock>(4, "consumerGroup", "namespace", "eventHub", Mock.Of(), default(EventProcessorOptions)) { CallBase = true }; - mockProcessor - .Setup(processor => processor.CreateConnection()) - .Returns(mockConnection.Object); + mockProcessor + .Setup(processor => processor.CreateConnection()) + .Returns(mockConnection.Object); mockProcessor .Protected() @@ -629,6 +633,10 @@ public async Task StartProcessingWarnsWhenConfiguredIntervalsAreTooClose() .Setup(lb => lb.RunLoadBalancingAsync(partitionIds, It.IsAny())) .Returns(new ValueTask(default(EventProcessorPartitionOwnership))); + mockConnection + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("eventHub", DateTimeOffset.Now, partitionIds, false)); + mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(partitionIds); @@ -730,6 +738,10 @@ public async Task StartProcessingDoesNotWarnForAppropriateIntervals(double owner .Setup(lb => lb.RunLoadBalancingAsync(partitionIds, It.IsAny())) .Returns(new ValueTask(default(EventProcessorPartitionOwnership))); + mockConnection + .Setup(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("eventHub", DateTimeOffset.Now, partitionIds, false)); + mockConnection .Setup(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(partitionIds); @@ -923,6 +935,10 @@ public async Task StopProcessingStopsTheLoadBalancer(bool async) .Returns(Task.CompletedTask) .Callback(() => stopCompletionSource.TrySetResult(true)); + mockConnection + .Setup(connection => connection.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("eventHub", DateTimeOffset.Now, Array.Empty(), false)); + mockConnection .Setup(connection => connection.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(Array.Empty()); @@ -1268,9 +1284,9 @@ public async Task StopProcessingIsSafeToCallInTheErrorHandler(bool async) .Callback(() => stopCompletionSource.TrySetResult(true)); mockConnection - .SetupSequence(conn => conn.GetPartitionIdsAsync(It.IsAny(), It.IsAny())) - .ReturnsAsync(Array.Empty()) - .ReturnsAsync(Array.Empty()) + .SetupSequence(conn => conn.GetPropertiesAsync(It.IsAny(), It.IsAny())) + .ReturnsAsync(new EventHubProperties("eventHub", DateTimeOffset.Now, Array.Empty(), false)) + .ReturnsAsync(new EventHubProperties("eventHub", DateTimeOffset.Now, Array.Empty(), false)) .Returns(async () => { await startCompletionSource.Task; @@ -1364,7 +1380,7 @@ public async Task StopProcessingLogsWarningForTokenCancellationErrors(bool async var firstCall = true; var partition = new EventProcessorPartition { PartitionId = "99" }; - var position = EventPosition.FromOffset(12); + var position = EventPosition.FromOffset("12"); var options = new EventProcessorOptions { TrackLastEnqueuedEventProperties = false, RetryOptions = new EventHubsRetryOptions { MaximumRetries = 0, MaximumDelay = TimeSpan.FromMilliseconds(5) } }; var handlerCompletion = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var mockEventSource = new Mock(); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/PartitionReceiverLiveTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/PartitionReceiverLiveTests.cs index 4389704f6148e..3acf3196450e8 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/PartitionReceiverLiveTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/PartitionReceiverLiveTests.cs @@ -590,7 +590,7 @@ await using (EventHubScope scope = await EventHubScope.CreateAsync(1)) // Once sent, query the partition and determine the offset of the last enqueued event, then send the new set // of events that should appear after the starting position. - long lastOffset; + string lastOffset; EventPosition startingPosition; await using (var producer = new EventHubProducerClient(connectionString)) diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/PartitionReceiverTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/PartitionReceiverTests.cs index e6edb55d04053..0728cc993a68d 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/PartitionReceiverTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/PartitionReceiverTests.cs @@ -582,7 +582,7 @@ public void ConnectionConstructorSetsThePartitionId() [Test] public void ConnectionStringConstructorSetsTheInitialPosition() { - var expectedPosition = EventPosition.FromOffset(999); + var expectedPosition = EventPosition.FromOffset("999"); var connectionString = "Endpoint=sb://somehost.com;SharedAccessKeyName=ABC;SharedAccessKey=123;EntityPath=somehub"; var receiver = new PartitionReceiver("cg", "pid", expectedPosition, connectionString); @@ -596,7 +596,7 @@ public void ConnectionStringConstructorSetsTheInitialPosition() [Test] public void TokenCredentialConstructorSetsTheInitialPosition() { - var expectedPosition = EventPosition.FromOffset(999); + var expectedPosition = EventPosition.FromOffset("999"); var receiver = new PartitionReceiver("cg", "pid", expectedPosition, "fqns", "eh", Mock.Of()); Assert.That(receiver.InitialPosition, Is.EqualTo(expectedPosition)); @@ -609,7 +609,7 @@ public void TokenCredentialConstructorSetsTheInitialPosition() [Test] public void SharedKeyCredentialConstructorSetsTheInitialPosition() { - var expectedPosition = EventPosition.FromOffset(999); + var expectedPosition = EventPosition.FromOffset("999"); var receiver = new PartitionReceiver("cg", "pid", expectedPosition, "fqns", "eh", new AzureNamedKeyCredential("key", "value")); Assert.That(receiver.InitialPosition, Is.EqualTo(expectedPosition)); @@ -622,7 +622,7 @@ public void SharedKeyCredentialConstructorSetsTheInitialPosition() [Test] public void SasCredentialConstructorSetsTheInitialPosition() { - var expectedPosition = EventPosition.FromOffset(999); + var expectedPosition = EventPosition.FromOffset("999"); var receiver = new PartitionReceiver("cg", "pid", expectedPosition, "fqns", "eh", new AzureSasCredential(new SharedAccessSignature("sb://this.is.Fake/blah", "key", "value").Value)); Assert.That(receiver.InitialPosition, Is.EqualTo(expectedPosition)); @@ -635,7 +635,7 @@ public void SasCredentialConstructorSetsTheInitialPosition() [Test] public void ConnectionConstructorSetsTheInitialPosition() { - var expectedPosition = EventPosition.FromOffset(999); + var expectedPosition = EventPosition.FromOffset("999"); var receiver = new PartitionReceiver("cg", "pid", expectedPosition, Mock.Of()); Assert.That(receiver.InitialPosition, Is.EqualTo(expectedPosition)); @@ -730,7 +730,7 @@ public void CreateTransportConsumerDelegatesToTheConnection() var expectedConsumerGroup = "consumerGroup"; var expectedPartitionId = "partitionId"; var expectedIdentifier = "customIdent!fi3r!"; - var expectedPosition = EventPosition.FromOffset(55); + var expectedPosition = EventPosition.FromOffset("55"); var expectedInvalidateOnSteal = false; var expectedOptions = new PartitionReceiverOptions @@ -771,7 +771,7 @@ public void ReadLastEnqueuedEventPropertiesDelegatesToTheTransportConsumer() ( eventBody: new BinaryData(Array.Empty()), lastPartitionSequenceNumber: 1234, - lastPartitionOffset: 42, + lastPartitionOffset: "42", lastPartitionEnqueuedTime: DateTimeOffset.Parse("2015-10-27T00:00:00Z"), lastPartitionPropertiesRetrievalTime: DateTimeOffset.Parse("2012-03-04T08:42Z") ); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/PluggableCheckpointStoreEventProcessorTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/PluggableCheckpointStoreEventProcessorTests.cs index 5ae1ae7be4993..feec30962f4b7 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/PluggableCheckpointStoreEventProcessorTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Primitives/PluggableCheckpointStoreEventProcessorTests.cs @@ -78,7 +78,7 @@ public void CheckpointStoreIsUsedByUpdateCheckpointAsync() var expectedException = new DivideByZeroException(); var expectedExceptionOld = new FormatException(); var partitionId = "fakePart"; - var offset = 12345; + var offset = "12345"; var sequence = 9987; var mockCheckpointStore = new Mock(); var mockProcessor = new MockCheckpointStoreProcessor(mockCheckpointStore.Object, 100, "fakeConsumer", "fakeNamespace", "fakeHub", Mock.Of()); @@ -229,7 +229,7 @@ private class MockCheckpointStoreProcessor : PluggableCheckpointStoreEventProces protected override Task OnProcessingErrorAsync(Exception exception, EventProcessorPartition partition, string operationDescription, CancellationToken cancellationToken) => throw new NotImplementedException(); public Task InvokeGetCheckpointAsync(string partitionId, CancellationToken cancellationToken) => GetCheckpointAsync(partitionId, cancellationToken); - public Task InvokeOldUpdateCheckpointAsync(string partitionId, long offset, long? sequenceNumber, CancellationToken cancellationToken) => UpdateCheckpointAsync(partitionId, offset, sequenceNumber, cancellationToken); + public Task InvokeOldUpdateCheckpointAsync(string partitionId, string offset, long? sequenceNumber, CancellationToken cancellationToken) => UpdateCheckpointAsync(partitionId, offset, sequenceNumber, cancellationToken); public Task InvokeUpdateCheckpointAsync(string partitionId, CheckpointPosition checkpointPosition, CancellationToken cancellationToken) => UpdateCheckpointAsync(partitionId, checkpointPosition, cancellationToken); public Task> InvokeListOwnershipAsync(CancellationToken cancellationToken) => ListOwnershipAsync(cancellationToken); public Task> InvokeClaimOwnershipAsync(IEnumerable desiredOwnership, CancellationToken cancellationToken) => ClaimOwnershipAsync(desiredOwnership, cancellationToken); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Processor/CheckpointPositionTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Processor/CheckpointPositionTests.cs index 6eeba1708c4bd..6bbd78dd71964 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Processor/CheckpointPositionTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Processor/CheckpointPositionTests.cs @@ -32,6 +32,22 @@ public void TheSamePositionAreEqual() Assert.That((first != second), Is.False, "The != operator comparison is incorrect."); } + /// + /// Verifies functionality of the + /// equality. + /// + [Test] + public void TheSamePositionAreEqualWithOffset() + { + var first = new CheckpointPosition("44", 121); + var second = new CheckpointPosition("44", 121); + + Assert.That(first.Equals((object)second), Is.True, "The default Equals comparison is incorrect."); + Assert.That(first.Equals(second), Is.True, "The IEquatable comparison is incorrect."); + Assert.That((first == second), Is.True, "The == operator comparison is incorrect."); + Assert.That((first != second), Is.False, "The != operator comparison is incorrect."); + } + /// /// Verifies functionality of the /// equality. @@ -50,11 +66,45 @@ public void DifferentPositionsAreNotEqual() } /// - /// Verifies functionality of the - /// method. + /// Verifies functionality of the + /// equality. /// /// [Test] + public void DifferentPositionsAreNotEqualWithDifferentMembers() + { + var first = new CheckpointPosition(10); + var second = new CheckpointPosition("121"); + + Assert.That(first.Equals((object)second), Is.False, "The default Equals comparison is incorrect."); + Assert.That(first.Equals(second), Is.False, "The IEquatable comparison is incorrect."); + Assert.That((first == second), Is.False, "The == operator comparison is incorrect."); + Assert.That((first != second), Is.True, "The != operator comparison is incorrect."); + } + + /// + /// Verifies functionality of the + /// equality. + /// + /// + [Test] + public void DifferentPositionsAreNotEqualWithOffset() + { + var first = new CheckpointPosition("10"); + var second = new CheckpointPosition("121"); + + Assert.That(first.Equals((object)second), Is.False, "The default Equals comparison is incorrect."); + Assert.That(first.Equals(second), Is.False, "The IEquatable comparison is incorrect."); + Assert.That((first == second), Is.False, "The == operator comparison is incorrect."); + Assert.That((first != second), Is.True, "The != operator comparison is incorrect."); + } + + /// + /// Verifies functionality of the + /// method. + /// + /// + [Test] public void GetHashCodeReturnsDifferentValuesForDifferentMembers() { var first = new CheckpointPosition(10); @@ -72,7 +122,7 @@ public void GetHashCodeReturnsDifferentValuesForDifferentMembers() public void FromEventSetsProperties() { var sequence = 4566; - var eventData = new EventData(new BinaryData("Hello"), sequenceNumber: sequence, offset: 123); + var eventData = new EventData(new BinaryData("Hello"), sequenceNumber: sequence, offset: "123"); var checkpoint = CheckpointPosition.FromEvent(eventData); @@ -102,7 +152,7 @@ public void ToStringReflectsTheState() [Test] public void ToStringReflectsTheStateFromEventData() { - var offset = 400; + var offset = "400"; var sequence = 121; var eventData = new EventData(new BinaryData("Hello"), sequenceNumber: sequence, offset: offset); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Producer/EventHubBufferedProducerClientTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Producer/EventHubBufferedProducerClientTests.cs index 2616c99758267..bc78073b0d426 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Producer/EventHubBufferedProducerClientTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Producer/EventHubBufferedProducerClientTests.cs @@ -412,7 +412,7 @@ public async Task GetPartitionPropertiesAsyncIsDelegated() .Setup(producer => producer.GetPartitionPropertiesAsync( It.IsAny(), It.IsAny())) - .ReturnsAsync(new PartitionProperties("test", "1", true, 12345, 6789, 22, new DateTimeOffset(2015, 10, 27, 0, 0, 0, TimeSpan.Zero))); + .ReturnsAsync(new PartitionProperties("test", "1", true, 12345, 6789, "22", new DateTimeOffset(2015, 10, 27, 0, 0, 0, TimeSpan.Zero))); await bufferedProducer.GetPartitionPropertiesAsync(expectedPartition, cancellationSource.Token); mockProducer.Verify(producer => producer.GetPartitionPropertiesAsync(expectedPartition, cancellationSource.Token), Times.Once); diff --git a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Snippets/Sample11_MockingClientTypesLiveTests.cs b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Snippets/Sample11_MockingClientTypesLiveTests.cs index 747da578b3491..d23e2d9fe8356 100644 --- a/sdk/eventhub/Azure.Messaging.EventHubs/tests/Snippets/Sample11_MockingClientTypesLiveTests.cs +++ b/sdk/eventhub/Azure.Messaging.EventHubs/tests/Snippets/Sample11_MockingClientTypesLiveTests.cs @@ -88,7 +88,7 @@ public async Task MockingProducerProperties() isEmpty : true, beginningSequenceNumber: 1000, lastSequenceNumber : 1100, - lastOffset : 500, + lastOffset : "500", lastEnqueuedTime : DateTime.UtcNow) }, // Empty partition @@ -98,7 +98,7 @@ public async Task MockingProducerProperties() isEmpty : false, beginningSequenceNumber : 2000, lastSequenceNumber : 2000, - lastOffset : 760, + lastOffset : "760", lastEnqueuedTime : DateTime.UtcNow) } }; @@ -360,7 +360,7 @@ public async Task MockingConsumerClient() LastEnqueuedEventProperties lastEnqueueEventProperties = EventHubsModelFactory.LastEnqueuedEventProperties( lastSequenceNumber : 1234, - lastOffset : 234, + lastOffset : "234", lastEnqueuedTime : DateTimeOffset.Parse("1:24 AM"), lastReceivedTime : DateTimeOffset.Parse("1:26 AM")); @@ -386,7 +386,7 @@ async IAsyncEnumerable mockReturn() systemProperties: new Dictionary(), //arbitrary value partitionKey: "sample-key", sequenceNumber: 1000, - offset: 1500, + offset: "1500", enqueuedTime: DateTimeOffset.Parse("11:36 PM")); EventData eventData2 = EventHubsModelFactory.EventData( @@ -394,7 +394,7 @@ async IAsyncEnumerable mockReturn() systemProperties: new Dictionary(), //arbitrary value partitionKey: "sample-key", sequenceNumber: 1000, - offset: 1500, + offset: "1500", enqueuedTime: DateTimeOffset.Parse("11:36 PM")); // This creates a mock PartitionEvent to return from the consumer client. @@ -480,7 +480,7 @@ public async Task PartitionReceiverMock() systemProperties: new Dictionary(), //arbitrary value partitionKey: $"sample-key-{index}", sequenceNumber: 1234, - offset: 234, + offset: "234", enqueuedTime: DateTimeOffset.Parse("9:25 AM")); receivedEvents.Add(eventData);