// 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; namespace System.Web.Http.Tracing.Tracers { public class HttpActionBindingTracerTest { private Mock _mockActionDescriptor; private Mock _mockParameterDescriptor; private Mock _mockParameterBinding; private HttpActionBinding _actionBinding; private HttpActionContext _actionContext; private HttpControllerContext _controllerContext; private HttpControllerDescriptor _controllerDescriptor; public HttpActionBindingTracerTest() { _mockActionDescriptor = new Mock() { CallBase = true }; _mockActionDescriptor.Setup(a => a.ActionName).Returns("test"); _mockActionDescriptor.Setup(a => a.GetParameters()).Returns(new Collection(new HttpParameterDescriptor[0])); _mockParameterDescriptor = new Mock() { CallBase = true }; _mockParameterBinding = new Mock(_mockParameterDescriptor.Object) { CallBase = true }; _actionBinding = new HttpActionBinding(_mockActionDescriptor.Object, new HttpParameterBinding[] { _mockParameterBinding.Object }); _controllerDescriptor = new HttpControllerDescriptor(new HttpConfiguration(), "controller", typeof(ApiController)); _controllerContext = ContextUtil.CreateControllerContext(request: new HttpRequestMessage()); _controllerContext.ControllerDescriptor = _controllerDescriptor; _actionContext = ContextUtil.CreateActionContext(_controllerContext, actionDescriptor: _mockActionDescriptor.Object); } [Fact] public void BindValuesAsync_Invokes_Inner_And_Traces() { // Arrange bool wasInvoked = false; Mock mockBinder = new Mock() { CallBase = true }; mockBinder.Setup(b => b.ExecuteBindingAsync( It.IsAny(), It.IsAny())). Callback(() => wasInvoked = true).Returns(TaskHelpers.Completed()); TestTraceWriter traceWriter = new TestTraceWriter(); HttpActionBindingTracer tracer = new HttpActionBindingTracer(mockBinder.Object, traceWriter); TraceRecord[] expectedTraces = new TraceRecord[] { new TraceRecord(_actionContext.Request, TraceCategories.ModelBindingCategory, TraceLevel.Info) { Kind = TraceKind.Begin }, new TraceRecord(_actionContext.Request, TraceCategories.ModelBindingCategory, TraceLevel.Info) { Kind = TraceKind.End } }; // Act tracer.ExecuteBindingAsync(_actionContext, CancellationToken.None).Wait(); // Assert Assert.Equal(expectedTraces, traceWriter.Traces, new TraceRecordComparer()); Assert.True(wasInvoked); } [Fact] public void ExecuteBindingAsync_Faults_And_Traces_When_Inner_Faults() { // Arrange InvalidOperationException exception = new InvalidOperationException(); TaskCompletionSource tcs = new TaskCompletionSource(); tcs.TrySetException(exception); Mock mockBinder = new Mock() { CallBase = true }; mockBinder.Setup(b => b.ExecuteBindingAsync( It.IsAny(), It.IsAny())). Returns(tcs.Task); TestTraceWriter traceWriter = new TestTraceWriter(); HttpActionBindingTracer tracer = new HttpActionBindingTracer(mockBinder.Object, traceWriter); TraceRecord[] expectedTraces = new TraceRecord[] { new TraceRecord(_actionContext.Request, TraceCategories.ModelBindingCategory, TraceLevel.Info) { Kind = TraceKind.Begin }, new TraceRecord(_actionContext.Request, TraceCategories.ModelBindingCategory, TraceLevel.Error) { Kind = TraceKind.End } }; // Act Task task = tracer.ExecuteBindingAsync(_actionContext, CancellationToken.None); // Assert Exception thrown = Assert.Throws(() => task.Wait()); Assert.Equal(expectedTraces, traceWriter.Traces, new TraceRecordComparer()); Assert.Same(exception, thrown); Assert.Same(exception, traceWriter.Traces[1].Exception); } } }