1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Collections.ObjectModel;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using Moq;
using Xunit;
using Assert = Microsoft.TestCommon.AssertEx;
using System.Web.Http.Hosting;
using System.Collections.Generic;
namespace System.Web.Http.Tracing.Tracers
{
public class HttpControllerTracerTest
{
private Mock<HttpActionDescriptor> _mockActionDescriptor;
private HttpControllerDescriptor _controllerDescriptor;
public HttpControllerTracerTest()
{
_mockActionDescriptor = new Mock<HttpActionDescriptor>() { CallBase = true };
_mockActionDescriptor.Setup(a => a.ActionName).Returns("test");
_mockActionDescriptor.Setup(a => a.GetParameters()).Returns(new Collection<HttpParameterDescriptor>(new HttpParameterDescriptor[0]));
_controllerDescriptor = new HttpControllerDescriptor(new HttpConfiguration(), "controller", typeof(ApiController));
}
[Fact]
public void Dispose_TracesAndInvokesInnerDisposeWhenControllerIsDisposable()
{
// Arrange
var mockController = new Mock<IHttpController>();
var mockDisposable = mockController.As<IDisposable>();
var request = new HttpRequestMessage();
var traceWriter = new TestTraceWriter();
var tracer = new HttpControllerTracer(request, mockController.Object, traceWriter);
var expectedTraces = new[]
{
new TraceRecord(request, TraceCategories.ControllersCategory, TraceLevel.Info) { Kind = TraceKind.Begin, Operation = "Dispose" },
new TraceRecord(request, TraceCategories.ControllersCategory, TraceLevel.Info) { Kind = TraceKind.End, Operation = "Dispose" }
};
// Act
((IDisposable)tracer).Dispose();
// Assert
Assert.Equal(expectedTraces, traceWriter.Traces, new TraceRecordComparer());
mockDisposable.Verify(d => d.Dispose(), Times.Once());
}
[Fact]
public void Dispose_DoesNotTraceWhenControllerIsNotDisposable()
{
// Arrange
var mockController = new Mock<IHttpController>();
var request = new HttpRequestMessage();
var traceWriter = new TestTraceWriter();
var tracer = new HttpControllerTracer(request, mockController.Object, traceWriter);
// Act
((IDisposable)tracer).Dispose();
// Assert
Assert.Empty(traceWriter.Traces);
}
[Fact]
public void ExecuteAsync_RemovesInnerControllerFromReleaseListAndAddsItselfInstead()
{
// Arrange
var request = new HttpRequestMessage();
var context = ContextUtil.CreateControllerContext(request: request);
var mockController = new Mock<IHttpController>();
var mockDisposable = mockController.As<IDisposable>();
mockController.Setup(c => c.ExecuteAsync(context, CancellationToken.None))
.Callback<HttpControllerContext, CancellationToken>((cc, ct) => cc.Request.RegisterForDispose(mockDisposable.Object))
.Returns(() => TaskHelpers.FromResult(new HttpResponseMessage()))
.Verifiable();
context.ControllerDescriptor = _controllerDescriptor;
context.Controller = mockController.Object;
var traceWriter = new TestTraceWriter();
var tracer = new HttpControllerTracer(request, mockController.Object, traceWriter);
// Act
((IHttpController)tracer).ExecuteAsync(context, CancellationToken.None).WaitUntilCompleted();
// Assert
IEnumerable<IDisposable> disposables = (IEnumerable<IDisposable>)request.Properties[HttpPropertyKeys.DisposableRequestResourcesKey];
Assert.Contains(tracer, disposables);
Assert.DoesNotContain(mockDisposable.Object, disposables);
}
[Fact]
public void ExecuteAsync_Invokes_Inner_And_Traces()
{
// Arrange
HttpResponseMessage response = new HttpResponseMessage();
Mock<ApiController> mockController = new Mock<ApiController>() { CallBase = true };
mockController.Setup(b => b.ExecuteAsync(It.IsAny<HttpControllerContext>(), It.IsAny<CancellationToken>())).Returns(TaskHelpers.FromResult<HttpResponseMessage>(response));
HttpRequestMessage request = new HttpRequestMessage();
HttpControllerContext controllerContext = ContextUtil.CreateControllerContext(request: request);
controllerContext.ControllerDescriptor = _controllerDescriptor;
controllerContext.Controller = mockController.Object;
HttpActionContext actionContext = ContextUtil.CreateActionContext(controllerContext, actionDescriptor: _mockActionDescriptor.Object);
TestTraceWriter traceWriter = new TestTraceWriter();
HttpControllerTracer tracer = new HttpControllerTracer(request, mockController.Object, traceWriter);
TraceRecord[] expectedTraces = new TraceRecord[]
{
new TraceRecord(actionContext.Request, TraceCategories.ControllersCategory, TraceLevel.Info) { Kind = TraceKind.Begin },
new TraceRecord(actionContext.Request, TraceCategories.ControllersCategory, TraceLevel.Info) { Kind = TraceKind.End }
};
// Act
HttpResponseMessage actualResponse = ((IHttpController)tracer).ExecuteAsync(controllerContext, CancellationToken.None).Result;
// Assert
Assert.Equal<TraceRecord>(expectedTraces, traceWriter.Traces, new TraceRecordComparer());
Assert.Same(response, actualResponse);
}
[Fact]
public void ExecuteAsync_Faults_And_Traces_When_Inner_Faults()
{
// Arrange
InvalidOperationException exception = new InvalidOperationException();
TaskCompletionSource<HttpResponseMessage> tcs = new TaskCompletionSource<HttpResponseMessage>();
tcs.TrySetException(exception);
Mock<ApiController> mockController = new Mock<ApiController>() { CallBase = true };
mockController.Setup(b => b.ExecuteAsync(It.IsAny<HttpControllerContext>(), It.IsAny<CancellationToken>())).Returns(tcs.Task);
HttpRequestMessage request = new HttpRequestMessage();
HttpControllerContext controllerContext = ContextUtil.CreateControllerContext(request: request);
controllerContext.ControllerDescriptor = _controllerDescriptor;
controllerContext.Controller = mockController.Object;
HttpActionContext actionContext = ContextUtil.CreateActionContext(controllerContext, actionDescriptor: _mockActionDescriptor.Object);
TestTraceWriter traceWriter = new TestTraceWriter();
HttpControllerTracer tracer = new HttpControllerTracer(request, mockController.Object, traceWriter);
TraceRecord[] expectedTraces = new TraceRecord[]
{
new TraceRecord(actionContext.Request, TraceCategories.ControllersCategory, TraceLevel.Info) { Kind = TraceKind.Begin },
new TraceRecord(actionContext.Request, TraceCategories.ControllersCategory, TraceLevel.Error) { Kind = TraceKind.End }
};
// Act
Exception thrown = Assert.Throws<InvalidOperationException>(() => ((IHttpController)tracer).ExecuteAsync(controllerContext, CancellationToken.None).Wait());
// Assert
Assert.Equal<TraceRecord>(expectedTraces, traceWriter.Traces, new TraceRecordComparer());
Assert.Same(exception, thrown);
Assert.Same(exception, traceWriter.Traces[1].Exception);
}
[Fact]
public void ExecuteAsync_IsCancelled_And_Traces_When_Inner_IsCancelled()
{
// Arrange
Mock<ApiController> mockController = new Mock<ApiController>() { CallBase = true };
mockController.Setup(b => b.ExecuteAsync(It.IsAny<HttpControllerContext>(), It.IsAny<CancellationToken>())).Returns(TaskHelpers.Canceled<HttpResponseMessage>());
HttpRequestMessage request = new HttpRequestMessage();
HttpControllerContext controllerContext = ContextUtil.CreateControllerContext(request: request);
controllerContext.ControllerDescriptor = _controllerDescriptor;
controllerContext.Controller = mockController.Object;
HttpActionContext actionContext = ContextUtil.CreateActionContext(controllerContext, actionDescriptor: _mockActionDescriptor.Object);
TestTraceWriter traceWriter = new TestTraceWriter();
HttpControllerTracer tracer = new HttpControllerTracer(request, mockController.Object, traceWriter);
TraceRecord[] expectedTraces = new TraceRecord[]
{
new TraceRecord(actionContext.Request, TraceCategories.ControllersCategory, TraceLevel.Info) { Kind = TraceKind.Begin },
new TraceRecord(actionContext.Request, TraceCategories.ControllersCategory, TraceLevel.Warn) { Kind = TraceKind.End }
};
// Act
Task task = ((IHttpController)tracer).ExecuteAsync(controllerContext, CancellationToken.None);
Exception thrown = Assert.Throws<TaskCanceledException>(() => task.Wait());
// Assert
Assert.Equal<TraceRecord>(expectedTraces, traceWriter.Traces, new TraceRecordComparer());
}
}
}
|