public async Task ProducerCanSendSingleLargeEventInASet()
        {
            await using (var scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString, new EventHubClientOptions {
                    RetryOptions = new RetryOptions {
                        TryTimeout = TimeSpan.FromMinutes(5)
                    }
                }))
                    await using (var producer = client.CreateProducer())
                    {
                        // Actual limit is 1046520 for a single event.
                        var eventSet = new[] { new EventData(new byte[100000]) };

                        Assert.That(async() => await producer.SendAsync(eventSet), Throws.Nothing);
                    }
            }
        }
예제 #2
0
        public async Task ProducerCanSendASetOfEvents()
        {
            await using (var scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                    await using (var producer = client.CreateProducer())
                    {
                        var events = new[]
                        {
                            new EventData(Encoding.UTF8.GetBytes("This is a message")),
                            new EventData(Encoding.UTF8.GetBytes("This is another message")),
                            new EventData(Encoding.UTF8.GetBytes("So many messages"))
                        };

                        Assert.That(async() => await producer.SendAsync(events), Throws.Nothing);
                    }
            }
        }
예제 #3
0
        public async Task ConsumerWithOptionsCanReceive()
        {
            await using (var scope = await EventHubScope.CreateAsync(4))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);
                var options          = new EventHubConsumerOptions {
                    Identifier = "FakeIdentifier"
                };

                await using (var client = new EventHubClient(connectionString))
                {
                    var partition = (await client.GetPartitionIdsAsync()).First();

                    await using (var consumer = client.CreateConsumer(EventHubConsumer.DefaultConsumerGroup, partition, EventPosition.Latest, options))
                    {
                        Assert.That(async() => await consumer.ReceiveAsync(1, TimeSpan.Zero), Throws.Nothing);
                    }
                }
            }
        }
        public async Task ProducerCanSendEventsUsingAPartitionHashKey()
        {
            await using (var scope = await EventHubScope.CreateAsync(2))
            {
                var events = Enumerable
                             .Range(0, 25)
                             .Select(index => new EventData(Encoding.UTF8.GetBytes(new String('X', index + 5))));

                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                    await using (var producer = client.CreateProducer())
                    {
                        var batchOptions = new SendOptions {
                            PartitionKey = "some123key-!d"
                        };
                        Assert.That(async() => await producer.SendAsync(events, batchOptions), Throws.Nothing);
                    }
            }
        }
예제 #5
0
        public async Task ProducerCanSendWhenPartitionIsNull()
        {
            await using (var scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                {
                    var producerOptions = new EventHubProducerOptions {
                        PartitionId = null
                    };

                    await using (var producer = client.CreateProducer(producerOptions))
                    {
                        var events = new[] { new EventData(Encoding.UTF8.GetBytes("Will it work")) };
                        Assert.That(async() => await producer.SendAsync(events), Throws.Nothing);
                    }
                }
            }
        }
예제 #6
0
        public async Task ProducerCanSendAnEventBatch()
        {
            await using (var scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                    await using (var producer = client.CreateProducer())
                    {
                        using var batch = await producer.CreateBatchAsync();

                        batch.TryAdd(new EventData(Encoding.UTF8.GetBytes("This is a message")));
                        batch.TryAdd(new EventData(Encoding.UTF8.GetBytes("This is another message")));
                        batch.TryAdd(new EventData(Encoding.UTF8.GetBytes("So many messages")));

                        Assert.That(batch.Count, Is.EqualTo(3), "The batch should contain all 3 events.");
                        Assert.That(async() => await producer.SendAsync(batch), Throws.Nothing);
                    }
            }
        }
예제 #7
0
        public async Task ProducerCanSendZeroLengthSet()
        {
            await using (var scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                    await using (var producer = client.CreateProducer())
                    {
                        var events = new[]
                        {
                            new EventData(Array.Empty <byte>()),
                            new EventData(Array.Empty <byte>()),
                            new EventData(Array.Empty <byte>())
                        };

                        Assert.That(async() => await producer.SendAsync(events), Throws.Nothing);
                    }
            }
        }
        public async Task ClientCanRetrievePartitionProperties()
        {
            var partitionCount = 4;

            await using (var scope = await EventHubScope.CreateAsync(partitionCount))
            {
                var clientOptions        = new EventHubClientOptions();
                var connectionString     = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);
                var connectionProperties = ConnectionStringParser.Parse(connectionString);

                var credential = new SharedAccessSignatureCredential
                                 (
                    new SharedAccessSignature
                    (
                        clientOptions.TransportType,
                        connectionProperties.Endpoint.Host,
                        connectionProperties.EventHubPath,
                        connectionProperties.SharedAccessKeyName,
                        connectionProperties.SharedAccessKey,
                        TimeSpan.FromHours(4)
                    )
                                 );

                await using (var client = new EventHubClient(connectionProperties.Endpoint.Host, connectionProperties.EventHubPath, credential))
                {
                    var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(20));
                    var properties   = await client.GetPropertiesAsync();

                    var partition           = properties.PartitionIds.First();
                    var partitionProperties = await client.GetPartitionPropertiesAsync(partition, cancellation.Token);

                    Assert.That(partitionProperties, Is.Not.Null, "A set of partition properties should have been returned.");
                    Assert.That(partitionProperties.Id, Is.EqualTo(partition), "The partition identifier should match.");
                    Assert.That(partitionProperties.EventHubPath, Is.EqualTo(connectionProperties.EventHubPath).Using((IEqualityComparer <string>)StringComparer.InvariantCultureIgnoreCase), "The Event Hub path should match.");
                    Assert.That(partitionProperties.BeginningSequenceNumber, Is.Not.EqualTo(default(Int64)), "The beginning sequence number should have been populated.");
                    Assert.That(partitionProperties.LastEnqueuedSequenceNumber, Is.Not.EqualTo(default(Int64)), "The last sequance number should have been populated.");
                    Assert.That(partitionProperties.LastEnqueuedOffset, Is.Not.Null.Or.Empty, "The last offset should have been populated.");
                    Assert.That(partitionProperties.PropertyRetrievalTimeUtc, Is.EqualTo(DateTime.UtcNow).Within(TimeSpan.FromSeconds(30)), "The property retrieval time should denote the current time.");
                }
            }
        }
예제 #9
0
        public async Task PartitionProcessorProcessEventsAsyncIsCalledWithNoEvents()
        {
            await using (EventHubScope scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                {
                    var receivedEventSets = new ConcurrentBag <IEnumerable <EventData> >();

                    // Create the event processor manager to manage our event processors.

                    var eventProcessorManager = new EventProcessorManager
                                                (
                        EventHubConsumer.DefaultConsumerGroupName,
                        client,
                        onProcessEvents: (partitionContext, events, cancellationToken) =>
                        receivedEventSets.Add(events)
                                                );

                    eventProcessorManager.AddEventProcessors(1);

                    // Start the event processors.

                    await eventProcessorManager.StartAllAsync();

                    // Make sure the event processors have enough time to stabilize.

                    await eventProcessorManager.WaitStabilization();

                    // Stop the event processors.

                    await eventProcessorManager.StopAllAsync();

                    // Validate results.

                    Assert.That(receivedEventSets, Is.Not.Empty);
                    Assert.That(receivedEventSets.Any(set => (set == null || set.Any())), Is.False);
                }
            }
        }
예제 #10
0
        public async Task PartitionProcessorProcessEventsAsyncIsCalledWithNoEvents()
        {
            await using (EventHubScope scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var connection = new EventHubConnection(connectionString))
                {
                    var receivedEvents = new ConcurrentBag <EventData>();

                    // Create the event processor manager to manage our event processors.

                    var eventProcessorManager = new EventProcessorManager
                                                (
                        EventHubConsumerClient.DefaultConsumerGroupName,
                        connection,
                        onProcessEvent: processorEvent =>
                        receivedEvents.Add(processorEvent.Data)
                                                );

                    eventProcessorManager.AddEventProcessors(1);

                    // Start the event processors.

                    await eventProcessorManager.StartAllAsync();

                    // Make sure the event processors have enough time to stabilize.

                    await eventProcessorManager.WaitStabilization();

                    // Stop the event processors.

                    await eventProcessorManager.StopAllAsync();

                    // Validate results.

                    Assert.That(receivedEvents, Is.Not.Empty);
                    Assert.That(receivedEvents.Any(eventData => eventData != null), Is.False);
                }
            }
        }
        public async Task ClientPartitionIdsMatchPartitionProperties()
        {
            var partitionCount = 4;

            await using (var scope = await EventHubScope.CreateAsync(partitionCount))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                {
                    var properties = await client.GetPropertiesAsync();

                    var partitions = await client.GetPartitionIdsAsync();

                    Assert.That(properties, Is.Not.Null, "A set of properties should have been returned.");
                    Assert.That(properties.PartitionIds, Is.Not.Null, "A set of partition identifiers for the properties should have been returned.");
                    Assert.That(partitions, Is.Not.Null, "A set of partition identifiers should have been returned.");
                    Assert.That(partitions, Is.EquivalentTo(properties.PartitionIds), "The partition identifiers returned directly should match those returned with properties.");
                }
            }
        }
예제 #12
0
        public async Task ProducerCannotSendWhenProxyIsInvalid()
        {
            await using (EventHubScope scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);
                var clientOptions    = new EventHubClientOptions
                {
                    Proxy         = new WebProxy("http://1.2.3.4:9999"),
                    TransportType = TransportType.AmqpWebSockets,
                    RetryOptions  = new RetryOptions {
                        TryTimeout = TimeSpan.FromMinutes(2)
                    }
                };

                await using (var invalidProxyClient = new EventHubClient(connectionString, clientOptions))
                    await using (EventHubProducer invalidProxyProducer = invalidProxyClient.CreateProducer())
                    {
                        Assert.That(async() => await invalidProxyProducer.SendAsync(new EventData(new byte[1])), Throws.InstanceOf <WebSocketException>().Or.InstanceOf <TimeoutException>());
                    }
            }
        }
예제 #13
0
        public async Task ProducerWithOptionsCanSend(TransportType transportType)
        {
            await using (var scope = await EventHubScope.CreateAsync(4))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);
                var producerOptions  = new EventHubProducerOptions {
                    RetryOptions = new RetryOptions {
                        MaximumRetries = 5
                    }
                };

                await using (var client = new EventHubClient(connectionString, new EventHubClientOptions {
                    TransportType = transportType
                }))
                    await using (var producer = client.CreateProducer(producerOptions))
                    {
                        var events = new[] { new EventData(Encoding.UTF8.GetBytes("AWord")) };
                        Assert.That(async() => await producer.SendAsync(events), Throws.Nothing);
                    }
            }
        }
        public async Task ProducerCannotSendBatchLargerThanMaximumSize()
        {
            await using (var scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                    await using (var producer = client.CreateProducer())
                    {
                        // Actual limit is 1046520 for a single event
                        var events = new[]
                        {
                            new EventData(new byte[1500000 / 3]),
                            new EventData(new byte[1500000 / 3]),
                            new EventData(new byte[1500000 / 3])
                        };

                        Assert.That(async() => await producer.SendAsync(events), Throws.TypeOf <TrackOne.MessageSizeExceededException>());
                    }
            }
        }
        public async Task ProducerCanSendToASpecificPartition()
        {
            await using (var scope = await EventHubScope.CreateAsync(4))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                {
                    var partition       = (await client.GetPartitionIdsAsync()).First();
                    var producerOptions = new EventHubProducerOptions {
                        PartitionId = partition
                    };

                    await using (var producer = client.CreateProducer(producerOptions))
                    {
                        var events = new[] { new EventData(Encoding.UTF8.GetBytes("AWord")) };
                        Assert.That(async() => await producer.SendAsync(events), Throws.Nothing);
                    }
                }
            }
        }
        public async Task ProducerCanSendLargeBatch()
        {
            await using (var scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                    await using (var producer = client.CreateProducer())
                    {
                        // Actual limit is 1046520 for a single event
                        var events = new[]
                        {
                            new EventData(new byte[1000000 / 3]),
                            new EventData(new byte[1000000 / 3]),
                            new EventData(new byte[1000000 / 3])
                        };

                        Assert.That(async() => await producer.SendAsync(events), Throws.Nothing);
                    }
            }
        }
        public async Task ClientCanRetrievePartitionProperties(TransportType transportType)
        {
            var partitionCount = 4;

            await using (EventHubScope scope = await EventHubScope.CreateAsync(partitionCount))
            {
                var clientOptions    = new EventHubClientOptions();
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);
                ConnectionStringProperties connectionProperties = ConnectionStringParser.Parse(connectionString);

                var credential = new SharedAccessSignatureCredential
                                 (
                    new SharedAccessSignature
                    (
                        $"{ clientOptions.TransportType.GetUriScheme() }://{ connectionProperties.Endpoint.Host }/{ connectionProperties.EventHubName }".ToLowerInvariant(),
                        connectionProperties.SharedAccessKeyName,
                        connectionProperties.SharedAccessKey,
                        TimeSpan.FromHours(4)
                    )
                                 );

                await using (var client = new EventHubClient(connectionProperties.Endpoint.Host, connectionProperties.EventHubName, credential, new EventHubClientOptions {
                    TransportType = transportType
                }))
                {
                    var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(20));
                    EventHubProperties properties = await client.GetPropertiesAsync();

                    var partition = properties.PartitionIds.First();
                    PartitionProperties partitionProperties = await client.GetPartitionPropertiesAsync(partition, cancellation.Token);

                    Assert.That(partitionProperties, Is.Not.Null, "A set of partition properties should have been returned.");
                    Assert.That(partitionProperties.Id, Is.EqualTo(partition), "The partition identifier should match.");
                    Assert.That(partitionProperties.EventHubName, Is.EqualTo(connectionProperties.EventHubName).Using((IEqualityComparer <string>)StringComparer.InvariantCultureIgnoreCase), "The Event Hub path should match.");
                    Assert.That(partitionProperties.BeginningSequenceNumber, Is.Not.EqualTo(default(long)), "The beginning sequence number should have been populated.");
                    Assert.That(partitionProperties.LastEnqueuedSequenceNumber, Is.Not.EqualTo(default(long)), "The last sequence number should have been populated.");
                    Assert.That(partitionProperties.LastEnqueuedOffset, Is.Not.EqualTo(default(long)), "The last offset should have been populated.");
                }
            }
        }
        public async Task ClientCannotRetrieveMetadataWhenProxyIsInvalid()
        {
            await using (var scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);
                var clientOptions    = new EventHubClientOptions
                {
                    Proxy         = new WebProxy("http://1.2.3.4:9999"),
                    TransportType = TransportType.AmqpWebSockets
                };

                await using (var client = new EventHubClient(connectionString))
                    await using (var invalidProxyClient = new EventHubClient(connectionString, clientOptions))
                    {
                        var partition = (await client.GetPartitionIdsAsync()).First();

                        Assert.That(async() => await invalidProxyClient.GetPartitionIdsAsync(), Throws.InstanceOf <WebSocketException>());
                        Assert.That(async() => await invalidProxyClient.GetPropertiesAsync(), Throws.InstanceOf <WebSocketException>());
                        Assert.That(async() => await invalidProxyClient.GetPartitionPropertiesAsync(partition), Throws.InstanceOf <WebSocketException>());
                    }
            }
        }
        public async Task ReceiverWithOptionsCanReceive()
        {
            await using (var scope = await EventHubScope.CreateAsync(4))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                var options = new EventReceiverOptions
                {
                    ConsumerGroup    = "$Default",
                    BeginReceivingAt = EventPosition.NewEventsOnly
                };

                await using (var client = new EventHubClient(connectionString))
                {
                    var partition = (await client.GetPartitionIdsAsync()).First();

                    await using (var receiver = client.CreateReceiver(partition, options))
                    {
                        Assert.That(async() => await receiver.ReceiveAsync(1, TimeSpan.Zero), Throws.Nothing);
                    }
                }
            }
        }
예제 #20
0
        public async Task ConnectionTransportCannotRetrieveMetadataWhenClosed()
        {
            await using (EventHubScope scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var connection = new TestConnectionWithTransport(connectionString))
                {
                    var partition = (await connection.GetPartitionIdsAsync()).First();

                    Assert.That(async() => await connection.GetPropertiesAsync(), Throws.Nothing);
                    Assert.That(async() => await connection.GetPartitionPropertiesAsync(partition), Throws.Nothing);

                    await connection.CloseAsync();

                    await Task.Delay(TimeSpan.FromSeconds(5));

                    Assert.That(async() => await connection.GetPartitionIdsAsync(), Throws.InstanceOf <EventHubsException>().And.Property(nameof(EventHubsException.Reason)).EqualTo(EventHubsException.FailureReason.ClientClosed));
                    Assert.That(async() => await connection.GetPropertiesAsync(), Throws.InstanceOf <EventHubsException>().And.Property(nameof(EventHubsException.Reason)).EqualTo(EventHubsException.FailureReason.ClientClosed));
                    Assert.That(async() => await connection.GetPartitionPropertiesAsync(partition), Throws.InstanceOf <EventHubsException>().And.Property(nameof(EventHubsException.Reason)).EqualTo(EventHubsException.FailureReason.ClientClosed));
                }
            }
        }
        public async Task PartitionReceiverCanRetrievePartitionProperties(EventHubsTransportType transportType)
        {
            var partitionCount = 1;

            await using (EventHubScope scope = await EventHubScope.CreateAsync(partitionCount))
            {
                var cancellationSource = new CancellationTokenSource(TimeSpan.FromSeconds(20));

                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);
                var receiverOptions  = new PartitionReceiverOptions {
                    ConnectionOptions = new EventHubConnectionOptions {
                        TransportType = transportType
                    }
                };

                var partitionId = default(string);

                await using (var producer = new EventHubProducerClient(connectionString))
                {
                    partitionId = (await producer.GetPartitionIdsAsync(cancellationSource.Token)).First();
                }

                await using (var receiver = new PartitionReceiver(EventHubConsumerClient.DefaultConsumerGroupName, partitionId, EventPosition.Earliest, connectionString, receiverOptions))
                {
                    var partitionProperties = await receiver.GetPartitionPropertiesAsync(cancellationSource.Token);

                    Assert.That(cancellationSource.IsCancellationRequested, Is.False, "The cancellation token should not have been signaled.");
                    Assert.That(partitionProperties, Is.Not.Null, "A set of partition properties should have been returned.");
                    Assert.That(partitionProperties.Id, Is.EqualTo(partitionId), "The partition identifier should match.");
                    Assert.That(partitionProperties.EventHubName, Is.EqualTo(scope.EventHubName).Using((IEqualityComparer <string>)StringComparer.InvariantCultureIgnoreCase), "The Event Hub path should match.");
                    Assert.That(partitionProperties.BeginningSequenceNumber, Is.Not.EqualTo(default(long)), "The beginning sequence number should have been populated.");
                    Assert.That(partitionProperties.LastEnqueuedSequenceNumber, Is.Not.EqualTo(default(long)), "The last sequence number should have been populated.");
                    Assert.That(partitionProperties.LastEnqueuedOffset, Is.Not.EqualTo(default(long)), "The last offset should have been populated.");
                }
            }
        }
        public async Task ProducerCanSendMultipleBatchesOfEventsUsingAPartitionHashHey()
        {
            await using (var scope = await EventHubScope.CreateAsync(4))
            {
                var batchOptions = new SendOptions {
                    PartitionKey = "some123key-!d"
                };

                for (var index = 0; index < 5; ++index)
                {
                    var events = Enumerable
                                 .Range(0, 25)
                                 .Select(index => new EventData(Encoding.UTF8.GetBytes(new String((char)(65 + index), index + 5))));

                    var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                    await using (var client = new EventHubClient(connectionString))
                        await using (var producer = client.CreateProducer())
                        {
                            Assert.That(async() => await producer.SendAsync(events, batchOptions), Throws.Nothing, $"Batch { index } should not have thrown an exception.");
                        }
                }
            }
        }
예제 #23
0
        public async Task EventProcessorCanReceiveFromCheckpointedEventPosition()
        {
            await using (EventHubScope scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                {
                    int receivedEventsCount = 0;

                    // Send some events.

                    var  expectedEventsCount        = 20;
                    var  dummyEvent                 = new EventData(Encoding.UTF8.GetBytes("I'm dummy."));
                    long?checkpointedSequenceNumber = default;

                    var partitionId = (await client.GetPartitionIdsAsync()).First();

                    await using (EventHubProducer producer = client.CreateProducer())
                        await using (EventHubConsumer consumer = client.CreateConsumer(EventHubConsumer.DefaultConsumerGroupName, partitionId, EventPosition.Earliest))
                        {
                            // Send a few dummy events.  We are not expecting to receive these.

                            var dummyEventsCount = 30;

                            for (int i = 0; i < dummyEventsCount; i++)
                            {
                                await producer.SendAsync(dummyEvent);
                            }

                            // Receive the events; because there is some non-determinism in the messaging flow, the
                            // sent events may not be immediately available.  Allow for a small number of attempts to receive, in order
                            // to account for availability delays.

                            var receivedEvents = new List <EventData>();
                            var index          = 0;

                            while ((receivedEvents.Count < dummyEventsCount) && (++index < ReceiveRetryLimit))
                            {
                                receivedEvents.AddRange(await consumer.ReceiveAsync(dummyEventsCount + 10, TimeSpan.FromMilliseconds(25)));
                            }

                            Assert.That(receivedEvents.Count, Is.EqualTo(dummyEventsCount));

                            checkpointedSequenceNumber = receivedEvents.Last().SequenceNumber;

                            // Send the events we expect to receive.

                            for (int i = 0; i < expectedEventsCount; i++)
                            {
                                await producer.SendAsync(dummyEvent);
                            }
                        }

                    // Create a partition manager and add an ownership with a checkpoint in it.

                    var partitionManager = new InMemoryPartitionManager();

                    await partitionManager.ClaimOwnershipAsync(new List <PartitionOwnership>()
                    {
                        new PartitionOwnership(client.FullyQualifiedNamespace, client.EventHubName,
                                               EventHubConsumer.DefaultConsumerGroupName, "ownerIdentifier", partitionId,
                                               sequenceNumber: checkpointedSequenceNumber, lastModifiedTime: DateTimeOffset.UtcNow)
                    });

                    // Create the event processor manager to manage our event processors.

                    var eventProcessorManager = new EventProcessorManager
                                                (
                        EventHubConsumer.DefaultConsumerGroupName,
                        client,
                        partitionManager,
                        onProcessEvents: (partitionContext, events, cancellationToken) =>
                    {
                        // Make it a list so we can safely enumerate it.

                        var eventsList = new List <EventData>(events ?? Enumerable.Empty <EventData>());

                        if (eventsList.Count > 0)
                        {
                            Interlocked.Add(ref receivedEventsCount, eventsList.Count);
                        }
                    }
                                                );

                    eventProcessorManager.AddEventProcessors(1);

                    // Start the event processors.

                    await eventProcessorManager.StartAllAsync();

                    // Make sure the event processors have enough time to stabilize and receive events.

                    await eventProcessorManager.WaitStabilization();

                    // Stop the event processors.

                    await eventProcessorManager.StopAllAsync();

                    // Validate results.

                    Assert.That(receivedEventsCount, Is.EqualTo(expectedEventsCount));
                }
            }
        }
        public async Task ProducerSendsEventsWithTheSamePartitionHashKeyToTheSamePartition()
        {
            var partitions   = 10;
            var partitionKey = "some123key-!d";

            await using (var scope = await EventHubScope.CreateAsync(partitions))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                    await using (var producer = client.CreateProducer())
                    {
                        var batches      = 5;
                        var partitionIds = await client.GetPartitionIdsAsync();

                        var partitionsCount     = 0;
                        var receivedEventsCount = 0;
                        var consumers           = new List <EventHubConsumer>();

                        try
                        {
                            for (var index = 0; index < partitions; index++)
                            {
                                consumers.Add(client.CreateConsumer(EventHubConsumer.DefaultConsumerGroupName, partitionIds[index], EventPosition.Latest));

                                // Initiate an operation to force the consumer to connect and set its position at the
                                // end of the event stream.

                                await consumers[index].ReceiveAsync(1, TimeSpan.Zero);
                            }

                            // Send the batches of events.

                            var batchOptions = new SendOptions {
                                PartitionKey = partitionKey
                            };

                            for (var index = 0; index < batches; index++)
                            {
                                await producer.SendAsync(new EventData(Encoding.UTF8.GetBytes($"Just a few messages ({ index })")), batchOptions);
                            }

                            // Receive the events; because there is some non-determinism in the messaging flow, the
                            // sent events may not be immediately available.  Allow for a small number of attempts to receive, in order
                            // to account for availability delays.

                            foreach (var consumer in consumers)
                            {
                                var receivedEvents = new List <EventData>();
                                var index          = 0;

                                while (++index < ReceiveRetryLimit)
                                {
                                    receivedEvents.AddRange(await consumer.ReceiveAsync(batches + 10, TimeSpan.FromMilliseconds(25)));
                                }

                                if (receivedEvents.Count > 0)
                                {
                                    partitionsCount++;
                                    receivedEventsCount += receivedEvents.Count;

                                    foreach (var receivedEvent in receivedEvents)
                                    {
                                        Assert.That(receivedEvent.PartitionKey, Is.EqualTo(partitionKey));
                                    }
                                }
                            }
                        }
                        finally
                        {
                            foreach (var consumer in consumers)
                            {
                                consumer.Close();
                            }
                        }

                        Assert.That(partitionsCount, Is.EqualTo(1));
                        Assert.That(receivedEventsCount, Is.EqualTo(batches));
                    }
            }
        }
        public async Task ProducerSendsEventsInTheSameBatchToTheSamePartition()
        {
            var partitions = 10;

            await using (var scope = await EventHubScope.CreateAsync(partitions))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                    await using (var producer = client.CreateProducer())
                    {
                        var eventBatch = Enumerable
                                         .Range(0, 30)
                                         .Select(index => new EventData(Encoding.UTF8.GetBytes("I'm getting used to this amount of messages")))
                                         .ToList();

                        var partitionIds = await client.GetPartitionIdsAsync();

                        var partitionsCount     = 0;
                        var receivedEventsCount = 0;
                        var consumers           = new List <EventHubConsumer>();

                        try
                        {
                            for (var index = 0; index < partitions; index++)
                            {
                                consumers.Add(client.CreateConsumer(EventHubConsumer.DefaultConsumerGroupName, partitionIds[index], EventPosition.Latest));

                                // Initiate an operation to force the consumer to connect and set its position at the
                                // end of the event stream.

                                await consumers[index].ReceiveAsync(1, TimeSpan.Zero);
                            }

                            // Send the batch of events.

                            await producer.SendAsync(eventBatch);

                            // Receive the events; because there is some non-determinism in the messaging flow, the
                            // sent events may not be immediately available.  Allow for a small number of attempts to receive, in order
                            // to account for availability delays.

                            foreach (var consumer in consumers)
                            {
                                var receivedEvents = new List <EventData>();
                                var index          = 0;

                                while (++index < ReceiveRetryLimit)
                                {
                                    receivedEvents.AddRange(await consumer.ReceiveAsync(eventBatch.Count + 10, TimeSpan.FromMilliseconds(25)));
                                }

                                if (receivedEvents.Count > 0)
                                {
                                    partitionsCount++;
                                    receivedEventsCount += receivedEvents.Count;
                                }
                            }
                        }
                        finally
                        {
                            foreach (var consumer in consumers)
                            {
                                consumer.Close();
                            }
                        }

                        Assert.That(partitionsCount, Is.EqualTo(1));
                        Assert.That(receivedEventsCount, Is.EqualTo(eventBatch.Count));
                    }
            }
        }
        public async Task ProducerDoesNotSendToSpecificPartitionWhenPartitionIdIsNotSpecified(bool nullPartition)
        {
            var partitions = 10;

            await using (var scope = await EventHubScope.CreateAsync(partitions))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                {
                    var producerOptions = new EventHubProducerOptions {
                    };

                    if (nullPartition)
                    {
                        producerOptions.PartitionId = null;
                    }

                    await using (var producer = client.CreateProducer(producerOptions))
                    {
                        var batches      = 30;
                        var partitionIds = await client.GetPartitionIdsAsync();

                        var partitionsCount = 0;
                        var consumers       = new List <EventHubConsumer>();

                        try
                        {
                            for (var index = 0; index < partitions; index++)
                            {
                                consumers.Add(client.CreateConsumer(EventHubConsumer.DefaultConsumerGroupName, partitionIds[index], EventPosition.Latest));

                                // Initiate an operation to force the consumer to connect and set its position at the
                                // end of the event stream.

                                await consumers[index].ReceiveAsync(1, TimeSpan.Zero);
                            }

                            // Send the batches of events.

                            for (var index = 0; index < batches; index++)
                            {
                                await producer.SendAsync(new EventData(Encoding.UTF8.GetBytes("It's not healthy to send so many messages")));
                            }

                            // Receive the events; because there is some non-determinism in the messaging flow, the
                            // sent events may not be immediately available.  Allow for a small number of attempts to receive, in order
                            // to account for availability delays.

                            foreach (var consumer in consumers)
                            {
                                var receivedEvents = new List <EventData>();
                                var index          = 0;

                                while (++index < ReceiveRetryLimit)
                                {
                                    receivedEvents.AddRange(await consumer.ReceiveAsync(batches + 10, TimeSpan.FromMilliseconds(25)));
                                }

                                if (receivedEvents.Count > 0)
                                {
                                    partitionsCount++;
                                }
                            }
                        }
                        finally
                        {
                            await Task.WhenAll(consumers.Select(consumer => consumer.CloseAsync()));
                        }

                        Assert.That(partitionsCount, Is.GreaterThan(1));
                    }
                }
            }
        }
예제 #27
0
        public async Task PartitionProcessorCanCreateACheckpointFromPartitionContext()
        {
            await using (EventHubScope scope = await EventHubScope.CreateAsync(1))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                {
                    // Send some events.

                    EventData lastEvent;
                    var       dummyEvent = new EventData(Encoding.UTF8.GetBytes("I'm dummy."));

                    var partitionId = (await client.GetPartitionIdsAsync()).First();

                    await using (EventHubProducer producer = client.CreateProducer())
                        await using (EventHubConsumer consumer = client.CreateConsumer(EventHubConsumer.DefaultConsumerGroupName, partitionId, EventPosition.Earliest))
                        {
                            // Send a few events.  We are only interested in the last one of them.

                            var dummyEventsCount = 10;

                            for (int i = 0; i < dummyEventsCount; i++)
                            {
                                await producer.SendAsync(dummyEvent);
                            }

                            // Receive the events; because there is some non-determinism in the messaging flow, the
                            // sent events may not be immediately available.  Allow for a small number of attempts to receive, in order
                            // to account for availability delays.

                            var receivedEvents = new List <EventData>();
                            var index          = 0;

                            while ((receivedEvents.Count < dummyEventsCount) && (++index < ReceiveRetryLimit))
                            {
                                receivedEvents.AddRange(await consumer.ReceiveAsync(dummyEventsCount + 10, TimeSpan.FromMilliseconds(25)));
                            }

                            Assert.That(receivedEvents.Count, Is.EqualTo(dummyEventsCount));

                            lastEvent = receivedEvents.Last();
                        }

                    // Create a partition manager so we can retrieve the created checkpoint from it.

                    var partitionManager = new InMemoryPartitionManager();

                    // Create the event processor manager to manage our event processors.

                    var eventProcessorManager = new EventProcessorManager
                                                (
                        EventHubConsumer.DefaultConsumerGroupName,
                        client,
                        partitionManager,
                        onProcessEvents: (partitionContext, events, cancellationToken) =>
                    {
                        // Make it a list so we can safely enumerate it.

                        var eventsList = new List <EventData>(events ?? Enumerable.Empty <EventData>());

                        if (eventsList.Any())
                        {
                            partitionContext.UpdateCheckpointAsync(eventsList.Last());
                        }
                    }
                                                );

                    eventProcessorManager.AddEventProcessors(1);

                    // Start the event processors.

                    await eventProcessorManager.StartAllAsync();

                    // Make sure the event processors have enough time to stabilize and receive events.

                    await eventProcessorManager.WaitStabilization();

                    // Stop the event processors.

                    await eventProcessorManager.StopAllAsync();

                    // Validate results.

                    IEnumerable <PartitionOwnership> ownershipEnumerable = await partitionManager.ListOwnershipAsync(client.FullyQualifiedNamespace, client.EventHubName, EventHubConsumer.DefaultConsumerGroupName);

                    Assert.That(ownershipEnumerable, Is.Not.Null);
                    Assert.That(ownershipEnumerable.Count, Is.EqualTo(1));

                    PartitionOwnership ownership = ownershipEnumerable.Single();

                    Assert.That(ownership.Offset.HasValue, Is.True);
                    Assert.That(ownership.Offset.Value, Is.EqualTo(lastEvent.Offset));

                    Assert.That(ownership.SequenceNumber.HasValue, Is.True);
                    Assert.That(ownership.SequenceNumber.Value, Is.EqualTo(lastEvent.SequenceNumber));
                }
            }
        }
예제 #28
0
        public async Task EventProcessorCanReceiveFromSpecifiedInitialEventPosition()
        {
            await using (EventHubScope scope = await EventHubScope.CreateAsync(2))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                {
                    int receivedEventsCount = 0;

                    // Send some events.

                    var            expectedEventsCount = 20;
                    var            dummyEvent          = new EventData(Encoding.UTF8.GetBytes("I'm dummy."));
                    DateTimeOffset enqueuedTime;

                    await using (EventHubProducer producer = client.CreateProducer())
                    {
                        // Send a few dummy events.  We are not expecting to receive these.

                        for (int i = 0; i < 30; i++)
                        {
                            await producer.SendAsync(dummyEvent);
                        }

                        // Wait a reasonable amount of time so the events are able to reach the service.

                        await Task.Delay(1000);

                        // Send the events we expect to receive.

                        enqueuedTime = DateTimeOffset.UtcNow;

                        for (int i = 0; i < expectedEventsCount; i++)
                        {
                            await producer.SendAsync(dummyEvent);
                        }
                    }

                    // Create the event processor manager to manage our event processors.

                    var eventProcessorManager = new EventProcessorManager
                                                (
                        EventHubConsumer.DefaultConsumerGroupName,
                        client,
                        options: new EventProcessorOptions {
                        InitialEventPosition = EventPosition.FromEnqueuedTime(enqueuedTime)
                    },
                        onProcessEvents: (partitionContext, events, cancellationToken) =>
                    {
                        // Make it a list so we can safely enumerate it.

                        var eventsList = new List <EventData>(events ?? Enumerable.Empty <EventData>());

                        if (eventsList.Count > 0)
                        {
                            Interlocked.Add(ref receivedEventsCount, eventsList.Count);
                        }
                    }
                                                );

                    eventProcessorManager.AddEventProcessors(1);

                    // Start the event processors.

                    await eventProcessorManager.StartAllAsync();

                    // Make sure the event processors have enough time to stabilize and receive events.

                    await eventProcessorManager.WaitStabilization();

                    // Stop the event processors.

                    await eventProcessorManager.StopAllAsync();

                    // Validate results.

                    Assert.That(receivedEventsCount, Is.EqualTo(expectedEventsCount));
                }
            }
        }
예제 #29
0
        public async Task EventProcessorWaitsMaximumReceiveWaitTimeForEvents(int maximumWaitTimeInSecs)
        {
            await using (EventHubScope scope = await EventHubScope.CreateAsync(2))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                {
                    var timestamps = new ConcurrentDictionary <string, List <DateTimeOffset> >();

                    // Create the event processor manager to manage our event processors.

                    var eventProcessorManager = new EventProcessorManager
                                                (
                        EventHubConsumer.DefaultConsumerGroupName,
                        client,
                        options: new EventProcessorOptions {
                        MaximumReceiveWaitTime = TimeSpan.FromSeconds(maximumWaitTimeInSecs)
                    },
                        onInitialize: partitionContext =>
                        timestamps.TryAdd(partitionContext.PartitionId, new List <DateTimeOffset> {
                        DateTimeOffset.UtcNow
                    }),
                        onProcessEvents: (partitionContext, events, cancellationToken) =>
                        timestamps.AddOrUpdate
                        (
                            // The key already exists, so the 'addValue' factory will never be called.

                            partitionContext.PartitionId,
                            partitionId => null,
                            (partitionId, list) =>
                    {
                        list.Add(DateTimeOffset.UtcNow);
                        return(list);
                    }
                        )
                                                );

                    eventProcessorManager.AddEventProcessors(1);

                    // Start the event processors.

                    await eventProcessorManager.StartAllAsync();

                    // Make sure the event processors have enough time to stabilize.

                    await eventProcessorManager.WaitStabilization();

                    // Stop the event processors.

                    await eventProcessorManager.StopAllAsync();

                    // Validate results.

                    foreach (KeyValuePair <string, List <DateTimeOffset> > kvp in timestamps)
                    {
                        var partitionId = kvp.Key;
                        List <DateTimeOffset> partitionTimestamps = kvp.Value;

                        Assert.That(partitionTimestamps.Count, Is.GreaterThan(1), $"{ partitionId }: more timestamp samples were expected.");

                        for (int index = 1; index < partitionTimestamps.Count; index++)
                        {
                            var elapsedTime = partitionTimestamps[index].Subtract(partitionTimestamps[index - 1]).TotalSeconds;

                            Assert.That(elapsedTime, Is.GreaterThan(maximumWaitTimeInSecs - 0.1), $"{ partitionId }: elapsed time between indexes { index - 1 } and { index } was too short.");
                            Assert.That(elapsedTime, Is.LessThan(maximumWaitTimeInSecs + 5), $"{ partitionId }: elapsed time between indexes { index - 1 } and { index } was too long.");

                            ++index;
                        }
                    }
                }
            }
        }
예제 #30
0
        public async Task EventProcessorCannotReceiveMoreThanMaximumMessageCountMessagesAtATime(int maximumMessageCount)
        {
            var partitions = 2;

            await using (EventHubScope scope = await EventHubScope.CreateAsync(partitions))
            {
                var connectionString = TestEnvironment.BuildConnectionStringForEventHub(scope.EventHubName);

                await using (var client = new EventHubClient(connectionString))
                {
                    var unexpectedMessageCount = -1;

                    // Send some events.

                    await using (EventHubProducer producer = client.CreateProducer())
                    {
                        var eventSet = Enumerable
                                       .Range(0, 20 * maximumMessageCount)
                                       .Select(index => new EventData(new byte[10]))
                                       .ToList();

                        // Send one set per partition.

                        for (int i = 0; i < partitions; i++)
                        {
                            await producer.SendAsync(eventSet);
                        }
                    }

                    // Create the event processor manager to manage our event processors.

                    var eventProcessorManager = new EventProcessorManager
                                                (
                        EventHubConsumer.DefaultConsumerGroupName,
                        client,
                        options: new EventProcessorOptions {
                        MaximumMessageCount = maximumMessageCount
                    },
                        onProcessEvents: (partitionContext, events, cancellationToken) =>
                    {
                        // Make it a list so we can safely enumerate it.

                        var eventsList = new List <EventData>(events ?? Enumerable.Empty <EventData>());

                        // In case we find a message count greater than the allowed amount, we only store the first
                        // occurrence and ignore the subsequent ones.

                        if (eventsList.Count > maximumMessageCount)
                        {
                            Interlocked.CompareExchange(ref unexpectedMessageCount, eventsList.Count, -1);
                        }
                    }
                                                );

                    eventProcessorManager.AddEventProcessors(1);

                    // Start the event processors.

                    await eventProcessorManager.StartAllAsync();

                    // Make sure the event processors have enough time to stabilize and receive events.

                    await eventProcessorManager.WaitStabilization();

                    // Stop the event processors.

                    await eventProcessorManager.StopAllAsync();

                    // Validate results.

                    Assert.That(unexpectedMessageCount, Is.EqualTo(-1), $"A set of { unexpectedMessageCount } events was received.");
                }
            }
        }