public async Task WritingToGroupWithOneConnectionFailingSecondConnectionStillReceivesMessage() { var manager = new RedisHubLifetimeManager<MyHub>(new LoggerFactory().CreateLogger<RedisHubLifetimeManager<MyHub>>(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client1 = new TestClient()) using (var client2 = new TestClient()) { // Force an exception when writing to connection var writer = new Mock<ChannelWriter<HubMessage>>(); writer.Setup(o => o.WaitToWriteAsync(It.IsAny<CancellationToken>())).Throws(new Exception()); var connection1 = HubConnectionContextUtils.Create(client1.Connection, new MockChannel(writer.Object)); var connection2 = HubConnectionContextUtils.Create(client2.Connection); await manager.OnConnectedAsync(connection1).OrTimeout(); await manager.AddGroupAsync(connection1.ConnectionId, "group"); await manager.OnConnectedAsync(connection2).OrTimeout(); await manager.AddGroupAsync(connection2.ConnectionId, "group"); await manager.InvokeGroupAsync("group", "Hello", new object[] { "World" }).OrTimeout(); // connection1 will throw when receiving a group message, we are making sure other connections // are not affected by another connection throwing await AssertMessageAsync(client2); // Repeat to check that group can still be sent to await manager.InvokeGroupAsync("group", "Hello", new object[] { "World" }).OrTimeout(); await AssertMessageAsync(client2); } }
public async Task InvokeConnectionAsyncForLocalConnectionDoesNotPublishToRedis() { var manager1 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); var manager2 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client = new TestClient()) { var output = Channel.CreateUnbounded <HubMessage>(); var connection = new HubConnectionContext(output, client.Connection); // Add connection to both "servers" to see if connection receives message twice await manager1.OnConnectedAsync(connection).OrTimeout(); await manager2.OnConnectedAsync(connection).OrTimeout(); await manager1.InvokeConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout(); AssertMessage(output); Assert.False(output.In.TryRead(out var item)); } }
// Re-enable micro-benchmark when https://github.com/aspnet/SignalR/issues/3088 is fixed // [GlobalSetup] public void GlobalSetup() { var server = new TestRedisServer(); var logger = NullLogger <RedisHubLifetimeManager <TestHub> > .Instance; var protocols = GenerateProtocols(ProtocolCount).ToArray(); var options = Options.Create(new RedisOptions() { ConnectionFactory = _ => Task.FromResult <IConnectionMultiplexer>(new TestConnectionMultiplexer(server)) }); var resolver = new DefaultHubProtocolResolver(protocols, NullLogger <DefaultHubProtocolResolver> .Instance); _manager1 = new RedisHubLifetimeManager <TestHub>(logger, options, resolver); _manager2 = new RedisHubLifetimeManager <TestHub>(logger, options, resolver); async Task ConnectClient(TestClient client, IHubProtocol protocol, string userId, string groupName) { await _manager2.OnConnectedAsync(HubConnectionContextUtils.Create(client.Connection, protocol, userId)); await _manager2.AddToGroupAsync(client.Connection.ConnectionId, "Everyone"); await _manager2.AddToGroupAsync(client.Connection.ConnectionId, groupName); } // Connect clients _clients = new TestClient[ClientCount]; var tasks = new Task[ClientCount]; for (var i = 0; i < _clients.Length; i++) { var protocol = protocols[i % ProtocolCount]; _clients[i] = new TestClient(protocol: protocol); string group; string user; if ((i % 2) == 0) { group = "Evens"; user = "******"; _excludedConnectionIds.Add(_clients[i].Connection.ConnectionId); } else { group = "Odds"; user = "******"; _sendIds.Add(_clients[i].Connection.ConnectionId); } tasks[i] = ConnectClient(_clients[i], protocol, user, group); _ = ConsumeAsync(_clients[i]); } Task.WaitAll(tasks); _groups.Add("Evens"); _groups.Add("Odds"); _users.Add("EvenUser"); _users.Add("OddUser"); _args = new object[] { "Foo" }; }
public async Task InvokeAllAsyncDoesNotWriteToDisconnectedConnectionsOutput() { using (var client1 = new TestClient()) using (var client2 = new TestClient()) { var manager = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); var connection1 = HubConnectionContextUtils.Create(client1.Connection); var connection2 = HubConnectionContextUtils.Create(client2.Connection); await manager.OnConnectedAsync(connection1).OrTimeout(); await manager.OnConnectedAsync(connection2).OrTimeout(); await manager.OnDisconnectedAsync(connection2).OrTimeout(); await manager.SendAllAsync("Hello", new object[] { "World" }).OrTimeout(); await AssertMessageAsync(client1); Assert.Null(client2.TryRead()); } }
public async Task InvokeGroupAsyncWritesToAllConnectionsInGroupOutput() { using (var client1 = new TestClient()) using (var client2 = new TestClient()) { var output1 = Channel.CreateUnbounded <HubMessage>(); var output2 = Channel.CreateUnbounded <HubMessage>(); var manager = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); var connection1 = new HubConnectionContext(output1, client1.Connection); var connection2 = new HubConnectionContext(output2, client2.Connection); await manager.OnConnectedAsync(connection1).OrTimeout(); await manager.OnConnectedAsync(connection2).OrTimeout(); await manager.AddGroupAsync(connection1.ConnectionId, "gunit").OrTimeout(); await manager.InvokeGroupAsync("gunit", "Hello", new object[] { "World" }).OrTimeout(); AssertMessage(output1); Assert.False(output2.In.TryRead(out var item)); } }
public async Task DisconnectConnectionRemovesConnectionFromGroup() { var manager = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client = new TestClient()) { var connection = HubConnectionContextUtils.Create(client.Connection); await manager.OnConnectedAsync(connection).OrTimeout(); await manager.AddGroupAsync(connection.ConnectionId, "name").OrTimeout(); await manager.OnDisconnectedAsync(connection).OrTimeout(); await manager.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout(); await connection.DisposeAsync().OrTimeout(); Assert.Null(client.TryRead()); } }
public async Task WritingToRemoteConnectionThatFailsDoesNotThrow() { var manager1 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); var manager2 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client = new TestClient()) { // Force an exception when writing to connection var writer = new Mock <ChannelWriter <HubMessage> >(); writer.Setup(o => o.WaitToWriteAsync(It.IsAny <CancellationToken>())).Throws(new Exception()); var connection = HubConnectionContextUtils.Create(client.Connection, new MockChannel(writer.Object)); await manager2.OnConnectedAsync(connection).OrTimeout(); // This doesn't throw because there is no connection.ConnectionId on this server so it has to publish to redis. // And once that happens there is no way to know if the invocation was successful or not. await manager1.InvokeConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout(); } }
public async Task InvokeGroupAsyncWritesToAllConnectionsInGroupOutput() { using (var client1 = new TestClient()) using (var client2 = new TestClient()) { var manager = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); var connection1 = HubConnectionContextUtils.Create(client1.Connection); var connection2 = HubConnectionContextUtils.Create(client2.Connection); await manager.OnConnectedAsync(connection1).OrTimeout(); await manager.OnConnectedAsync(connection2).OrTimeout(); await manager.AddGroupAsync(connection1.ConnectionId, "gunit").OrTimeout(); await manager.InvokeGroupAsync("gunit", "Hello", new object[] { "World" }).OrTimeout(); await AssertMessageAsync(client1); await connection1.DisposeAsync().OrTimeout(); await connection2.DisposeAsync().OrTimeout(); Assert.Null(client2.TryRead()); } }
public async Task RemoveGroupAsyncForConnectionOnDifferentServerWorks() { var manager1 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); var manager2 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client = new TestClient()) { var connection = HubConnectionContextUtils.Create(client.Connection); await manager1.OnConnectedAsync(connection).OrTimeout(); await manager1.AddGroupAsync(connection.ConnectionId, "name").OrTimeout(); await manager2.InvokeGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout(); await AssertMessageAsync(client); await manager2.RemoveGroupAsync(connection.ConnectionId, "name").OrTimeout(); await manager2.InvokeGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout(); await connection.DisposeAsync().OrTimeout(); Assert.Null(client.TryRead()); } }
public async Task InvokeConnectionAsyncForLocalConnectionDoesNotPublishToRedis() { var manager1 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); var manager2 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client = new TestClient()) { var connection = HubConnectionContextUtils.Create(client.Connection); // Add connection to both "servers" to see if connection receives message twice await manager1.OnConnectedAsync(connection).OrTimeout(); await manager2.OnConnectedAsync(connection).OrTimeout(); await manager1.InvokeConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout(); await connection.DisposeAsync().OrTimeout(); await AssertMessageAsync(client); Assert.Null(client.TryRead()); } }
public async Task InvokeGroupAsyncOnServerWithoutConnectionWritesOutputToGroupConnection() { var manager1 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); var manager2 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client = new TestClient()) { var connection = HubConnectionContextUtils.Create(client.Connection); await manager1.OnConnectedAsync(connection).OrTimeout(); await manager1.AddGroupAsync(connection.ConnectionId, "name").OrTimeout(); await manager2.InvokeGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout(); await AssertMessageAsync(client); } }
public async Task RemoveGroupAsyncForConnectionOnDifferentServerWorks() { var manager1 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); var manager2 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client = new TestClient()) { var output = Channel.CreateUnbounded <HubMessage>(); var connection = new HubConnectionContext(output, client.Connection); await manager1.OnConnectedAsync(connection).OrTimeout(); await manager1.AddGroupAsync(connection.ConnectionId, "name").OrTimeout(); await manager2.InvokeGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout(); AssertMessage(output); await manager2.RemoveGroupAsync(connection.ConnectionId, "name").OrTimeout(); await manager2.InvokeGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout(); Assert.False(output.In.TryRead(out var item)); } }
public async Task InvokeAllAsyncWithMultipleServersWritesToAllConnectionsOutput() { var manager1 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); var manager2 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client1 = new TestClient()) using (var client2 = new TestClient()) { var connection1 = HubConnectionContextUtils.Create(client1.Connection); var connection2 = HubConnectionContextUtils.Create(client2.Connection); await manager1.OnConnectedAsync(connection1).OrTimeout(); await manager2.OnConnectedAsync(connection2).OrTimeout(); await manager1.InvokeAllAsync("Hello", new object[] { "World" }).OrTimeout(); await AssertMessageAsync(client1); await AssertMessageAsync(client2); } }
public async Task AddGroupAsyncForLocalConnectionAlreadyInGroupDoesNothing() { var manager = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client = new TestClient()) { var connection = HubConnectionContextUtils.Create(client.Connection); await manager.OnConnectedAsync(connection).OrTimeout(); await manager.AddGroupAsync(connection.ConnectionId, "name").OrTimeout(); await manager.AddGroupAsync(connection.ConnectionId, "name").OrTimeout(); await manager.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout(); await AssertMessageAsync(client); Assert.Null(client.TryRead()); } }
public async Task InvokeConnectionAsyncOnServerWithoutConnectionWritesOutputToConnection() { var manager1 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); var manager2 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client = new TestClient()) { var output = Channel.CreateUnbounded <HubMessage>(); var connection = new HubConnectionContext(output, client.Connection); await manager1.OnConnectedAsync(connection).OrTimeout(); await manager2.InvokeConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout(); AssertMessage(output); } }
public async Task InvokeAllAsyncWithMultipleServersDoesNotWriteToDisconnectedConnectionsOutput() { var manager1 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); var manager2 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client1 = new TestClient()) using (var client2 = new TestClient()) { var output1 = Channel.CreateUnbounded <HubMessage>(); var output2 = Channel.CreateUnbounded <HubMessage>(); var connection1 = new HubConnectionContext(output1, client1.Connection); var connection2 = new HubConnectionContext(output2, client2.Connection); await manager1.OnConnectedAsync(connection1).OrTimeout(); await manager2.OnConnectedAsync(connection2).OrTimeout(); await manager2.OnDisconnectedAsync(connection2).OrTimeout(); await manager2.InvokeAllAsync("Hello", new object[] { "World" }).OrTimeout(); AssertMessage(output1); Assert.False(output2.In.TryRead(out var item)); } }
public async Task InvokeConnectionAsyncOnNonExistentConnectionDoesNotThrow() { var manager = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); await manager.InvokeConnectionAsync("NotARealConnectionId", "Hello", new object[] { "World" }).OrTimeout(); }
public async Task RemoveGroupFromLocalConnectionNotInGroupDoesNothing() { var manager = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client = new TestClient()) { var connection = HubConnectionContextUtils.Create(client.Connection); await manager.OnConnectedAsync(connection).OrTimeout(); await manager.RemoveGroupAsync(connection.ConnectionId, "name").OrTimeout(); } }
public async Task InvokeConnectionAsyncWritesToConnectionOutput() { using (var client = new TestClient()) { var manager = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); var connection = HubConnectionContextUtils.Create(client.Connection); await manager.OnConnectedAsync(connection).OrTimeout(); await manager.SendConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout(); await AssertMessageAsync(client); } }
public async Task WritingToLocalConnectionThatFailsDoesNotThrowException() { var manager = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client = new TestClient()) { // Force an exception when writing to connection var connectionMock = HubConnectionContextUtils.CreateMock(client.Connection); connectionMock.Setup(m => m.WriteAsync(It.IsAny <HubMessage>())).Throws(new Exception("Message")); var connection = connectionMock.Object; await manager.OnConnectedAsync(connection).OrTimeout(); await manager.SendConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout(); } }
public async Task WritingToLocalConnectionThatFailsThrowsException() { var manager = new RedisHubLifetimeManager<MyHub>(new LoggerFactory().CreateLogger<RedisHubLifetimeManager<MyHub>>(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client = new TestClient()) { // Force an exception when writing to connection var writer = new Mock<ChannelWriter<HubMessage>>(); writer.Setup(o => o.WaitToWriteAsync(It.IsAny<CancellationToken>())).Throws(new Exception("Message")); var connection = HubConnectionContextUtils.Create(client.Connection, new MockChannel(writer.Object)); await manager.OnConnectedAsync(connection).OrTimeout(); var exception = await Assert.ThrowsAsync<Exception>(() => manager.InvokeConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout()); Assert.Equal("Message", exception.Message); } }
public async Task RemoveGroupFromConnectionOnDifferentServerNotInGroupDoesNothing() { var manager1 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); var manager2 = new RedisHubLifetimeManager <MyHub>(new LoggerFactory().CreateLogger <RedisHubLifetimeManager <MyHub> >(), Options.Create(new RedisOptions() { Factory = t => new TestConnectionMultiplexer() })); using (var client = new TestClient()) { var output = Channel.CreateUnbounded <HubMessage>(); var connection = new HubConnectionContext(output, client.Connection); await manager1.OnConnectedAsync(connection).OrTimeout(); await manager2.RemoveGroupAsync(connection.ConnectionId, "name").OrTimeout(); } }