diff --git a/src/Components/.vscode/launch.json b/src/Components/.vscode/launch.json index 39daed7ea684be6d12d008b67f74de1fb0eb5ce8..2d3a3106f85e436f9c7900fe72bae6558b92719b 100644 --- a/src/Components/.vscode/launch.json +++ b/src/Components/.vscode/launch.json @@ -1,6 +1,12 @@ { "version": "0.2.0", "configurations": [ + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}" + }, { "name": "BlazorServerApp", "type": "coreclr", diff --git a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj index 1bb8e17fcfaf44e84c3966c4ae2e569c29e0fc00..0b1af77eda8acce6af74e144494d2a572b722b6d 100644 --- a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj +++ b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj @@ -84,6 +84,10 @@ <Compile Include="$(RepoRoot)src\Shared\Components\WebAssemblyComponentMarker.cs" /> </ItemGroup> + <ItemGroup> + <Compile Include="$(RepoRoot)src\Shared\SignalR\*.cs" /> + </ItemGroup> + <ItemGroup> <AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute"> <_Parameter1>Microsoft.AspNetCore.E2ETesting.TestTrimmedApps</_Parameter1> diff --git a/src/Components/test/E2ETest/ServerExecutionTests/ComponentHubReliabilityTest.cs b/src/Components/test/E2ETest/ServerExecutionTests/ComponentHubReliabilityTest.cs index 520c90d59b4fc25bdeea7084da792d23e4eb2e58..bbbdece67bf5511c0fac221a553aee7efbbd4b03 100644 --- a/src/Components/test/E2ETest/ServerExecutionTests/ComponentHubReliabilityTest.cs +++ b/src/Components/test/E2ETest/ServerExecutionTests/ComponentHubReliabilityTest.cs @@ -7,47 +7,49 @@ using System.Net.Http; using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures; +using Microsoft.AspNetCore.SignalR.Tests; using Microsoft.AspNetCore.SignalR.Client; using Microsoft.AspNetCore.Testing; +using System.Collections.Concurrent; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; using TestServer; using Xunit; +using Ignitor; +using System.Collections.Generic; using Xunit.Abstractions; +using System.Diagnostics; namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests { [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/19666")] - public class ComponentHubReliabilityTest : IgnitorTest<ServerStartup> + public class ComponentHubReliabilityTest : FunctionalTestBase { - public ComponentHubReliabilityTest(BasicTestAppServerSiteFixture<ServerStartup> serverFixture, ITestOutputHelper output) - : base(serverFixture, output) - { - } + private static readonly TimeSpan DefaultTimeout = Debugger.IsAttached ? TimeSpan.MaxValue : TimeSpan.FromSeconds(30); - protected override async Task InitializeAsync() - { - await base.InitializeAsync(); + protected BlazorClient Client { get; private set; } - var rootUri = ServerFixture.RootUri; - var baseUri = new Uri(rootUri, "/subdir"); - var client = new HttpClient(); - for (var i = 0; i < 10; i++) - { - try - { - var response = await client.GetAsync(baseUri + "/_negotiate"); - if (response.StatusCode == HttpStatusCode.OK) - { - break; - } - } - catch - { - await Task.Delay(500); - throw; - } - } + protected ITestOutputHelper Output { get; } + + protected TimeSpan Timeout { get; set; } = DefaultTimeout; + protected IReadOnlyCollection<CapturedRenderBatch> Batches => Client?.Operations?.Batches; + + protected IReadOnlyCollection<string> DotNetCompletions => Client?.Operations?.DotNetCompletions; + + protected IReadOnlyCollection<string> Errors => Client?.Operations?.Errors; + + protected IReadOnlyCollection<CapturedJSInteropCall> JSInteropCalls => Client?.Operations?.JSInteropCalls; + + public ComponentHubReliabilityTest(ITestOutputHelper output) + { + Output = output; + Client = new BlazorClient() + { + CaptureOperations = true, + DefaultOperationTimeout = Timeout, + }; + Client.LoggerProvider = new XunitLoggerProvider(Output); } [Fact] @@ -56,24 +58,30 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests // Arrange var expectedError = "The circuit host '.*?' has already been initialized."; - var rootUri = ServerFixture.RootUri; - var baseUri = new Uri(rootUri, "/subdir"); - await ConnectAutomaticallyAndWait(baseUri); - - var descriptors = await Client.GetPrerenderDescriptors(baseUri); - - // Act - await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync( - "StartCircuit", - baseUri, - baseUri + "/home", - descriptors, - null)); - - // Assert - var actualError = Assert.Single(Errors); - Assert.Matches(expectedError, actualError); - Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information); + await using (var server = await StartServer<ServerStartup>()) + { + ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new(); + server.ServerLogged += (LogRecord record) => logs.Enqueue(record); + + var baseUri = new Uri($"{server.Url}/subdir"); + Assert.True(await Client.ConnectAsync(baseUri), "Couldn't connect to the app"); + Assert.Single(Batches); + + var descriptors = await Client.GetPrerenderDescriptors(baseUri); + + // Act + await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync( + "StartCircuit", + baseUri, + baseUri + "/home", + descriptors, + null)); + + // Assert + var actualError = Assert.Single(Errors); + Assert.Matches(expectedError, actualError); + Assert.DoesNotContain(logs, l => l.Write.LogLevel > LogLevel.Information); + } } [Fact] @@ -81,18 +89,20 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests { // Arrange var expectedError = "The uris provided are invalid."; - var rootUri = ServerFixture.RootUri; - var uri = new Uri(rootUri, "/subdir"); - Assert.True(await Client.ConnectAsync(uri, connectAutomatically: false), "Couldn't connect to the app"); - var descriptors = await Client.GetPrerenderDescriptors(uri); - - // Act - await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync("StartCircuit", null, null, descriptors, null)); - - // Assert - var actualError = Assert.Single(Errors); - Assert.Matches(expectedError, actualError); - Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information); + await using (var server = await StartServer<ServerStartup>()) + { + var rootUri = server.Url; + var uri = new Uri($"{rootUri}/subdir"); + Assert.True(await Client.ConnectAsync(uri, connectAutomatically: false), "Couldn't connect to the app"); + var descriptors = await Client.GetPrerenderDescriptors(uri); + + // Act + await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync("StartCircuit", null, null, descriptors, null)); + + // Assert + var actualError = Assert.Single(Errors); + Assert.Matches(expectedError, actualError); + } } // This is a hand-chosen example of something that will cause an exception in creating the circuit host. @@ -103,20 +113,23 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests { // Arrange var expectedError = "The circuit failed to initialize."; - var rootUri = ServerFixture.RootUri; - var uri = new Uri(rootUri, "/subdir"); - Assert.True(await Client.ConnectAsync(uri, connectAutomatically: false), "Couldn't connect to the app"); - var descriptors = await Client.GetPrerenderDescriptors(uri); - - // Act - // - // These are valid URIs by the BaseUri doesn't contain the Uri - so it fails to initialize. - await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync("StartCircuit", uri, "http://example.com", descriptors, null), Timeout); - - // Assert - var actualError = Assert.Single(Errors); - Assert.Matches(expectedError, actualError); - Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information); + + await using (var server = await StartServer<ServerStartup>()) + { + var rootUri = server.Url; + var uri = new Uri($"{rootUri}/subdir"); + Assert.True(await Client.ConnectAsync(uri, connectAutomatically: false), "Couldn't connect to the app"); + var descriptors = await Client.GetPrerenderDescriptors(uri); + + // Act + // + // These are valid URIs by the BaseUri doesn't contain the Uri - so it fails to initialize. + await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync("StartCircuit", uri, "http://example.com", descriptors, null), Timeout); + + // Assert + var actualError = Assert.Single(Errors); + Assert.Matches(expectedError, actualError); + } } [Fact] @@ -124,25 +137,31 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests { // Arrange var expectedError = "Circuit not initialized."; - var rootUri = ServerFixture.RootUri; - var baseUri = new Uri(rootUri, "/subdir"); - Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false)); - Assert.Empty(Batches); - - // Act - await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync( - "BeginInvokeDotNetFromJS", - "", - "", - "", - 0, - "")); - - // Assert - var actualError = Assert.Single(Errors); - Assert.Equal(expectedError, actualError); - Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information); - Assert.Contains(Logs, l => (l.LogLevel, l.Message) == (LogLevel.Debug, "Call to 'BeginInvokeDotNetFromJS' received before the circuit host initialization")); + await using (var server = await StartServer<ServerStartup>()) + { + ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new(); + server.ServerLogged += (LogRecord record) => logs.Enqueue(record); + var rootUri = server.Url; + var baseUri = new Uri($"{rootUri}/subdir"); + Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false)); + Assert.Empty(Batches); + + // Act + await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync( + "BeginInvokeDotNetFromJS", + "", + "", + "", + 0, + "")); + + // Assert + var actualError = Assert.Single(Errors); + Assert.Equal(expectedError, actualError); + Assert.DoesNotContain(logs, l => l.Write.LogLevel > LogLevel.Information); + Assert.Contains(logs, l => + l.Write.LogLevel == LogLevel.Debug && l.Write.Message.Contains("Call to 'BeginInvokeDotNetFromJS' received before the circuit host initialization")); + } } [Fact] @@ -151,23 +170,28 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests { // Arrange var expectedError = "Circuit not initialized."; - var rootUri = ServerFixture.RootUri; - var baseUri = new Uri(rootUri, "/subdir"); - Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false)); - Assert.Empty(Batches); - - // Act - await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync( - "EndInvokeJSFromDotNet", - 3, - true, - "[]"), Timeout); - - // Assert - var actualError = Assert.Single(Errors); - Assert.Equal(expectedError, actualError); - Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information); - Assert.Contains(Logs, l => (l.LogLevel, l.Message) == (LogLevel.Debug, "Call to 'EndInvokeJSFromDotNet' received before the circuit host initialization")); + await using (var server = await StartServer<ServerStartup>()) + { + ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new(); + server.ServerLogged += (LogRecord record) => logs.Enqueue(record); + var rootUri = server.Url; + var baseUri = new Uri($"{rootUri}/subdir"); + Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false)); + Assert.Empty(Batches); + + // Act + await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync( + "EndInvokeJSFromDotNet", + 3, + true, + "[]"), Timeout); + + // Assert + var actualError = Assert.Single(Errors); + Assert.Equal(expectedError, actualError); + Assert.DoesNotContain(logs, l => l.Write.LogLevel > LogLevel.Information); + Assert.Contains(logs, l => l.Write.LogLevel == LogLevel.Debug && l.Write.Message.Contains("Call to 'EndInvokeJSFromDotNet' received before the circuit host initialization")); + } } [Fact] @@ -175,22 +199,27 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests { // Arrange var expectedError = "Circuit not initialized."; - var rootUri = ServerFixture.RootUri; - var baseUri = new Uri(rootUri, "/subdir"); - Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false)); - Assert.Empty(Batches); - - // Act - await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync( - "DispatchBrowserEvent", - "", - "")); - - // Assert - var actualError = Assert.Single(Errors); - Assert.Equal(expectedError, actualError); - Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information); - Assert.Contains(Logs, l => (l.LogLevel, l.Message) == (LogLevel.Debug, "Call to 'DispatchBrowserEvent' received before the circuit host initialization")); + await using (var server = await StartServer<ServerStartup>()) + { + ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new(); + server.ServerLogged += (LogRecord record) => logs.Enqueue(record); + var rootUri = server.Url; + var baseUri = new Uri($"{rootUri}/subdir"); + Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false)); + Assert.Empty(Batches); + + // Act + await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync( + "DispatchBrowserEvent", + "", + "")); + + // Assert + var actualError = Assert.Single(Errors); + Assert.Equal(expectedError, actualError); + Assert.DoesNotContain(logs, l => l.Write.LogLevel > LogLevel.Information); + Assert.Contains(logs, l => l.Write.LogLevel == LogLevel.Debug && l.Write.Message.Contains("Call to 'DispatchBrowserEvent' received before the circuit host initialization")); + } } [Fact] @@ -198,22 +227,27 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests { // Arrange var expectedError = "Circuit not initialized."; - var rootUri = ServerFixture.RootUri; - var baseUri = new Uri(rootUri, "/subdir"); - Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false)); - Assert.Empty(Batches); - - // Act - await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync( - "OnRenderCompleted", - 5, - null)); - - // Assert - var actualError = Assert.Single(Errors); - Assert.Equal(expectedError, actualError); - Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information); - Assert.Contains(Logs, l => (l.LogLevel, l.Message) == (LogLevel.Debug, "Call to 'OnRenderCompleted' received before the circuit host initialization")); + await using (var server = await StartServer<ServerStartup>()) + { + ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new(); + server.ServerLogged += (LogRecord record) => logs.Enqueue(record); + var rootUri = server.Url; + var baseUri = new Uri($"{rootUri}/subdir"); + Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false)); + Assert.Empty(Batches); + + // Act + await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync( + "OnRenderCompleted", + 5, + null)); + + // Assert + var actualError = Assert.Single(Errors); + Assert.Equal(expectedError, actualError); + Assert.DoesNotContain(logs, l => l.Write.LogLevel > LogLevel.Information); + Assert.Contains(logs, l => l.Write.LogLevel == LogLevel.Debug && l.Write.Message.Contains("Call to 'OnRenderCompleted' received before the circuit host initialization")); + } } [Fact] @@ -221,22 +255,27 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests { // Arrange var expectedError = "Circuit not initialized."; - var rootUri = ServerFixture.RootUri; - var baseUri = new Uri(rootUri, "/subdir"); - Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false)); - Assert.Empty(Batches); - - // Act - await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync( - "OnLocationChanged", - baseUri.AbsoluteUri, - false)); - - // Assert - var actualError = Assert.Single(Errors); - Assert.Equal(expectedError, actualError); - Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information); - Assert.Contains(Logs, l => (l.LogLevel, l.Message) == (LogLevel.Debug, "Call to 'OnLocationChanged' received before the circuit host initialization")); + await using (var server = await StartServer<ServerStartup>()) + { + ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new(); + server.ServerLogged += (LogRecord record) => logs.Enqueue(record); + var rootUri = server.Url; + var baseUri = new Uri($"{rootUri}/subdir"); + Assert.True(await Client.ConnectAsync(baseUri, connectAutomatically: false)); + Assert.Empty(Batches); + + // Act + await Client.ExpectCircuitErrorAndDisconnect(() => Client.HubConnection.SendAsync( + "OnLocationChanged", + baseUri.AbsoluteUri, + false)); + + // Assert + var actualError = Assert.Single(Errors); + Assert.Equal(expectedError, actualError); + Assert.DoesNotContain(logs, l => l.Write.LogLevel > LogLevel.Information); + Assert.Contains(logs, l => l.Write.LogLevel == LogLevel.Debug && l.Write.Message.Contains("Call to 'OnLocationChanged' received before the circuit host initialization")); + } } [Fact] @@ -247,28 +286,34 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests "For more details turn on detailed exceptions by setting 'DetailedErrors: true' in 'appSettings.Development.json' or set 'CircuitOptions.DetailedErrors'. " + "Location change to 'http://example.com' failed."; - var rootUri = ServerFixture.RootUri; - var baseUri = new Uri(rootUri, "/subdir"); - await ConnectAutomaticallyAndWait(baseUri); - - // Act - await Client.ExpectCircuitError(() => Client.HubConnection.SendAsync( - "OnLocationChanged", - "http://example.com", - false)); - - // Assert - var actualError = Assert.Single(Errors); - Assert.Equal(expectedError, actualError); - Assert.DoesNotContain(Logs, l => l.LogLevel > LogLevel.Information); - - var entry = Assert.Single(Logs, l => l.EventId.Name == "LocationChangeFailed"); - Assert.Equal(LogLevel.Debug, entry.LogLevel); - Assert.Matches("Location change to 'http://example.com' in circuit '.*' failed\\.", entry.Message); + await using (var server = await StartServer<ServerStartup>(expectedErrorsFilter: (WriteContext val) => true)) + { + ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new(); + server.ServerLogged += (LogRecord record) => logs.Enqueue(record); + var rootUri = server.Url; + var baseUri = new Uri($"{rootUri}/subdir"); + + Assert.True(await Client.ConnectAsync(baseUri)); + Assert.Single(Batches); + + // Act + await Client.ExpectCircuitError(() => Client.HubConnection.SendAsync( + "OnLocationChanged", + "http://example.com", + false)); + + // Assert + var actualError = Assert.Single(Errors); + Assert.Equal(expectedError, actualError); + Assert.DoesNotContain(logs, l => l.Write.LogLevel > LogLevel.Information); + + var entry = Assert.Single(logs, l => l.Write.EventId.Name == "LocationChangeFailed"); + Assert.Equal(LogLevel.Debug, entry.Write.LogLevel); + Assert.Matches("Location change to 'http://example.com' in circuit '.*' failed\\.", entry.Write.Message); + } } [Fact] - [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/19666")] public async Task OnLocationChanged_ReportsErrorForExceptionInUserCode() { // Arrange @@ -276,26 +321,32 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests "For more details turn on detailed exceptions by setting 'DetailedErrors: true' in 'appSettings.Development.json' or set 'CircuitOptions.DetailedErrors'. " + "Location change failed."; - var rootUri = ServerFixture.RootUri; - var baseUri = new Uri(rootUri, "/subdir"); + await using (var server = await StartServer<ServerStartup>(expectedErrorsFilter: (WriteContext val) => true)) + { + ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new(); + server.ServerLogged += (LogRecord record) => logs.Enqueue(record); + var rootUri = server.Url; + var baseUri = new Uri($"{rootUri}/subdir"); - await ConnectAutomaticallyAndWait(baseUri); + Assert.True(await Client.ConnectAsync(baseUri)); + Assert.Single(Batches); - await Client.SelectAsync("test-selector-select", "BasicTestApp.NavigationFailureComponent"); + await Client.SelectAsync("test-selector-select", "BasicTestApp.NavigationFailureComponent"); - // Act - await Client.ExpectCircuitError(() => Client.HubConnection.SendAsync( - "OnLocationChanged", - new Uri(baseUri, "/test").AbsoluteUri, - false)); + // Act + await Client.ExpectCircuitError(() => Client.HubConnection.SendAsync( + "OnLocationChanged", + new Uri(baseUri, "/test").AbsoluteUri, + false)); - // Assert - var actualError = Assert.Single(Errors); - Assert.Equal(expectedError, actualError); + // Assert + var actualError = Assert.Single(Errors); + Assert.Equal(expectedError, actualError); - var entry = Assert.Single(Logs, l => l.EventId.Name == "LocationChangeFailed"); - Assert.Equal(LogLevel.Error, entry.LogLevel); - Assert.Matches($"Location change to '{new Uri(ServerFixture.RootUri, "/test")}' in circuit '.*' failed\\.", entry.Message); + var entry = Assert.Single(logs, l => l.Write.EventId.Name == "LocationChangeFailed"); + Assert.Equal(LogLevel.Error, entry.Write.LogLevel); + Assert.Matches($"Location change to '{new Uri($"{server.Url}/test")}' in circuit '.*' failed.", entry.Write.Message); + } } [Theory] @@ -306,7 +357,6 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests [InlineData("render-throw")] [InlineData("afterrender-sync-throw")] [InlineData("afterrender-async-throw")] - [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/19666")] public async Task ComponentLifecycleMethodThrowsExceptionTerminatesTheCircuit(string id) { if (id == "setparameters-async-throw") @@ -322,61 +372,74 @@ namespace Microsoft.AspNetCore.Components.E2ETest.ServerExecutionTests // Arrange var expectedError = "Unhandled exception in circuit .*"; - var rootUri = ServerFixture.RootUri; - var baseUri = new Uri(rootUri, "/subdir"); - await ConnectAutomaticallyAndWait(baseUri); + await using (var server = await StartServer<ServerStartup>(expectedErrorsFilter: (WriteContext val) => true)) + { + ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new(); + server.ServerLogged += (LogRecord record) => logs.Enqueue(record); + var rootUri = server.Url; + var baseUri = new Uri($"{rootUri}/subdir"); - await Client.SelectAsync("test-selector-select", "BasicTestApp.ReliabilityComponent"); + Assert.True(await Client.ConnectAsync(baseUri)); + Assert.Single(Batches); - // Act - await Client.ExpectCircuitError(async () => - { - await Client.ClickAsync(id, expectRenderBatch: false); - }); + await Client.SelectAsync("test-selector-select", "BasicTestApp.ReliabilityComponent"); - // Now if you try to click again, you will get *forcibly* disconnected for trying to talk to - // a circuit that's gone. - await Client.ExpectCircuitErrorAndDisconnect(async () => - { - await Assert.ThrowsAsync<TaskCanceledException>(async () => await Client.ClickAsync(id, expectRenderBatch: false)); - }); + // Act + await Client.ExpectCircuitError(async () => + { + await Client.ClickAsync(id, expectRenderBatch: false); + }); - // Checking logs at the end to avoid race condition. - Assert.Contains( - Logs, - e => LogLevel.Error == e.LogLevel && Regex.IsMatch(e.Message, expectedError)); + // Now if you try to click again, you will get *forcibly* disconnected for trying to talk to + // a circuit that's gone. + await Client.ExpectCircuitErrorAndDisconnect(async () => + { + await Assert.ThrowsAsync<TaskCanceledException>(async () => await Client.ClickAsync(id, expectRenderBatch: false)); + }); + + // Checking logs at the end to avoid race condition. + Assert.Contains( + logs, + e => LogLevel.Error == e.Write.LogLevel && Regex.IsMatch(e.Write.Message, expectedError)); + } } [Fact] - [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/19666")] public async Task ComponentDisposeMethodThrowsExceptionTerminatesTheCircuit() { // Arrange var expectedError = "Unhandled exception in circuit .*"; - var rootUri = ServerFixture.RootUri; - var baseUri = new Uri(rootUri, "/subdir"); - await ConnectAutomaticallyAndWait(baseUri); + await using (var server = await StartServer<ServerStartup>(expectedErrorsFilter: (WriteContext val) => true)) + { + ConcurrentQueue<Microsoft.AspNetCore.SignalR.Tests.LogRecord> logs = new(); + server.ServerLogged += (LogRecord record) => logs.Enqueue(record); + var rootUri = server.Url; + var baseUri = new Uri($"{rootUri}/subdir"); - await Client.SelectAsync("test-selector-select", "BasicTestApp.ReliabilityComponent"); + Assert.True(await Client.ConnectAsync(baseUri)); + Assert.Single(Batches); - // Act - show then hide - await Client.ClickAsync("dispose-throw"); - await Client.ExpectCircuitError(async () => - { - await Client.ClickAsync("dispose-throw", expectRenderBatch: false); - }); + await Client.SelectAsync("test-selector-select", "BasicTestApp.ReliabilityComponent"); - // Now if you try to click again, you will get *forcibly* disconnected for trying to talk to - // a circuit that's gone. - await Client.ExpectCircuitErrorAndDisconnect(async () => - { - await Assert.ThrowsAsync<TaskCanceledException>(async () => await Client.ClickAsync("dispose-throw", expectRenderBatch: false)); - }); + // Act - show then hide + await Client.ClickAsync("dispose-throw"); + await Client.ExpectCircuitError(async () => + { + await Client.ClickAsync("dispose-throw", expectRenderBatch: false); + }); - // Checking logs at the end to avoid race condition. - Assert.Contains( - Logs, - e => LogLevel.Error == e.LogLevel && Regex.IsMatch(e.Message, expectedError)); + // Now if you try to click again, you will get *forcibly* disconnected for trying to talk to + // a circuit that's gone. + await Client.ExpectCircuitErrorAndDisconnect(async () => + { + await Assert.ThrowsAsync<TaskCanceledException>(async () => await Client.ClickAsync("dispose-throw", expectRenderBatch: false)); + }); + + // Checking logs at the end to avoid race condition. + Assert.Contains( + logs, + e => LogLevel.Error == e.Write.LogLevel && Regex.IsMatch(e.Write.Message, expectedError)); + } } } } diff --git a/src/SignalR/common/testassets/Tests.Utils/FunctionalTestBase.cs b/src/Shared/SignalR/FunctionalTestBase.cs similarity index 100% rename from src/SignalR/common/testassets/Tests.Utils/FunctionalTestBase.cs rename to src/Shared/SignalR/FunctionalTestBase.cs diff --git a/src/SignalR/common/testassets/Tests.Utils/InProcessTestServer.cs b/src/Shared/SignalR/InProcessTestServer.cs similarity index 100% rename from src/SignalR/common/testassets/Tests.Utils/InProcessTestServer.cs rename to src/Shared/SignalR/InProcessTestServer.cs diff --git a/src/SignalR/common/testassets/Tests.Utils/LogRecord.cs b/src/Shared/SignalR/LogRecord.cs similarity index 100% rename from src/SignalR/common/testassets/Tests.Utils/LogRecord.cs rename to src/Shared/SignalR/LogRecord.cs diff --git a/src/SignalR/common/testassets/Tests.Utils/LogSinkProvider.cs b/src/Shared/SignalR/LogSinkProvider.cs similarity index 100% rename from src/SignalR/common/testassets/Tests.Utils/LogSinkProvider.cs rename to src/Shared/SignalR/LogSinkProvider.cs diff --git a/src/SignalR/common/testassets/Tests.Utils/VerifiableLoggedTest.cs b/src/Shared/SignalR/VerifiableLoggedTest.cs similarity index 100% rename from src/SignalR/common/testassets/Tests.Utils/VerifiableLoggedTest.cs rename to src/Shared/SignalR/VerifiableLoggedTest.cs diff --git a/src/SignalR/common/testassets/Tests.Utils/VerifyNoErrorsScope.cs b/src/Shared/SignalR/VerifyNoErrorScope.cs similarity index 100% rename from src/SignalR/common/testassets/Tests.Utils/VerifyNoErrorsScope.cs rename to src/Shared/SignalR/VerifyNoErrorScope.cs diff --git a/src/SignalR/common/testassets/Tests.Utils/WrappingLoggerFactory.cs b/src/Shared/SignalR/WrappingLoggerFactory.cs similarity index 98% rename from src/SignalR/common/testassets/Tests.Utils/WrappingLoggerFactory.cs rename to src/Shared/SignalR/WrappingLoggerFactory.cs index 05b6f79b30df445944177a4c445056520f826626..bf34b1a1a581830f731d17018b301a2251675d44 100644 --- a/src/SignalR/common/testassets/Tests.Utils/WrappingLoggerFactory.cs +++ b/src/Shared/SignalR/WrappingLoggerFactory.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; diff --git a/src/SignalR/common/testassets/Tests.Utils/Microsoft.AspNetCore.SignalR.Tests.Utils.csproj b/src/SignalR/common/testassets/Tests.Utils/Microsoft.AspNetCore.SignalR.Tests.Utils.csproj index dc4198b92409ba8a8b74d353c1384b88ac9a7ea4..80b109210370e5b934cd7eca423a0d081b4030c5 100644 --- a/src/SignalR/common/testassets/Tests.Utils/Microsoft.AspNetCore.SignalR.Tests.Utils.csproj +++ b/src/SignalR/common/testassets/Tests.Utils/Microsoft.AspNetCore.SignalR.Tests.Utils.csproj @@ -23,6 +23,7 @@ <Reference Include="Microsoft.AspNetCore.SignalR.Common" /> <Compile Include="$(SharedSourceRoot)ValueStopwatch\*.cs" /> + <Compile Include="$(SharedSourceRoot)SignalR\*.cs" /> </ItemGroup> </Project>