Skip to content

Commit 4b877a4

Browse files
committed
Add tests
1 parent 2b365b3 commit 4b877a4

File tree

1 file changed

+104
-36
lines changed

1 file changed

+104
-36
lines changed

src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerMiddlewareTest.cs

Lines changed: 104 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
using Microsoft.Extensions.Hosting;
2323
using Microsoft.Extensions.Logging;
2424
using Microsoft.Extensions.Logging.Abstractions;
25+
using Microsoft.Extensions.Logging.Testing;
2526
using Microsoft.Extensions.Options;
2627
using Moq;
2728

@@ -81,6 +82,7 @@ public async Task ExceptionIsSetOnProblemDetailsContext()
8182
public async Task Invoke_ExceptionThrownResultsInClearedRouteValuesAndEndpoint()
8283
{
8384
// Arrange
85+
var sink = new TestSink();
8486
var httpContext = CreateHttpContext();
8587
httpContext.SetEndpoint(new Endpoint((_) => Task.CompletedTask, new EndpointMetadataCollection(), "Test"));
8688
httpContext.Request.RouteValues["John"] = "Doe";
@@ -92,10 +94,39 @@ public async Task Invoke_ExceptionThrownResultsInClearedRouteValuesAndEndpoint()
9294
Assert.Null(context.GetEndpoint());
9395
return Task.CompletedTask;
9496
});
95-
var middleware = CreateMiddleware(_ => throw new InvalidOperationException(), optionsAccessor);
97+
var middleware = CreateMiddleware(_ => throw new InvalidOperationException(), optionsAccessor, loggerFactory: new TestLoggerFactory(sink, true));
9698

9799
// Act & Assert
98100
await middleware.Invoke(httpContext);
101+
102+
Assert.Collection(sink.Writes, w => Assert.Equal("UnhandledException", w.EventId.Name));
103+
}
104+
105+
[Fact]
106+
public async Task Invoke_HasExceptionHandler_SuppressIExceptionHandlerLogging_HasLogs()
107+
{
108+
// Arrange
109+
var sink = new TestSink();
110+
var httpContext = CreateHttpContext();
111+
112+
var optionsAccessor = CreateOptionsAccessor(
113+
exceptionHandler: context =>
114+
{
115+
context.Features.Set<IHttpResponseFeature>(new TestHttpResponseFeature());
116+
return Task.CompletedTask;
117+
},
118+
suppressLoggingHandlingException: true);
119+
var middleware = CreateMiddleware(_ => throw new InvalidOperationException(), optionsAccessor, loggerFactory: new TestLoggerFactory(sink, true));
120+
121+
// Act & Assert
122+
await middleware.Invoke(httpContext);
123+
124+
Assert.Collection(sink.Writes, w => Assert.Equal("UnhandledException", w.EventId.Name));
125+
}
126+
127+
private sealed class TestHttpResponseFeature : HttpResponseFeature
128+
{
129+
public override bool HasStarted => true;
99130
}
100131

101132
[Fact]
@@ -126,6 +157,7 @@ public async Task Invoke_ExceptionHandlerCaptureRouteValuesAndEndpoint()
126157
public async Task IExceptionHandlers_CallNextIfNotHandled()
127158
{
128159
// Arrange
160+
var sink = new TestSink();
129161
var httpContext = CreateHttpContext();
130162

131163
var optionsAccessor = CreateOptionsAccessor();
@@ -137,14 +169,49 @@ public async Task IExceptionHandlers_CallNextIfNotHandled()
137169
new TestExceptionHandler(true, "3"),
138170
};
139171

140-
var middleware = CreateMiddleware(_ => throw new InvalidOperationException(), optionsAccessor, exceptionHandlers);
172+
var middleware = CreateMiddleware(_ => throw new InvalidOperationException(), optionsAccessor, exceptionHandlers, loggerFactory: new TestLoggerFactory(sink, true));
141173

142174
// Act & Assert
143175
await middleware.Invoke(httpContext);
144176

145177
Assert.True(httpContext.Items.ContainsKey("1"));
146178
Assert.True(httpContext.Items.ContainsKey("2"));
147179
Assert.True(httpContext.Items.ContainsKey("3"));
180+
181+
Assert.Collection(sink.Writes, w => Assert.Equal("UnhandledException", w.EventId.Name));
182+
}
183+
184+
[Theory]
185+
[InlineData(true)]
186+
[InlineData(false)]
187+
public async Task IExceptionHandlers_SuppressLogging_TestLogs(bool suppressedLogs)
188+
{
189+
// Arrange
190+
var sink = new TestSink();
191+
var httpContext = CreateHttpContext();
192+
193+
var optionsAccessor = CreateOptionsAccessor(suppressLoggingHandlingException: suppressedLogs);
194+
195+
var exceptionHandlers = new List<IExceptionHandler>
196+
{
197+
new TestExceptionHandler(true, "1")
198+
};
199+
200+
var middleware = CreateMiddleware(_ => throw new InvalidOperationException(), optionsAccessor, exceptionHandlers, loggerFactory: new TestLoggerFactory(sink, true));
201+
202+
// Act & Assert
203+
await middleware.Invoke(httpContext);
204+
205+
Assert.True(httpContext.Items.ContainsKey("1"));
206+
207+
if (suppressedLogs)
208+
{
209+
Assert.Empty(sink.Writes);
210+
}
211+
else
212+
{
213+
Assert.Collection(sink.Writes, w => Assert.Equal("UnhandledException", w.EventId.Name));
214+
}
148215
}
149216

150217
[Fact]
@@ -247,32 +314,6 @@ public async Task Metrics_ExceptionThrown_Handled_Reported()
247314
m => AssertRequestException(m, "System.InvalidOperationException", "handled", typeof(TestExceptionHandler).FullName));
248315
}
249316

250-
[Fact]
251-
public async Task Metrics_ExceptionThrown_ErrorPathHandled_Reported()
252-
{
253-
// Arrange
254-
var httpContext = CreateHttpContext();
255-
var optionsAccessor = CreateOptionsAccessor(
256-
exceptionHandler: context =>
257-
{
258-
context.Features.Set<IHttpResponseFeature>(new TestHttpResponseFeature());
259-
return Task.CompletedTask;
260-
},
261-
exceptionHandlingPath: "/error");
262-
var meterFactory = new TestMeterFactory();
263-
var middleware = CreateMiddleware(_ => throw new InvalidOperationException(), optionsAccessor, meterFactory: meterFactory);
264-
var meter = meterFactory.Meters.Single();
265-
266-
using var diagnosticsRequestExceptionCollector = new MetricCollector<long>(meterFactory, DiagnosticsMetrics.MeterName, "aspnetcore.diagnostics.exceptions");
267-
268-
// Act
269-
await middleware.Invoke(httpContext);
270-
271-
// Assert
272-
Assert.Collection(diagnosticsRequestExceptionCollector.GetMeasurementSnapshot(),
273-
m => AssertRequestException(m, "System.InvalidOperationException", "handled", "/error"));
274-
}
275-
276317
[Fact]
277318
public async Task Metrics_ExceptionThrown_ResponseStarted_Skipped()
278319
{
@@ -471,6 +512,32 @@ public async Task Metrics_ExceptionThrown_Unhandled_Reported()
471512
m => AssertRequestException(m, "System.InvalidOperationException", "unhandled"));
472513
}
473514

515+
[Fact]
516+
public async Task Metrics_ExceptionThrown_ErrorPathHandled_Reported()
517+
{
518+
// Arrange
519+
var httpContext = CreateHttpContext();
520+
var optionsAccessor = CreateOptionsAccessor(
521+
exceptionHandler: context =>
522+
{
523+
context.Features.Set<IHttpResponseFeature>(new TestHttpResponseFeature());
524+
return Task.CompletedTask;
525+
},
526+
exceptionHandlingPath: "/error");
527+
var meterFactory = new TestMeterFactory();
528+
var middleware = CreateMiddleware(_ => throw new InvalidOperationException(), optionsAccessor, meterFactory: meterFactory);
529+
var meter = meterFactory.Meters.Single();
530+
531+
using var diagnosticsRequestExceptionCollector = new MetricCollector<long>(meterFactory, DiagnosticsMetrics.MeterName, "aspnetcore.diagnostics.exceptions");
532+
533+
// Act
534+
await middleware.Invoke(httpContext);
535+
536+
// Assert
537+
Assert.Collection(diagnosticsRequestExceptionCollector.GetMeasurementSnapshot(),
538+
m => AssertRequestException(m, "System.InvalidOperationException", "handled", "/error"));
539+
}
540+
474541
private static void AssertRequestException(CollectedMeasurement<long> measurement, string exceptionName, string result, string handler = null)
475542
{
476543
Assert.Equal(1, measurement.Value);
@@ -516,14 +583,19 @@ private HttpContext CreateHttpContext()
516583

517584
private IOptions<ExceptionHandlerOptions> CreateOptionsAccessor(
518585
RequestDelegate exceptionHandler = null,
519-
string exceptionHandlingPath = null)
586+
string exceptionHandlingPath = null,
587+
bool? suppressLoggingHandlingException = null)
520588
{
521589
exceptionHandler ??= c => Task.CompletedTask;
522590
var options = new ExceptionHandlerOptions()
523591
{
524592
ExceptionHandler = exceptionHandler,
525593
ExceptionHandlingPath = exceptionHandlingPath,
526594
};
595+
if (suppressLoggingHandlingException != null)
596+
{
597+
options.SuppressLoggingIExceptionHandler = suppressLoggingHandlingException.Value;
598+
}
527599
var optionsAccessor = Mock.Of<IOptions<ExceptionHandlerOptions>>(o => o.Value == options);
528600
return optionsAccessor;
529601
}
@@ -532,14 +604,15 @@ private ExceptionHandlerMiddlewareImpl CreateMiddleware(
532604
RequestDelegate next,
533605
IOptions<ExceptionHandlerOptions> options,
534606
IEnumerable<IExceptionHandler> exceptionHandlers = null,
535-
IMeterFactory meterFactory = null)
607+
IMeterFactory meterFactory = null,
608+
ILoggerFactory loggerFactory = null)
536609
{
537610
next ??= c => Task.CompletedTask;
538611
var listener = new DiagnosticListener("Microsoft.AspNetCore");
539612

540613
var middleware = new ExceptionHandlerMiddlewareImpl(
541614
next,
542-
NullLoggerFactory.Instance,
615+
loggerFactory ?? NullLoggerFactory.Instance,
543616
options,
544617
listener,
545618
exceptionHandlers ?? Enumerable.Empty<IExceptionHandler>(),
@@ -555,9 +628,4 @@ public object GetService(Type serviceType)
555628
throw new NotImplementedException();
556629
}
557630
}
558-
559-
private class TestHttpResponseFeature : HttpResponseFeature
560-
{
561-
public override bool HasStarted => true;
562-
}
563631
}

0 commit comments

Comments
 (0)