Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>14</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public async Task UnknownMethodId(TestStreamingHubClientFactory clientFactory)
Assert.NotNull(ex);
var rpcException = Assert.IsType<RpcException>(ex);
Assert.Equal(StatusCode.Unimplemented, rpcException.Status.StatusCode);
Assert.Contains(factory.Logs, x => x.Contains("HubMethodNotFound\tStreamingHub method '-1'"));
Assert.Contains(factory.Logs.GetSnapshot(), x => x.Id.Name == "HubMethodNotFound" && x.Message.Contains("StreamingHub method '-1'"));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>14</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Logging.Testing;

namespace MagicOnion.Server.InternalTesting;

Expand All @@ -19,18 +20,12 @@ protected override IEnumerable<Type> GetServiceImplementationTypes()
public abstract class MagicOnionApplicationFactory : WebApplicationFactory<Program>
{
public const string ItemsKey = "MagicOnionApplicationFactory.Items";
public ConcurrentDictionary<string, object> Items => Services.GetRequiredKeyedService<ConcurrentDictionary<string, object>>(ItemsKey);
public ConcurrentBag<string> Logs { get; } = new();

protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureLogging(logger =>
{
logger.AddFakeLogging(options =>
{
options.OutputFormatter = x => $"{x.Timestamp}\t{x.Level}\t{x.Id}\t{x.Message}\t{x.Exception}";
options.OutputSink = x => Logs.Add(x);
});
logger.AddFakeLogging();
});
builder.ConfigureServices(services =>
{
Expand All @@ -53,18 +48,28 @@ protected virtual void OnConfigureMagicOnionBuilder(IMagicOnionServerBuilder bui

public WebApplicationFactory<Program> WithMagicOnionOptions(Action<MagicOnionOptions> configure)
{
return this.WithWebHostBuilder(x =>
return WithWebHostBuilder(builder =>
{
x.ConfigureServices(services =>
builder.ConfigureServices(services =>
{
services.Configure<MagicOnionOptions>(configure);
});
});
}
}


public void Initialize()
public static class WebApplicationBuilderExtensions
{
extension(WebApplicationFactory<Program> @this)
{
Items.Clear();
Logs.Clear();
public ConcurrentDictionary<string, object> Items => @this.Services.GetRequiredKeyedService<ConcurrentDictionary<string, object>>(MagicOnionApplicationFactory.ItemsKey);
public FakeLogCollector Logs => @this.Services.GetRequiredService<FakeLogCollector>();

public void Initialize()
{
@this.Logs.Clear();
@this.Items.Clear();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
<Nullable>enable</Nullable>

<IsTestProject>true</IsTestProject>

<LangVersion>14</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>14</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<LangVersion>default</LangVersion>
<LangVersion>14</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>

<!-- CS8002: Referenced assembly '{0}' does not have a strong name. -->
Expand Down
1 change: 1 addition & 0 deletions tests/MagicOnion.Server.Tests/MagicOnionMetricsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public MagicOnionMetricsTest(MagicOnionApplicationFactory<MagicOnionMetricsTestH
services.AddSingleton<MagicOnionMetrics>(new MagicOnionMetrics(meterFactory));
});
});
this.factory.Initialize();
}

[Fact]
Expand Down
1 change: 1 addition & 0 deletions tests/MagicOnion.Server.Tests/RawBytesResponseTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class RawBytesResponseTest : IClassFixture<MagicOnionApplicationFactory<R
public RawBytesResponseTest(MagicOnionApplicationFactory<RawBytesResponseTestService> factory)
{
this.factory = factory.WithMagicOnionOptions(options => {});
this.factory.Initialize();
}

[Fact]
Expand Down
30 changes: 15 additions & 15 deletions tests/MagicOnion.Server.Tests/StreamingHubConnectionEventsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,19 @@
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using NSubstitute;

namespace MagicOnion.Server.Tests;

public class StreamingHubConnectionEventsTest: IClassFixture<MagicOnionApplicationFactory<StreamingHubConnectionEventsTestHub>>
{
readonly WebApplicationFactory<Program> factory;
readonly ConcurrentBag<string> logs;
readonly ConcurrentDictionary<string, object> items;

public StreamingHubConnectionEventsTest(MagicOnionApplicationFactory<StreamingHubConnectionEventsTestHub> factory)
{
factory.Initialize();
this.factory = factory;
this.logs = factory.Logs;
this.items = factory.Items;
this.factory.Initialize();
}

[Fact]
Expand All @@ -37,10 +34,10 @@ public async Task EventsCalled()
await client.DisposeAsync();
await Task.Delay(100, TestContext.Current.CancellationToken);

Assert.True((bool)items.GetValueOrDefault("OnConnecting", false));
Assert.True((bool)items.GetValueOrDefault("OnConnected", false));
Assert.True((bool)items.GetValueOrDefault("OnDisconnected", false));
Assert.Equal(["E/OnDisconnected", "E/OnConnected", "E/OnConnecting"], logs.Select(x => x.Split('\t')[3]).Where(x => x.StartsWith("E")));
Assert.True((bool)factory.Items.GetValueOrDefault("OnConnecting", false));
Assert.True((bool)factory.Items.GetValueOrDefault("OnConnected", false));
Assert.True((bool)factory.Items.GetValueOrDefault("OnDisconnected", false));
Assert.Equal(["E/OnConnecting", "E/OnConnected", "E/OnDisconnected"], factory.Logs.GetSnapshot().Select(x => x.Message).Where(x => x.StartsWith("E/")));
}

[Fact]
Expand All @@ -56,10 +53,11 @@ await StreamingHubClient.ConnectAsync<IStreamingHubConnectionEventsTestHub, IStr
option: new CallOptions(new Metadata(){ { "ThrowsRSEOnConnecting", "1" }}),
cancellationToken: TestContext.Current.CancellationToken));

var logSnapshot = factory.Logs.GetSnapshot();
Assert.Equal(StatusCode.FailedPrecondition, ex.StatusCode);
Assert.True(logs.Any(x => x.Contains("\tE/OnConnecting\t")));
Assert.False(logs.Any(x => x.Contains("\tE/OnConnected\t")));
Assert.False(logs.Any(x => x.Contains("\tError\t")));
Assert.Contains(logSnapshot.Select(x => x.Message), x => x == "E/OnConnecting");
Assert.DoesNotContain(logSnapshot.Select(x => x.Message), x => x == "E/OnConnected");
Assert.DoesNotContain(logSnapshot.Select(x => x.Message), x => x == "Error");
}

[Fact]
Expand All @@ -78,11 +76,13 @@ await StreamingHubClient.ConnectAsync<IStreamingHubConnectionEventsTestHub, IStr
cancellationToken: TestContext.Current.CancellationToken);

var ex = await Assert.ThrowsAsync<RpcException>(async () => await client.HelloAsync());
var logSnapshot = factory.Logs.GetSnapshot();
Assert.Contains("StreamingHubClient has already been disconnected from the server", ex.Message);
Assert.Equal(StatusCode.Unavailable, ex.StatusCode);
Assert.True(logs.Any(x => x.Contains("\tE/OnConnecting\t")));
Assert.True(logs.Any(x => x.Contains("\tE/OnConnected\t")));
Assert.False(logs.Any(x => x.Contains("\tError\t")));
Assert.Contains(logSnapshot.Select(x => x.Message), x => x == "E/OnConnecting");
Assert.Contains(logSnapshot.Select(x => x.Message), x => x == "E/OnConnected");
Assert.DoesNotContain(logSnapshot.Select(x => x.Message), x => x == "Error");

}
}

Expand Down
10 changes: 5 additions & 5 deletions tests/MagicOnion.Server.Tests/StreamingHubDisconnectionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,19 @@
using MagicOnion.Server.Hubs;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using NSubstitute;

namespace MagicOnion.Server.Tests;

public class StreamingHubDisconnectionTest : IClassFixture<MagicOnionApplicationFactory<StreamingHubDisconnectionTestHub>>
{
readonly ConcurrentBag<string> logs;
readonly WebApplicationFactory<Program> factory;

public StreamingHubDisconnectionTest(MagicOnionApplicationFactory<StreamingHubDisconnectionTestHub> factory)
{
factory.Initialize();
this.factory = factory;
this.logs = factory.Logs;
this.factory.Initialize();
}

[Fact]
Expand All @@ -42,8 +41,9 @@ public async Task DisconnectWhileConsumingHubMethodQueue()

await Task.Delay(500);

var doWorkAsyncCallCount = logs.Count(x => x.Contains("DoWorkAsync:Begin"));
var doWorkAsyncDoneCallCount = logs.Count(x => x.Contains("DoWorkAsync:Done"));
var logs = factory.Logs.GetSnapshot();
var doWorkAsyncCallCount = logs.Count(x => x.Message == "DoWorkAsync:Begin");
var doWorkAsyncDoneCallCount = logs.Count(x => x.Message == "DoWorkAsync:Done");
Assert.True(doWorkAsyncCallCount < 3);
Assert.True(doWorkAsyncCallCount == doWorkAsyncDoneCallCount);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,17 @@
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using NSubstitute;

namespace MagicOnion.Server.Tests;

public class StreamingHubThrowOnDisconnectTest : IClassFixture<MagicOnionApplicationFactory<StreamingHubThrowOnDisconnectTestHub>>
{
readonly ConcurrentBag<string> logs;
readonly WebApplicationFactory<Program> factory;

public StreamingHubThrowOnDisconnectTest(MagicOnionApplicationFactory<StreamingHubThrowOnDisconnectTestHub> factory)
{
factory.Initialize();
this.factory = factory.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
Expand All @@ -31,7 +30,7 @@ public StreamingHubThrowOnDisconnectTest(MagicOnionApplicationFactory<StreamingH
(IRemoteClientResultPendingTaskRegistry)(desc.ImplementationInstance ?? desc.ImplementationFactory(sp))));
});
});
this.logs = factory.Logs;
this.factory.Initialize();
}

[Fact]
Expand All @@ -52,7 +51,8 @@ public async Task ThrowOnDisconnect()

await Task.Delay(100);

Assert.True(logs.Any(x => x.Contains("OnDisconnected")));
var logs = this.factory.Logs.GetSnapshot();
Assert.True(logs.Any(x => x.Message == "OnDisconnected"));
Assert.True(pendingTaskRegistry.IsDisposed);
}
}
Expand Down
23 changes: 12 additions & 11 deletions tests/MagicOnion.Server.Tests/UnaryServiceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,24 @@
using MagicOnion.Client;
using MessagePack;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Logging.Testing;

namespace MagicOnion.Server.Tests;

public class UnaryServiceTest_ReturnExceptionStackTrace : IClassFixture<MagicOnionApplicationFactory<UnaryTestService>>
{
readonly ConcurrentBag<string> logs;
readonly WebApplicationFactory<Program> factory;
readonly FakeLogCollector logs;

public UnaryServiceTest_ReturnExceptionStackTrace(MagicOnionApplicationFactory<UnaryTestService> factory)
{
factory.Initialize();
this.factory = factory.WithMagicOnionOptions(options =>
{
options.IsReturnExceptionStackTraceInErrorDetail = true;
});

this.logs = factory.Logs;
this.factory.Initialize();
this.logs = this.factory.Logs;
}

[Fact]
Expand All @@ -32,7 +33,7 @@ public async Task ReturnTypeIsNilAndNonSuccessResponse()
var ex = await Assert.ThrowsAsync<RpcException>(async () => await client.ReturnTypeIsNilAndNonSuccessResponseAsync(StatusCode.AlreadyExists));
Assert.Equal(StatusCode.AlreadyExists, ex.StatusCode);
Assert.Equal(nameof(IUnaryTestService.ReturnTypeIsNilAndNonSuccessResponseAsync), ex.Status.Detail);
Assert.Single(logs);
Assert.Equal(1, logs.Count);
}

[Fact]
Expand All @@ -43,7 +44,7 @@ public async Task Throw_NoParameterReturnNil()

var ex = await Assert.ThrowsAsync<RpcException>(async () => await client.ThrowAsync());
Assert.Equal(StatusCode.Unknown, ex.StatusCode);
Assert.Single(logs);
Assert.Equal(1, logs.Count);
Assert.Contains("Something went wrong", ex.Message);
}

Expand All @@ -55,7 +56,7 @@ public async Task Throw_OneParameterReturnNil()

var ex = await Assert.ThrowsAsync<RpcException>(async () => await client.ThrowOneValueTypeParameterReturnNilAsync(1234));
Assert.Equal(StatusCode.Unknown, ex.StatusCode);
Assert.Single(logs);
Assert.Equal(1, factory.Logs.Count);
Assert.Contains("Something went wrong", ex.Message);
}

Expand All @@ -67,14 +68,14 @@ public async Task Throw_TwoParameterReturnNil()

var ex = await Assert.ThrowsAsync<RpcException>(async () => await client.ThrowTwoValueTypeParameterReturnNilAsync(1234, 5678));
Assert.Equal(StatusCode.Unknown, ex.StatusCode);
Assert.Single(logs);
Assert.Equal(1, logs.Count);
Assert.Contains("Something went wrong", ex.Message);
}
}

public class UnaryServiceTest : IClassFixture<MagicOnionApplicationFactory<UnaryTestService>>
{
readonly ConcurrentBag<string> logs;
readonly FakeLogCollector logs;
readonly WebApplicationFactory<Program> factory;

public UnaryServiceTest(MagicOnionApplicationFactory<UnaryTestService> factory)
Expand All @@ -92,7 +93,7 @@ public async Task Throw_NoParameterReturnNil()

var ex = await Assert.ThrowsAsync<RpcException>(async () => await client.ThrowAsync());
Assert.Equal(StatusCode.Unknown, ex.StatusCode);
Assert.Single(logs);
Assert.Single(logs.GetSnapshot());
Assert.DoesNotContain("Something went wrong", ex.Message);
}

Expand All @@ -104,7 +105,7 @@ public async Task Throw_OneParameterReturnNil()

var ex = await Assert.ThrowsAsync<RpcException>(async () => await client.ThrowOneValueTypeParameterReturnNilAsync(1234));
Assert.Equal(StatusCode.Unknown, ex.StatusCode);
Assert.Single(logs);
Assert.Single(logs.GetSnapshot());
Assert.DoesNotContain("Something went wrong", ex.Message);
}

Expand All @@ -116,7 +117,7 @@ public async Task Throw_TwoParameterReturnNil()

var ex = await Assert.ThrowsAsync<RpcException>(async () => await client.ThrowTwoValueTypeParameterReturnNilAsync(1234, 5678));
Assert.Equal(StatusCode.Unknown, ex.StatusCode);
Assert.Single(logs);
Assert.Single(logs.GetSnapshot());
Assert.DoesNotContain("Something went wrong", ex.Message);
}

Expand Down
Loading