233 lines
6.6 KiB
C#
233 lines
6.6 KiB
C#
using Grpc.Core;
|
|
using Grpc.Net.Client;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using Microsoft.AspNetCore.TestHost;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using System.Diagnostics;
|
|
using Xunit.Abstractions;
|
|
|
|
namespace TestGrpc.Test;
|
|
|
|
public class UnitTest1 : IntegrationTestBase
|
|
{
|
|
public UnitTest1(GrpcTestFixture<Startup> fixture, ITestOutputHelper outputHelper)
|
|
: base(fixture, outputHelper)
|
|
{
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Test1()
|
|
{
|
|
// Arrange
|
|
var client = new Greeter.GreeterClient(Channel);
|
|
|
|
// Act
|
|
using var response = client.DownloadFile(new FileRequest { FilePath = "Files/test.txt" });
|
|
using var memoryStream = new MemoryStream();
|
|
|
|
var receivedFileName = string.Empty;
|
|
await foreach (var chunk in response.ResponseStream.ReadAllAsync())
|
|
{
|
|
if (!string.IsNullOrEmpty(chunk.FileName))
|
|
{
|
|
receivedFileName = chunk.FileName;
|
|
}
|
|
|
|
memoryStream.Write(chunk.Chunk.Span);
|
|
}
|
|
|
|
memoryStream.Seek(0, SeekOrigin.Begin);
|
|
using var reader = new StreamReader(memoryStream);
|
|
while (!reader.EndOfStream)
|
|
{
|
|
var line = await reader.ReadLineAsync();
|
|
Console.WriteLine(line);
|
|
}
|
|
|
|
// Assert
|
|
Assert.Equal("test.txt", receivedFileName);
|
|
}
|
|
}
|
|
|
|
internal class ForwardingLoggerProvider : ILoggerProvider
|
|
{
|
|
private readonly LogMessage _logAction;
|
|
|
|
public ForwardingLoggerProvider(LogMessage logAction)
|
|
{
|
|
_logAction = logAction;
|
|
}
|
|
|
|
public ILogger CreateLogger(string categoryName)
|
|
{
|
|
return new ForwardingLogger(categoryName, _logAction);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
}
|
|
|
|
internal class ForwardingLogger : ILogger
|
|
{
|
|
private readonly string _categoryName;
|
|
private readonly LogMessage _logAction;
|
|
|
|
public ForwardingLogger(string categoryName, LogMessage logAction)
|
|
{
|
|
_categoryName = categoryName;
|
|
_logAction = logAction;
|
|
}
|
|
|
|
public IDisposable BeginScope<TState>(TState state)
|
|
{
|
|
return null!;
|
|
}
|
|
|
|
public bool IsEnabled(LogLevel logLevel)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
|
|
{
|
|
_logAction(logLevel, _categoryName, eventId, formatter(state, exception), exception);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class GrpcTestContext<TStartup> : IDisposable where TStartup : class
|
|
{
|
|
private readonly Stopwatch _stopwatch;
|
|
private readonly GrpcTestFixture<TStartup> _fixture;
|
|
private readonly ITestOutputHelper _outputHelper;
|
|
|
|
public GrpcTestContext(GrpcTestFixture<TStartup> fixture, ITestOutputHelper outputHelper)
|
|
{
|
|
_stopwatch = Stopwatch.StartNew();
|
|
_fixture = fixture;
|
|
_outputHelper = outputHelper;
|
|
_fixture.LoggedMessage += WriteMessage;
|
|
}
|
|
|
|
private void WriteMessage(LogLevel logLevel, string category, EventId eventId, string message, Exception? exception)
|
|
{
|
|
var log = $"{_stopwatch.Elapsed.TotalSeconds:N3}s {category} - {logLevel}: {message}";
|
|
if (exception != null)
|
|
{
|
|
log += Environment.NewLine + exception.ToString();
|
|
}
|
|
_outputHelper.WriteLine(log);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_fixture.LoggedMessage -= WriteMessage;
|
|
}
|
|
}
|
|
|
|
public delegate void LogMessage(LogLevel logLevel, string categoryName, EventId eventId, string message, Exception? exception);
|
|
|
|
public class GrpcTestFixture<TStartup> : IDisposable where TStartup : class
|
|
{
|
|
private TestServer? _server;
|
|
private IHost? _host;
|
|
private HttpMessageHandler? _handler;
|
|
private Action<IWebHostBuilder>? _configureWebHost;
|
|
|
|
public event LogMessage? LoggedMessage;
|
|
|
|
public GrpcTestFixture()
|
|
{
|
|
LoggerFactory = new LoggerFactory();
|
|
LoggerFactory.AddProvider(new ForwardingLoggerProvider((logLevel, category, eventId, message, exception) =>
|
|
{
|
|
LoggedMessage?.Invoke(logLevel, category, eventId, message, exception);
|
|
}));
|
|
}
|
|
|
|
public void ConfigureWebHost(Action<IWebHostBuilder> configure)
|
|
{
|
|
_configureWebHost = configure;
|
|
}
|
|
|
|
private void EnsureServer()
|
|
{
|
|
if (_host == null)
|
|
{
|
|
var builder = new HostBuilder()
|
|
.ConfigureServices(services =>
|
|
{
|
|
services.AddSingleton<ILoggerFactory>(LoggerFactory);
|
|
})
|
|
.ConfigureWebHostDefaults(webHost =>
|
|
{
|
|
webHost
|
|
.UseTestServer()
|
|
.UseStartup<TStartup>();
|
|
|
|
_configureWebHost?.Invoke(webHost);
|
|
});
|
|
_host = builder.Start();
|
|
_server = _host.GetTestServer();
|
|
_handler = _server.CreateHandler();
|
|
}
|
|
}
|
|
|
|
public LoggerFactory LoggerFactory { get; }
|
|
|
|
public HttpMessageHandler Handler
|
|
{
|
|
get
|
|
{
|
|
EnsureServer();
|
|
return _handler!;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_handler?.Dispose();
|
|
_host?.Dispose();
|
|
_server?.Dispose();
|
|
}
|
|
|
|
public IDisposable GetTestContext(ITestOutputHelper outputHelper)
|
|
{
|
|
return new GrpcTestContext<TStartup>(this, outputHelper);
|
|
}
|
|
}
|
|
|
|
public class IntegrationTestBase : IClassFixture<GrpcTestFixture<Startup>>, IDisposable
|
|
{
|
|
private GrpcChannel? _channel;
|
|
private IDisposable? _testContext;
|
|
|
|
protected GrpcTestFixture<Startup> Fixture { get; set; }
|
|
|
|
protected ILoggerFactory LoggerFactory => Fixture.LoggerFactory;
|
|
|
|
protected GrpcChannel Channel => _channel ??= CreateChannel();
|
|
|
|
protected GrpcChannel CreateChannel()
|
|
{
|
|
return GrpcChannel.ForAddress("http://localhost", new GrpcChannelOptions
|
|
{
|
|
LoggerFactory = LoggerFactory,
|
|
HttpHandler = Fixture.Handler
|
|
});
|
|
}
|
|
|
|
public IntegrationTestBase(GrpcTestFixture<Startup> fixture, ITestOutputHelper outputHelper)
|
|
{
|
|
Fixture = fixture;
|
|
_testContext = Fixture.GetTestContext(outputHelper);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_testContext?.Dispose();
|
|
_channel = null;
|
|
}
|
|
} |