public async Task Removes_Removes_Given_Connection_Then_Activates_Queued()
        {
            var key1  = new ConnectionKey(new IPAddress(0x1), 1);
            var mock1 = new Mock <IConnection>();

            mock1.Setup(m => m.Key).Returns(key1);

            var key2  = new ConnectionKey(new IPAddress(0x2), 2);
            var mock2 = new Mock <IConnection>();

            mock2.Setup(m => m.Key).Returns(key2);

            var c = new ConnectionManager <IConnection>(1);
            await c.AddAsync(mock1.Object);

            await c.AddAsync(mock2.Object);

            var active = c.GetProperty <ConcurrentDictionary <ConnectionKey, IConnection> >("Connections");
            var queued = c.GetProperty <ConcurrentQueue <IConnection> >("ConnectionQueue");

            // ensure connection 1 was added and immediately activated
            Assert.Single(active);
            Assert.True(active.TryGetValue(mock1.Object.Key, out var _), "Connection 1 was added");

            // ensure connection 2 was added and queued
            Assert.Single(queued);
            var peek = queued.TryPeek(out var peeked);

            Assert.True(peek);
            Assert.True(peeked.Key == key2, "Connection 2 was queued");

            await c.RemoveAsync(mock1.Object);

            Assert.Empty(queued);
            Assert.Single(active);

            Assert.False(active.TryGetValue(mock1.Object.Key, out var _), "Connection 1 was removed");
            Assert.True(active.TryGetValue(mock2.Object.Key, out var _), "Connection 2 was activated");

            // ensure mock 1 was disposed when removed
            mock1.Verify(m => m.Dispose(), Times.Once);

            // ensure mock 2 was connected when activated
            mock2.Verify(m => m.ConnectAsync(It.IsAny <CancellationToken>()), Times.Once);
        }
        public async Task Add_Does_Not_Throw_On_Null_Connection()
        {
            var c = new ConnectionManager <IConnection>();

            var ex = await Record.ExceptionAsync(async() => await c.AddAsync(null));

            Assert.Null(ex);
            Assert.Equal(0, c.Active);
            Assert.Equal(0, c.Queued);
        }
        public async Task Add_Adds_Given_Connection_And_Queues()
        {
            var key = new ConnectionKey(new IPAddress(0x0), 1);

            var mock = new Mock <IConnection>();

            mock.Setup(m => m.Key).Returns(key);

            var c = new ConnectionManager <IConnection>(0); // enqueue all

            var ex = await Record.ExceptionAsync(async() => await c.AddAsync(mock.Object));

            Assert.Null(ex);
            Assert.Equal(0, c.Active);
            Assert.Equal(1, c.Queued);

            mock.Verify(m => m.ConnectAsync(), Times.Never);
        }
        public async Task Add_Adds_Given_Connection_And_Activates_Immediately()
        {
            var key = new ConnectionKey(new IPAddress(0x0), 1);

            var mock = new Mock <IConnection>();

            mock.Setup(m => m.Key).Returns(key);

            var c = new ConnectionManager <IConnection>();

            var ex = await Record.ExceptionAsync(async() => await c.AddAsync(mock.Object));

            Assert.Null(ex);
            Assert.Equal(1, c.Active);
            Assert.Equal(0, c.Queued);

            mock.Verify(m => m.ConnectAsync(It.IsAny <CancellationToken>()), Times.Once);
        }
        public async Task Get_Returns_Active_Connection()
        {
            var key = new ConnectionKey(new IPAddress(0x0), 1);

            var mock = new Mock <IConnection>();

            mock.Setup(m => m.Key).Returns(key);

            var c = new ConnectionManager <IConnection>();
            await c.AddAsync(mock.Object);

            Assert.Equal(0, c.Queued);
            Assert.Equal(1, c.Active);

            var conn = c.Get(key);

            Assert.NotNull(conn);
            Assert.Equal(mock.Object, conn);

            mock.Verify(m => m.ConnectAsync(It.IsAny <CancellationToken>()), Times.Once);
        }
        public async Task Get_Returns_Queued_Connection()
        {
            var key = new ConnectionKey(new IPAddress(0x0), 1);

            var mock = new Mock <IConnection>();

            mock.Setup(m => m.Key).Returns(key);

            var c = new ConnectionManager <IConnection>(0); // force enqueue
            await c.AddAsync(mock.Object);

            Assert.Equal(1, c.Queued);
            Assert.Equal(0, c.Active);

            var conn = c.Get(key);

            Assert.NotNull(conn);
            Assert.Equal(mock.Object, conn);

            mock.Verify(m => m.ConnectAsync(), Times.Never);
        }
        public async Task Removes_Removes_Given_Connection()
        {
            var key = new ConnectionKey(new IPAddress(0x0), 1);

            var mock = new Mock <IConnection>();

            mock.Setup(m => m.Key).Returns(key);

            var c = new ConnectionManager <IConnection>();
            await c.AddAsync(mock.Object);

            var active = c.GetProperty <ConcurrentDictionary <ConnectionKey, IConnection> >("Connections");

            Assert.True(active.TryGetValue(mock.Object.Key, out var _), "Connection was added");

            await c.RemoveAsync(mock.Object);

            Assert.Empty(active);
            Assert.False(active.TryGetValue(mock.Object.Key, out var _), "Connection was removed");
            mock.Verify(m => m.Dispose(), Times.Once);
        }