From a3a8bdf6df8a4b8eb42175f286271986446b9a14 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Sun, 25 Mar 2018 17:17:49 +0200 Subject: [PATCH] Started to migrate the tests. --- Dockerfile | 3 +- .../EnrichWithSchemaIdCommandMiddleware.cs | 2 + .../Pipeline/EnforceHttpsMiddleware.cs | 4 +- src/Squidex/Squidex.csproj | 5 + tests/RunCoverage.ps1 | 12 + .../Pipeline/ActionContextLogAppenderTests.cs | 86 ------- .../Pipeline/ApiAuthorizeAttributeTests.cs | 32 --- tests/Squidex.Tests/Pipeline/ApiCostTests.cs | 104 --------- .../ApiExceptionFilterAttributeTests.cs | 101 -------- tests/Squidex.Tests/Pipeline/AppApiTests.cs | 90 ------- .../Pipeline/AppPermissionAttributeTests.cs | 130 ----------- .../ETagCommandMiddlewareTests.cs | 49 +++- .../EnrichWithActorCommandMiddlewareTests.cs | 94 +++++--- .../EnrichWithAppIdCommandMiddlewareTests.cs | 106 +++++++-- ...nrichWithSchemaIdCommandMiddlewareTests.cs | 220 +++++++++++++----- .../Pipeline/EnforceHttpsMiddlewareTests.cs | 82 ++++--- .../Pipeline/FileCallbackResultTests.cs | 70 ------ .../Pipeline/Swagger/SwaggerHelperTests.cs | 120 ---------- tests/Squidex.Tests/Squidex.Tests.csproj | 44 ++-- 19 files changed, 420 insertions(+), 934 deletions(-) delete mode 100644 tests/Squidex.Tests/Pipeline/ActionContextLogAppenderTests.cs delete mode 100644 tests/Squidex.Tests/Pipeline/ApiAuthorizeAttributeTests.cs delete mode 100644 tests/Squidex.Tests/Pipeline/ApiCostTests.cs delete mode 100644 tests/Squidex.Tests/Pipeline/ApiExceptionFilterAttributeTests.cs delete mode 100644 tests/Squidex.Tests/Pipeline/AppApiTests.cs delete mode 100644 tests/Squidex.Tests/Pipeline/AppPermissionAttributeTests.cs delete mode 100644 tests/Squidex.Tests/Pipeline/FileCallbackResultTests.cs delete mode 100644 tests/Squidex.Tests/Pipeline/Swagger/SwaggerHelperTests.cs diff --git a/Dockerfile b/Dockerfile index 3895f5fcf..de1b25aee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,8 @@ RUN dotnet restore \ && dotnet test tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj \ && dotnet test tests/Squidex.Domain.Apps.Core.Tests/Squidex.Domain.Apps.Core.Tests.csproj \ && dotnet test tests/Squidex.Domain.Apps.Entities.Tests/Squidex.Domain.Apps.Entities.Tests.csproj \ - && dotnet test tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj + && dotnet test tests/Squidex.Domain.Users.Tests/Squidex.Domain.Users.Tests.csproj \ + && dotnet test tests/Squidex.Tests/Squidex.Tests.csproj # Publish RUN dotnet publish src/Squidex/Squidex.csproj --output /out/ --configuration Release diff --git a/src/Squidex/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs b/src/Squidex/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs index 40b660c8a..e385b6025 100644 --- a/src/Squidex/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs +++ b/src/Squidex/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs @@ -32,6 +32,8 @@ namespace Squidex.Pipeline.CommandMiddlewares if (actionContextAccessor.ActionContext == null) { await next(); + + return; } if (context.Command is ISchemaCommand schemaCommand && schemaCommand.SchemaId == null) diff --git a/src/Squidex/Pipeline/EnforceHttpsMiddleware.cs b/src/Squidex/Pipeline/EnforceHttpsMiddleware.cs index 556f90fb8..5cbc5efbe 100644 --- a/src/Squidex/Pipeline/EnforceHttpsMiddleware.cs +++ b/src/Squidex/Pipeline/EnforceHttpsMiddleware.cs @@ -36,9 +36,9 @@ namespace Squidex.Pipeline if (!string.Equals(context.Request.Scheme, "https", StringComparison.OrdinalIgnoreCase)) { - var newUrl = string.Concat("https://", hostName, context.Request.Path); + var newUrl = string.Concat("https://", hostName, context.Request.Path, context.Request.QueryString); - context.Response.Redirect(newUrl + context.Request.QueryString, true); + context.Response.Redirect(newUrl, true); } else { diff --git a/src/Squidex/Squidex.csproj b/src/Squidex/Squidex.csproj index e898de24f..773334ee1 100644 --- a/src/Squidex/Squidex.csproj +++ b/src/Squidex/Squidex.csproj @@ -11,6 +11,11 @@ true + + full + True + + diff --git a/tests/RunCoverage.ps1 b/tests/RunCoverage.ps1 index 6affb6d9e..3b46fc1dc 100644 --- a/tests/RunCoverage.ps1 +++ b/tests/RunCoverage.ps1 @@ -3,6 +3,7 @@ Param( [switch]$appsCore, [switch]$appsEntities, [switch]$users, + [switch]$web, [switch]$all ) @@ -64,6 +65,17 @@ if ($all -Or $users) { -oldStyle } +if ($all -Or $web) { + &"$folderHome\.nuget\packages\OpenCover\4.6.519\tools\OpenCover.Console.exe" ` + -register:user ` + -target:"C:\Program Files\dotnet\dotnet.exe" ` + -targetargs:"test $folderWorking\Squidex.Tests\Squidex.Tests.csproj" ` + -filter:"+[Squidex]Squidex.Pipeline*" ` + -skipautoprops ` + -output:"$folderWorking\$folderReports\Web.xml" ` + -oldStyle +} + &"$folderHome\.nuget\packages\ReportGenerator\3.1.1\tools\ReportGenerator.exe" ` -reports:"$folderWorking\$folderReports\*.xml" ` -targetdir:"$folderWorking\$folderReports\Output" \ No newline at end of file diff --git a/tests/Squidex.Tests/Pipeline/ActionContextLogAppenderTests.cs b/tests/Squidex.Tests/Pipeline/ActionContextLogAppenderTests.cs deleted file mode 100644 index 04dbaf26e..000000000 --- a/tests/Squidex.Tests/Pipeline/ActionContextLogAppenderTests.cs +++ /dev/null @@ -1,86 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using System.Collections.Generic; -using FakeItEasy; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Abstractions; -using Microsoft.AspNetCore.Mvc.Infrastructure; -using Microsoft.AspNetCore.Routing; -using Moq; -using Squidex.Infrastructure.Log; -using Squidex.Pipeline; -using Xunit; - -namespace Squidex.Tests.Pipeline -{ - public class ActionContextLogAppenderTests - { - private readonly Mock actionContextAccessor = new Mock(); - private readonly Mock httpContextMock = new Mock(); - private readonly ActionDescriptor actionDescriptor = new ActionDescriptor(); - private readonly RouteData routeData = new RouteData(); - private readonly Guid requestId = Guid.NewGuid(); - private readonly IDictionary items = new Dictionary(); - private readonly IObjectWriter writer = A.Fake(); - private readonly HttpRequest request = A.Fake(); - private ActionContextLogAppender sut; - private ActionContext actionContext; - - [Fact] - public void Append_should_get_requestId() - { - items.Add(nameof(requestId), requestId); - SetupTest(); - - A.CallTo(() => writer.WriteObject(It.IsAny(), It.IsAny>())).Returns(writer); - sut.Append(writer); - - Assert.NotNull(writer); - } - - [Fact] - public void Append_should_put_requestId() - { - SetupTest(); - - sut.Append(writer); - } - - [Fact] - public void Append_should_return_if_no_actionContext() - { - sut = new ActionContextLogAppender(actionContextAccessor.Object); - - sut.Append(writer); - } - - [Fact] - public void Append_should_return_if_no_httpContext_method() - { - A.CallTo(() => request.Method).Returns(string.Empty); - httpContextMock.Setup(x => x.Request).Returns(request); - actionContext = new ActionContext(httpContextMock.Object, routeData, actionDescriptor); - actionContextAccessor.Setup(x => x.ActionContext).Returns(actionContext); - sut = new ActionContextLogAppender(actionContextAccessor.Object); - - sut.Append(writer); - } - - private void SetupTest() - { - A.CallTo(() => request.Method).Returns("Get"); - httpContextMock.Setup(x => x.Items).Returns(items); - httpContextMock.Setup(x => x.Request).Returns(request); - actionContext = new ActionContext(httpContextMock.Object, routeData, actionDescriptor); - actionContextAccessor.Setup(x => x.ActionContext).Returns(actionContext); - sut = new ActionContextLogAppender(actionContextAccessor.Object); - } - } -} diff --git a/tests/Squidex.Tests/Pipeline/ApiAuthorizeAttributeTests.cs b/tests/Squidex.Tests/Pipeline/ApiAuthorizeAttributeTests.cs deleted file mode 100644 index c37d6c309..000000000 --- a/tests/Squidex.Tests/Pipeline/ApiAuthorizeAttributeTests.cs +++ /dev/null @@ -1,32 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using IdentityServer4.AccessTokenValidation; -using Squidex.Pipeline; -using Squidex.Shared.Identity; -using Xunit; - -namespace Squidex.Tests.Pipeline -{ - public class ApiAuthorizeAttributeTests - { - private ApiAuthorizeAttribute sut = new ApiAuthorizeAttribute(); - - [Fact] - public void AuthenticationSchemes_should_be_default() - { - Assert.Equal(IdentityServerAuthenticationDefaults.AuthenticationScheme, sut.AuthenticationSchemes); - } - - [Fact] - public void MustBeAdmin_Test() - { - sut = new MustBeAdministratorAttribute(); - Assert.Equal(SquidexRoles.Administrator, sut.Roles); - } - } -} diff --git a/tests/Squidex.Tests/Pipeline/ApiCostTests.cs b/tests/Squidex.Tests/Pipeline/ApiCostTests.cs deleted file mode 100644 index 173fff69b..000000000 --- a/tests/Squidex.Tests/Pipeline/ApiCostTests.cs +++ /dev/null @@ -1,104 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using FakeItEasy; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Abstractions; -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.AspNetCore.Mvc.Infrastructure; -using Microsoft.AspNetCore.Routing; -using Moq; -using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Domain.Apps.Entities.Apps.Services; -using Squidex.Infrastructure.UsageTracking; -using Squidex.Pipeline; -using Xunit; -using static Squidex.Pipeline.AppApiFilter; - -namespace Squidex.Tests.Pipeline -{ - public class ApiCostTests - { - private readonly Mock actionContextAccessor = new Mock(); - private readonly RouteData routeData = new RouteData(); - private readonly ActionDescriptor actionDescriptor = new ActionDescriptor(); - private readonly IAppPlansProvider appPlanProvider = A.Fake(); - private readonly IUsageTracker usageTracker = A.Fake(); - private readonly long usage = 1; - private readonly Mock httpContextMock = new Mock(); - private readonly IFeatureCollection features = new FeatureCollection(); - private readonly IAppEntity appEntity = A.Fake(); - private readonly IAppFeature appFeature = A.Fake(); - private readonly IAppLimitsPlan appPlan = A.Fake(); - private readonly Guid appId = Guid.NewGuid(); - private ActionExecutingContext context; - private ActionExecutionDelegate next; - private ApiCostsFilter sut; - - public ApiCostTests() - { - var actionContext = new ActionContext(httpContextMock.Object, routeData, actionDescriptor); - actionContextAccessor.Setup(x => x.ActionContext).Returns(actionContext); - context = new ActionExecutingContext(actionContext, new List(), new Dictionary(), null); - context.Filters.Add(new ServiceFilterAttribute(typeof(ApiCostsFilter))); - - A.CallTo(() => appEntity.Id).Returns(appId); - A.CallTo(() => appFeature.App).Returns(appEntity); - - features.Set(new AppFeature(appEntity)); - httpContextMock.Setup(x => x.Features).Returns(features); - A.CallTo(() => usageTracker.GetMonthlyCalls(appId.ToString(), DateTime.Today)) - .Returns(usage); - } - - [Fact] - public async Task Should_return_429_status_code_if_max_calls_over_limit() - { - SetupSystem(2, 1); - - next = new ActionExecutionDelegate(async () => - { - return null; - }); - await sut.OnActionExecutionAsync(context, next); - - Assert.Equal(new StatusCodeResult(429).StatusCode, (context.Result as StatusCodeResult).StatusCode); - } - - [Fact] - public async Task Should_call_next_if_weight_is_0() - { - SetupSystem(0, 1); - - var result = 0; - next = new ActionExecutionDelegate(async () => - { - result = 1; - return null; - }); - await sut.OnActionExecutionAsync(context, next); - - Assert.Equal(1, result); - } - - private ApiCostsFilter SetupSystem(double weight, long maxCalls) - { - A.CallTo(() => appPlan.MaxApiCalls).Returns(maxCalls); - A.CallTo(() => appPlanProvider.GetPlanForApp(appFeature.App)).Returns(appPlan); - - sut = new ApiCostsFilter(appPlanProvider, usageTracker); - sut.FilterDefinition = new ApiCostsAttribute(weight); - - return sut; - } - } -} diff --git a/tests/Squidex.Tests/Pipeline/ApiExceptionFilterAttributeTests.cs b/tests/Squidex.Tests/Pipeline/ApiExceptionFilterAttributeTests.cs deleted file mode 100644 index 5f4e48653..000000000 --- a/tests/Squidex.Tests/Pipeline/ApiExceptionFilterAttributeTests.cs +++ /dev/null @@ -1,101 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System.Collections.Generic; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Abstractions; -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.AspNetCore.Routing; -using Moq; -using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Infrastructure; -using Squidex.Pipeline; -using Xunit; - -namespace Squidex.Tests.Pipeline -{ - public class ApiExceptionFilterAttributeTests - { - private readonly Mock httpContextMock = new Mock(); - private readonly ActionDescriptor actionDescriptor = new ActionDescriptor(); - private readonly RouteData routeData = new RouteData(); - private readonly ApiExceptionFilterAttribute sut = new ApiExceptionFilterAttribute(); - private readonly ExceptionContext context; - private ActionContext actionContext; - - public ApiExceptionFilterAttributeTests() - { - actionContext = new ActionContext(httpContextMock.Object, routeData, actionDescriptor); - context = new ExceptionContext(actionContext, new List()); - } - - [Fact] - public void Domain_Object_Not_Found_Exception_should_be_caught() - { - context.Exception = new DomainObjectNotFoundException("id", typeof(IAppEntity)); - - sut.OnException(context); - - Assert.Equal(new NotFoundResult().StatusCode, (context.Result as NotFoundResult).StatusCode); - } - - [Fact] - public void Domain_Object_Version_Exception_should_be_caught() - { - context.Exception = new DomainObjectVersionException("id", typeof(IAppEntity), 0, 1); - - sut.OnException(context); - var exptectedResult = BuildErrorResult(412, new ErrorDto { Message = context.Exception.Message }); - - Assert.Equal(exptectedResult.StatusCode, (context.Result as ObjectResult).StatusCode); - Assert.StartsWith("Requested version", ((context.Result as ObjectResult).Value as ErrorDto).Message); - } - - [Fact] - public void Domain_Exception_should_be_caught() - { - context.Exception = new DomainException("Domain exception caught."); - - sut.OnException(context); - var exptectedResult = BuildErrorResult(400, new ErrorDto { Message = context.Exception.Message }); - - Assert.Equal(exptectedResult.StatusCode, (context.Result as ObjectResult).StatusCode); - Assert.Equal("Domain exception caught.", ((context.Result as ObjectResult).Value as ErrorDto).Message); - } - - [Fact] - public void Domain_Forbidden_Exception_should_be_caught() - { - context.Exception = new DomainForbiddenException("Domain forbidden exception caught."); - - sut.OnException(context); - var exptectedResult = BuildErrorResult(403, new ErrorDto { Message = context.Exception.Message }); - - Assert.Equal(exptectedResult.StatusCode, (context.Result as ObjectResult).StatusCode); - Assert.Equal("Domain forbidden exception caught.", ((context.Result as ObjectResult).Value as ErrorDto).Message); - } - - [Fact] - public void Validation_Exception_should_be_caught() - { - var errors = new ValidationError("Validation error 1", new string[] { "prop1" }); - context.Exception = new ValidationException("Validation exception caught.", errors); - - sut.OnException(context); - var exptectedResult = BuildErrorResult(400, new ErrorDto { Message = context.Exception.Message }); - - Assert.Equal(exptectedResult.StatusCode, (context.Result as ObjectResult).StatusCode); - Assert.Equal("Validation exception caught: Validation error 1.", ((context.Result as ObjectResult).Value as ErrorDto).Message); - } - - private ObjectResult BuildErrorResult(int code, ErrorDto error) - { - return new ObjectResult(error) { StatusCode = code }; - } - } -} diff --git a/tests/Squidex.Tests/Pipeline/AppApiTests.cs b/tests/Squidex.Tests/Pipeline/AppApiTests.cs deleted file mode 100644 index 560d0a757..000000000 --- a/tests/Squidex.Tests/Pipeline/AppApiTests.cs +++ /dev/null @@ -1,90 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using System.Collections.Generic; -using System.Net; -using System.Threading.Tasks; -using FakeItEasy; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Abstractions; -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.AspNetCore.Mvc.Infrastructure; -using Microsoft.AspNetCore.Routing; -using Moq; -using Squidex.Domain.Apps.Entities; -using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Domain.Apps.Entities.Apps.Services; -using Squidex.Infrastructure.UsageTracking; -using Squidex.Pipeline; -using Xunit; - -namespace Squidex.Tests.Pipeline -{ - public class AppApiTests - { - private readonly Mock actionContextAccessor = new Mock(); - private readonly RouteData routeData = new RouteData(); - private readonly ActionDescriptor actionDescriptor = new ActionDescriptor(); - private readonly IAppPlansProvider appPlanProvider = A.Fake(); - private readonly IUsageTracker usageTracker = A.Fake(); - private readonly long usage = 1; - private readonly Mock httpContextMock = new Mock(); - private readonly IFeatureCollection features = new FeatureCollection(); - private readonly IAppEntity appEntity = A.Fake(); - private readonly IAppFeature appFeature = A.Fake(); - private readonly IAppProvider appProvider = A.Fake(); - private readonly Guid appId = Guid.NewGuid(); - private readonly ActionExecutingContext context; - private readonly AppApiFilter sut; - private ActionExecutionDelegate next; - - public AppApiTests() - { - var actionContext = new ActionContext(httpContextMock.Object, routeData, actionDescriptor); - actionContextAccessor.Setup(x => x.ActionContext).Returns(actionContext); - context = new ActionExecutingContext(actionContext, new List(), new Dictionary(), null); - context.Filters.Add(new AppApiAttribute()); - context.RouteData.Values.Add("app", "appName"); - - httpContextMock.Setup(x => x.Features).Returns(features); - A.CallTo(() => appProvider.GetAppAsync("appName")).Returns(appEntity); - - sut = new AppApiFilter(appProvider); - } - - [Fact] - public async Task Should_set_features_if_app_found() - { - next = new ActionExecutionDelegate(async () => - { - return null; - }); - await sut.OnActionExecutionAsync(context, next); - - Assert.NotEmpty(context.HttpContext.Features); - } - - [Fact] - public async Task Should_return_not_found_result_if_app_not_found() - { - next = new ActionExecutionDelegate(async () => - { - return null; - }); - - A.CallTo(() => appProvider.GetAppAsync("appName")).Returns((IAppEntity)null); - await sut.OnActionExecutionAsync(context, next); - - var result = context.Result as NotFoundResult; - Assert.NotNull(result); - Assert.Equal((int)HttpStatusCode.NotFound, result.StatusCode); - } - } -} diff --git a/tests/Squidex.Tests/Pipeline/AppPermissionAttributeTests.cs b/tests/Squidex.Tests/Pipeline/AppPermissionAttributeTests.cs deleted file mode 100644 index e0a960e12..000000000 --- a/tests/Squidex.Tests/Pipeline/AppPermissionAttributeTests.cs +++ /dev/null @@ -1,130 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Net; -using System.Security.Claims; -using FakeItEasy; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Abstractions; -using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.AspNetCore.Mvc.Infrastructure; -using Microsoft.AspNetCore.Routing; -using Moq; -using Squidex.Domain.Apps.Core.Apps; -using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Infrastructure.Security; -using Squidex.Pipeline; -using Xunit; - -namespace Squidex.Tests.Pipeline -{ - public class AppPermissionAttributeTests - { - private readonly Mock httpContextMock = new Mock(); - private readonly Mock mockUser = new Mock(); - private readonly ActionDescriptor actionDescriptor = new ActionDescriptor(); - private readonly Mock actionContextAccessor = new Mock(); - private readonly IAppEntity appEntity = A.Fake(); - private readonly ClaimsIdentity identity = new ClaimsIdentity(); - private readonly AppClient client = new AppClient("clientId", "secret", AppClientPermission.Reader); - private readonly IAppFeature appFeature = A.Fake(); - private readonly IFeatureCollection features = new FeatureCollection(); - private readonly RouteData routeData = new RouteData(); - private readonly ActionExecutingContext context; - private ActionContext actionContext; - private Claim clientClaim; - private Claim subjectClaim; - private AppPermissionAttribute sut = new MustBeAppReaderAttribute(); - - public AppPermissionAttributeTests() - { - actionContext = new ActionContext(httpContextMock.Object, routeData, actionDescriptor); - actionContextAccessor.Setup(x => x.ActionContext).Returns(actionContext); - clientClaim = new Claim("client_id", $"test:clientId"); - subjectClaim = new Claim("sub", "user"); - - var clients = ImmutableDictionary.CreateBuilder(); - clients.Add("clientId", client); - var contributors = ImmutableDictionary.CreateBuilder(); - contributors.Add("user", AppContributorPermission.Owner); - - A.CallTo(() => appFeature.App).Returns(appEntity); - A.CallTo(() => appEntity.Clients).Returns(new AppClients(clients.ToImmutable())); - A.CallTo(() => appEntity.Contributors).Returns(new AppContributors(contributors.ToImmutable())); - features.Set(appFeature); - mockUser.Setup(x => x.Identities).Returns(new List { identity }); - - httpContextMock.Setup(x => x.Features).Returns(features); - httpContextMock.Setup(x => x.User).Returns(mockUser.Object); - - context = new ActionExecutingContext(actionContext, new List(), new Dictionary(), null); - context.Filters.Clear(); - sut = new MustBeAppDeveloperAttribute(); - } - - [Fact] - public void Null_Permission_Returns_Not_Found() - { - // Arrange - sut = new MustBeAppReaderAttribute(); - context.Filters.Add(sut); - mockUser.Setup(x => x.FindFirst(OpenIdClaims.Subject)).Returns((Claim)null); - clientClaim = new Claim("client_id", "test"); - mockUser.Setup(x => x.FindFirst(OpenIdClaims.ClientId)).Returns(clientClaim); - - // Act - sut.OnActionExecuting(context); - - // Assert - var result = context.Result as NotFoundResult; - Assert.NotNull(result); - Assert.Equal((int)HttpStatusCode.NotFound, result.StatusCode); - } - - [Fact] - public void Lower_Permission_Returns_Forbidden() - { - // Arrange - sut = new MustBeAppEditorAttribute(); - context.Filters.Add(sut); - mockUser.Setup(x => x.FindFirst(OpenIdClaims.Subject)).Returns((Claim)null); - mockUser.Setup(x => x.FindFirst(OpenIdClaims.ClientId)).Returns(clientClaim); - - // Act - sut.OnActionExecuting(context); - - // Assert - var result = context.Result as StatusCodeResult; - Assert.NotNull(result); - Assert.Equal((int)HttpStatusCode.Forbidden, result.StatusCode); - } - - [Fact] - public void Higher_Permission_Should_Get_All_Lesser_Permissions() - { - // Arrange - sut = new MustBeAppOwnerAttribute(); - context.Filters.Add(sut); - mockUser.Setup(x => x.FindFirst(OpenIdClaims.Subject)).Returns(subjectClaim); - - // Act - sut.OnActionExecuting(context); - - // Assert - var result = context.HttpContext.User.Identities.First()?.Claims; - Assert.NotNull(result); - Assert.NotEmpty(result); - Assert.Equal(Enum.GetNames(typeof(AppPermission)).Length, result.Count()); - } - } -} diff --git a/tests/Squidex.Tests/Pipeline/CommandMiddlewares/ETagCommandMiddlewareTests.cs b/tests/Squidex.Tests/Pipeline/CommandMiddlewares/ETagCommandMiddlewareTests.cs index dc57d19b8..eb8f56bb1 100644 --- a/tests/Squidex.Tests/Pipeline/CommandMiddlewares/ETagCommandMiddlewareTests.cs +++ b/tests/Squidex.Tests/Pipeline/CommandMiddlewares/ETagCommandMiddlewareTests.cs @@ -9,38 +9,65 @@ using System.Threading.Tasks; using FakeItEasy; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; -using Squidex.Domain.Apps.Entities.Assets.Commands; +using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Infrastructure.Commands; -using Squidex.Pipeline.CommandMiddlewares; using Xunit; -namespace Squidex.Tests.Pipeline.CommandMiddlewares +namespace Squidex.Pipeline.CommandMiddlewares { public class ETagCommandMiddlewareTests { private readonly IHttpContextAccessor httpContextAccessor = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); - private readonly IHeaderDictionary headers = new HeaderDictionary { { "If-Match", "1" } }; - private readonly UpdateAsset command = new UpdateAsset(); - private readonly EntitySavedResult entitySavedResult = new EntitySavedResult(1); + private readonly IHeaderDictionary requestHeaders = new HeaderDictionary(); private readonly ETagCommandMiddleware sut; public ETagCommandMiddlewareTests() { - A.CallTo(() => httpContextAccessor.HttpContext.Request.Headers).Returns(headers); + A.CallTo(() => httpContextAccessor.HttpContext.Request.Headers) + .Returns(requestHeaders); + sut = new ETagCommandMiddleware(httpContextAccessor); } [Fact] - public async Task Should_add_etag_header_and_expected_version() + public async Task Should_do_nothing_when_context_is_null() + { + A.CallTo(() => httpContextAccessor.HttpContext) + .Returns(null); + + var command = new CreateContent(); + var context = new CommandContext(command, commandBus); + + await sut.HandleAsync(context); + + Assert.Null(command.Actor); + } + + [Fact] + public async Task Should_add_expected_version_to_command() { + requestHeaders["If-Match"] = "13"; + + var command = new CreateContent(); + var context = new CommandContext(command, commandBus); + + await sut.HandleAsync(context); + + Assert.Equal(13, context.Command.ExpectedVersion); + } + + [Fact] + public async Task Should_add_etag_header_to_response() + { + var command = new CreateContent(); var context = new CommandContext(command, commandBus); - context.Complete(entitySavedResult); + + context.Complete(new EntitySavedResult(17)); await sut.HandleAsync(context); - Assert.Equal(1, context.Command.ExpectedVersion); - Assert.Equal(new StringValues("1"), httpContextAccessor.HttpContext.Response.Headers["ETag"]); + Assert.Equal(new StringValues("17"), httpContextAccessor.HttpContext.Response.Headers["ETag"]); } } } diff --git a/tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithActorCommandMiddlewareTests.cs b/tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithActorCommandMiddlewareTests.cs index 78e2e45c9..ce0ce1d9a 100644 --- a/tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithActorCommandMiddlewareTests.cs +++ b/tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithActorCommandMiddlewareTests.cs @@ -5,81 +5,105 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System; using System.Security; using System.Security.Claims; using System.Threading.Tasks; using FakeItEasy; using Microsoft.AspNetCore.Http; using Squidex.Domain.Apps.Entities.Contents.Commands; +using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Security; -using Squidex.Pipeline.CommandMiddlewares; using Xunit; -namespace Squidex.Tests.Pipeline.CommandMiddlewares +namespace Squidex.Pipeline.CommandMiddlewares { public class EnrichWithActorCommandMiddlewareTests { private readonly IHttpContextAccessor httpContextAccessor = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); - private readonly CreateContent command = new CreateContent { Actor = null }; + private readonly HttpContext httpContext = new DefaultHttpContext(); + private readonly EnrichWithActorCommandMiddleware sut; + + public EnrichWithActorCommandMiddlewareTests() + { + A.CallTo(() => httpContextAccessor.HttpContext) + .Returns(httpContext); + + sut = new EnrichWithActorCommandMiddleware(httpContextAccessor); + } + + [Fact] + public async Task Should_throw_security_exception_when_no_subject_or_client_is_found() + { + var command = new CreateContent(); + var context = new CommandContext(command, commandBus); + + await Assert.ThrowsAsync(() => sut.HandleAsync(context)); + } + + [Fact] + public async Task Should_do_nothing_when_context_is_null() + { + A.CallTo(() => httpContextAccessor.HttpContext) + .Returns(null); + + var command = new CreateContent(); + var context = new CommandContext(command, commandBus); + + await sut.HandleAsync(context); + + Assert.Null(command.Actor); + } [Fact] - public async Task HandleAsync_should_throw_security_exception() + public async Task Should_assign_actor_from_subject() { + httpContext.User = CreatePrincipal(OpenIdClaims.Subject, "me"); + + var command = new CreateContent(); var context = new CommandContext(command, commandBus); - var sut = SetupSystem(null, out string claimValue); - await Assert.ThrowsAsync(() => - { - return sut.HandleAsync(context); - }); + await sut.HandleAsync(context); + + Assert.Equal(new RefToken("subject", "me"), command.Actor); } [Fact] - public async Task HandleAsync_should_find_actor_from_subject() + public async Task Should_assign_actor_from_client() { + httpContext.User = CreatePrincipal(OpenIdClaims.ClientId, "my-client"); + + var command = new CreateContent(); var context = new CommandContext(command, commandBus); - var sut = SetupSystem("subject", out string claimValue); await sut.HandleAsync(context); - Assert.Equal(claimValue, command.Actor.Identifier); + Assert.Equal(new RefToken("client", "my-client"), command.Actor); } [Fact] - public async Task HandleAsync_should_find_actor_from_client() + public async Task Should_not_override_actor() { + httpContext.User = CreatePrincipal(OpenIdClaims.ClientId, "my-client"); + + var command = new CreateContent { Actor = new RefToken("subject", "me") }; var context = new CommandContext(command, commandBus); - var sut = SetupSystem("client", out string claimValue); await sut.HandleAsync(context); - Assert.Equal(claimValue, command.Actor.Identifier); + Assert.Equal(new RefToken("subject", "me"), command.Actor); } - private EnrichWithActorCommandMiddleware SetupSystem(string refTokenType, out string claimValue) + private static ClaimsPrincipal CreatePrincipal(string claimType, string claimValue) { - Claim actorClaim; - claimValue = Guid.NewGuid().ToString(); - var user = new ClaimsPrincipal(); + var claimsPrincipal = new ClaimsPrincipal(); var claimsIdentity = new ClaimsIdentity(); - switch (refTokenType) - { - case "subject": - actorClaim = new Claim(OpenIdClaims.Subject, claimValue); - claimsIdentity.AddClaim(actorClaim); - break; - case "client": - actorClaim = new Claim(OpenIdClaims.ClientId, claimValue); - claimsIdentity.AddClaim(actorClaim); - break; - } - - user.AddIdentity(claimsIdentity); - A.CallTo(() => httpContextAccessor.HttpContext.User).Returns(user); - return new EnrichWithActorCommandMiddleware(httpContextAccessor); + + claimsIdentity.AddClaim(new Claim(claimType, claimValue)); + claimsPrincipal.AddIdentity(claimsIdentity); + + return claimsPrincipal; } } } diff --git a/tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs b/tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs index b4df7d6ad..6c5633b24 100644 --- a/tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs +++ b/tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs @@ -4,62 +4,120 @@ // Copyright (c) Squidex UG (haftungsbeschränkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== + using System; using System.Threading.Tasks; using FakeItEasy; using Microsoft.AspNetCore.Http; using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Domain.Apps.Entities.Apps.State; +using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; -using Squidex.Pipeline; -using Squidex.Pipeline.CommandMiddlewares; using Xunit; -using static Squidex.Pipeline.AppApiFilter; -namespace Squidex.Tests.Pipeline.CommandMiddlewares +namespace Squidex.Pipeline.CommandMiddlewares { public class EnrichWithAppIdCommandMiddlewareTests { private readonly IHttpContextAccessor httpContextAccessor = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); - private readonly CreateContent command = new CreateContent { AppId = null }; + private readonly HttpContext httpContext = new DefaultHttpContext(); + private readonly EnrichWithAppIdCommandMiddleware sut; + + public EnrichWithAppIdCommandMiddlewareTests() + { + A.CallTo(() => httpContextAccessor.HttpContext) + .Returns(httpContext); + + sut = new EnrichWithAppIdCommandMiddleware(httpContextAccessor); + } + + [Fact] + public async Task Should_throw_exception_if_app_not_found() + { + var command = new CreateContent(); + var context = new CommandContext(command, commandBus); + + await Assert.ThrowsAsync(() => sut.HandleAsync(context)); + } [Fact] - public async Task HandleAsync_should_throw_exception_if_app_id_not_found() + public async Task Should_do_nothing_when_context_is_null() { + A.CallTo(() => httpContextAccessor.HttpContext) + .Returns(null); + + var command = new CreateContent(); var context = new CommandContext(command, commandBus); - var sut = SetupSystem(null); - await Assert.ThrowsAsync(() => - { - return sut.HandleAsync(context); - }); + await sut.HandleAsync(context); + + Assert.Null(command.Actor); } [Fact] - public async Task HandleAsync_should_find_app_id_from_features() + public async Task Should_assign_app_id_and_name_to_app_command() { + SetupApp(out var appId, out var appName); + + var command = new CreateContent(); var context = new CommandContext(command, commandBus); - var app = new AppState - { - Name = "app", - Id = Guid.NewGuid() - }; - var sut = SetupSystem(app); await sut.HandleAsync(context); - Assert.Equal(new NamedId(app.Id, app.Name), command.AppId); + Assert.Equal(new NamedId(appId, appName), command.AppId); } - private EnrichWithAppIdCommandMiddleware SetupSystem(IAppEntity app) + [Fact] + public async Task Should_assign_app_id_to_app_self_command() { - var appFeature = app == null ? null : new AppFeature(app); - A.CallTo(() => httpContextAccessor.HttpContext.Features.Get()).Returns(appFeature); + SetupApp(out var appId, out var appName); + + var command = new AddPattern(); + var context = new CommandContext(command, commandBus); + + await sut.HandleAsync(context); + + Assert.Equal(appId, command.AppId); + } + + [Fact] + public async Task Should_not_override_app_id() + { + SetupApp(out var appId, out var appName); + + var command = new AddPattern { AppId = Guid.NewGuid() }; + var context = new CommandContext(command, commandBus); + + await sut.HandleAsync(context); + + Assert.NotEqual(appId, command.AppId); + } + + [Fact] + public async Task Should_not_override_app_id_and_name() + { + SetupApp(out var appId, out var appName); + + var command = new CreateContent { AppId = new NamedId(Guid.NewGuid(), "other-app") }; + var context = new CommandContext(command, commandBus); + + await sut.HandleAsync(context); + + Assert.NotEqual(new NamedId(appId, appName), command.AppId); + } + + private void SetupApp(out Guid appId, out string appName) + { + appId = Guid.NewGuid(); + appName = "my-app"; + + var appEntity = A.Fake(); + A.CallTo(() => appEntity.Id).Returns(appId); + A.CallTo(() => appEntity.Name).Returns(appName); - return new EnrichWithAppIdCommandMiddleware(httpContextAccessor); + httpContext.Features.Set(new AppApiFilter.AppFeature(appEntity)); } } } diff --git a/tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs b/tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs index ff8411c92..d00ae9453 100644 --- a/tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs +++ b/tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs @@ -4,62 +4,116 @@ // Copyright (c) Squidex UG (haftungsbeschränkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== + using System; using System.Threading.Tasks; using FakeItEasy; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Routing; -using Moq; -using Squidex.Domain.Apps.Core; -using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities; +using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Schemas; -using Squidex.Domain.Apps.Entities.Schemas.State; +using Squidex.Domain.Apps.Entities.Schemas.Commands; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; -using Squidex.Pipeline.CommandMiddlewares; using Xunit; -namespace Squidex.Tests.Pipeline.CommandMiddlewares +namespace Squidex.Pipeline.CommandMiddlewares { public class EnrichWithSchemaIdCommandMiddlewareTests { - private readonly Mock actionContextAccessor = new Mock(); - private readonly ICommandBus commandBus = A.Fake(); - private readonly Mock httpContextMock = new Mock(); - private readonly ActionDescriptor actionDescriptor = new ActionDescriptor(); + private readonly IActionContextAccessor actionContextAccessor = A.Fake(); private readonly IAppProvider appProvider = A.Fake(); - private readonly Guid appId = Guid.NewGuid(); - private readonly string appName = "app"; - private readonly Guid schemaId = Guid.NewGuid(); - private readonly string schemaName = "schema"; - private readonly CreateContent command = new CreateContent(); - private readonly RouteData routeData = new RouteData(); - private ISchemaEntity schema; + private readonly ICommandBus commandBus = A.Fake(); + private readonly HttpContext httpContext = new DefaultHttpContext(); + private readonly ActionContext actionContext = new ActionContext(); + private readonly EnrichWithSchemaIdCommandMiddleware sut; + + public EnrichWithSchemaIdCommandMiddlewareTests() + { + actionContext.RouteData = new RouteData(); + actionContext.HttpContext = httpContext; + + A.CallTo(() => actionContextAccessor.ActionContext) + .Returns(actionContext); + + sut = new EnrichWithSchemaIdCommandMiddleware(appProvider, actionContextAccessor); + } + + [Fact] + public async Task Should_throw_exception_if_app_not_found() + { + SetupApp(out var appId, out var appName); + SetupSchema(appId, out var schemaId, out var schemaName); + + A.CallTo(() => appProvider.GetSchemaAsync(appId, "other-schema")) + .Returns(Task.FromResult(null)); + + actionContext.RouteData.Values["name"] = "other-schema"; + + var command = new CreateContent(); + var context = new CommandContext(command, commandBus); + + await Assert.ThrowsAsync(() => sut.HandleAsync(context)); + } + + [Fact] + public async Task Should_do_nothing_when_context_is_null() + { + A.CallTo(() => actionContextAccessor.ActionContext) + .Returns(null); + + var command = new CreateContent(); + var context = new CommandContext(command, commandBus); + + await sut.HandleAsync(context); + + Assert.Null(command.Actor); + } [Fact] - public async Task HandleAsync_should_throw_exception_if_schema_not_found() + public async Task Should_do_nothing_when_route_has_no_parameter() { + SetupApp(out var appId, out var appName); + SetupSchema(appId, out var schemaId, out var schemaName); + + var command = new CreateContent(); var context = new CommandContext(command, commandBus); - var sut = SetupSchemaCommand(false); - await Assert.ThrowsAsync(() => - { - return sut.HandleAsync(context); - }); + await sut.HandleAsync(context); + + Assert.Null(command.Actor); } [Fact] - public async Task HandleAsync_should_find_schema_id_by_name() + public async Task Should_assign_schema_id_and_name_from_name() { + SetupApp(out var appId, out var appName); + SetupSchema(appId, out var schemaId, out var schemaName); + + actionContext.RouteData.Values["name"] = schemaName; + + var command = new CreateContent(); var context = new CommandContext(command, commandBus); - SetupSchema(); - var sut = SetupSchemaCommand(false); + await sut.HandleAsync(context); + + Assert.Equal(new NamedId(schemaId, schemaName), command.SchemaId); + } + + [Fact] + public async Task Should_assign_schema_id_and_name_from_id() + { + SetupApp(out var appId, out var appName); + SetupSchema(appId, out var schemaId, out var schemaName); + + actionContext.RouteData.Values["name"] = schemaId.ToString(); + + var command = new CreateContent(); + var context = new CommandContext(command, commandBus); await sut.HandleAsync(context); @@ -67,56 +121,94 @@ namespace Squidex.Tests.Pipeline.CommandMiddlewares } [Fact] - public async Task HandleAsync_should_find_schema_id_by_id() + public async Task Should_assign_schema_id_from_id() { + SetupApp(out var appId, out var appName); + SetupSchema(appId, out var schemaId, out var schemaName); + + actionContext.RouteData.Values["name"] = schemaId.ToString(); + + var command = new UpdateSchema(); var context = new CommandContext(command, commandBus); - SetupSchema(); - var sut = SetupSchemaCommand(true); + await sut.HandleAsync(context); + + Assert.Equal(schemaId, command.SchemaId); + } + + [Fact] + public async Task Should_use_app_id_from_command() + { + var appId = new NamedId(Guid.NewGuid(), "my-app"); + + SetupSchema(appId.Id, out var schemaId, out var schemaName); + + actionContext.RouteData.Values["name"] = schemaId.ToString(); + + var command = new CreateContent { AppId = appId }; + var context = new CommandContext(command, commandBus); await sut.HandleAsync(context); Assert.Equal(new NamedId(schemaId, schemaName), command.SchemaId); } - private void SetupSchema() + [Fact] + public async Task Should_not_override_schema_id() + { + SetupApp(out var appId, out var appName); + SetupSchema(appId, out var schemaId, out var schemaName); + + var command = new CreateSchema { SchemaId = Guid.NewGuid() }; + var context = new CommandContext(command, commandBus); + + await sut.HandleAsync(context); + + Assert.NotEqual(schemaId, command.SchemaId); + } + + [Fact] + public async Task Should_not_override_schema_id_and_name() { - var schemaDef = new Schema(schemaName); - var stringValidatorProperties = new StringFieldProperties - { - Pattern = "A-Z" - }; - var stringFieldWithValidator = new StringField(1, "validator", Partitioning.Invariant, stringValidatorProperties); - - schemaDef = schemaDef.AddField(stringFieldWithValidator); - - schema = new SchemaState - { - Name = schemaName, - Id = schemaId, - AppId = new NamedId(appId, appName), - SchemaDef = schemaDef - }; + SetupApp(out var appId, out var appName); + SetupSchema(appId, out var schemaId, out var schemaName); + + var command = new CreateContent { SchemaId = new NamedId(Guid.NewGuid(), "other-schema") }; + var context = new CommandContext(command, commandBus); + + await sut.HandleAsync(context); + + Assert.NotEqual(new NamedId(appId, appName), command.AppId); } - private EnrichWithSchemaIdCommandMiddleware SetupSchemaCommand(bool byId) + private void SetupSchema(Guid appId, out Guid schemaId, out string schemaName) { - command.AppId = new NamedId(appId, appName); - - if (byId) - { - routeData.Values.Add("name", schemaId.ToString()); - A.CallTo(() => appProvider.GetSchemaAsync(appId, schemaId, false)).Returns(schema); - } - else - { - routeData.Values.Add("name", "schema"); - A.CallTo(() => appProvider.GetSchemaAsync(appId, schemaName)).Returns(schema); - } - - var actionContext = new ActionContext(httpContextMock.Object, routeData, actionDescriptor); - actionContextAccessor.Setup(x => x.ActionContext).Returns(actionContext); - return new EnrichWithSchemaIdCommandMiddleware(appProvider, actionContextAccessor.Object); + schemaId = Guid.NewGuid(); + schemaName = "my-schema"; + + var schemaEntity = A.Fake(); + A.CallTo(() => schemaEntity.Id).Returns(schemaId); + A.CallTo(() => schemaEntity.Name).Returns(schemaName); + + var temp1 = schemaName; + var temp2 = schemaId; + + A.CallTo(() => appProvider.GetSchemaAsync(appId, temp1)) + .Returns(schemaEntity); + A.CallTo(() => appProvider.GetSchemaAsync(appId, temp2, false)) + .Returns(schemaEntity); + } + + private void SetupApp(out Guid appId, out string appName) + { + appId = Guid.NewGuid(); + appName = "my-app"; + + var appEntity = A.Fake(); + A.CallTo(() => appEntity.Id).Returns(appId); + A.CallTo(() => appEntity.Name).Returns(appName); + + httpContext.Features.Set(new AppApiFilter.AppFeature(appEntity)); } } } diff --git a/tests/Squidex.Tests/Pipeline/EnforceHttpsMiddlewareTests.cs b/tests/Squidex.Tests/Pipeline/EnforceHttpsMiddlewareTests.cs index c237567fc..d61b1969f 100644 --- a/tests/Squidex.Tests/Pipeline/EnforceHttpsMiddlewareTests.cs +++ b/tests/Squidex.Tests/Pipeline/EnforceHttpsMiddlewareTests.cs @@ -5,73 +5,79 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Options; -using Moq; using Squidex.Config; -using Squidex.Pipeline; +using Squidex.Infrastructure.Tasks; using Xunit; +using Options = Microsoft.Extensions.Options.Options; -namespace Squidex.Tests.Pipeline +namespace Squidex.Pipeline { public class EnforceHttpsMiddlewareTests { - private readonly Mock next = new Mock(); - private readonly Mock httpContextMock = new Mock(); - private readonly Mock requestMock = new Mock(); - private readonly Mock responseMock = new Mock(); - private IOptions urls; - private EnforceHttpsMiddleware sut; + private bool isNextCalled; + private RequestDelegate next; public EnforceHttpsMiddlewareTests() { - requestMock.Setup(x => x.Host).Returns(new HostString("test.squidex.com")); - requestMock.Setup(x => x.Scheme).Returns("https"); - httpContextMock.Setup(x => x.Request).Returns(requestMock.Object); - httpContextMock.Setup(x => x.Response).Returns(responseMock.Object); + next = (context) => + { + isNextCalled = true; + + return TaskHelper.Done; + }; } [Fact] - public async Task Should_Continue_EnforceHTTPS_Is_False_Then_Return() + public async Task Should_make_permanent_redirect_if_redirect_is_required() { - urls = new OptionsManager(new OptionsFactory( - new List>(), new List>())); - urls.Value.EnforceHTTPS = false; + var httpContext = CreateHttpContext(); + + var sut = new EnforceHttpsMiddleware(next, Options.Create(new MyUrlsOptions { EnforceHTTPS = true })); - sut = new EnforceHttpsMiddleware(next.Object, urls); - await sut.Invoke(httpContextMock.Object); + await sut.Invoke(httpContext); - next.Verify(x => x(It.IsAny()), Times.Once); + Assert.False(isNextCalled); + Assert.Equal("https://squidex.local/path?query=1", httpContext.Response.Headers["Location"]); } [Fact] - public async Task Should_Call_Next_If_EnforceHTTPS_Is_True_And_Request_Scheme_Is_Https() + public async Task Should_not_redirect_if_already_on_https() { - urls = new OptionsManager(new OptionsFactory( - new List>(), new List>())); - urls.Value.EnforceHTTPS = true; + var httpContext = CreateHttpContext("https"); + + var sut = new EnforceHttpsMiddleware(next, Options.Create(new MyUrlsOptions { EnforceHTTPS = true })); - sut = new EnforceHttpsMiddleware(next.Object, urls); - await sut.Invoke(httpContextMock.Object); + await sut.Invoke(httpContext); - next.Verify(x => x(It.IsAny()), Times.Once); + Assert.True(isNextCalled); + Assert.Null((string)httpContext.Response.Headers["Location"]); } [Fact] - public async Task Should_Call_Next_If_EnforceHTTPS_Is_False_Then_Return() + public async Task Should_not_redirect_if_not_required() + { + var httpContext = CreateHttpContext("http"); + + var sut = new EnforceHttpsMiddleware(next, Options.Create(new MyUrlsOptions { EnforceHTTPS = false })); + + await sut.Invoke(httpContext); + + Assert.True(isNextCalled); + Assert.Null((string)httpContext.Response.Headers["Location"]); + } + + private static DefaultHttpContext CreateHttpContext(string scheme = "http") { - urls = new OptionsManager(new OptionsFactory( - new List>(), new List>())); - urls.Value.EnforceHTTPS = true; + var httpContext = new DefaultHttpContext(); - requestMock.Setup(x => x.Scheme).Returns("http"); - sut = new EnforceHttpsMiddleware(next.Object, urls); - await sut.Invoke(httpContextMock.Object); + httpContext.Request.QueryString = new QueryString("?query=1"); + httpContext.Request.Host = new HostString("squidex.local"); + httpContext.Request.Path = new PathString("/path"); + httpContext.Request.Scheme = scheme; - next.Verify(x => x(It.IsAny()), Times.Never); - responseMock.Verify(x => x.Redirect(It.IsAny(), true), Times.Once); + return httpContext; } } } diff --git a/tests/Squidex.Tests/Pipeline/FileCallbackResultTests.cs b/tests/Squidex.Tests/Pipeline/FileCallbackResultTests.cs deleted file mode 100644 index b75f8cf20..000000000 --- a/tests/Squidex.Tests/Pipeline/FileCallbackResultTests.cs +++ /dev/null @@ -1,70 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System; -using System.IO; -using System.Threading.Tasks; -using FakeItEasy; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Abstractions; -using Microsoft.AspNetCore.Routing; -using Microsoft.Extensions.Logging; -using Moq; -using Squidex.Pipeline; -using Xunit; - -namespace Squidex.Tests.Pipeline -{ - public class FileCallbackResultTests - { - private readonly ILoggerFactory loggerFactory = A.Fake(); - private readonly ActionContext context; - private readonly ActionDescriptor actionDescriptor = new ActionDescriptor(); - private readonly Mock httpContext = new Mock(); - private readonly Mock requestMock = new Mock(); - private readonly Mock responseMock = new Mock(); - private readonly Mock serviceProvider = new Mock(); - private readonly Func callback; - private readonly FileCallbackResult sut; - private readonly FileCallbackResultExecutor callbackExecutor; - private bool callbackWasCalled; - - public FileCallbackResultTests() - { - requestMock.Setup(x => x.Headers).Returns(new HeaderDictionary()); - responseMock.Setup(x => x.Headers).Returns(new HeaderDictionary()); - httpContext.Setup(x => x.RequestServices).Returns(serviceProvider.Object); - httpContext.Setup(x => x.Request).Returns(requestMock.Object); - httpContext.Setup(x => x.Response).Returns(responseMock.Object); - - context = new ActionContext(httpContext.Object, new RouteData(), actionDescriptor); - callback = async bodyStream => { callbackWasCalled = true; }; - callbackExecutor = new FileCallbackResultExecutor(loggerFactory); - sut = new FileCallbackResult("text/plain", "test.txt", callback); - } - - [Fact] - public async Task Should_Execute_Callback_Function() - { - serviceProvider.Setup(x => x.GetService(It.IsAny())).Returns(callbackExecutor); - await sut.ExecuteResultAsync(context); - - Assert.True(callbackWasCalled); - } - - [Fact] - public async Task Should_Not_Call_Callback_If_Exception_Thrown_While_Logging() - { - httpContext.Setup(x => x.Request).Returns((HttpRequest)null); - serviceProvider.Setup(x => x.GetService(It.IsAny())).Returns(callbackExecutor); - await sut.ExecuteResultAsync(context); - - Assert.False(callbackWasCalled); - } - } -} diff --git a/tests/Squidex.Tests/Pipeline/Swagger/SwaggerHelperTests.cs b/tests/Squidex.Tests/Pipeline/Swagger/SwaggerHelperTests.cs deleted file mode 100644 index 413484034..000000000 --- a/tests/Squidex.Tests/Pipeline/Swagger/SwaggerHelperTests.cs +++ /dev/null @@ -1,120 +0,0 @@ -// ========================================================================== -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex UG (haftungsbeschränkt) -// All rights reserved. Licensed under the MIT license. -// ========================================================================== - -using System.Threading.Tasks; -using FakeItEasy; -using Microsoft.AspNetCore.Http; -using NJsonSchema; -using NSwag; -using NSwag.AspNetCore; -using NSwag.SwaggerGeneration; -using Squidex.Config; -using Squidex.Infrastructure; -using Squidex.Pipeline.Swagger; -using Xunit; - -namespace Squidex.Tests.Pipeline.Swagger -{ - public class SwaggerHelperTests - { - private readonly IHttpContextAccessor contextAccessor = A.Fake(); - private readonly string appName = "app"; - private readonly string host = "kraken"; - private readonly MyUrlsOptions myUrlsOptions = new MyUrlsOptions { BaseUrl = "www.test.com" }; - private readonly SwaggerOperation operation = new SwaggerOperation(); - - [Fact] - public void Should_load_docs() - { - var doc = SwaggerHelper.LoadDocs("security"); - Assert.StartsWith("Squidex", doc); - } - - [Fact] - public void Should_throw_exception_when_base_url_is_empty() - { - var testUrlOptions = new MyUrlsOptions(); - Assert.Throws(() => testUrlOptions.BuildUrl("/api")); - } - - [Fact] - public void Should_create_swagger_document() - { - var swaggerDoc = CreateSwaggerDocument(); - - Assert.NotNull(swaggerDoc.Tags); - Assert.Contains("application/json", swaggerDoc.Consumes); - Assert.Contains("application/json", swaggerDoc.Produces); - Assert.NotNull(swaggerDoc.Info.ExtensionData["x-logo"]); - Assert.Equal($"Squidex API for {appName} App", swaggerDoc.Info.Title); - Assert.Equal("/api", swaggerDoc.BasePath); - Assert.Equal(host, swaggerDoc.Host); - Assert.NotEmpty(swaggerDoc.SecurityDefinitions); - } - - [Fact] - public void Should_create_OAuth_schema() - { - var oauthSchema = SwaggerHelper.CreateOAuthSchema(myUrlsOptions); - - Assert.Equal(myUrlsOptions.BuildUrl($"{Constants.IdentityServerPrefix}/connect/token"), oauthSchema.TokenUrl); - Assert.Equal(SwaggerSecuritySchemeType.OAuth2, oauthSchema.Type); - Assert.Equal(SwaggerOAuth2Flow.Application, oauthSchema.Flow); - Assert.NotEmpty(oauthSchema.Scopes); - Assert.Contains(myUrlsOptions.BuildUrl($"{Constants.IdentityServerPrefix}/connect/token"), - oauthSchema.Description); - Assert.DoesNotContain("", oauthSchema.Description); - } - - [Fact] - public async Task Should_get_error_dto_schema() - { - var swaggerDoc = CreateSwaggerDocument(); - - var schemaGenerator = new SwaggerJsonSchemaGenerator(new SwaggerSettings()); - var schemaResolver = new SwaggerSchemaResolver(swaggerDoc, new SwaggerSettings()); - var errorDto = await schemaGenerator.GetErrorDtoSchemaAsync(schemaResolver); - - Assert.NotNull(errorDto); - } - - [Fact] - public void Should_add_query_parameter() - { - operation.AddQueryParameter("test", JsonObjectType.String, "Test parameter"); - Assert.Contains(operation.Parameters, p => p.Kind == SwaggerParameterKind.Query); - } - - [Fact] - public void Should_add_path_parameter() - { - operation.AddPathParameter("test", JsonObjectType.String, "Test parameter"); - Assert.Contains(operation.Parameters, p => p.Kind == SwaggerParameterKind.Path); - } - - [Fact] - public void Should_add_body_parameter() - { - operation.AddBodyParameter("test", null, "Test parameter"); - Assert.Contains(operation.Parameters, p => p.Kind == SwaggerParameterKind.Body); - } - - [Fact] - public void Should_add_response_parameter() - { - operation.AddResponse("200", "Test is ok"); - Assert.Contains(operation.Responses, r => r.Key == "200"); - } - - private SwaggerDocument CreateSwaggerDocument() - { - A.CallTo(() => contextAccessor.HttpContext.Request.Scheme).Returns("http"); - A.CallTo(() => contextAccessor.HttpContext.Request.Host).Returns(new HostString(host)); - return SwaggerHelper.CreateApiDocument(contextAccessor.HttpContext, myUrlsOptions, appName); - } - } -} diff --git a/tests/Squidex.Tests/Squidex.Tests.csproj b/tests/Squidex.Tests/Squidex.Tests.csproj index 08d8df293..5eb6cd98e 100644 --- a/tests/Squidex.Tests/Squidex.Tests.csproj +++ b/tests/Squidex.Tests/Squidex.Tests.csproj @@ -1,39 +1,31 @@  - - + + Exe netcoreapp2.0 + Squidex - - - + + + + + + - - - + + + + - - - - - - - - ..\..\..\identityserver\CivicPlusIdentityServer.SDK.NetCore\bin\Debug\netcoreapp2.0\CivicPlusIdentityServer.SDK.NetCore.dll - - - ..\..\..\restsharp_core\RestSharp\bin\Debug\netstandard2.0\RestSharp.dll - - - ..\..\..\..\Desktop\RestSharp.NetCore.dll - + - + + ..\..\Squidex.ruleset + - + -