コード例 #1
0
        public async Task DisconnectedCircuitIsRemovedAfterConfiguredTimeout()
        {
            // Arrange
            var circuitIdFactory = TestCircuitIdFactory.CreateTestFactory();
            var circuitOptions   = new CircuitOptions
            {
                DisconnectedCircuitRetentionPeriod = TimeSpan.FromSeconds(3),
            };
            var registry = new TestCircuitRegistry(circuitIdFactory, circuitOptions);
            var tcs      = new TaskCompletionSource <object>();

            registry.OnAfterEntryEvicted = () =>
            {
                tcs.TrySetResult(new object());
            };
            var circuitHost = TestCircuitHost.Create();

            registry.RegisterDisconnectedCircuit(circuitHost);

            // Act
            // Verify it's present in the dictionary.
            Assert.True(registry.DisconnectedCircuits.TryGetValue(circuitHost.CircuitId.Secret, out var _));
            await Task.Run(() => tcs.Task.TimeoutAfter(TimeSpan.FromSeconds(10)));

            Assert.False(registry.DisconnectedCircuits.TryGetValue(circuitHost.CircuitId.Secret, out var _));
        }
コード例 #2
0
        public async Task ConnectAsync_InvokesCircuitHandlers_WhenCircuitWasPreviouslyDisconnected()
        {
            // Arrange
            var circuitIdFactory = TestCircuitIdFactory.CreateTestFactory();
            var registry         = CreateRegistry(circuitIdFactory);
            var handler          = new Mock <CircuitHandler> {
                CallBase = true
            };
            var circuitHost = TestCircuitHost.Create(circuitIdFactory.CreateCircuitId(), handlers: new[] { handler.Object });

            registry.DisconnectedCircuits.Set(circuitHost.CircuitId, circuitHost, new MemoryCacheEntryOptions {
                Size = 1
            });

            var newClient       = Mock.Of <IClientProxy>();
            var newConnectionId = "new-id";

            // Act
            var result = await registry.ConnectAsync(circuitHost.CircuitId, newClient, newConnectionId, default);

            // Assert
            Assert.NotNull(result);
            handler.Verify(v => v.OnCircuitOpenedAsync(It.IsAny <Circuit>(), It.IsAny <CancellationToken>()), Times.Never());
            handler.Verify(v => v.OnConnectionUpAsync(It.IsAny <Circuit>(), It.IsAny <CancellationToken>()), Times.Once());
            handler.Verify(v => v.OnConnectionDownAsync(It.IsAny <Circuit>(), It.IsAny <CancellationToken>()), Times.Never());
            handler.Verify(v => v.OnCircuitClosedAsync(It.IsAny <Circuit>(), It.IsAny <CancellationToken>()), Times.Never());
        }
コード例 #3
0
        public async Task ConnectAsync_MakesInactiveCircuitActive()
        {
            // Arrange
            var circuitIdFactory = TestCircuitIdFactory.CreateTestFactory();

            var registry    = CreateRegistry(circuitIdFactory);
            var circuitHost = TestCircuitHost.Create(circuitIdFactory.CreateCircuitId());

            registry.DisconnectedCircuits.Set(circuitHost.CircuitId, circuitHost, new MemoryCacheEntryOptions {
                Size = 1
            });

            var newClient       = Mock.Of <IClientProxy>();
            var newConnectionId = "new-id";

            // Act
            var result = await registry.ConnectAsync(circuitHost.CircuitId, newClient, newConnectionId, default);

            // Assert
            Assert.Same(circuitHost, result);
            Assert.Same(newClient, circuitHost.Client.Client);
            Assert.Same(newConnectionId, circuitHost.Client.ConnectionId);

            var actual = Assert.Single(registry.ConnectedCircuits.Values);

            Assert.Same(circuitHost, actual);
            Assert.False(registry.DisconnectedCircuits.TryGetValue(circuitHost.CircuitId, out _));
        }
コード例 #4
0
        public void CircuitRegistryUsesConfiguredMaxRetainedDisconnectedCircuitsValue()
        {
            // Arrange
            var circuitIdFactory = TestCircuitIdFactory.CreateTestFactory();
            var maxCircuits      = 3;
            var circuitOptions   = new CircuitOptions
            {
                MaxRetainedDisconnectedCircuits = maxCircuits,
            };
            var registry = new TestCircuitRegistry(circuitIdFactory, circuitOptions);
            var hosts    = Enumerable.Range(0, maxCircuits + 2)
                           .Select(_ => TestCircuitHost.Create())
                           .ToArray();

            // Act
            for (var i = 0; i < hosts.Length; i++)
            {
                registry.RegisterDisconnectedCircuit(hosts[i]);
            }

            // Assert
            for (var i = 0; i < maxCircuits; i++)
            {
                Assert.True(registry.DisconnectedCircuits.TryGetValue(hosts[i].CircuitId, out var _));
            }

            // Additional circuits do not get registered.
            Assert.False(registry.DisconnectedCircuits.TryGetValue(hosts[maxCircuits].CircuitId, out var _));
            Assert.False(registry.DisconnectedCircuits.TryGetValue(hosts[maxCircuits + 1].CircuitId, out var _));
        }
コード例 #5
0
        public async Task ConnectAsync_TransfersClientOnActiveCircuit()
        {
            // Arrange
            var circuitIdFactory = TestCircuitIdFactory.CreateTestFactory();

            var registry    = CreateRegistry(circuitIdFactory);
            var circuitHost = TestCircuitHost.Create(circuitIdFactory.CreateCircuitId());

            registry.Register(circuitHost);

            var newClient       = Mock.Of <IClientProxy>();
            var newConnectionId = "new-id";

            // Act
            var result = await registry.ConnectAsync(circuitHost.CircuitId, newClient, newConnectionId, default);

            // Assert
            Assert.Same(circuitHost, result);
            Assert.Same(newClient, circuitHost.Client.Client);
            Assert.Same(newConnectionId, circuitHost.Client.ConnectionId);

            var actual = Assert.Single(registry.ConnectedCircuits.Values);

            Assert.Same(circuitHost, actual);
        }
コード例 #6
0
 private static CircuitRegistry CreateRegistry(CircuitIdFactory factory = null)
 {
     return(new CircuitRegistry(
                Options.Create(new CircuitOptions()),
                NullLogger <CircuitRegistry> .Instance,
                factory ?? TestCircuitIdFactory.CreateTestFactory()));
 }
コード例 #7
0
        public async Task ReconnectBeforeTimeoutDoesNotGetEntryToBeEvicted()
        {
            // Arrange
            var circuitIdFactory = TestCircuitIdFactory.CreateTestFactory();
            var circuitOptions   = new CircuitOptions
            {
                DisconnectedCircuitRetentionPeriod = TimeSpan.FromSeconds(8),
            };
            var registry = new TestCircuitRegistry(circuitIdFactory, circuitOptions);
            var tcs      = new TaskCompletionSource <object>();

            registry.OnAfterEntryEvicted = () =>
            {
                tcs.TrySetResult(new object());
            };
            var circuitHost = TestCircuitHost.Create(circuitIdFactory.CreateCircuitId());

            registry.RegisterDisconnectedCircuit(circuitHost);
            await registry.ConnectAsync(circuitHost.CircuitId, Mock.Of <IClientProxy>(), "new-connection", default);

            // Act
            await Task.Run(() => tcs.Task.TimeoutAfter(TimeSpan.FromSeconds(10)));

            // Verify it's still connected
            Assert.True(registry.ConnectedCircuits.TryGetValue(circuitHost.CircuitId, out var cacheValue));
            Assert.Same(circuitHost, cacheValue);
            // Nothing should be disconnected.
            Assert.False(registry.DisconnectedCircuits.TryGetValue(circuitHost.CircuitId.Secret, out var _));
        }
コード例 #8
0
        public async Task DisconnectWhenAConnectIsInProgress()
        {
            // Arrange
            var circuitIdFactory = TestCircuitIdFactory.CreateTestFactory();

            var registry = new TestCircuitRegistry(circuitIdFactory);

            registry.BeforeConnect = new ManualResetEventSlim();
            var circuitHost = TestCircuitHost.Create(circuitIdFactory.CreateCircuitId());

            registry.Register(circuitHost);
            var client = Mock.Of <IClientProxy>();
            var oldId  = circuitHost.Client.ConnectionId;
            var newId  = "new-connection";

            // Act
            var connect    = Task.Run(() => registry.ConnectAsync(circuitHost.CircuitId, client, newId, default));
            var disconnect = Task.Run(() => registry.DisconnectAsync(circuitHost, oldId));

            registry.BeforeConnect.Set();
            await Task.WhenAll(connect, disconnect);

            // Assert
            // We expect the disconnect to fail since the client identifier has changed.
            var actual = Assert.Single(registry.ConnectedCircuits.Values);

            Assert.Same(circuitHost, actual);
            Assert.Same(client, circuitHost.Client.Client);
            Assert.Equal(newId, circuitHost.Client.ConnectionId);

            Assert.False(registry.DisconnectedCircuits.TryGetValue(circuitHost.CircuitId, out _));
        }
コード例 #9
0
        public async Task ConnectAsync_InvokesCircuitHandlers_DisposesCircuitOnFailure()
        {
            // Arrange
            var circuitIdFactory = TestCircuitIdFactory.CreateTestFactory();
            var registry         = CreateRegistry(circuitIdFactory);
            var handler          = new Mock <CircuitHandler> {
                CallBase = true
            };

            handler.Setup(h => h.OnConnectionUpAsync(It.IsAny <Circuit>(), It.IsAny <CancellationToken>())).Throws(new InvalidTimeZoneException());
            var circuitHost = TestCircuitHost.Create(circuitIdFactory.CreateCircuitId(), handlers: new[] { handler.Object });

            registry.Register(circuitHost);

            var newClient       = Mock.Of <IClientProxy>();
            var newConnectionId = "new-id";

            // Act
            var result = await registry.ConnectAsync(circuitHost.CircuitId, newClient, newConnectionId, default);

            // Assert
            Assert.Null(result);
            Assert.Null(circuitHost.Handle.CircuitHost); // Will be null if disposed.
            Assert.Empty(registry.ConnectedCircuits);
            Assert.Equal(0, registry.DisconnectedCircuits.Count);
        }
コード例 #10
0
        public void ValidateCircuitId_ReturnsFalseForMalformedPayloads()
        {
            // Arrange
            var factory = TestCircuitIdFactory.CreateTestFactory();

            // Act
            var isValid = factory.TryParseCircuitId("$%@&==", out _);

            // Assert
            Assert.False(isValid, "Accepted an invalid payload");
        }
コード例 #11
0
        public void CircuitIds_Roundtrip()
        {
            // Arrange
            var factory = TestCircuitIdFactory.CreateTestFactory();
            var id      = factory.CreateCircuitId();

            // Act
            var isValid = factory.ValidateCircuitId(id);

            // Assert
            Assert.True(isValid, "Failed to validate id");
        }
コード例 #12
0
        public void CreateCircuitId_Generates_GeneratesDifferentIds_ForSuccessiveCalls()
        {
            // Arrange
            var factory = TestCircuitIdFactory.CreateTestFactory();

            // Act
            var secrets = Enumerable.Range(0, 100).Select(i => factory.CreateCircuitId()).Select(s => s.Secret).ToArray();

            // Assert
            Assert.All(secrets, secret => Assert.NotNull(secret));
            Assert.Equal(100, secrets.Distinct(StringComparer.Ordinal).Count());
        }
コード例 #13
0
        public void CreateCircuitId_Generates_NewRandomId()
        {
            var factory = TestCircuitIdFactory.CreateTestFactory();

            // Act
            var secret = factory.CreateCircuitId();

            // Assert
            Assert.NotNull(secret.Secret);
            // This is the magic data protection header that validates its protected
            Assert.StartsWith("CfDJ", secret.Secret);
        }
コード例 #14
0
        public void CircuitIds_Roundtrip()
        {
            // Arrange
            var factory = TestCircuitIdFactory.CreateTestFactory();
            var id      = factory.CreateCircuitId();

            // Act
            var isValid = factory.TryParseCircuitId(id.Secret, out var parsed);

            // Assert
            Assert.True(isValid, "Failed to validate id");
            Assert.Equal(id, parsed);
            Assert.Equal(id.Secret, parsed.Secret);
            Assert.Equal(id.Id, parsed.Id);
        }
コード例 #15
0
        public async Task Connect_WhileDisconnectIsInProgress()
        {
            // Arrange
            var circuitIdFactory = TestCircuitIdFactory.CreateTestFactory();

            var registry = new TestCircuitRegistry(circuitIdFactory);

            registry.BeforeDisconnect = new ManualResetEventSlim();
            var tcs = new TaskCompletionSource <int>();

            var circuitHost = TestCircuitHost.Create(circuitIdFactory.CreateCircuitId());

            registry.Register(circuitHost);
            var client = Mock.Of <IClientProxy>();
            var newId  = "new-connection";

            // Act
            var disconnect = Task.Run(() =>
            {
                var task = registry.DisconnectAsync(circuitHost, circuitHost.Client.ConnectionId);
                tcs.SetResult(0);
                return(task);
            });
            var connect = Task.Run(async() =>
            {
                registry.BeforeDisconnect.Set();
                await tcs.Task;
                await registry.ConnectAsync(circuitHost.CircuitId, client, newId, default);
            });

            registry.BeforeDisconnect.Set();
            await Task.WhenAll(disconnect, connect);

            // Assert
            // We expect the disconnect to finish followed by a reconnect
            var actual = Assert.Single(registry.ConnectedCircuits.Values);

            Assert.Same(circuitHost, actual);
            Assert.Same(client, circuitHost.Client.Client);
            Assert.Equal(newId, circuitHost.Client.ConnectionId);

            Assert.False(registry.DisconnectedCircuits.TryGetValue(circuitHost.CircuitId, out _));
        }
コード例 #16
0
        public void ValidateCircuitId_ReturnsFalseForPotentiallyTamperedPayloads()
        {
            // Arrange
            var factory        = TestCircuitIdFactory.CreateTestFactory();
            var secret         = factory.CreateCircuitId();
            var protectedBytes = Base64UrlTextEncoder.Decode(secret.Secret);

            for (int i = protectedBytes.Length - 10; i < protectedBytes.Length; i++)
            {
                protectedBytes[i] = 0;
            }
            var tampered = Base64UrlTextEncoder.Encode(protectedBytes);

            // Act
            var isValid = factory.TryParseCircuitId(tampered, out _);

            // Assert
            Assert.False(isValid, "Accepted a tampered payload");
        }
コード例 #17
0
        public async Task Connect_WhileDisconnectIsInProgress_SeriallyExecutesCircuitHandlers()
        {
            // Arrange
            var circuitIdFactory = TestCircuitIdFactory.CreateTestFactory();

            var registry = new TestCircuitRegistry(circuitIdFactory);

            registry.BeforeDisconnect = new ManualResetEventSlim();
            // This verifies that connection up \ down events on a circuit handler are always invoked serially.
            var circuitHandler = new SerialCircuitHandler();
            var tcs            = new TaskCompletionSource <int>();

            var circuitHost = TestCircuitHost.Create(circuitIdFactory.CreateCircuitId(), handlers: new[] { circuitHandler });

            registry.Register(circuitHost);
            var client = Mock.Of <IClientProxy>();
            var newId  = "new-connection";

            // Act
            var disconnect = Task.Run(() =>
            {
                var task = registry.DisconnectAsync(circuitHost, circuitHost.Client.ConnectionId);
                tcs.SetResult(0);
                return(task);
            });
            var connect = Task.Run(async() =>
            {
                registry.BeforeDisconnect.Set();
                await tcs.Task;
                await registry.ConnectAsync(circuitHost.CircuitId, client, newId, default);
            });
            await Task.WhenAll(disconnect, connect);

            // Assert
            Assert.Single(registry.ConnectedCircuits.Values);
            Assert.False(registry.DisconnectedCircuits.TryGetValue(circuitHost.CircuitId, out _));

            Assert.True(circuitHandler.OnConnectionDownExecuted, "OnConnectionDownAsync should have been executed.");
            Assert.True(circuitHandler.OnConnectionUpExecuted, "OnConnectionUpAsync should have been executed.");
        }