// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information. using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using System.Web.Http.Controllers; using System.Web.Http.Filters; using Moq; using Xunit; using Assert = Microsoft.TestCommon.AssertEx; namespace System.Web.Http.Tracing.Tracers { public class HttpActionDescriptorTracerTest { // This test verifies only one kind of filter is wrapped, proving // the static FilterTracer.CreateFilterTracer was called from GetFilterPipeline. // Deeper testing of FilterTracer.CreateFilterTracer is in FilterTracerTest. [Fact] public void GetFilterPipeline_Returns_Wrapped_Filters() { // Arrange Mock mockFilter = new Mock(); FilterInfo filter = new FilterInfo(mockFilter.Object, FilterScope.Global); Collection filterCollection = new Collection(new FilterInfo[] { filter }); Mock mockActionDescriptor = new Mock() { CallBase = true }; mockActionDescriptor.Setup(a => a.ActionName).Returns("test"); mockActionDescriptor.Setup(a => a.GetFilterPipeline()).Returns(filterCollection); HttpControllerContext controllerContext = ContextUtil.CreateControllerContext(); controllerContext.ControllerDescriptor = new HttpControllerDescriptor(controllerContext.Configuration, "test", typeof(ApiController)); HttpActionDescriptorTracer tracer = new HttpActionDescriptorTracer(controllerContext, mockActionDescriptor.Object, new TestTraceWriter()); // Act Collection wrappedFilterCollection = tracer.GetFilterPipeline(); // Assert Assert.IsType(wrappedFilterCollection[0].Instance); } // This test verifies only one kind of filter is wrapped, proving // the static FilterTracer.CreateFilterTracer was called from GetFilterPipeline. // Deeper testing of FilterTracer.CreateFilterTracer is in FilterTracerTest. [Fact] public void GetFilters_Returns_Wrapped_IFilters() { // Arrange Mock mockFilter = new Mock(); Collection filters = new Collection(new IFilter[] { mockFilter.Object }); Mock mockActionDescriptor = new Mock() { CallBase = true }; mockActionDescriptor.Setup(a => a.ActionName).Returns("test"); mockActionDescriptor.Setup(a => a.GetFilters()).Returns(filters); HttpControllerContext controllerContext = ContextUtil.CreateControllerContext(); controllerContext.ControllerDescriptor = new HttpControllerDescriptor(controllerContext.Configuration, "test", typeof(ApiController)); HttpActionDescriptorTracer tracer = new HttpActionDescriptorTracer(controllerContext, mockActionDescriptor.Object, new TestTraceWriter()); // Act IFilter[] wrappedFilters = tracer.GetFilters().ToArray(); // Assert Assert.IsType(wrappedFilters[0]); } [Fact] public void ExecuteAsync_Invokes_Inner_ExecuteAsync() { // Arrange bool executeCalled = false; Mock mockActionDescriptor = new Mock() { CallBase = true }; mockActionDescriptor.Setup(a => a.ActionName).Returns("test"); mockActionDescriptor.Setup( a => a.ExecuteAsync(It.IsAny(), It.IsAny>())).Callback(() => executeCalled = true); HttpControllerContext controllerContext = ContextUtil.CreateControllerContext(); controllerContext.ControllerDescriptor = new HttpControllerDescriptor(controllerContext.Configuration, "test", typeof(ApiController)); IDictionary arguments = new Dictionary(); HttpActionDescriptorTracer tracer = new HttpActionDescriptorTracer(controllerContext, mockActionDescriptor.Object, new TestTraceWriter()); // Act tracer.ExecuteAsync(controllerContext, arguments); // Assert Assert.True(executeCalled); } [Fact] public void ExecuteAsync_Traces() { // Arrange Mock mockActionDescriptor = new Mock() { CallBase = true }; mockActionDescriptor.Setup(a => a.ActionName).Returns("test"); mockActionDescriptor.Setup(a => a.ExecuteAsync(It.IsAny(), It.IsAny>())) .Returns(TaskHelpers.FromResult(null)); HttpControllerContext controllerContext = ContextUtil.CreateControllerContext(); controllerContext.ControllerDescriptor = new HttpControllerDescriptor(controllerContext.Configuration, "test", typeof(ApiController)); IDictionary arguments = new Dictionary(); TestTraceWriter traceWriter = new TestTraceWriter(); HttpActionDescriptorTracer tracer = new HttpActionDescriptorTracer(controllerContext, mockActionDescriptor.Object, traceWriter); TraceRecord[] expectedTraces = new TraceRecord[] { new TraceRecord(controllerContext.Request, TraceCategories.ActionCategory, TraceLevel.Info) { Kind = TraceKind.Begin, Operation = "ExecuteAsync" }, new TraceRecord(controllerContext.Request, TraceCategories.ActionCategory, TraceLevel.Info) { Kind = TraceKind.End } }; // Act var result = tracer.ExecuteAsync(controllerContext, arguments); // Assert result.WaitUntilCompleted(); Assert.Equal(expectedTraces, traceWriter.Traces, new TraceRecordComparer()); } [Fact] public void ExecuteAsync_Throws_What_Inner_Throws_And_Traces() { // Arrange Mock mockActionDescriptor = new Mock() { CallBase = true }; InvalidOperationException exception = new InvalidOperationException("test"); mockActionDescriptor.Setup( a => a.ExecuteAsync(It.IsAny(), It.IsAny>())).Throws(exception); mockActionDescriptor.Setup(a => a.ActionName).Returns("test"); HttpControllerContext controllerContext = ContextUtil.CreateControllerContext(); controllerContext.ControllerDescriptor = new HttpControllerDescriptor(controllerContext.Configuration, "test", typeof(ApiController)); IDictionary arguments = new Dictionary(); TestTraceWriter traceWriter = new TestTraceWriter(); HttpActionDescriptorTracer tracer = new HttpActionDescriptorTracer(controllerContext, mockActionDescriptor.Object, traceWriter); TraceRecord[] expectedTraces = new TraceRecord[] { new TraceRecord(controllerContext.Request, TraceCategories.ActionCategory, TraceLevel.Info) { Kind = TraceKind.Begin }, new TraceRecord(controllerContext.Request, TraceCategories.ActionCategory, TraceLevel.Error) { Kind = TraceKind.End } }; // Act & Assert Assert.Throws(() => tracer.ExecuteAsync(controllerContext, arguments)); // Assert Assert.Equal(expectedTraces, traceWriter.Traces, new TraceRecordComparer()); Assert.Same(exception, traceWriter.Traces[1].Exception); } } }