a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
266 lines
10 KiB
C#
266 lines
10 KiB
C#
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
|
|
using System.Collections.Generic;
|
|
using System.Web.Mvc.Async;
|
|
using System.Web.Mvc.Async.Test;
|
|
using System.Web.Routing;
|
|
using Moq;
|
|
using Xunit;
|
|
using Assert = Microsoft.TestCommon.AssertEx;
|
|
|
|
namespace System.Web.Mvc.Test
|
|
{
|
|
public class AsyncControllerTest
|
|
{
|
|
[Fact]
|
|
public void ActionInvokerProperty()
|
|
{
|
|
// Arrange
|
|
EmptyController controller = new EmptyController();
|
|
|
|
// Act
|
|
IActionInvoker invoker = controller.ActionInvoker;
|
|
|
|
// Assert
|
|
Assert.IsType<AsyncControllerActionInvoker>(invoker);
|
|
}
|
|
|
|
[Fact]
|
|
public void AsyncManagerProperty()
|
|
{
|
|
// Arrange
|
|
EmptyController controller = new EmptyController();
|
|
|
|
// Act
|
|
AsyncManager asyncManager = controller.AsyncManager;
|
|
|
|
// Assert
|
|
Assert.NotNull(asyncManager);
|
|
}
|
|
|
|
[Fact]
|
|
public void Execute_ThrowsIfCalledMoreThanOnce()
|
|
{
|
|
// Arrange
|
|
IAsyncController controller = new EmptyController();
|
|
RequestContext requestContext = GetRequestContext("SomeAction");
|
|
|
|
// Act & assert
|
|
controller.BeginExecute(requestContext, null, null);
|
|
Assert.Throws<InvalidOperationException>(
|
|
delegate { controller.BeginExecute(requestContext, null, null); },
|
|
@"A single instance of controller 'System.Web.Mvc.Test.AsyncControllerTest+EmptyController' cannot be used to handle multiple requests. If a custom controller factory is in use, make sure that it creates a new instance of the controller for each request.");
|
|
}
|
|
|
|
[Fact]
|
|
public void Execute_ThrowsIfRequestContextIsNull()
|
|
{
|
|
// Arrange
|
|
IAsyncController controller = new EmptyController();
|
|
|
|
// Act & assert
|
|
Assert.ThrowsArgumentNull(
|
|
delegate { controller.BeginExecute(null, null, null); }, "requestContext");
|
|
}
|
|
|
|
[Fact]
|
|
public void ExecuteCore_Asynchronous_ActionFound()
|
|
{
|
|
// Arrange
|
|
MockAsyncResult innerAsyncResult = new MockAsyncResult();
|
|
|
|
Mock<IAsyncActionInvoker> mockActionInvoker = new Mock<IAsyncActionInvoker>();
|
|
mockActionInvoker.Setup(o => o.BeginInvokeAction(It.IsAny<ControllerContext>(), "SomeAction", It.IsAny<AsyncCallback>(), It.IsAny<object>())).Returns(innerAsyncResult);
|
|
mockActionInvoker.Setup(o => o.EndInvokeAction(innerAsyncResult)).Returns(true);
|
|
|
|
RequestContext requestContext = GetRequestContext("SomeAction");
|
|
EmptyController controller = new EmptyController()
|
|
{
|
|
ActionInvoker = mockActionInvoker.Object
|
|
};
|
|
|
|
// Act & assert
|
|
IAsyncResult outerAsyncResult = ((IAsyncController)controller).BeginExecute(requestContext, null, null);
|
|
Assert.False(controller.TempDataSaved);
|
|
|
|
((IAsyncController)controller).EndExecute(outerAsyncResult);
|
|
Assert.True(controller.TempDataSaved);
|
|
Assert.False(controller.HandleUnknownActionCalled);
|
|
}
|
|
|
|
[Fact]
|
|
public void ExecuteCore_Asynchronous_ActionNotFound()
|
|
{
|
|
// Arrange
|
|
MockAsyncResult innerAsyncResult = new MockAsyncResult();
|
|
|
|
Mock<IAsyncActionInvoker> mockActionInvoker = new Mock<IAsyncActionInvoker>();
|
|
mockActionInvoker.Setup(o => o.BeginInvokeAction(It.IsAny<ControllerContext>(), "SomeAction", It.IsAny<AsyncCallback>(), It.IsAny<object>())).Returns(innerAsyncResult);
|
|
mockActionInvoker.Setup(o => o.EndInvokeAction(innerAsyncResult)).Returns(false);
|
|
|
|
RequestContext requestContext = GetRequestContext("SomeAction");
|
|
EmptyController controller = new EmptyController()
|
|
{
|
|
ActionInvoker = mockActionInvoker.Object
|
|
};
|
|
|
|
// Act & assert
|
|
IAsyncResult outerAsyncResult = ((IAsyncController)controller).BeginExecute(requestContext, null, null);
|
|
Assert.False(controller.TempDataSaved);
|
|
|
|
((IAsyncController)controller).EndExecute(outerAsyncResult);
|
|
Assert.True(controller.TempDataSaved);
|
|
Assert.True(controller.HandleUnknownActionCalled);
|
|
}
|
|
|
|
[Fact]
|
|
public void ExecuteCore_Synchronous_ActionFound()
|
|
{
|
|
// Arrange
|
|
MockAsyncResult innerAsyncResult = new MockAsyncResult();
|
|
|
|
Mock<IActionInvoker> mockActionInvoker = new Mock<IActionInvoker>();
|
|
mockActionInvoker.Setup(o => o.InvokeAction(It.IsAny<ControllerContext>(), "SomeAction")).Returns(true);
|
|
|
|
RequestContext requestContext = GetRequestContext("SomeAction");
|
|
EmptyController controller = new EmptyController()
|
|
{
|
|
ActionInvoker = mockActionInvoker.Object
|
|
};
|
|
|
|
// Act & assert
|
|
IAsyncResult outerAsyncResult = ((IAsyncController)controller).BeginExecute(requestContext, null, null);
|
|
Assert.False(controller.TempDataSaved);
|
|
|
|
((IAsyncController)controller).EndExecute(outerAsyncResult);
|
|
Assert.True(controller.TempDataSaved);
|
|
Assert.False(controller.HandleUnknownActionCalled);
|
|
}
|
|
|
|
[Fact]
|
|
public void ExecuteCore_Synchronous_ActionNotFound()
|
|
{
|
|
// Arrange
|
|
MockAsyncResult innerAsyncResult = new MockAsyncResult();
|
|
|
|
Mock<IActionInvoker> mockActionInvoker = new Mock<IActionInvoker>();
|
|
mockActionInvoker.Setup(o => o.InvokeAction(It.IsAny<ControllerContext>(), "SomeAction")).Returns(false);
|
|
|
|
RequestContext requestContext = GetRequestContext("SomeAction");
|
|
EmptyController controller = new EmptyController()
|
|
{
|
|
ActionInvoker = mockActionInvoker.Object
|
|
};
|
|
|
|
// Act & assert
|
|
IAsyncResult outerAsyncResult = ((IAsyncController)controller).BeginExecute(requestContext, null, null);
|
|
Assert.False(controller.TempDataSaved);
|
|
|
|
((IAsyncController)controller).EndExecute(outerAsyncResult);
|
|
Assert.True(controller.TempDataSaved);
|
|
Assert.True(controller.HandleUnknownActionCalled);
|
|
}
|
|
|
|
[Fact]
|
|
public void ExecuteCore_SavesTempDataOnException()
|
|
{
|
|
// Arrange
|
|
Mock<IAsyncActionInvoker> mockActionInvoker = new Mock<IAsyncActionInvoker>();
|
|
mockActionInvoker
|
|
.Setup(o => o.BeginInvokeAction(It.IsAny<ControllerContext>(), "SomeAction", It.IsAny<AsyncCallback>(), It.IsAny<object>()))
|
|
.Throws(new Exception("Some exception text."));
|
|
|
|
RequestContext requestContext = GetRequestContext("SomeAction");
|
|
EmptyController controller = new EmptyController()
|
|
{
|
|
ActionInvoker = mockActionInvoker.Object
|
|
};
|
|
|
|
// Act & assert
|
|
Assert.Throws<Exception>(
|
|
delegate { ((IAsyncController)controller).BeginExecute(requestContext, null, null); },
|
|
@"Some exception text.");
|
|
Assert.True(controller.TempDataSaved);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateActionInvokerCallsIntoResolverInstance()
|
|
{
|
|
// Controller uses an IDependencyResolver to create an IActionInvoker.
|
|
var controller = new EmptyController();
|
|
Mock<IDependencyResolver> resolverMock = new Mock<IDependencyResolver>();
|
|
Mock<IAsyncActionInvoker> actionInvokerMock = new Mock<IAsyncActionInvoker>();
|
|
resolverMock.Setup(r => r.GetService(typeof(IAsyncActionInvoker))).Returns(actionInvokerMock.Object);
|
|
controller.Resolver = resolverMock.Object;
|
|
|
|
var ai = controller.CreateActionInvoker();
|
|
|
|
resolverMock.Verify(r => r.GetService(typeof(IAsyncActionInvoker)), Times.Once());
|
|
Assert.Same(actionInvokerMock.Object, ai);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateActionInvokerCallsIntoResolverInstanceAndCreatesANewOneIfNecessary()
|
|
{
|
|
// If IDependencyResolver is set, but empty, falls back and still creates.
|
|
var controller = new EmptyController();
|
|
Mock<IDependencyResolver> resolverMock = new Mock<IDependencyResolver>();
|
|
resolverMock.Setup(r => r.GetService(typeof(IAsyncActionInvoker))).Returns(null);
|
|
resolverMock.Setup(r => r.GetService(typeof(IActionInvoker))).Returns(null);
|
|
controller.Resolver = resolverMock.Object;
|
|
|
|
var ai = controller.CreateActionInvoker();
|
|
|
|
resolverMock.Verify(r => r.GetService(typeof(IAsyncActionInvoker)), Times.Once());
|
|
resolverMock.Verify(r => r.GetService(typeof(IActionInvoker)), Times.Once());
|
|
Assert.NotNull(ai);
|
|
}
|
|
|
|
|
|
private static RequestContext GetRequestContext(string actionName)
|
|
{
|
|
Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
|
|
RouteData routeData = new RouteData();
|
|
routeData.Values["action"] = actionName;
|
|
|
|
return new RequestContext(mockHttpContext.Object, routeData);
|
|
}
|
|
|
|
private class EmptyController : AsyncController
|
|
{
|
|
public bool TempDataSaved;
|
|
public bool HandleUnknownActionCalled;
|
|
|
|
protected override ITempDataProvider CreateTempDataProvider()
|
|
{
|
|
return new DummyTempDataProvider();
|
|
}
|
|
|
|
protected override void HandleUnknownAction(string actionName)
|
|
{
|
|
HandleUnknownActionCalled = true;
|
|
}
|
|
|
|
// Test can expose protected method as public.
|
|
public new IActionInvoker CreateActionInvoker()
|
|
{
|
|
return base.CreateActionInvoker();
|
|
}
|
|
|
|
|
|
private class DummyTempDataProvider : ITempDataProvider
|
|
{
|
|
public IDictionary<string, object> LoadTempData(ControllerContext controllerContext)
|
|
{
|
|
return new TempDataDictionary();
|
|
}
|
|
|
|
public void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values)
|
|
{
|
|
((EmptyController)controllerContext.Controller).TempDataSaved = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|