Create a Public Test Suite for HubLifetimeManager implementations (#2353)
This commit is contained in:
parent
4a34b879dd
commit
648705f648
|
|
@ -89,6 +89,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Crankier", "benchmarkapps\C
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarkapps", "benchmarkapps", "{43F352F3-4E2B-4ED7-901B-36E6671251F5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.SignalR.Specification.Tests", "src\Microsoft.AspNetCore.SignalR.Specification.Tests\Microsoft.AspNetCore.SignalR.Specification.Tests.csproj", "{2B03333F-3ACD-474C-862B-FA97D3BA03B5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -207,6 +209,10 @@ Global
|
|||
{8D3E3E7D-452B-44F4-86CA-111003EA11ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8D3E3E7D-452B-44F4-86CA-111003EA11ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8D3E3E7D-452B-44F4-86CA-111003EA11ED}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2B03333F-3ACD-474C-862B-FA97D3BA03B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2B03333F-3ACD-474C-862B-FA97D3BA03B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2B03333F-3ACD-474C-862B-FA97D3BA03B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2B03333F-3ACD-474C-862B-FA97D3BA03B5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -240,6 +246,7 @@ Global
|
|||
{896FA5EE-63A5-4EAC-9F09-346584BB4830} = {DA69F624-5398-4884-87E4-B816698CDE65}
|
||||
{8C75AC94-C980-4FE1-9F79-6CED3C8665CE} = {43F352F3-4E2B-4ED7-901B-36E6671251F5}
|
||||
{8D3E3E7D-452B-44F4-86CA-111003EA11ED} = {43F352F3-4E2B-4ED7-901B-36E6671251F5}
|
||||
{2B03333F-3ACD-474C-862B-FA97D3BA03B5} = {DA69F624-5398-4884-87E4-B816698CDE65}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {7945A4E4-ACDB-4F6E-95CA-6AC6E7C2CD59}
|
||||
|
|
|
|||
|
|
@ -11,4 +11,4 @@
|
|||
<PackageReference Include="Internal.AspNetCore.Sdk" PrivateAssets="All" Version="$(InternalAspNetCoreSdkPackageVersion)" />
|
||||
<PackageReference Include="Internal.AspNetCore.Analyzers" PrivateAssets="All" Version="$(InternalAspNetCoreAnalyzersPackageVersion)" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
@ -23,4 +23,4 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Options" Version="$(MicrosoftExtensionsOptionsPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
@ -99,7 +99,7 @@ namespace Microsoft.AspNetCore.SignalR
|
|||
/// <summary>
|
||||
/// Gets the protocol used by this connection.
|
||||
/// </summary>
|
||||
public virtual IHubProtocol Protocol { get; internal set; }
|
||||
public virtual IHubProtocol Protocol { get; set; }
|
||||
|
||||
// Currently used only for streaming methods
|
||||
internal ConcurrentDictionary<string, CancellationTokenSource> ActiveRequestCancellationSources { get; } = new ConcurrentDictionary<string, CancellationTokenSource>(StringComparer.Ordinal);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||
using Microsoft.AspNetCore.SignalR.Tests;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Specification.Tests
|
||||
{
|
||||
public abstract class HubLifetimeManagerTestsBase<THub> where THub : Hub
|
||||
{
|
||||
public HubLifetimeManager<THub> Manager { get; set; }
|
||||
|
||||
public abstract HubLifetimeManager<THub> CreateNewHubLifetimeManager();
|
||||
|
||||
[Fact]
|
||||
public async Task SendAllAsyncWritesToAllConnectionsOutput()
|
||||
{
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
var manager = CreateNewHubLifetimeManager();
|
||||
var connection1 = HubConnectionContextUtils.Create(client1.Connection);
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
|
||||
await manager.SendAllAsync("Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
var message = Assert.IsType<InvocationMessage>(client1.TryRead());
|
||||
Assert.Equal("Hello", message.Target);
|
||||
Assert.Single(message.Arguments);
|
||||
Assert.Equal("World", (string)message.Arguments[0]);
|
||||
|
||||
message = Assert.IsType<InvocationMessage>(client2.TryRead());
|
||||
Assert.Equal("Hello", message.Target);
|
||||
Assert.Single(message.Arguments);
|
||||
Assert.Equal("World", (string)message.Arguments[0]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendAllAsyncDoesNotWriteToDisconnectedConnectionsOutput()
|
||||
{
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
var manager = CreateNewHubLifetimeManager();
|
||||
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();
|
||||
|
||||
var message = Assert.IsType<InvocationMessage>(client1.TryRead());
|
||||
Assert.Equal("Hello", message.Target);
|
||||
Assert.Single(message.Arguments);
|
||||
Assert.Equal("World", (string)message.Arguments[0]);
|
||||
|
||||
Assert.Null(client2.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendGroupAsyncWritesToAllConnectionsInGroupOutput()
|
||||
{
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
var manager = CreateNewHubLifetimeManager();
|
||||
var connection1 = HubConnectionContextUtils.Create(client1.Connection);
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
|
||||
await manager.AddToGroupAsync(connection1.ConnectionId, "group").OrTimeout();
|
||||
|
||||
await manager.SendGroupAsync("group", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
var message = Assert.IsType<InvocationMessage>(client1.TryRead());
|
||||
Assert.Equal("Hello", message.Target);
|
||||
Assert.Single(message.Arguments);
|
||||
Assert.Equal("World", (string)message.Arguments[0]);
|
||||
|
||||
Assert.Null(client2.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendGroupExceptAsyncDoesNotWriteToExcludedConnections()
|
||||
{
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
var manager = CreateNewHubLifetimeManager();
|
||||
var connection1 = HubConnectionContextUtils.Create(client1.Connection);
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
|
||||
await manager.AddToGroupAsync(connection1.ConnectionId, "group1").OrTimeout();
|
||||
await manager.AddToGroupAsync(connection2.ConnectionId, "group1").OrTimeout();
|
||||
|
||||
await manager.SendGroupExceptAsync("group1", "Hello", new object[] { "World" }, new[] { connection2.ConnectionId }).OrTimeout();
|
||||
|
||||
var message = Assert.IsType<InvocationMessage>(client1.TryRead());
|
||||
Assert.Equal("Hello", message.Target);
|
||||
Assert.Single(message.Arguments);
|
||||
Assert.Equal("World", (string)message.Arguments[0]);
|
||||
|
||||
Assert.Null(client2.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendConnectionAsyncWritesToConnectionOutput()
|
||||
{
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var manager = CreateNewHubLifetimeManager();
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager.SendConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
var message = Assert.IsType<InvocationMessage>(client.TryRead());
|
||||
Assert.Equal("Hello", message.Target);
|
||||
Assert.Single(message.Arguments);
|
||||
Assert.Equal("World", (string)message.Arguments[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>Tests for users to verify their own implementations of SignalR types</Description>
|
||||
<DeveloperBuildTestTfms>netcoreapp2.2</DeveloperBuildTestTfms>
|
||||
<StandardTestTfms>$(DeveloperBuildTestTfms)</StandardTestTfms>
|
||||
<StandardTestTfms Condition=" '$(DeveloperBuild)' != 'true' AND '$(OS)' == 'Windows_NT' ">$(StandardTestTfms);net461</StandardTestTfms>
|
||||
<RuntimeIdentifier Condition="'$(TargetFramework)' == 'net461'">win7-x86</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Common\DuplexPipe.cs" Link="DuplexPipe.cs" />
|
||||
<Compile Include="..\Common\MemoryBufferWriter.cs" Link="Internal\MemoryBufferWriter.cs" />
|
||||
<Compile Include="..\..\test\Microsoft.AspNetCore.SignalR.Tests.Utils\HubConnectionContextUtils.cs" Link="HubConnectionContextUtils.cs" />
|
||||
<Compile Include="..\..\test\Microsoft.AspNetCore.SignalR.Tests.Utils\TaskExtensions.cs" Link="TaskExtensions.cs" />
|
||||
<Compile Include="..\..\test\Microsoft.AspNetCore.SignalR.Tests.Utils\TestClient.cs" Link="TestClient.cs" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Core\Microsoft.AspNetCore.SignalR.Core.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Common\Microsoft.AspNetCore.SignalR.Common.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Protocols.MessagePack\Microsoft.AspNetCore.SignalR.Protocols.MessagePack.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Internal.AspNetCore.Sdk" PrivateAssets="All" Version="$(InternalAspNetCoreSdkPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Testing" Version="$(MicrosoftAspNetCoreTestingPackageVersion)" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
|
||||
<PackageReference Include="Moq" Version="$(MoqPackageVersion)" />
|
||||
<PackageReference Include="xunit" Version="$(XunitPackageVersion)" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitRunnerVisualStudioPackageVersion)" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Common\Microsoft.AspNetCore.SignalR.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,399 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||
using Microsoft.AspNetCore.SignalR.Tests;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Specification.Tests
|
||||
{
|
||||
public abstract class ScaleoutHubLifetimeManagerTests<TBackplane> : HubLifetimeManagerTestsBase<MyHub>
|
||||
{
|
||||
public abstract TBackplane CreateBackplane();
|
||||
public abstract HubLifetimeManager<MyHub> CreateNewHubLifetimeManager(TBackplane backplane);
|
||||
|
||||
private async Task AssertMessageAsync(TestClient client)
|
||||
{
|
||||
var message = Assert.IsType<InvocationMessage>(await client.ReadAsync().OrTimeout());
|
||||
Assert.Equal("Hello", message.Target);
|
||||
Assert.Single(message.Arguments);
|
||||
Assert.Equal("World", (string)message.Arguments[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAllAsyncWithMultipleServersWritesToAllConnectionsOutput()
|
||||
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
var manager1 = CreateNewHubLifetimeManager(backplane);
|
||||
var manager2 = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
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.SendAllAsync("Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client1);
|
||||
await AssertMessageAsync(client2);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAllAsyncWithMultipleServersDoesNotWriteToDisconnectedConnectionsOutput()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
var manager1 = CreateNewHubLifetimeManager(backplane);
|
||||
var manager2 = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
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 manager2.OnDisconnectedAsync(connection2).OrTimeout();
|
||||
|
||||
await manager2.SendAllAsync("Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client1);
|
||||
|
||||
Assert.Null(client2.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeConnectionAsyncOnServerWithoutConnectionWritesOutputToConnection()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
|
||||
var manager1 = CreateNewHubLifetimeManager(backplane);
|
||||
var manager2 = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager1.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager2.SendConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeGroupAsyncOnServerWithoutConnectionWritesOutputToGroupConnection()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
|
||||
var manager1 = CreateNewHubLifetimeManager(backplane);
|
||||
var manager2 = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager1.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager1.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
|
||||
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DisconnectConnectionRemovesConnectionFromGroup()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
var manager = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
|
||||
await manager.OnDisconnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
Assert.Null(client.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RemoveGroupFromLocalConnectionNotInGroupDoesNothing()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
var manager = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager.RemoveFromGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RemoveGroupFromConnectionOnDifferentServerNotInGroupDoesNothing()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
var manager1 = CreateNewHubLifetimeManager(backplane);
|
||||
var manager2 = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager1.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager2.RemoveFromGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddGroupAsyncForConnectionOnDifferentServerWorks()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
var manager1 = CreateNewHubLifetimeManager(backplane);
|
||||
var manager2 = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager1.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager2.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
|
||||
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddGroupAsyncForLocalConnectionAlreadyInGroupDoesNothing()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
var manager = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
await manager.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
|
||||
await manager.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
Assert.Null(client.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddGroupAsyncForConnectionOnDifferentServerAlreadyInGroupDoesNothing()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
var manager1 = CreateNewHubLifetimeManager(backplane);
|
||||
var manager2 = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager1.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager1.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
await manager2.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
|
||||
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
Assert.Null(client.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RemoveGroupAsyncForConnectionOnDifferentServerWorks()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
var manager1 = CreateNewHubLifetimeManager(backplane);
|
||||
var manager2 = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager1.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager1.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
|
||||
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
|
||||
await manager2.RemoveFromGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
|
||||
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
Assert.Null(client.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeConnectionAsyncForLocalConnectionDoesNotPublishToBackplane()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
var manager1 = CreateNewHubLifetimeManager(backplane);
|
||||
var manager2 = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
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.SendConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
Assert.Null(client.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WritingToRemoteConnectionThatFailsDoesNotThrow()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
var manager1 = CreateNewHubLifetimeManager(backplane);
|
||||
var manager2 = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
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>(), It.IsAny<CancellationToken>())).Throws(new Exception());
|
||||
var connection = connectionMock.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 the backplane.
|
||||
// And once that happens there is no way to know if the invocation was successful or not.
|
||||
await manager1.SendConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WritingToGroupWithOneConnectionFailingSecondConnectionStillReceivesMessage()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
var manager = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
// Force an exception when writing to connection
|
||||
var connectionMock = HubConnectionContextUtils.CreateMock(client1.Connection);
|
||||
connectionMock.Setup(m => m.WriteAsync(It.IsAny<HubMessage>(), It.IsAny<CancellationToken>())).Throws(new Exception());
|
||||
|
||||
var connection1 = connectionMock.Object;
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.AddToGroupAsync(connection1.ConnectionId, "group");
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
await manager.AddToGroupAsync(connection2.ConnectionId, "group");
|
||||
|
||||
await manager.SendGroupAsync("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.SendGroupAsync("group", "Hello", new object[] { "World" }).OrTimeout();
|
||||
await AssertMessageAsync(client2);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeUserSendsToAllConnectionsForUser()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
var manager = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
using (var client3 = new TestClient())
|
||||
{
|
||||
var connection1 = HubConnectionContextUtils.Create(client1.Connection, userIdentifier: "userA");
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection, userIdentifier: "userA");
|
||||
var connection3 = HubConnectionContextUtils.Create(client3.Connection, userIdentifier: "userB");
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection3).OrTimeout();
|
||||
|
||||
await manager.SendUserAsync("userA", "Hello", new object[] { "World" }).OrTimeout();
|
||||
await AssertMessageAsync(client1);
|
||||
await AssertMessageAsync(client2);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StillSubscribedToUserAfterOneOfMultipleConnectionsAssociatedWithUserDisconnects()
|
||||
{
|
||||
var backplane = CreateBackplane();
|
||||
var manager = CreateNewHubLifetimeManager(backplane);
|
||||
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
using (var client3 = new TestClient())
|
||||
{
|
||||
var connection1 = HubConnectionContextUtils.Create(client1.Connection, userIdentifier: "userA");
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection, userIdentifier: "userA");
|
||||
var connection3 = HubConnectionContextUtils.Create(client3.Connection, userIdentifier: "userB");
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection3).OrTimeout();
|
||||
|
||||
await manager.SendUserAsync("userA", "Hello", new object[] { "World" }).OrTimeout();
|
||||
await AssertMessageAsync(client1);
|
||||
await AssertMessageAsync(client2);
|
||||
|
||||
// Disconnect one connection for the user
|
||||
await manager.OnDisconnectedAsync(connection1).OrTimeout();
|
||||
await manager.SendUserAsync("userA", "Hello", new object[] { "World" }).OrTimeout();
|
||||
await AssertMessageAsync(client2);
|
||||
}
|
||||
}
|
||||
}
|
||||
public class MyHub : Hub
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -20,4 +20,4 @@
|
|||
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR\Microsoft.AspNetCore.SignalR.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Specification.Tests\Microsoft.AspNetCore.SignalR.Specification.Tests.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,558 +1,58 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.SignalR.Internal;
|
||||
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||
using Microsoft.AspNetCore.SignalR.Tests;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using Microsoft.AspNetCore.SignalR.Specification.Tests;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Redis.Tests
|
||||
{
|
||||
public class RedisHubLifetimeManagerTests
|
||||
public class RedisHubLifetimeManagerTests : ScaleoutHubLifetimeManagerTests<TestRedisServer>
|
||||
{
|
||||
[Fact]
|
||||
public async Task InvokeAllAsyncWritesToAllConnectionsOutput()
|
||||
private TestRedisServer _server;
|
||||
|
||||
public override HubLifetimeManager<MyHub> CreateNewHubLifetimeManager(TestRedisServer backplane)
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
var manager = CreateLifetimeManager(server);
|
||||
var connection1 = HubConnectionContextUtils.Create(client1.Connection);
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
|
||||
await manager.SendAllAsync("Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client1);
|
||||
await AssertMessageAsync(client2);
|
||||
}
|
||||
return CreateLifetimeManager(backplane);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAllExceptAsyncExcludesSpecifiedConnections()
|
||||
public override TestRedisServer CreateBackplane()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
using (var client3 = new TestClient())
|
||||
{
|
||||
var manager1 = CreateLifetimeManager(server);
|
||||
var manager2 = CreateLifetimeManager(server);
|
||||
var manager3 = CreateLifetimeManager(server);
|
||||
|
||||
var connection1 = HubConnectionContextUtils.Create(client1.Connection);
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection);
|
||||
var connection3 = HubConnectionContextUtils.Create(client3.Connection);
|
||||
|
||||
await manager1.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager2.OnConnectedAsync(connection2).OrTimeout();
|
||||
await manager3.OnConnectedAsync(connection3).OrTimeout();
|
||||
|
||||
await manager1.SendAllExceptAsync("Hello", new object[] { "World" }, new[] { client3.Connection.ConnectionId }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client1);
|
||||
await AssertMessageAsync(client2);
|
||||
Assert.Null(client3.TryRead());
|
||||
}
|
||||
return new TestRedisServer();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAllAsyncDoesNotWriteToDisconnectedConnectionsOutput()
|
||||
public override HubLifetimeManager<MyHub> CreateNewHubLifetimeManager()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
_server = new TestRedisServer();
|
||||
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
var manager = CreateLifetimeManager(server);
|
||||
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());
|
||||
}
|
||||
return CreateLifetimeManager(_server);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeGroupAsyncWritesToAllConnectionsInGroupOutput()
|
||||
public class TestObject
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
var manager = CreateLifetimeManager(server);
|
||||
var connection1 = HubConnectionContextUtils.Create(client1.Connection);
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
|
||||
await manager.AddToGroupAsync(connection1.ConnectionId, "gunit").OrTimeout();
|
||||
|
||||
await manager.SendGroupAsync("gunit", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client1);
|
||||
Assert.Null(client2.TryRead());
|
||||
}
|
||||
public string TestProperty { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeGroupExceptAsyncWritesToAllValidConnectionsInGroupOutput()
|
||||
private RedisHubLifetimeManager<MyHub> CreateLifetimeManager(TestRedisServer server, MessagePackHubProtocolOptions messagePackOptions = null, JsonHubProtocolOptions jsonOptions = null)
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
var manager = CreateLifetimeManager(server);
|
||||
var connection1 = HubConnectionContextUtils.Create(client1.Connection);
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
|
||||
await manager.AddToGroupAsync(connection1.ConnectionId, "gunit").OrTimeout();
|
||||
await manager.AddToGroupAsync(connection2.ConnectionId, "gunit").OrTimeout();
|
||||
|
||||
var excludedConnectionIds = new List<string> { client2.Connection.ConnectionId };
|
||||
await manager.SendGroupExceptAsync("gunit", "Hello", new object[] { "World" }, excludedConnectionIds).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client1);
|
||||
Assert.Null(client2.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeConnectionAsyncWritesToConnectionOutput()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var manager = CreateLifetimeManager(server);
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager.SendConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeConnectionAsyncOnNonExistentConnectionDoesNotThrow()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager = CreateLifetimeManager(server);
|
||||
await manager.SendConnectionAsync("NotARealConnectionId", "Hello", new object[] { "World" }).OrTimeout();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAllAsyncWithMultipleServersWritesToAllConnectionsOutput()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager1 = CreateLifetimeManager(server);
|
||||
var manager2 = CreateLifetimeManager(server);
|
||||
|
||||
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.SendAllAsync("Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client1);
|
||||
await AssertMessageAsync(client2);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeAllAsyncWithMultipleServersDoesNotWriteToDisconnectedConnectionsOutput()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager1 = CreateLifetimeManager(server);
|
||||
var manager2 = CreateLifetimeManager(server);
|
||||
|
||||
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 manager2.OnDisconnectedAsync(connection2).OrTimeout();
|
||||
|
||||
await manager2.SendAllAsync("Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client1);
|
||||
|
||||
Assert.Null(client2.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeConnectionAsyncOnServerWithoutConnectionWritesOutputToConnection()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager1 = CreateLifetimeManager(server);
|
||||
var manager2 = CreateLifetimeManager(server);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager1.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager2.SendConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeGroupAsyncOnServerWithoutConnectionWritesOutputToGroupConnection()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager1 = CreateLifetimeManager(server);
|
||||
var manager2 = CreateLifetimeManager(server);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager1.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager1.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
|
||||
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DisconnectConnectionRemovesConnectionFromGroup()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager = CreateLifetimeManager(server);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
|
||||
await manager.OnDisconnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
Assert.Null(client.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RemoveGroupFromLocalConnectionNotInGroupDoesNothing()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager = CreateLifetimeManager(server);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager.RemoveFromGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RemoveGroupFromConnectionOnDifferentServerNotInGroupDoesNothing()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager1 = CreateLifetimeManager(server);
|
||||
var manager2 = CreateLifetimeManager(server);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager1.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager2.RemoveFromGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddGroupAsyncForConnectionOnDifferentServerWorks()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager1 = CreateLifetimeManager(server);
|
||||
var manager2 = CreateLifetimeManager(server);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager1.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager2.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
|
||||
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddGroupAsyncForLocalConnectionAlreadyInGroupDoesNothing()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager = CreateLifetimeManager(server);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
await manager.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
|
||||
await manager.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
Assert.Null(client.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddGroupAsyncForConnectionOnDifferentServerAlreadyInGroupDoesNothing()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager1 = CreateLifetimeManager(server);
|
||||
var manager2 = CreateLifetimeManager(server);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager1.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager1.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
await manager2.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
|
||||
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
Assert.Null(client.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RemoveGroupAsyncForConnectionOnDifferentServerWorks()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager1 = CreateLifetimeManager(server);
|
||||
var manager2 = CreateLifetimeManager(server);
|
||||
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager1.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager1.AddToGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
|
||||
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
|
||||
await manager2.RemoveFromGroupAsync(connection.ConnectionId, "name").OrTimeout();
|
||||
|
||||
await manager2.SendGroupAsync("name", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
Assert.Null(client.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeConnectionAsyncForLocalConnectionDoesNotPublishToRedis()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager1 = CreateLifetimeManager(server);
|
||||
var manager2 = CreateLifetimeManager(server);
|
||||
|
||||
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.SendConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
await AssertMessageAsync(client);
|
||||
Assert.Null(client.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WritingToRemoteConnectionThatFailsDoesNotThrow()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager1 = CreateLifetimeManager(server);
|
||||
var manager2 = CreateLifetimeManager(server);
|
||||
|
||||
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>(), It.IsAny<CancellationToken>())).Throws(new Exception());
|
||||
var connection = connectionMock.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.SendConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WritingToGroupWithOneConnectionFailingSecondConnectionStillReceivesMessage()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager = CreateLifetimeManager(server);
|
||||
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
// Force an exception when writing to connection
|
||||
var connectionMock = HubConnectionContextUtils.CreateMock(client1.Connection);
|
||||
connectionMock.Setup(m => m.WriteAsync(It.IsAny<HubMessage>(), It.IsAny<CancellationToken>())).Throws(new Exception());
|
||||
|
||||
var connection1 = connectionMock.Object;
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.AddToGroupAsync(connection1.ConnectionId, "group");
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
await manager.AddToGroupAsync(connection2.ConnectionId, "group");
|
||||
|
||||
await manager.SendGroupAsync("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.SendGroupAsync("group", "Hello", new object[] { "World" }).OrTimeout();
|
||||
await AssertMessageAsync(client2);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokeUserSendsToAllConnectionsForUser()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager = CreateLifetimeManager(server);
|
||||
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
using (var client3 = new TestClient())
|
||||
{
|
||||
var connection1 = HubConnectionContextUtils.Create(client1.Connection, userIdentifier: "userA");
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection, userIdentifier: "userA");
|
||||
var connection3 = HubConnectionContextUtils.Create(client3.Connection, userIdentifier: "userB");
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection3).OrTimeout();
|
||||
|
||||
await manager.SendUserAsync("userA", "Hello", new object[] { "World" }).OrTimeout();
|
||||
await AssertMessageAsync(client1);
|
||||
await AssertMessageAsync(client2);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task StillSubscribedToUserAfterOneOfMultipleConnectionsAssociatedWithUserDisconnects()
|
||||
{
|
||||
var server = new TestRedisServer();
|
||||
|
||||
var manager = CreateLifetimeManager(server);
|
||||
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
using (var client3 = new TestClient())
|
||||
{
|
||||
var connection1 = HubConnectionContextUtils.Create(client1.Connection, userIdentifier: "userA");
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection, userIdentifier: "userA");
|
||||
var connection3 = HubConnectionContextUtils.Create(client3.Connection, userIdentifier: "userB");
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection3).OrTimeout();
|
||||
|
||||
await manager.SendUserAsync("userA", "Hello", new object[] { "World" }).OrTimeout();
|
||||
await AssertMessageAsync(client1);
|
||||
await AssertMessageAsync(client2);
|
||||
|
||||
// Disconnect one connection for the user
|
||||
await manager.OnDisconnectedAsync(connection1).OrTimeout();
|
||||
await manager.SendUserAsync("userA", "Hello", new object[] { "World" }).OrTimeout();
|
||||
await AssertMessageAsync(client2);
|
||||
}
|
||||
var options = new RedisOptions() { ConnectionFactory = async (t) => await Task.FromResult(new TestConnectionMultiplexer(server)) };
|
||||
messagePackOptions = messagePackOptions ?? new MessagePackHubProtocolOptions();
|
||||
jsonOptions = jsonOptions ?? new JsonHubProtocolOptions();
|
||||
return new RedisHubLifetimeManager<MyHub>(
|
||||
NullLogger<RedisHubLifetimeManager<MyHub>>.Instance,
|
||||
Options.Create(options),
|
||||
new DefaultHubProtocolResolver(new IHubProtocol[]
|
||||
{
|
||||
new JsonHubProtocol(Options.Create(jsonOptions)),
|
||||
new MessagePackHubProtocol(Options.Create(messagePackOptions)),
|
||||
}, NullLogger<DefaultHubProtocolResolver>.Instance));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -598,46 +98,5 @@ namespace Microsoft.AspNetCore.SignalR.Redis.Tests
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class TestObject
|
||||
{
|
||||
public string TestProperty { get; set; }
|
||||
}
|
||||
|
||||
private RedisHubLifetimeManager<MyHub> CreateLifetimeManager(TestRedisServer server, MessagePackHubProtocolOptions messagePackOptions = null, JsonHubProtocolOptions jsonOptions = null)
|
||||
{
|
||||
var options = new RedisOptions() { ConnectionFactory = async (t) => await Task.FromResult(new TestConnectionMultiplexer(server)) };
|
||||
messagePackOptions = messagePackOptions ?? new MessagePackHubProtocolOptions();
|
||||
jsonOptions = jsonOptions ?? new JsonHubProtocolOptions();
|
||||
|
||||
return new RedisHubLifetimeManager<MyHub>(
|
||||
NullLogger<RedisHubLifetimeManager<MyHub>>.Instance,
|
||||
Options.Create(options),
|
||||
new DefaultHubProtocolResolver(new IHubProtocol[]
|
||||
{
|
||||
new JsonHubProtocol(Options.Create(jsonOptions)),
|
||||
new MessagePackHubProtocol(Options.Create(messagePackOptions)),
|
||||
}, NullLogger<DefaultHubProtocolResolver>.Instance));
|
||||
}
|
||||
|
||||
private async Task AssertMessageAsync(TestClient client)
|
||||
{
|
||||
var message = Assert.IsType<InvocationMessage>(await client.ReadAsync().OrTimeout());
|
||||
Assert.Equal("Hello", message.Target);
|
||||
Assert.Single(message.Arguments);
|
||||
Assert.Equal("World", (string)message.Arguments[0]);
|
||||
}
|
||||
|
||||
private class MyHub : Hub
|
||||
{
|
||||
}
|
||||
|
||||
private class MockChannel : Channel<HubMessage>
|
||||
{
|
||||
public MockChannel(ChannelWriter<HubMessage> writer = null)
|
||||
{
|
||||
Writer = writer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,12 @@ using Moq;
|
|||
|
||||
namespace Microsoft.AspNetCore.SignalR.Tests
|
||||
{
|
||||
public static class HubConnectionContextUtils
|
||||
#if TESTUTILS
|
||||
public
|
||||
#else
|
||||
internal
|
||||
#endif
|
||||
static class HubConnectionContextUtils
|
||||
{
|
||||
public static HubConnectionContext Create(ConnectionContext connection, IHubProtocol protocol = null, string userIdentifier = null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
|
||||
<RootNamespace>Microsoft.AspNetCore.SignalR.Tests</RootNamespace>
|
||||
<DefineConstants>$(DefineConstants);TESTUTILS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,12 @@ using System.Runtime.CompilerServices;
|
|||
|
||||
namespace System.Threading.Tasks
|
||||
{
|
||||
public static class TaskExtensions
|
||||
#if TESTUTILS
|
||||
public
|
||||
#else
|
||||
internal
|
||||
#endif
|
||||
static class TaskExtensions
|
||||
{
|
||||
private const int DefaultTimeout = 5000;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,12 @@ using Microsoft.AspNetCore.SignalR.Protocol;
|
|||
|
||||
namespace Microsoft.AspNetCore.SignalR.Tests
|
||||
{
|
||||
public class TestClient : ITransferFormatFeature, IConnectionHeartbeatFeature, IDisposable
|
||||
#if TESTUTILS
|
||||
public
|
||||
#else
|
||||
internal
|
||||
#endif
|
||||
class TestClient : ITransferFormatFeature, IConnectionHeartbeatFeature, IDisposable
|
||||
{
|
||||
private readonly object _heartbeatLock = new object();
|
||||
private List<(Action<object> handler, object state)> _heartbeatHandlers;
|
||||
|
|
|
|||
|
|
@ -1,172 +1,17 @@
|
|||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.SignalR.Protocol;
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Xunit;
|
||||
using Microsoft.AspNetCore.SignalR.Specification.Tests;
|
||||
|
||||
namespace Microsoft.AspNetCore.SignalR.Tests
|
||||
{
|
||||
public class DefaultHubLifetimeManagerTests
|
||||
public class DefaultHubLifetimeManagerTests : HubLifetimeManagerTestsBase<MyHub>
|
||||
{
|
||||
[Fact]
|
||||
public async Task SendAllAsyncWritesToAllConnectionsOutput()
|
||||
public override HubLifetimeManager<MyHub> CreateNewHubLifetimeManager()
|
||||
{
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
var manager = new DefaultHubLifetimeManager<MyHub>(new Logger<DefaultHubLifetimeManager<MyHub>>(NullLoggerFactory.Instance));
|
||||
var connection1 = HubConnectionContextUtils.Create(client1.Connection);
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
|
||||
await manager.SendAllAsync("Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
var message = Assert.IsType<InvocationMessage>(client1.TryRead());
|
||||
Assert.Equal("Hello", message.Target);
|
||||
Assert.Single(message.Arguments);
|
||||
Assert.Equal("World", (string)message.Arguments[0]);
|
||||
|
||||
message = Assert.IsType<InvocationMessage>(client2.TryRead());
|
||||
Assert.Equal("Hello", message.Target);
|
||||
Assert.Single(message.Arguments);
|
||||
Assert.Equal("World", (string)message.Arguments[0]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendAllAsyncDoesNotWriteToDisconnectedConnectionsOutput()
|
||||
{
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
var manager = new DefaultHubLifetimeManager<MyHub>(new Logger<DefaultHubLifetimeManager<MyHub>>(NullLoggerFactory.Instance));
|
||||
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();
|
||||
|
||||
var message = Assert.IsType<InvocationMessage>(client1.TryRead());
|
||||
Assert.Equal("Hello", message.Target);
|
||||
Assert.Single(message.Arguments);
|
||||
Assert.Equal("World", (string)message.Arguments[0]);
|
||||
|
||||
Assert.Null(client2.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendGroupAsyncWritesToAllConnectionsInGroupOutput()
|
||||
{
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
var manager = new DefaultHubLifetimeManager<MyHub>(new Logger<DefaultHubLifetimeManager<MyHub>>(NullLoggerFactory.Instance));
|
||||
var connection1 = HubConnectionContextUtils.Create(client1.Connection);
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
|
||||
await manager.AddToGroupAsync(connection1.ConnectionId, "gunit").OrTimeout();
|
||||
|
||||
await manager.SendGroupAsync("gunit", "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
var message = Assert.IsType<InvocationMessage>(client1.TryRead());
|
||||
Assert.Equal("Hello", message.Target);
|
||||
Assert.Single(message.Arguments);
|
||||
Assert.Equal("World", (string)message.Arguments[0]);
|
||||
|
||||
Assert.Null(client2.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendGroupExceptAsyncDoesNotWriteToExcludedConnections()
|
||||
{
|
||||
using (var client1 = new TestClient())
|
||||
using (var client2 = new TestClient())
|
||||
{
|
||||
var manager = new DefaultHubLifetimeManager<MyHub>(new Logger<DefaultHubLifetimeManager<MyHub>>(NullLoggerFactory.Instance));
|
||||
var connection1 = HubConnectionContextUtils.Create(client1.Connection);
|
||||
var connection2 = HubConnectionContextUtils.Create(client2.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection1).OrTimeout();
|
||||
await manager.OnConnectedAsync(connection2).OrTimeout();
|
||||
|
||||
await manager.AddToGroupAsync(connection1.ConnectionId, "gunit").OrTimeout();
|
||||
await manager.AddToGroupAsync(connection2.ConnectionId, "gunit").OrTimeout();
|
||||
|
||||
await manager.SendGroupExceptAsync("gunit", "Hello", new object[] { "World" }, new []{ connection2.ConnectionId }).OrTimeout();
|
||||
|
||||
var message = Assert.IsType<InvocationMessage>(client1.TryRead());
|
||||
Assert.Equal("Hello", message.Target);
|
||||
Assert.Single(message.Arguments);
|
||||
Assert.Equal("World", (string)message.Arguments[0]);
|
||||
|
||||
Assert.Null(client2.TryRead());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendConnectionAsyncWritesToConnectionOutput()
|
||||
{
|
||||
using (var client = new TestClient())
|
||||
{
|
||||
var manager = new DefaultHubLifetimeManager<MyHub>(new Logger<DefaultHubLifetimeManager<MyHub>>(NullLoggerFactory.Instance));
|
||||
var connection = HubConnectionContextUtils.Create(client.Connection);
|
||||
|
||||
await manager.OnConnectedAsync(connection).OrTimeout();
|
||||
|
||||
await manager.SendConnectionAsync(connection.ConnectionId, "Hello", new object[] { "World" }).OrTimeout();
|
||||
|
||||
var message = Assert.IsType<InvocationMessage>(client.TryRead());
|
||||
Assert.Equal("Hello", message.Target);
|
||||
Assert.Single(message.Arguments);
|
||||
Assert.Equal("World", (string)message.Arguments[0]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SendConnectionAsyncOnNonExistentConnectionNoops()
|
||||
{
|
||||
var manager = new DefaultHubLifetimeManager<MyHub>(new Logger<DefaultHubLifetimeManager<MyHub>>(NullLoggerFactory.Instance));
|
||||
await manager.SendConnectionAsync("NotARealConnectionId", "Hello", new object[] { "World" }).OrTimeout();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddGroupOnNonExistentConnectionNoops()
|
||||
{
|
||||
var manager = new DefaultHubLifetimeManager<MyHub>(new Logger<DefaultHubLifetimeManager<MyHub>>(NullLoggerFactory.Instance));
|
||||
await manager.AddToGroupAsync("NotARealConnectionId", "MyGroup").OrTimeout();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RemoveGroupOnNonExistentConnectionNoops()
|
||||
{
|
||||
var manager = new DefaultHubLifetimeManager<MyHub>(new Logger<DefaultHubLifetimeManager<MyHub>>(NullLoggerFactory.Instance));
|
||||
await manager.RemoveFromGroupAsync("NotARealConnectionId", "MyGroup").OrTimeout();
|
||||
}
|
||||
|
||||
private class MyHub : Hub
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private class MockChannel: Channel<HubMessage>
|
||||
{
|
||||
|
||||
public MockChannel(ChannelWriter<HubMessage> writer = null)
|
||||
{
|
||||
Writer = writer;
|
||||
}
|
||||
return new DefaultHubLifetimeManager<MyHub>(new Logger<DefaultHubLifetimeManager<MyHub>>(NullLoggerFactory.Instance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(StandardTestTfms)</TargetFrameworks>
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR\Microsoft.AspNetCore.SignalR.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Client\Microsoft.AspNetCore.SignalR.Client.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.SignalR.Specification.Tests\Microsoft.AspNetCore.SignalR.Specification.Tests.csproj" />
|
||||
<ProjectReference Include="..\Microsoft.AspNetCore.SignalR.Tests.Utils\Microsoft.AspNetCore.SignalR.Tests.Utils.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue