public async Task ProducerInitializesPropertiesWhenPublishing() { await using (EventHubScope scope = await EventHubScope.CreateAsync(1)) { var connectionString = EventHubsTestEnvironment.Instance.BuildConnectionStringForEventHub(scope.EventHubName); var options = new IdempotentProducerOptions { EnableIdempotentPartitions = true }; await using var producer = new IdempotentProducer(connectionString, options); var cancellationSource = new CancellationTokenSource(); cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partition = (await producer.GetPartitionIdsAsync(cancellationSource.Token)).First(); var sendOptions = new SendEventOptions { PartitionId = partition }; var events = EventGenerator.CreateEvents(10).ToArray(); await producer.SendAsync(events, sendOptions, cancellationSource.Token); var partitionProperties = await producer.GetPartitionPublishingPropertiesAsync(partition); Assert.That(partitionProperties, Is.Not.Null, "The properties should have been created."); Assert.That(partitionProperties.IsIdempotentPublishingEnabled, Is.True, "Idempotent publishing should be enabled."); Assert.That(partitionProperties.ProducerGroupId.HasValue, Is.True, "The producer group identifier should have a value."); Assert.That(partitionProperties.OwnerLevel.HasValue, Is.True, "The owner level should have a value."); Assert.That(partitionProperties.LastPublishedSequenceNumber.HasValue, Is.True, "The last published sequence number should have a value."); } }
public async Task ProducerCanPublishEvents(EventHubsTransportType transportType) { await using (EventHubScope scope = await EventHubScope.CreateAsync(1)) { var connectionString = EventHubsTestEnvironment.Instance.BuildConnectionStringForEventHub(scope.EventHubName); var options = new IdempotentProducerOptions { EnableIdempotentPartitions = true, ConnectionOptions = new EventHubConnectionOptions { TransportType = transportType } }; await using var producer = new IdempotentProducer(connectionString, options); var cancellationSource = new CancellationTokenSource(); cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partition = (await producer.GetPartitionIdsAsync(cancellationSource.Token)).First(); var sendOptions = new SendEventOptions { PartitionId = partition }; Assert.That(async() => await producer.SendAsync(EventGenerator.CreateEvents(2), sendOptions, cancellationSource.Token), Throws.Nothing, "The first publishing operation was not successful."); Assert.That(async() => await producer.SendAsync(EventGenerator.CreateEvents(2), sendOptions, cancellationSource.Token), Throws.Nothing, "The second publishing operation was not successful."); } }
public void ToCoreOptionsCopiesProperties() { var options = new IdempotentProducerOptions { Identifier = "Test-123", EnableIdempotentPartitions = true, ConnectionOptions = new EventHubConnectionOptions { TransportType = EventHubsTransportType.AmqpWebSockets }, RetryOptions = new EventHubsRetryOptions { TryTimeout = TimeSpan.FromMinutes(36) } }; options.PartitionOptions.Add("0", new PartitionPublishingOptions { OwnerLevel = 3, ProducerGroupId = 99, StartingSequenceNumber = 42 }); var clone = options.ToCoreOptions(); Assert.That(clone, Is.Not.Null, "The clone should not be null."); Assert.That(clone.Identifier, Is.EqualTo(options.Identifier), "The identifier should match."); Assert.That(clone.EnableIdempotentPartitions, Is.EqualTo(options.EnableIdempotentPartitions), "The flag to enable idempotent publishing should have been copied."); Assert.That(clone.ConnectionOptions.TransportType, Is.EqualTo(options.ConnectionOptions.TransportType), "The connection options of the clone should copy properties."); Assert.That(clone.RetryOptions.IsEquivalentTo(options.RetryOptions), Is.True, "The retry options of the clone should be considered equal."); Assert.That(clone.PartitionOptions, Is.Not.SameAs(options.PartitionOptions), "The partitions options of the clone should be a copy, not the same instance."); Assert.That(clone.PartitionOptions.Keys, Is.EquivalentTo(options.PartitionOptions.Keys), "The partition options of the clone should contain the same items"); }
public async Task ProducerCanInitializeWithPartialPartitionOptions() { await using (EventHubScope scope = await EventHubScope.CreateAsync(2)) { var connectionString = EventHubsTestEnvironment.Instance.BuildConnectionStringForEventHub(scope.EventHubName); var options = new IdempotentProducerOptions { EnableIdempotentPartitions = true }; var cancellationSource = new CancellationTokenSource(); cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partition = default(string); var partitionProperties = default(PartitionPublishingProperties); // Create a producer for a small scope that will Send some events and read the properties. await using (var initialProducer = new IdempotentProducer(connectionString, options)) { partition = (await initialProducer.GetPartitionIdsAsync(cancellationSource.Token)).Last(); await initialProducer.SendAsync(EventGenerator.CreateEvents(10), new SendEventOptions { PartitionId = partition }, cancellationSource.Token); partitionProperties = await initialProducer.GetPartitionPublishingPropertiesAsync(partition); } // Create a new producer using the previously read properties to set options for the partition. options.PartitionOptions.Add(partition, new PartitionPublishingOptions { ProducerGroupId = partitionProperties.ProducerGroupId, OwnerLevel = partitionProperties.OwnerLevel }); Assert.That(options.PartitionOptions[partition].StartingSequenceNumber.HasValue, Is.False, "The partition options should not specifiy a starting sequence number."); await using var producer = new IdempotentProducer(connectionString, options); // Verify that the properties were fully initialized when using partial options. partitionProperties = await producer.GetPartitionPublishingPropertiesAsync(partition); Assert.That(partitionProperties, Is.Not.Null, "The properties should have been created."); Assert.That(partitionProperties.IsIdempotentPublishingEnabled, Is.True, "Idempotent publishing should be enabled."); Assert.That(partitionProperties.ProducerGroupId.HasValue, Is.True, "The producer group identifier should have a value."); Assert.That(partitionProperties.OwnerLevel.HasValue, Is.True, "The owner level should have a value."); Assert.That(partitionProperties.LastPublishedSequenceNumber.HasValue, Is.True, "The last published sequence number should have a value."); // Ensure that the state supports publishing. Assert.That(async() => await producer.SendAsync(EventGenerator.CreateEvents(10), new SendEventOptions { PartitionId = partition }, cancellationSource.Token), Throws.Nothing); } }
public async Task ProducerCanOptIntoIdempotentPublishing() { await using (EventHubScope scope = await EventHubScope.CreateAsync(1)) { var connectionString = EventHubsTestEnvironment.Instance.BuildConnectionStringForEventHub(scope.EventHubName); var options = new IdempotentProducerOptions { EnableIdempotentPartitions = true }; var cancellationSource = new CancellationTokenSource(); cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); await using var producer = new IdempotentProducer(connectionString, options); Assert.That(async() => await producer.GetPartitionIdsAsync(cancellationSource.Token), Throws.Nothing); } }
public async Task ProducerIsRejectedWithPartitionOptionsForInvalidState() { await using (EventHubScope scope = await EventHubScope.CreateAsync(2)) { var connectionString = EventHubsTestEnvironment.Instance.BuildConnectionStringForEventHub(scope.EventHubName); var options = new IdempotentProducerOptions { EnableIdempotentPartitions = true }; var cancellationSource = new CancellationTokenSource(); cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partition = default(string); var partitionProperties = default(PartitionPublishingProperties); // Create a producer for a small scope that will Send some events and read the properties. await using (var initialProducer = new IdempotentProducer(connectionString, options)) { partition = (await initialProducer.GetPartitionIdsAsync(cancellationSource.Token)).Last(); await initialProducer.SendAsync(EventGenerator.CreateEvents(10), new SendEventOptions { PartitionId = partition }, cancellationSource.Token); partitionProperties = await initialProducer.GetPartitionPublishingPropertiesAsync(partition); } // Create a new producer using the previously read properties to set options for the partition. options.PartitionOptions.Add(partition, new PartitionPublishingOptions { ProducerGroupId = partitionProperties.ProducerGroupId, OwnerLevel = partitionProperties.OwnerLevel, StartingSequenceNumber = (partitionProperties.LastPublishedSequenceNumber - 5) }); await using var producer = new IdempotentProducer(connectionString, options); Assert.That(async() => await producer.SendAsync(EventGenerator.CreateEvents(10), new SendEventOptions { PartitionId = partition }, cancellationSource.Token), Throws.InstanceOf <EventHubsException>().And.Property("Reason").EqualTo(EventHubsException.FailureReason.InvalidClientState)); } }
public async Task ProducerUpdatesPropertiesAfterPublishingBatches() { await using (EventHubScope scope = await EventHubScope.CreateAsync(1)) { var connectionString = EventHubsTestEnvironment.Instance.BuildConnectionStringForEventHub(scope.EventHubName); var options = new IdempotentProducerOptions { EnableIdempotentPartitions = true }; await using var producer = new IdempotentProducer(connectionString, options); var cancellationSource = new CancellationTokenSource(); cancellationSource.CancelAfter(EventHubsTestEnvironment.Instance.TestExecutionTimeLimit); var partition = (await producer.GetPartitionIdsAsync(cancellationSource.Token)).First(); var initialPartitionProperties = await producer.GetPartitionPublishingPropertiesAsync(partition); var batchOptions = new CreateBatchOptions { PartitionId = partition }; using var batch = await producer.CreateBatchAsync(batchOptions, cancellationSource.Token); batch.TryAdd(EventGenerator.CreateEvents(1).First()); batch.TryAdd(EventGenerator.CreateEvents(1).First()); batch.TryAdd(EventGenerator.CreateEvents(1).First()); await producer.SendAsync(batch, cancellationSource.Token); var updatedPartitionProperties = await producer.GetPartitionPublishingPropertiesAsync(partition); Assert.That(updatedPartitionProperties.IsIdempotentPublishingEnabled, Is.True, "Idempotent publishing should be enabled."); Assert.That(updatedPartitionProperties.ProducerGroupId, Is.EqualTo(initialPartitionProperties.ProducerGroupId), "The producer group identifier should not have changed."); Assert.That(updatedPartitionProperties.OwnerLevel, Is.EqualTo(initialPartitionProperties.OwnerLevel), "The owner level should not have changed."); Assert.That(updatedPartitionProperties.LastPublishedSequenceNumber, Is.GreaterThan(initialPartitionProperties.LastPublishedSequenceNumber), "The last published sequence number should have increased."); } }