Browse Source

Started to migrate the tests.

pull/262/head
Sebastian Stehle 8 years ago
parent
commit
a3a8bdf6df
  1. 3
      Dockerfile
  2. 2
      src/Squidex/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs
  3. 4
      src/Squidex/Pipeline/EnforceHttpsMiddleware.cs
  4. 5
      src/Squidex/Squidex.csproj
  5. 12
      tests/RunCoverage.ps1
  6. 86
      tests/Squidex.Tests/Pipeline/ActionContextLogAppenderTests.cs
  7. 32
      tests/Squidex.Tests/Pipeline/ApiAuthorizeAttributeTests.cs
  8. 104
      tests/Squidex.Tests/Pipeline/ApiCostTests.cs
  9. 101
      tests/Squidex.Tests/Pipeline/ApiExceptionFilterAttributeTests.cs
  10. 90
      tests/Squidex.Tests/Pipeline/AppApiTests.cs
  11. 130
      tests/Squidex.Tests/Pipeline/AppPermissionAttributeTests.cs
  12. 49
      tests/Squidex.Tests/Pipeline/CommandMiddlewares/ETagCommandMiddlewareTests.cs
  13. 94
      tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithActorCommandMiddlewareTests.cs
  14. 106
      tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs
  15. 220
      tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs
  16. 82
      tests/Squidex.Tests/Pipeline/EnforceHttpsMiddlewareTests.cs
  17. 70
      tests/Squidex.Tests/Pipeline/FileCallbackResultTests.cs
  18. 120
      tests/Squidex.Tests/Pipeline/Swagger/SwaggerHelperTests.cs
  19. 44
      tests/Squidex.Tests/Squidex.Tests.csproj

3
Dockerfile

@ -24,7 +24,8 @@ RUN dotnet restore \
&& dotnet test tests/Squidex.Infrastructure.Tests/Squidex.Infrastructure.Tests.csproj \ && 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.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.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 # Publish
RUN dotnet publish src/Squidex/Squidex.csproj --output /out/ --configuration Release RUN dotnet publish src/Squidex/Squidex.csproj --output /out/ --configuration Release

2
src/Squidex/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddleware.cs

@ -32,6 +32,8 @@ namespace Squidex.Pipeline.CommandMiddlewares
if (actionContextAccessor.ActionContext == null) if (actionContextAccessor.ActionContext == null)
{ {
await next(); await next();
return;
} }
if (context.Command is ISchemaCommand schemaCommand && schemaCommand.SchemaId == null) if (context.Command is ISchemaCommand schemaCommand && schemaCommand.SchemaId == null)

4
src/Squidex/Pipeline/EnforceHttpsMiddleware.cs

@ -36,9 +36,9 @@ namespace Squidex.Pipeline
if (!string.Equals(context.Request.Scheme, "https", StringComparison.OrdinalIgnoreCase)) 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 else
{ {

5
src/Squidex/Squidex.csproj

@ -11,6 +11,11 @@
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>full</DebugType>
<DebugSymbols>True</DebugSymbols>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Areas\IdentityServer\Config\Cert\*.*;Docs\*.md" /> <EmbeddedResource Include="Areas\IdentityServer\Config\Cert\*.*;Docs\*.md" />
<EmbeddedResource Include="Areas\Api\Controllers\Users\Assets\Avatar.png" /> <EmbeddedResource Include="Areas\Api\Controllers\Users\Assets\Avatar.png" />

12
tests/RunCoverage.ps1

@ -3,6 +3,7 @@ Param(
[switch]$appsCore, [switch]$appsCore,
[switch]$appsEntities, [switch]$appsEntities,
[switch]$users, [switch]$users,
[switch]$web,
[switch]$all [switch]$all
) )
@ -64,6 +65,17 @@ if ($all -Or $users) {
-oldStyle -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" ` &"$folderHome\.nuget\packages\ReportGenerator\3.1.1\tools\ReportGenerator.exe" `
-reports:"$folderWorking\$folderReports\*.xml" ` -reports:"$folderWorking\$folderReports\*.xml" `
-targetdir:"$folderWorking\$folderReports\Output" -targetdir:"$folderWorking\$folderReports\Output"

86
tests/Squidex.Tests/Pipeline/ActionContextLogAppenderTests.cs

@ -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<IActionContextAccessor> actionContextAccessor = new Mock<IActionContextAccessor>();
private readonly Mock<HttpContext> httpContextMock = new Mock<HttpContext>();
private readonly ActionDescriptor actionDescriptor = new ActionDescriptor();
private readonly RouteData routeData = new RouteData();
private readonly Guid requestId = Guid.NewGuid();
private readonly IDictionary<object, object> items = new Dictionary<object, object>();
private readonly IObjectWriter writer = A.Fake<IObjectWriter>();
private readonly HttpRequest request = A.Fake<HttpRequest>();
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<string>(), It.IsAny<Action<IObjectWriter>>())).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);
}
}
}

32
tests/Squidex.Tests/Pipeline/ApiAuthorizeAttributeTests.cs

@ -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);
}
}
}

104
tests/Squidex.Tests/Pipeline/ApiCostTests.cs

@ -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<IActionContextAccessor> actionContextAccessor = new Mock<IActionContextAccessor>();
private readonly RouteData routeData = new RouteData();
private readonly ActionDescriptor actionDescriptor = new ActionDescriptor();
private readonly IAppPlansProvider appPlanProvider = A.Fake<IAppPlansProvider>();
private readonly IUsageTracker usageTracker = A.Fake<IUsageTracker>();
private readonly long usage = 1;
private readonly Mock<HttpContext> httpContextMock = new Mock<HttpContext>();
private readonly IFeatureCollection features = new FeatureCollection();
private readonly IAppEntity appEntity = A.Fake<IAppEntity>();
private readonly IAppFeature appFeature = A.Fake<IAppFeature>();
private readonly IAppLimitsPlan appPlan = A.Fake<IAppLimitsPlan>();
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<IFilterMetadata>(), new Dictionary<string, object>(), null);
context.Filters.Add(new ServiceFilterAttribute(typeof(ApiCostsFilter)));
A.CallTo(() => appEntity.Id).Returns(appId);
A.CallTo(() => appFeature.App).Returns(appEntity);
features.Set<IAppFeature>(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;
}
}
}

101
tests/Squidex.Tests/Pipeline/ApiExceptionFilterAttributeTests.cs

@ -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<HttpContext> httpContextMock = new Mock<HttpContext>();
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<IFilterMetadata>());
}
[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 };
}
}
}

90
tests/Squidex.Tests/Pipeline/AppApiTests.cs

@ -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<IActionContextAccessor> actionContextAccessor = new Mock<IActionContextAccessor>();
private readonly RouteData routeData = new RouteData();
private readonly ActionDescriptor actionDescriptor = new ActionDescriptor();
private readonly IAppPlansProvider appPlanProvider = A.Fake<IAppPlansProvider>();
private readonly IUsageTracker usageTracker = A.Fake<IUsageTracker>();
private readonly long usage = 1;
private readonly Mock<HttpContext> httpContextMock = new Mock<HttpContext>();
private readonly IFeatureCollection features = new FeatureCollection();
private readonly IAppEntity appEntity = A.Fake<IAppEntity>();
private readonly IAppFeature appFeature = A.Fake<IAppFeature>();
private readonly IAppProvider appProvider = A.Fake<IAppProvider>();
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<IFilterMetadata>(), new Dictionary<string, object>(), 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);
}
}
}

130
tests/Squidex.Tests/Pipeline/AppPermissionAttributeTests.cs

@ -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<HttpContext> httpContextMock = new Mock<HttpContext>();
private readonly Mock<ClaimsPrincipal> mockUser = new Mock<ClaimsPrincipal>();
private readonly ActionDescriptor actionDescriptor = new ActionDescriptor();
private readonly Mock<IActionContextAccessor> actionContextAccessor = new Mock<IActionContextAccessor>();
private readonly IAppEntity appEntity = A.Fake<IAppEntity>();
private readonly ClaimsIdentity identity = new ClaimsIdentity();
private readonly AppClient client = new AppClient("clientId", "secret", AppClientPermission.Reader);
private readonly IAppFeature appFeature = A.Fake<IAppFeature>();
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<string, AppClient>();
clients.Add("clientId", client);
var contributors = ImmutableDictionary.CreateBuilder<string, AppContributorPermission>();
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<IAppFeature>(appFeature);
mockUser.Setup(x => x.Identities).Returns(new List<ClaimsIdentity> { identity });
httpContextMock.Setup(x => x.Features).Returns(features);
httpContextMock.Setup(x => x.User).Returns(mockUser.Object);
context = new ActionExecutingContext(actionContext, new List<IFilterMetadata>(), new Dictionary<string, object>(), 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());
}
}
}

49
tests/Squidex.Tests/Pipeline/CommandMiddlewares/ETagCommandMiddlewareTests.cs

@ -9,38 +9,65 @@ using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Pipeline.CommandMiddlewares;
using Xunit; using Xunit;
namespace Squidex.Tests.Pipeline.CommandMiddlewares namespace Squidex.Pipeline.CommandMiddlewares
{ {
public class ETagCommandMiddlewareTests public class ETagCommandMiddlewareTests
{ {
private readonly IHttpContextAccessor httpContextAccessor = A.Fake<IHttpContextAccessor>(); private readonly IHttpContextAccessor httpContextAccessor = A.Fake<IHttpContextAccessor>();
private readonly ICommandBus commandBus = A.Fake<ICommandBus>(); private readonly ICommandBus commandBus = A.Fake<ICommandBus>();
private readonly IHeaderDictionary headers = new HeaderDictionary { { "If-Match", "1" } }; private readonly IHeaderDictionary requestHeaders = new HeaderDictionary();
private readonly UpdateAsset command = new UpdateAsset();
private readonly EntitySavedResult entitySavedResult = new EntitySavedResult(1);
private readonly ETagCommandMiddleware sut; private readonly ETagCommandMiddleware sut;
public ETagCommandMiddlewareTests() public ETagCommandMiddlewareTests()
{ {
A.CallTo(() => httpContextAccessor.HttpContext.Request.Headers).Returns(headers); A.CallTo(() => httpContextAccessor.HttpContext.Request.Headers)
.Returns(requestHeaders);
sut = new ETagCommandMiddleware(httpContextAccessor); sut = new ETagCommandMiddleware(httpContextAccessor);
} }
[Fact] [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); var context = new CommandContext(command, commandBus);
context.Complete(entitySavedResult);
context.Complete(new EntitySavedResult(17));
await sut.HandleAsync(context); await sut.HandleAsync(context);
Assert.Equal(1, context.Command.ExpectedVersion); Assert.Equal(new StringValues("17"), httpContextAccessor.HttpContext.Response.Headers["ETag"]);
Assert.Equal(new StringValues("1"), httpContextAccessor.HttpContext.Response.Headers["ETag"]);
} }
} }
} }

94
tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithActorCommandMiddlewareTests.cs

@ -5,81 +5,105 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System;
using System.Security; using System.Security;
using System.Security.Claims; using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Security; using Squidex.Infrastructure.Security;
using Squidex.Pipeline.CommandMiddlewares;
using Xunit; using Xunit;
namespace Squidex.Tests.Pipeline.CommandMiddlewares namespace Squidex.Pipeline.CommandMiddlewares
{ {
public class EnrichWithActorCommandMiddlewareTests public class EnrichWithActorCommandMiddlewareTests
{ {
private readonly IHttpContextAccessor httpContextAccessor = A.Fake<IHttpContextAccessor>(); private readonly IHttpContextAccessor httpContextAccessor = A.Fake<IHttpContextAccessor>();
private readonly ICommandBus commandBus = A.Fake<ICommandBus>(); private readonly ICommandBus commandBus = A.Fake<ICommandBus>();
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<SecurityException>(() => 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] [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 context = new CommandContext(command, commandBus);
var sut = SetupSystem(null, out string claimValue);
await Assert.ThrowsAsync<SecurityException>(() => await sut.HandleAsync(context);
{
return sut.HandleAsync(context); Assert.Equal(new RefToken("subject", "me"), command.Actor);
});
} }
[Fact] [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 context = new CommandContext(command, commandBus);
var sut = SetupSystem("subject", out string claimValue);
await sut.HandleAsync(context); await sut.HandleAsync(context);
Assert.Equal(claimValue, command.Actor.Identifier); Assert.Equal(new RefToken("client", "my-client"), command.Actor);
} }
[Fact] [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 context = new CommandContext(command, commandBus);
var sut = SetupSystem("client", out string claimValue);
await sut.HandleAsync(context); 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; var claimsPrincipal = new ClaimsPrincipal();
claimValue = Guid.NewGuid().ToString();
var user = new ClaimsPrincipal();
var claimsIdentity = new ClaimsIdentity(); var claimsIdentity = new ClaimsIdentity();
switch (refTokenType)
{ claimsIdentity.AddClaim(new Claim(claimType, claimValue));
case "subject": claimsPrincipal.AddIdentity(claimsIdentity);
actorClaim = new Claim(OpenIdClaims.Subject, claimValue);
claimsIdentity.AddClaim(actorClaim); return claimsPrincipal;
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);
} }
} }
} }

106
tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs

@ -4,62 +4,120 @@
// Copyright (c) Squidex UG (haftungsbeschränkt) // Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Squidex.Domain.Apps.Entities.Apps; 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.Domain.Apps.Entities.Contents.Commands;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Pipeline;
using Squidex.Pipeline.CommandMiddlewares;
using Xunit; using Xunit;
using static Squidex.Pipeline.AppApiFilter;
namespace Squidex.Tests.Pipeline.CommandMiddlewares namespace Squidex.Pipeline.CommandMiddlewares
{ {
public class EnrichWithAppIdCommandMiddlewareTests public class EnrichWithAppIdCommandMiddlewareTests
{ {
private readonly IHttpContextAccessor httpContextAccessor = A.Fake<IHttpContextAccessor>(); private readonly IHttpContextAccessor httpContextAccessor = A.Fake<IHttpContextAccessor>();
private readonly ICommandBus commandBus = A.Fake<ICommandBus>(); private readonly ICommandBus commandBus = A.Fake<ICommandBus>();
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<InvalidOperationException>(() => sut.HandleAsync(context));
}
[Fact] [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 context = new CommandContext(command, commandBus);
var sut = SetupSystem(null);
await Assert.ThrowsAsync<InvalidOperationException>(() => await sut.HandleAsync(context);
{
return sut.HandleAsync(context); Assert.Null(command.Actor);
});
} }
[Fact] [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 context = new CommandContext(command, commandBus);
var app = new AppState
{
Name = "app",
Id = Guid.NewGuid()
};
var sut = SetupSystem(app);
await sut.HandleAsync(context); await sut.HandleAsync(context);
Assert.Equal(new NamedId<Guid>(app.Id, app.Name), command.AppId); Assert.Equal(new NamedId<Guid>(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); SetupApp(out var appId, out var appName);
A.CallTo(() => httpContextAccessor.HttpContext.Features.Get<IAppFeature>()).Returns(appFeature);
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>(Guid.NewGuid(), "other-app") };
var context = new CommandContext(command, commandBus);
await sut.HandleAsync(context);
Assert.NotEqual(new NamedId<Guid>(appId, appName), command.AppId);
}
private void SetupApp(out Guid appId, out string appName)
{
appId = Guid.NewGuid();
appName = "my-app";
var appEntity = A.Fake<IAppEntity>();
A.CallTo(() => appEntity.Id).Returns(appId);
A.CallTo(() => appEntity.Name).Returns(appName);
return new EnrichWithAppIdCommandMiddleware(httpContextAccessor); httpContext.Features.Set<IAppFeature>(new AppApiFilter.AppFeature(appEntity));
} }
} }
} }

220
tests/Squidex.Tests/Pipeline/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs

@ -4,62 +4,116 @@
// Copyright (c) Squidex UG (haftungsbeschränkt) // Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing; 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;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Domain.Apps.Entities.Schemas; 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;
using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Commands;
using Squidex.Pipeline.CommandMiddlewares;
using Xunit; using Xunit;
namespace Squidex.Tests.Pipeline.CommandMiddlewares namespace Squidex.Pipeline.CommandMiddlewares
{ {
public class EnrichWithSchemaIdCommandMiddlewareTests public class EnrichWithSchemaIdCommandMiddlewareTests
{ {
private readonly Mock<IActionContextAccessor> actionContextAccessor = new Mock<IActionContextAccessor>(); private readonly IActionContextAccessor actionContextAccessor = A.Fake<IActionContextAccessor>();
private readonly ICommandBus commandBus = A.Fake<ICommandBus>();
private readonly Mock<HttpContext> httpContextMock = new Mock<HttpContext>();
private readonly ActionDescriptor actionDescriptor = new ActionDescriptor();
private readonly IAppProvider appProvider = A.Fake<IAppProvider>(); private readonly IAppProvider appProvider = A.Fake<IAppProvider>();
private readonly Guid appId = Guid.NewGuid(); private readonly ICommandBus commandBus = A.Fake<ICommandBus>();
private readonly string appName = "app"; private readonly HttpContext httpContext = new DefaultHttpContext();
private readonly Guid schemaId = Guid.NewGuid(); private readonly ActionContext actionContext = new ActionContext();
private readonly string schemaName = "schema"; private readonly EnrichWithSchemaIdCommandMiddleware sut;
private readonly CreateContent command = new CreateContent();
private readonly RouteData routeData = new RouteData(); public EnrichWithSchemaIdCommandMiddlewareTests()
private ISchemaEntity schema; {
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<ISchemaEntity>(null));
actionContext.RouteData.Values["name"] = "other-schema";
var command = new CreateContent();
var context = new CommandContext(command, commandBus);
await Assert.ThrowsAsync<DomainObjectNotFoundException>(() => 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] [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 context = new CommandContext(command, commandBus);
var sut = SetupSchemaCommand(false);
await Assert.ThrowsAsync<DomainObjectNotFoundException>(() => await sut.HandleAsync(context);
{
return sut.HandleAsync(context); Assert.Null(command.Actor);
});
} }
[Fact] [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); var context = new CommandContext(command, commandBus);
SetupSchema();
var sut = SetupSchemaCommand(false); await sut.HandleAsync(context);
Assert.Equal(new NamedId<Guid>(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); await sut.HandleAsync(context);
@ -67,56 +121,94 @@ namespace Squidex.Tests.Pipeline.CommandMiddlewares
} }
[Fact] [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); 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>(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); await sut.HandleAsync(context);
Assert.Equal(new NamedId<Guid>(schemaId, schemaName), command.SchemaId); Assert.Equal(new NamedId<Guid>(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); SetupApp(out var appId, out var appName);
var stringValidatorProperties = new StringFieldProperties SetupSchema(appId, out var schemaId, out var schemaName);
{
Pattern = "A-Z" var command = new CreateContent { SchemaId = new NamedId<Guid>(Guid.NewGuid(), "other-schema") };
}; var context = new CommandContext(command, commandBus);
var stringFieldWithValidator = new StringField(1, "validator", Partitioning.Invariant, stringValidatorProperties);
await sut.HandleAsync(context);
schemaDef = schemaDef.AddField(stringFieldWithValidator);
Assert.NotEqual(new NamedId<Guid>(appId, appName), command.AppId);
schema = new SchemaState
{
Name = schemaName,
Id = schemaId,
AppId = new NamedId<Guid>(appId, appName),
SchemaDef = schemaDef
};
} }
private EnrichWithSchemaIdCommandMiddleware SetupSchemaCommand(bool byId) private void SetupSchema(Guid appId, out Guid schemaId, out string schemaName)
{ {
command.AppId = new NamedId<Guid>(appId, appName); schemaId = Guid.NewGuid();
schemaName = "my-schema";
if (byId)
{ var schemaEntity = A.Fake<ISchemaEntity>();
routeData.Values.Add("name", schemaId.ToString()); A.CallTo(() => schemaEntity.Id).Returns(schemaId);
A.CallTo(() => appProvider.GetSchemaAsync(appId, schemaId, false)).Returns(schema); A.CallTo(() => schemaEntity.Name).Returns(schemaName);
}
else var temp1 = schemaName;
{ var temp2 = schemaId;
routeData.Values.Add("name", "schema");
A.CallTo(() => appProvider.GetSchemaAsync(appId, schemaName)).Returns(schema); A.CallTo(() => appProvider.GetSchemaAsync(appId, temp1))
} .Returns(schemaEntity);
A.CallTo(() => appProvider.GetSchemaAsync(appId, temp2, false))
var actionContext = new ActionContext(httpContextMock.Object, routeData, actionDescriptor); .Returns(schemaEntity);
actionContextAccessor.Setup(x => x.ActionContext).Returns(actionContext); }
return new EnrichWithSchemaIdCommandMiddleware(appProvider, actionContextAccessor.Object);
private void SetupApp(out Guid appId, out string appName)
{
appId = Guid.NewGuid();
appName = "my-app";
var appEntity = A.Fake<IAppEntity>();
A.CallTo(() => appEntity.Id).Returns(appId);
A.CallTo(() => appEntity.Name).Returns(appName);
httpContext.Features.Set<IAppFeature>(new AppApiFilter.AppFeature(appEntity));
} }
} }
} }

82
tests/Squidex.Tests/Pipeline/EnforceHttpsMiddlewareTests.cs

@ -5,73 +5,79 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Moq;
using Squidex.Config; using Squidex.Config;
using Squidex.Pipeline; using Squidex.Infrastructure.Tasks;
using Xunit; using Xunit;
using Options = Microsoft.Extensions.Options.Options;
namespace Squidex.Tests.Pipeline namespace Squidex.Pipeline
{ {
public class EnforceHttpsMiddlewareTests public class EnforceHttpsMiddlewareTests
{ {
private readonly Mock<RequestDelegate> next = new Mock<RequestDelegate>(); private bool isNextCalled;
private readonly Mock<HttpContext> httpContextMock = new Mock<HttpContext>(); private RequestDelegate next;
private readonly Mock<HttpRequest> requestMock = new Mock<HttpRequest>();
private readonly Mock<HttpResponse> responseMock = new Mock<HttpResponse>();
private IOptions<MyUrlsOptions> urls;
private EnforceHttpsMiddleware sut;
public EnforceHttpsMiddlewareTests() public EnforceHttpsMiddlewareTests()
{ {
requestMock.Setup(x => x.Host).Returns(new HostString("test.squidex.com")); next = (context) =>
requestMock.Setup(x => x.Scheme).Returns("https"); {
httpContextMock.Setup(x => x.Request).Returns(requestMock.Object); isNextCalled = true;
httpContextMock.Setup(x => x.Response).Returns(responseMock.Object);
return TaskHelper.Done;
};
} }
[Fact] [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<MyUrlsOptions>(new OptionsFactory<MyUrlsOptions>( var httpContext = CreateHttpContext();
new List<IConfigureOptions<MyUrlsOptions>>(), new List<IPostConfigureOptions<MyUrlsOptions>>()));
urls.Value.EnforceHTTPS = false; var sut = new EnforceHttpsMiddleware(next, Options.Create(new MyUrlsOptions { EnforceHTTPS = true }));
sut = new EnforceHttpsMiddleware(next.Object, urls); await sut.Invoke(httpContext);
await sut.Invoke(httpContextMock.Object);
next.Verify(x => x(It.IsAny<HttpContext>()), Times.Once); Assert.False(isNextCalled);
Assert.Equal("https://squidex.local/path?query=1", httpContext.Response.Headers["Location"]);
} }
[Fact] [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<MyUrlsOptions>(new OptionsFactory<MyUrlsOptions>( var httpContext = CreateHttpContext("https");
new List<IConfigureOptions<MyUrlsOptions>>(), new List<IPostConfigureOptions<MyUrlsOptions>>()));
urls.Value.EnforceHTTPS = true; var sut = new EnforceHttpsMiddleware(next, Options.Create(new MyUrlsOptions { EnforceHTTPS = true }));
sut = new EnforceHttpsMiddleware(next.Object, urls); await sut.Invoke(httpContext);
await sut.Invoke(httpContextMock.Object);
next.Verify(x => x(It.IsAny<HttpContext>()), Times.Once); Assert.True(isNextCalled);
Assert.Null((string)httpContext.Response.Headers["Location"]);
} }
[Fact] [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<MyUrlsOptions>(new OptionsFactory<MyUrlsOptions>( var httpContext = new DefaultHttpContext();
new List<IConfigureOptions<MyUrlsOptions>>(), new List<IPostConfigureOptions<MyUrlsOptions>>()));
urls.Value.EnforceHTTPS = true;
requestMock.Setup(x => x.Scheme).Returns("http"); httpContext.Request.QueryString = new QueryString("?query=1");
sut = new EnforceHttpsMiddleware(next.Object, urls); httpContext.Request.Host = new HostString("squidex.local");
await sut.Invoke(httpContextMock.Object); httpContext.Request.Path = new PathString("/path");
httpContext.Request.Scheme = scheme;
next.Verify(x => x(It.IsAny<HttpContext>()), Times.Never); return httpContext;
responseMock.Verify(x => x.Redirect(It.IsAny<string>(), true), Times.Once);
} }
} }
} }

70
tests/Squidex.Tests/Pipeline/FileCallbackResultTests.cs

@ -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<ILoggerFactory>();
private readonly ActionContext context;
private readonly ActionDescriptor actionDescriptor = new ActionDescriptor();
private readonly Mock<HttpContext> httpContext = new Mock<HttpContext>();
private readonly Mock<HttpRequest> requestMock = new Mock<HttpRequest>();
private readonly Mock<HttpResponse> responseMock = new Mock<HttpResponse>();
private readonly Mock<IServiceProvider> serviceProvider = new Mock<IServiceProvider>();
private readonly Func<Stream, Task> 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<Type>())).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<Type>())).Returns(callbackExecutor);
await sut.ExecuteResultAsync(context);
Assert.False(callbackWasCalled);
}
}
}

120
tests/Squidex.Tests/Pipeline/Swagger/SwaggerHelperTests.cs

@ -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<IHttpContextAccessor>();
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<ConfigurationException>(() => 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("<TOKEN_URL>", 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);
}
}
}

44
tests/Squidex.Tests/Squidex.Tests.csproj

@ -1,39 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PropertyGroup> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp2.0</TargetFramework>
<RootNamespace>Squidex</RootNamespace>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FakeItEasy" Version="4.3.0" /> <ProjectReference Include="..\..\src\Squidex.Domain.Users\Squidex.Domain.Users.csproj" />
<PackageReference Include="IdentityServer4" Version="2.1.1" /> <ProjectReference Include="..\..\src\Squidex\Squidex.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FakeItEasy" Version="4.5.1" />
<PackageReference Include="IdentityServer4" Version="2.1.2" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="2.1.0" /> <PackageReference Include="IdentityServer4.AspNetIdentity" Version="2.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.1" />
<PackageReference Include="Moq" Version="4.7.145" /> <PackageReference Include="NJsonSchema" Version="9.10.35" />
<PackageReference Include="NJsonSchema" Version="9.10.19" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2" />
<PackageReference Include="xunit" Version="2.3.1" /> <PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Squidex.Domain.Users\Squidex.Domain.Users.csproj" /> <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" />
<ProjectReference Include="..\..\src\Squidex\Squidex.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="CivicPlusIdentityServer.SDK.NetCore">
<HintPath>..\..\..\identityserver\CivicPlusIdentityServer.SDK.NetCore\bin\Debug\netcoreapp2.0\CivicPlusIdentityServer.SDK.NetCore.dll</HintPath>
</Reference>
<Reference Include="RestSharp">
<HintPath>..\..\..\restsharp_core\RestSharp\bin\Debug\netstandard2.0\RestSharp.dll</HintPath>
</Reference>
<Reference Include="RestSharp.NetCore">
<HintPath>..\..\..\..\Desktop\RestSharp.NetCore.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\Squidex.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" /> <AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" />
</ItemGroup> </ItemGroup>
</Project> </Project>

Loading…
Cancel
Save