public void TransportProducerPoolAllowsTakingTheRightTransportProducer(string partitionId)
        {
            var transportProducer = new ObservableTransportProducerMock();
            var partitionProducer = new ObservableTransportProducerMock(partitionId);
            var connection        = new MockConnection(() => partitionProducer);
            var retryPolicy       = new EventHubProducerClientOptions().RetryOptions.ToRetryPolicy();
            var startingPool      = new ConcurrentDictionary <string, TransportProducerPool.PoolItem>
            {
                ["0"] = new TransportProducerPool.PoolItem("0", partitionProducer)
            };
            TransportProducerPool transportProducerPool = new TransportProducerPool(connection, retryPolicy, eventHubProducer: transportProducer);

            var returnedProducer = transportProducerPool.GetPooledProducer(partitionId).TransportProducer as ObservableTransportProducerMock;

            Assert.That(returnedProducer.PartitionId, Is.EqualTo(partitionId));
        }
        public async Task TransportProducerPoolAllowsConfiguringRemoveAfter()
        {
            var transportProducer = new ObservableTransportProducerMock();
            var connection        = new MockConnection(() => transportProducer);
            var retryPolicy       = new EventHubProducerClientOptions().RetryOptions.ToRetryPolicy();
            var startingPool      = new ConcurrentDictionary <string, TransportProducerPool.PoolItem>
            {
                ["0"] = new TransportProducerPool.PoolItem("0", transportProducer)
            };
            TransportProducerPool transportProducerPool = new TransportProducerPool(connection, retryPolicy, startingPool);

            var pooledProducer = transportProducerPool.GetPooledProducer("0", TimeSpan.FromMinutes(-1));

            await using (var _ = pooledProducer.ConfigureAwait(false))
            {
            };

            GetExpirationCallBack(transportProducerPool).Invoke(null);

            Assert.That(transportProducer.CloseCallCount, Is.EqualTo(1));
        }
        public async Task ExpireRemovesTheRequestedItem()
        {
            var wasFactoryCalled  = false;
            var transportProducer = new ObservableTransportProducerMock();

            var startingPool = new ConcurrentDictionary <string, TransportProducerPool.PoolItem>
            {
                ["0"] = new TransportProducerPool.PoolItem("0", transportProducer),
                ["1"] = new TransportProducerPool.PoolItem("1", transportProducer),
                ["2"] = new TransportProducerPool.PoolItem("2", transportProducer),
            };

            Func <string, TransportProducer> producerFactory = partition =>
            {
                wasFactoryCalled = true;
                return(transportProducer);
            };

            var transportProducerPool = new TransportProducerPool(producerFactory, pool: startingPool, eventHubProducer: transportProducer);

            // Validate the initial state.

            Assert.That(startingPool.TryGetValue("0", out _), Is.True, "The requested partition should appear in the pool.");
            Assert.That(wasFactoryCalled, Is.False, "No producer should not have been created.");
            Assert.That(transportProducer.CloseCallCount, Is.EqualTo(0), "The producer should not have been closed.");

            // Expire the producer and validate the removal state.

            await transportProducerPool.ExpirePooledProducerAsync("0");

            Assert.That(startingPool.TryGetValue("0", out _), Is.False, "The requested partition should have been removed.");
            Assert.That(transportProducer.CloseCallCount, Is.EqualTo(1), "The producer should have been closed.");
            Assert.That(wasFactoryCalled, Is.False, "The requested partition should not have been created.");

            // Request the producer again and validate a new producer is created.

            Assert.That(transportProducerPool.GetPooledProducer("0"), Is.Not.Null, "The requested partition should be available.");
            Assert.That(wasFactoryCalled, Is.True, "A new producer for the requested partition should have been created.");
        }
        public async Task TransportProducerPoolTracksAProducerUsage()
        {
            DateTimeOffset oneMinuteAgo      = DateTimeOffset.UtcNow.Subtract(TimeSpan.FromMinutes(1));
            var            transportProducer = new ObservableTransportProducerMock();
            var            connection        = new MockConnection(() => transportProducer);
            var            retryPolicy       = new EventHubProducerClientOptions().RetryOptions.ToRetryPolicy();
            var            startingPool      = new ConcurrentDictionary <string, TransportProducerPool.PoolItem>
            {
                // An expired item in the pool
                ["0"] = new TransportProducerPool.PoolItem("0", transportProducer, removeAfter: oneMinuteAgo)
            };
            TransportProducerPool transportProducerPool = new TransportProducerPool(connection, retryPolicy, startingPool);

            var pooledProducer = transportProducerPool.GetPooledProducer("0");

            startingPool.TryGetValue("0", out var poolItem);

            await using (pooledProducer)
            {
                Assert.That(poolItem.ActiveInstances.Count, Is.EqualTo(1), "The usage of a transport producer should be tracked.");
            }

            Assert.That(poolItem.ActiveInstances.Count, Is.EqualTo(0), "After usage an active instance should be removed from the pool.");
        }