Browse Source

Fix and simplify tests.

pull/656/head
Sebastian 5 years ago
parent
commit
d521775c11
  1. 8
      backend/src/Squidex.Domain.Apps.Entities/Contents/DefaultContentWorkflow.cs
  2. 6
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/GuardContent.cs
  3. 10
      backend/src/Squidex.Domain.Apps.Entities/Contents/DynamicContentWorkflow.cs
  4. 8
      backend/src/Squidex.Domain.Apps.Entities/Contents/IContentWorkflow.cs
  5. 2
      backend/src/Squidex.Domain.Apps.Entities/SquidexCommand.cs
  6. 5
      backend/src/Squidex.Infrastructure/RefToken.cs
  7. 15
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppCommandMiddlewareTests.cs
  8. 64
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetCommandMiddlewareTests.cs
  9. 15
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentCommandMiddlewareTests.cs
  10. 161
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/Guards/GuardContentTests.cs
  11. 22
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs
  12. 26
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/GuardRuleTests.cs
  13. 15
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleCommandMiddlewareTests.cs
  14. 81
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/Guards/GuardSchemaTests.cs
  15. 2
      backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs

8
backend/src/Squidex.Domain.Apps.Entities/Contents/DefaultContentWorkflow.cs

@ -52,19 +52,19 @@ namespace Squidex.Domain.Apps.Entities.Contents
return Task.FromResult(Status.Draft); return Task.FromResult(Status.Draft);
} }
public Task<bool> CanPublishOnCreateAsync(ISchemaEntity schema, ContentData data, ClaimsPrincipal user) public Task<bool> CanPublishOnCreateAsync(ISchemaEntity schema, ContentData data, ClaimsPrincipal? user)
{ {
return Task.FromResult(true); return Task.FromResult(true);
} }
public Task<bool> CanMoveToAsync(IContentEntity content, Status status, Status next, ClaimsPrincipal user) public Task<bool> CanMoveToAsync(IContentEntity content, Status status, Status next, ClaimsPrincipal? user)
{ {
var result = Flow.TryGetValue(status, out var step) && step.Transitions.Any(x => x.Status == next); var result = Flow.TryGetValue(status, out var step) && step.Transitions.Any(x => x.Status == next);
return Task.FromResult(result); return Task.FromResult(result);
} }
public Task<bool> CanUpdateAsync(IContentEntity content, Status status, ClaimsPrincipal user) public Task<bool> CanUpdateAsync(IContentEntity content, Status status, ClaimsPrincipal? user)
{ {
var result = status != Status.Archived; var result = status != Status.Archived;
@ -78,7 +78,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
return Task.FromResult(result); return Task.FromResult(result);
} }
public Task<StatusInfo[]> GetNextAsync(IContentEntity content, Status status, ClaimsPrincipal user) public Task<StatusInfo[]> GetNextAsync(IContentEntity content, Status status, ClaimsPrincipal? user)
{ {
var result = Flow.TryGetValue(status, out var step) ? step.Transitions : Array.Empty<StatusInfo>(); var result = Flow.TryGetValue(status, out var step) ? step.Transitions : Array.Empty<StatusInfo>();

6
backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/GuardContent.cs

@ -169,7 +169,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
if (command.CheckReferrers) if (command.CheckReferrers)
{ {
var hasReferrer = await contentRepository.HasReferrersAsync(content.AppId.Id, command.ContentId, SearchScope.All); var hasReferrer = await contentRepository.HasReferrersAsync(content.AppId.Id, content.Id, SearchScope.All);
if (hasReferrer) if (hasReferrer)
{ {
@ -186,7 +186,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
} }
} }
private static async Task ValidateCanUpdate(IContentEntity content, IContentWorkflow contentWorkflow, ClaimsPrincipal user) private static async Task ValidateCanUpdate(IContentEntity content, IContentWorkflow contentWorkflow, ClaimsPrincipal? user)
{ {
var status = content.NewStatus ?? content.Status; var status = content.NewStatus ?? content.Status;
@ -198,7 +198,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
public static void CheckPermission(IContentEntity content, ContentCommand command, string permission) public static void CheckPermission(IContentEntity content, ContentCommand command, string permission)
{ {
if (content.CreatedBy?.Equals(command.Actor) == true) if (Equals(content.CreatedBy, command.Actor) || command.User == null)
{ {
return; return;
} }

10
backend/src/Squidex.Domain.Apps.Entities/Contents/DynamicContentWorkflow.cs

@ -38,21 +38,21 @@ namespace Squidex.Domain.Apps.Entities.Contents
return workflow.Steps.Select(x => new StatusInfo(x.Key, GetColor(x.Value))).ToArray(); return workflow.Steps.Select(x => new StatusInfo(x.Key, GetColor(x.Value))).ToArray();
} }
public async Task<bool> CanMoveToAsync(IContentEntity content, Status status, Status next, ClaimsPrincipal user) public async Task<bool> CanMoveToAsync(IContentEntity content, Status status, Status next, ClaimsPrincipal? user)
{ {
var workflow = await GetWorkflowAsync(content.AppId.Id, content.SchemaId.Id); var workflow = await GetWorkflowAsync(content.AppId.Id, content.SchemaId.Id);
return workflow.TryGetTransition(status, next, out var transition) && IsTrue(transition, content.Data, user); return workflow.TryGetTransition(status, next, out var transition) && IsTrue(transition, content.Data, user);
} }
public async Task<bool> CanPublishOnCreateAsync(ISchemaEntity schema, ContentData data, ClaimsPrincipal user) public async Task<bool> CanPublishOnCreateAsync(ISchemaEntity schema, ContentData data, ClaimsPrincipal? user)
{ {
var workflow = await GetWorkflowAsync(schema.AppId.Id, schema.Id); var workflow = await GetWorkflowAsync(schema.AppId.Id, schema.Id);
return workflow.TryGetTransition(workflow.Initial, Status.Published, out var transition) && IsTrue(transition, data, user); return workflow.TryGetTransition(workflow.Initial, Status.Published, out var transition) && IsTrue(transition, data, user);
} }
public async Task<bool> CanUpdateAsync(IContentEntity content, Status status, ClaimsPrincipal user) public async Task<bool> CanUpdateAsync(IContentEntity content, Status status, ClaimsPrincipal? user)
{ {
var workflow = await GetWorkflowAsync(content.AppId.Id, content.SchemaId.Id); var workflow = await GetWorkflowAsync(content.AppId.Id, content.SchemaId.Id);
@ -85,7 +85,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
return status; return status;
} }
public async Task<StatusInfo[]> GetNextAsync(IContentEntity content, Status status, ClaimsPrincipal user) public async Task<StatusInfo[]> GetNextAsync(IContentEntity content, Status status, ClaimsPrincipal? user)
{ {
var result = new List<StatusInfo>(); var result = new List<StatusInfo>();
@ -102,7 +102,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
return result.ToArray(); return result.ToArray();
} }
private bool IsTrue(WorkflowCondition condition, ContentData data, ClaimsPrincipal user) private bool IsTrue(WorkflowCondition condition, ContentData data, ClaimsPrincipal? user)
{ {
if (condition?.Roles != null && user != null) if (condition?.Roles != null && user != null)
{ {

8
backend/src/Squidex.Domain.Apps.Entities/Contents/IContentWorkflow.cs

@ -16,15 +16,15 @@ namespace Squidex.Domain.Apps.Entities.Contents
{ {
Task<Status> GetInitialStatusAsync(ISchemaEntity schema); Task<Status> GetInitialStatusAsync(ISchemaEntity schema);
Task<bool> CanPublishOnCreateAsync(ISchemaEntity schema, ContentData data, ClaimsPrincipal user); Task<bool> CanPublishOnCreateAsync(ISchemaEntity schema, ContentData data, ClaimsPrincipal? user);
Task<bool> CanMoveToAsync(IContentEntity content, Status status, Status next, ClaimsPrincipal user); Task<bool> CanMoveToAsync(IContentEntity content, Status status, Status next, ClaimsPrincipal? user);
Task<bool> CanUpdateAsync(IContentEntity content, Status status, ClaimsPrincipal user); Task<bool> CanUpdateAsync(IContentEntity content, Status status, ClaimsPrincipal? user);
Task<StatusInfo> GetInfoAsync(IContentEntity content, Status status); Task<StatusInfo> GetInfoAsync(IContentEntity content, Status status);
Task<StatusInfo[]> GetNextAsync(IContentEntity content, Status status, ClaimsPrincipal user); Task<StatusInfo[]> GetNextAsync(IContentEntity content, Status status, ClaimsPrincipal? user);
Task<StatusInfo[]> GetAllAsync(ISchemaEntity schema); Task<StatusInfo[]> GetAllAsync(ISchemaEntity schema);
} }

2
backend/src/Squidex.Domain.Apps.Entities/SquidexCommand.cs

@ -15,7 +15,7 @@ namespace Squidex.Domain.Apps.Entities
{ {
public RefToken Actor { get; set; } public RefToken Actor { get; set; }
public ClaimsPrincipal User { get; set; } public ClaimsPrincipal? User { get; set; }
public bool FromRule { get; set; } public bool FromRule { get; set; }

5
backend/src/Squidex.Infrastructure/RefToken.cs

@ -54,11 +54,6 @@ namespace Squidex.Infrastructure
return $"{Type.ToString().ToLowerInvariant()}:{Identifier}"; return $"{Type.ToString().ToLowerInvariant()}:{Identifier}";
} }
public override int GetHashCode()
{
return (Type.GetHashCode() * 397) ^ Identifier.GetHashCode();
}
public static bool TryParse(string? value, [MaybeNullWhen(false)] out RefToken result) public static bool TryParse(string? value, [MaybeNullWhen(false)] out RefToken result)
{ {
value = value?.Trim(TrimChars); value = value?.Trim(TrimChars);

15
backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppCommandMiddlewareTests.cs

@ -53,8 +53,9 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
{ {
var result = A.Fake<IAppEntity>(); var result = A.Fake<IAppEntity>();
var command = CreateCommand(new MyCommand()); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new MyCommand());
context.Complete(result); context.Complete(result);
@ -68,8 +69,9 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
{ {
var file = new NoopAssetFile(); var file = new NoopAssetFile();
var command = CreateCommand(new UploadAppImage { AppId = appId, File = file }); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new UploadAppImage { AppId = appId, File = file });
A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(A<Stream>._)) A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(A<Stream>._))
.Returns(new ImageInfo(100, 100, false)); .Returns(new ImageInfo(100, 100, false));
@ -87,8 +89,9 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
var file = new NoopAssetFile(); var file = new NoopAssetFile();
var command = CreateCommand(new UploadAppImage { AppId = appId, File = file }); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new UploadAppImage { AppId = appId, File = file });
A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(stream)) A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(stream))
.Returns(Task.FromResult<ImageInfo?>(null)); .Returns(Task.FromResult<ImageInfo?>(null));

64
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetCommandMiddlewareTests.cs

@ -87,8 +87,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
[Fact] [Fact]
public async Task Should_not_invoke_enricher_for_other_result() public async Task Should_not_invoke_enricher_for_other_result()
{ {
var command = CreateCommand(new MyCommand()); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new MyCommand());
context.Complete(12); context.Complete(12);
@ -103,8 +104,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
{ {
var result = new AssetEntity(); var result = new AssetEntity();
var command = CreateCommand(new MyCommand()); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new MyCommand());
context.Complete(result); context.Complete(result);
@ -121,8 +123,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
{ {
var result = A.Fake<IAssetEntity>(); var result = A.Fake<IAssetEntity>();
var command = CreateCommand(new MyCommand()); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new MyCommand());
context.Complete(result); context.Complete(result);
@ -139,8 +142,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
[Fact] [Fact]
public async Task Create_should_create_domain_object() public async Task Create_should_create_domain_object()
{ {
var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file }); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new CreateAsset { AssetId = assetId, File = file });
await sut.HandleAsync(context); await sut.HandleAsync(context);
@ -155,8 +159,11 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
[Fact] [Fact]
public async Task Create_should_calculate_hash() public async Task Create_should_calculate_hash()
{ {
var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file }); var command = new CreateAsset { AssetId = assetId, File = file };
var context = CreateContextForCommand(command);
var context =
CreateCommandContext(
command);
await sut.HandleAsync(context); await sut.HandleAsync(context);
@ -166,8 +173,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
[Fact] [Fact]
public async Task Create_should_return_duplicate_result_if_file_with_same_hash_found() public async Task Create_should_return_duplicate_result_if_file_with_same_hash_found()
{ {
var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file }); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new CreateAsset { AssetId = assetId, File = file });
SetupSameHashAsset(file.FileName, file.FileSize, out _); SetupSameHashAsset(file.FileName, file.FileSize, out _);
@ -181,8 +189,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
[Fact] [Fact]
public async Task Create_should_not_return_duplicate_result_if_file_with_same_hash_found_but_duplicate_allowed() public async Task Create_should_not_return_duplicate_result_if_file_with_same_hash_found_but_duplicate_allowed()
{ {
var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file, Duplicate = true }); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new CreateAsset { AssetId = assetId, File = file, Duplicate = true });
SetupSameHashAsset(file.FileName, file.FileSize, out _); SetupSameHashAsset(file.FileName, file.FileSize, out _);
@ -196,8 +205,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
[Fact] [Fact]
public async Task Create_should_pass_through_duplicate() public async Task Create_should_pass_through_duplicate()
{ {
var command = CreateCommand(new CreateAsset { AssetId = assetId, File = file }); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new CreateAsset { AssetId = assetId, File = file });
SetupSameHashAsset(file.FileName, file.FileSize, out var duplicate); SetupSameHashAsset(file.FileName, file.FileSize, out var duplicate);
@ -213,8 +223,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
[Fact] [Fact]
public async Task Update_should_update_domain_object() public async Task Update_should_update_domain_object()
{ {
var command = CreateCommand(new UpdateAsset { AssetId = assetId, File = file }); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new UpdateAsset { AssetId = assetId, File = file });
await ExecuteCreateAsync(); await ExecuteCreateAsync();
@ -227,8 +238,11 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
[Fact] [Fact]
public async Task Update_should_calculate_hash() public async Task Update_should_calculate_hash()
{ {
var command = CreateCommand(new UpdateAsset { AssetId = assetId, File = file }); var command = new UpdateAsset { AssetId = assetId, File = file };
var context = CreateContextForCommand(command);
var context =
CreateCommandContext(
command);
await ExecuteCreateAsync(); await ExecuteCreateAsync();
@ -240,8 +254,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
[Fact] [Fact]
public async Task Update_should_enrich_asset() public async Task Update_should_enrich_asset()
{ {
var command = CreateCommand(new UpdateAsset { AssetId = assetId, File = file }); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new UpdateAsset { AssetId = assetId, File = file });
await ExecuteCreateAsync(); await ExecuteCreateAsync();
@ -255,8 +270,9 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
[Fact] [Fact]
public async Task AnnotateAsset_should_enrich_asset() public async Task AnnotateAsset_should_enrich_asset()
{ {
var command = CreateCommand(new AnnotateAsset { AssetId = assetId, FileName = "newName" }); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new AnnotateAsset { AssetId = assetId, FileName = "newName" });
await ExecuteCreateAsync(); await ExecuteCreateAsync();

15
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentCommandMiddlewareTests.cs

@ -46,8 +46,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
[Fact] [Fact]
public async Task Should_not_invoke_enricher_for_other_result() public async Task Should_not_invoke_enricher_for_other_result()
{ {
var command = CreateCommand(new MyCommand()); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new MyCommand());
context.Complete(12); context.Complete(12);
@ -62,8 +63,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
{ {
var result = new ContentEntity(); var result = new ContentEntity();
var command = CreateCommand(new MyCommand()); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new MyCommand());
context.Complete(result); context.Complete(result);
@ -80,8 +82,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject
{ {
var result = A.Fake<IContentEntity>(); var result = A.Fake<IContentEntity>();
var command = CreateCommand(new MyCommand()); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new MyCommand());
context.Complete(result); context.Complete(result);

161
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/Guards/GuardContentTests.cs

@ -25,88 +25,86 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
{ {
public class GuardContentTests : IClassFixture<TranslationsFixture> public class GuardContentTests : IClassFixture<TranslationsFixture>
{ {
private readonly IContentWorkflow contentWorkflow = A.Fake<IContentWorkflow>(); private readonly IContentWorkflow workflow = A.Fake<IContentWorkflow>();
private readonly IContentRepository contentRepository = A.Fake<IContentRepository>(); private readonly IContentRepository contentRepository = A.Fake<IContentRepository>();
private readonly NamedId<DomainId> appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly NamedId<DomainId> appId = NamedId.Of(DomainId.NewGuid(), "my-app");
private readonly NamedId<DomainId> schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly NamedId<DomainId> schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema");
private readonly ISchemaEntity schema;
private readonly ISchemaEntity singleton;
private readonly ClaimsPrincipal user = Mocks.FrontendUser(); private readonly ClaimsPrincipal user = Mocks.FrontendUser();
private readonly Instant dueTimeInPast = SystemClock.Instance.GetCurrentInstant().Minus(Duration.FromHours(1)); private readonly Instant dueTimeInPast = SystemClock.Instance.GetCurrentInstant().Minus(Duration.FromHours(1));
private readonly RefToken actor = RefToken.User("123"); private readonly RefToken actor = RefToken.User("123");
public GuardContentTests()
{
schema =
Mocks.Schema(appId, schemaId, new Schema(schemaId.Name));
singleton =
Mocks.Schema(appId, schemaId, new Schema(schemaId.Name, isSingleton: true));
}
[Fact] [Fact]
public async Task CanCreate_should_throw_exception_if_data_is_null() public async Task CanCreate_should_throw_exception_if_data_is_null()
{ {
var schema = CreateSchema(false);
var command = new CreateContent(); var command = new CreateContent();
await ValidationAssert.ThrowsAsync(() => GuardContent.CanCreate(command, contentWorkflow, schema), await ValidationAssert.ThrowsAsync(() => GuardContent.CanCreate(command, workflow, schema),
new ValidationError("Data is required.", "Data")); new ValidationError("Data is required.", "Data"));
} }
[Fact] [Fact]
public async Task CanCreate_should_throw_exception_if_singleton() public async Task CanCreate_should_throw_exception_if_singleton()
{ {
var schema = CreateSchema(true);
var command = new CreateContent { Data = new ContentData() }; var command = new CreateContent { Data = new ContentData() };
await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanCreate(command, contentWorkflow, schema)); await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanCreate(command, workflow, singleton));
} }
[Fact] [Fact]
public async Task CanCreate_should_not_throw_exception_if_singleton_and_id_is_schema_id() public async Task CanCreate_should_not_throw_exception_if_singleton_and_id_is_schema_id()
{ {
var schema = CreateSchema(true);
var command = new CreateContent { Data = new ContentData(), ContentId = schema.Id }; var command = new CreateContent { Data = new ContentData(), ContentId = schema.Id };
await GuardContent.CanCreate(command, contentWorkflow, schema); await GuardContent.CanCreate(command, workflow, schema);
} }
[Fact] [Fact]
public async Task CanCreate_should_throw_exception_publish_not_allowed() public async Task CanCreate_should_throw_exception_if_publishing_not_allowed()
{ {
var schema = CreateSchema(false); SetupCanCreatePublish(false);
SetupCanCreatePublish(schema, false);
var command = new CreateContent { Data = new ContentData(), Publish = true }; var command = new CreateContent { Data = new ContentData(), Publish = true };
await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanCreate(command, contentWorkflow, schema)); await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanCreate(command, workflow, schema));
} }
[Fact] [Fact]
public async Task CanCreate_should_not_throw_exception_publishing_allowed() public async Task CanCreate_should_not_throw_exception_if_publishing_allowed()
{ {
var schema = CreateSchema(false); SetupCanCreatePublish(true);
SetupCanCreatePublish(schema, true);
var command = new CreateContent { Data = new ContentData(), Publish = true }; var command = new CreateContent { Data = new ContentData(), Publish = true };
await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanCreate(command, contentWorkflow, schema)); await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanCreate(command, workflow, schema));
} }
[Fact] [Fact]
public async Task CanCreate_should_not_throw_exception_if_data_is_not_null() public async Task CanCreate_should_not_throw_exception_if_data_is_not_null()
{ {
var schema = CreateSchema(false);
var command = new CreateContent { Data = new ContentData() }; var command = new CreateContent { Data = new ContentData() };
await GuardContent.CanCreate(command, contentWorkflow, schema); await GuardContent.CanCreate(command, workflow, schema);
} }
[Fact] [Fact]
public async Task CanUpdate_should_throw_exception_if_data_is_null() public async Task CanUpdate_should_throw_exception_if_data_is_null()
{ {
SetupCanUpdate(true);
var content = CreateContent(Status.Draft); var content = CreateContent(Status.Draft);
var command = CreateCommand(new UpdateContent()); var command = CreateCommand(new UpdateContent());
await ValidationAssert.ThrowsAsync(() => GuardContent.CanUpdate(command, content, contentWorkflow), await ValidationAssert.ThrowsAsync(() => GuardContent.CanUpdate(command, content, workflow),
new ValidationError("Data is required.", "Data")); new ValidationError("Data is required.", "Data"));
} }
@ -116,9 +114,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
SetupCanUpdate(false); SetupCanUpdate(false);
var content = CreateContent(Status.Draft); var content = CreateContent(Status.Draft);
var command = CreateCommand(new UpdateContent { Data = new ContentData() }); var command = CreateCommand(new UpdateContent { Data = new ContentData() });
await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanUpdate(command, content, contentWorkflow)); await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanUpdate(command, content, workflow));
} }
[Fact] [Fact]
@ -127,9 +126,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
SetupCanUpdate(true); SetupCanUpdate(true);
var content = CreateContent(Status.Draft); var content = CreateContent(Status.Draft);
var command = CreateCommand(new UpdateContent { Data = new ContentData() }); var command = CreateCommand(new UpdateContent { Data = new ContentData() });
await GuardContent.CanUpdate(command, content, contentWorkflow); await GuardContent.CanUpdate(command, content, workflow);
} }
[Fact] [Fact]
@ -138,9 +138,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
SetupCanUpdate(true); SetupCanUpdate(true);
var content = CreateContent(Status.Draft); var content = CreateContent(Status.Draft);
var command = CreateCommand(new PatchContent()); var command = CreateCommand(new PatchContent());
await ValidationAssert.ThrowsAsync(() => GuardContent.CanPatch(command, content, contentWorkflow), await ValidationAssert.ThrowsAsync(() => GuardContent.CanPatch(command, content, workflow),
new ValidationError("Data is required.", "Data")); new ValidationError("Data is required.", "Data"));
} }
@ -150,9 +151,10 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
SetupCanUpdate(false); SetupCanUpdate(false);
var content = CreateContent(Status.Draft); var content = CreateContent(Status.Draft);
var command = CreateCommand(new PatchContent { Data = new ContentData() }); var command = CreateCommand(new PatchContent { Data = new ContentData() });
await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanPatch(command, content, contentWorkflow)); await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanPatch(command, content, workflow));
} }
[Fact] [Fact]
@ -161,95 +163,91 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
SetupCanUpdate(true); SetupCanUpdate(true);
var content = CreateContent(Status.Draft); var content = CreateContent(Status.Draft);
var command = CreateCommand(new PatchContent { Data = new ContentData() }); var command = CreateCommand(new PatchContent { Data = new ContentData() });
await GuardContent.CanPatch(command, content, contentWorkflow); await GuardContent.CanPatch(command, content, workflow);
} }
[Fact] [Fact]
public async Task CanChangeStatus_should_throw_exception_if_singleton() public async Task CanChangeStatus_should_throw_exception_if_singleton()
{ {
var schema = CreateSchema(true);
var content = CreateContent(Status.Published); var content = CreateContent(Status.Published);
var command = CreateCommand(new ChangeContentStatus { Status = Status.Draft }); var command = CreateCommand(new ChangeContentStatus { Status = Status.Draft });
await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanChangeStatus(command, content, contentWorkflow, contentRepository, schema)); await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanChangeStatus(command, content, workflow, contentRepository, singleton));
} }
[Fact] [Fact]
public async Task CanChangeStatus_should_throw_exception_if_due_date_in_past() public async Task CanChangeStatus_should_throw_exception_if_due_date_in_past()
{ {
var schema = CreateSchema(false);
var content = CreateContent(Status.Draft); var content = CreateContent(Status.Draft);
var command = CreateCommand(new ChangeContentStatus { Status = Status.Published, DueTime = dueTimeInPast }); var command = CreateCommand(new ChangeContentStatus { Status = Status.Published, DueTime = dueTimeInPast });
A.CallTo(() => contentWorkflow.CanMoveToAsync(content, content.Status, command.Status, user)) A.CallTo(() => workflow.CanMoveToAsync(content, content.Status, command.Status, user))
.Returns(true); .Returns(true);
await ValidationAssert.ThrowsAsync(() => GuardContent.CanChangeStatus(command, content, contentWorkflow, contentRepository, schema), await ValidationAssert.ThrowsAsync(() => GuardContent.CanChangeStatus(command, content, workflow, contentRepository, schema),
new ValidationError("Due time must be in the future.", "DueTime")); new ValidationError("Due time must be in the future.", "DueTime"));
} }
[Fact] [Fact]
public async Task CanChangeStatus_should_throw_exception_if_status_flow_not_valid() public async Task CanChangeStatus_should_throw_exception_if_status_flow_not_valid()
{ {
var schema = CreateSchema(false);
var content = CreateContent(Status.Draft); var content = CreateContent(Status.Draft);
var command = CreateCommand(new ChangeContentStatus { Status = Status.Published }); var command = CreateCommand(new ChangeContentStatus { Status = Status.Published });
A.CallTo(() => contentWorkflow.CanMoveToAsync(content, content.Status, command.Status, user)) A.CallTo(() => workflow.CanMoveToAsync(content, content.Status, command.Status, user))
.Returns(false); .Returns(false);
await ValidationAssert.ThrowsAsync(() => GuardContent.CanChangeStatus(command, content, contentWorkflow, contentRepository, schema), await ValidationAssert.ThrowsAsync(() => GuardContent.CanChangeStatus(command, content, workflow, contentRepository, schema),
new ValidationError("Cannot change status from Draft to Published.", "Status")); new ValidationError("Cannot change status from Draft to Published.", "Status"));
} }
[Fact] [Fact]
public async Task CanChangeStatus_should_throw_exception_if_referenced() public async Task CanChangeStatus_should_throw_exception_if_referenced()
{ {
var schema = CreateSchema(true);
var content = CreateContent(Status.Published); var content = CreateContent(Status.Published);
var command = CreateCommand(new ChangeContentStatus { Status = Status.Draft }); var command = CreateCommand(new ChangeContentStatus { Status = Status.Draft });
A.CallTo(() => contentRepository.HasReferrersAsync(appId.Id, content.Id, SearchScope.Published)) A.CallTo(() => contentRepository.HasReferrersAsync(appId.Id, content.Id, SearchScope.Published))
.Returns(true); .Returns(true);
await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanChangeStatus(command, content, contentWorkflow, contentRepository, schema)); await Assert.ThrowsAsync<ValidationException>(() => GuardContent.CanChangeStatus(command, content, workflow, contentRepository, schema));
} }
[Fact] [Fact]
public async Task CanChangeStatus_should_not_throw_exception_if_singleton_is_published() public async Task CanChangeStatus_should_not_throw_exception_if_singleton_is_published()
{ {
var schema = CreateSchema(true);
var content = CreateDraftContent(Status.Draft); var content = CreateDraftContent(Status.Draft);
var command = CreateCommand(new ChangeContentStatus { Status = Status.Published }); var command = CreateCommand(new ChangeContentStatus { Status = Status.Published });
await GuardContent.CanChangeStatus(command, content, contentWorkflow, contentRepository, schema); await GuardContent.CanChangeStatus(command, content, workflow, contentRepository, singleton);
} }
[Fact] [Fact]
public async Task CanChangeStatus_should_not_throw_exception_if_status_flow_valid() public async Task CanChangeStatus_should_not_throw_exception_if_status_flow_valid()
{ {
var schema = CreateSchema(false);
var content = CreateContent(Status.Draft); var content = CreateContent(Status.Draft);
var command = CreateCommand(new ChangeContentStatus { Status = Status.Published }); var command = CreateCommand(new ChangeContentStatus { Status = Status.Published });
A.CallTo(() => contentWorkflow.CanMoveToAsync(content, content.Status, command.Status, user)) A.CallTo(() => workflow.CanMoveToAsync(content, content.Status, command.Status, user))
.Returns(true); .Returns(true);
await GuardContent.CanChangeStatus(command, content, contentWorkflow, contentRepository, schema); await GuardContent.CanChangeStatus(command, content, workflow, contentRepository, schema);
} }
[Fact] [Fact]
public void CreateDraft_should_throw_exception_if_not_published() public void CreateDraft_should_throw_exception_if_not_published()
{ {
var content = CreateContent(Status.Draft); var content = CreateContent(Status.Draft);
var command = CreateCommand(new CreateContentDraft()); var command = CreateCommand(new CreateContentDraft());
Assert.Throws<DomainException>(() => GuardContent.CanCreateDraft(command, content)); Assert.Throws<DomainException>(() => GuardContent.CanCreateDraft(command, content));
@ -259,6 +257,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
public void CreateDraft_should_not_throw_exception() public void CreateDraft_should_not_throw_exception()
{ {
var content = CreateContent(Status.Published); var content = CreateContent(Status.Published);
var command = CreateCommand(new CreateContentDraft()); var command = CreateCommand(new CreateContentDraft());
GuardContent.CanCreateDraft(command, content); GuardContent.CanCreateDraft(command, content);
@ -267,9 +266,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
[Fact] [Fact]
public void CanDeleteDraft_should_throw_exception_if_no_draft_found() public void CanDeleteDraft_should_throw_exception_if_no_draft_found()
{ {
CreateSchema(false);
var content = CreateContent(Status.Published); var content = CreateContent(Status.Published);
var command = CreateCommand(new DeleteContentDraft()); var command = CreateCommand(new DeleteContentDraft());
Assert.Throws<DomainException>(() => GuardContent.CanDeleteDraft(command, content)); Assert.Throws<DomainException>(() => GuardContent.CanDeleteDraft(command, content));
@ -279,6 +277,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
public void CanDeleteDraft_should_not_throw_exception() public void CanDeleteDraft_should_not_throw_exception()
{ {
var content = CreateDraftContent(Status.Draft); var content = CreateDraftContent(Status.Draft);
var command = CreateCommand(new DeleteContentDraft()); var command = CreateCommand(new DeleteContentDraft());
GuardContent.CanDeleteDraft(command, content); GuardContent.CanDeleteDraft(command, content);
@ -287,21 +286,19 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
[Fact] [Fact]
public async Task CanDelete_should_throw_exception_if_singleton() public async Task CanDelete_should_throw_exception_if_singleton()
{ {
var schema = CreateSchema(true);
var content = CreateContent(Status.Published); var content = CreateContent(Status.Published);
var command = CreateCommand(new DeleteContent()); var command = CreateCommand(new DeleteContent());
await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanDelete(command, content, contentRepository, schema)); await Assert.ThrowsAsync<DomainException>(() => GuardContent.CanDelete(command, content, contentRepository, singleton));
} }
[Fact] [Fact]
public async Task CanDelete_should_throw_exception_if_referenced() public async Task CanDelete_should_throw_exception_if_referenced()
{ {
var schema = CreateSchema(true);
var content = CreateContent(Status.Published); var content = CreateContent(Status.Published);
var command = CreateCommand(new DeleteContent());
var command = CreateCommand(new DeleteContent { CheckReferrers = true });
A.CallTo(() => contentRepository.HasReferrersAsync(appId.Id, content.Id, SearchScope.All)) A.CallTo(() => contentRepository.HasReferrersAsync(appId.Id, content.Id, SearchScope.All))
.Returns(true); .Returns(true);
@ -312,9 +309,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
[Fact] [Fact]
public async Task CanDelete_should_not_throw_exception() public async Task CanDelete_should_not_throw_exception()
{ {
var schema = CreateSchema(false);
var content = CreateContent(Status.Published); var content = CreateContent(Status.Published);
var command = CreateCommand(new DeleteContent()); var command = CreateCommand(new DeleteContent());
await GuardContent.CanDelete(command, content, contentRepository, schema); await GuardContent.CanDelete(command, content, contentRepository, schema);
@ -324,21 +320,35 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
public void CheckPermission_should_not_throw_exception_if_content_is_from_current_user() public void CheckPermission_should_not_throw_exception_if_content_is_from_current_user()
{ {
var content = CreateContent(status: Status.Published); var content = CreateContent(status: Status.Published);
var command = CreateCommand(new DeleteContent()); var command = CreateCommand(new DeleteContent());
GuardContent.CheckPermission(content, command, Permissions.AppContentsDelete); GuardContent.CheckPermission(content, command, Permissions.AppContentsDelete);
} }
[Fact] [Fact]
public void CheckPermission_should_not_throw_exception_if_content_is_from_another_user_but_user_has_permission() public void CheckPermission_should_not_throw_exception_if_user_is_null()
{ {
var permission = Permissions.ForApp(Permissions.AppContentsDelete, appId.Name, schemaId.Name).Id; var content = CreateContent(Status.Published);
var otherUser = Mocks.FrontendUser(permission: permission); var commandActor = RefToken.User("456");
var otherActor = RefToken.User("456"); var command = CreateCommand(new DeleteContent { Actor = commandActor });
command.User = null;
GuardContent.CheckPermission(content, command, Permissions.AppContentsDelete);
}
[Fact]
public void CheckPermission_should_not_throw_exception_if_content_is_from_another_user_but_user_has_permission()
{
var content = CreateContent(Status.Published); var content = CreateContent(Status.Published);
var command = CreateCommand(new DeleteContent { Actor = otherActor, User = otherUser });
var permission = Permissions.ForApp(Permissions.AppContentsDelete, appId.Name, schemaId.Name).Id;
var commandUser = Mocks.FrontendUser(permission: permission);
var commandActor = RefToken.User("456");
var command = CreateCommand(new DeleteContent { Actor = commandActor, User = commandUser });
GuardContent.CheckPermission(content, command, Permissions.AppContentsDelete); GuardContent.CheckPermission(content, command, Permissions.AppContentsDelete);
} }
@ -346,31 +356,26 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards
[Fact] [Fact]
public void CheckPermission_should_exception_if_content_is_from_another_user_and_user_has_no_permission() public void CheckPermission_should_exception_if_content_is_from_another_user_and_user_has_no_permission()
{ {
var otherActor = RefToken.User("456");
var content = CreateContent(Status.Published); var content = CreateContent(Status.Published);
var command = CreateCommand(new DeleteContent { Actor = otherActor });
var commandActor = RefToken.User("456");
var command = CreateCommand(new DeleteContent { Actor = commandActor });
Assert.Throws<DomainForbiddenException>(() => GuardContent.CheckPermission(content, command, Permissions.AppContentsDelete)); Assert.Throws<DomainForbiddenException>(() => GuardContent.CheckPermission(content, command, Permissions.AppContentsDelete));
} }
private void SetupCanUpdate(bool canUpdate) private void SetupCanUpdate(bool canUpdate)
{ {
A.CallTo(() => contentWorkflow.CanUpdateAsync(A<IContentEntity>._, A<Status>._, user)) A.CallTo(() => workflow.CanUpdateAsync(A<IContentEntity>._, A<Status>._, user))
.Returns(canUpdate); .Returns(canUpdate);
} }
private void SetupCanCreatePublish(ISchemaEntity schema, bool canCreate) private void SetupCanCreatePublish(bool canCreate)
{ {
A.CallTo(() => contentWorkflow.CanPublishOnCreateAsync(schema, A<ContentData>._, user)) A.CallTo(() => workflow.CanPublishOnCreateAsync(schema, A<ContentData>._, user))
.Returns(canCreate); .Returns(canCreate);
} }
private ISchemaEntity CreateSchema(bool isSingleton)
{
return Mocks.Schema(appId, schemaId, new Schema(schemaId.Name, isSingleton: isSingleton));
}
private T CreateCommand<T>(T command) where T : ContentCommand private T CreateCommand<T>(T command) where T : ContentCommand
{ {
if (command.Actor == null) if (command.Actor == null)

22
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs

@ -18,7 +18,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
public class EnrichWithWorkflowsTests public class EnrichWithWorkflowsTests
{ {
private readonly IContentWorkflow contentWorkflow = A.Fake<IContentWorkflow>(); private readonly IContentWorkflow workflow = A.Fake<IContentWorkflow>();
private readonly Context requestContext; private readonly Context requestContext;
private readonly NamedId<DomainId> appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly NamedId<DomainId> appId = NamedId.Of(DomainId.NewGuid(), "my-app");
private readonly NamedId<DomainId> schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly NamedId<DomainId> schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema");
@ -29,7 +29,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
requestContext = new Context(Mocks.FrontendUser(), Mocks.App(appId)); requestContext = new Context(Mocks.FrontendUser(), Mocks.App(appId));
sut = new EnrichWithWorkflows(contentWorkflow); sut = new EnrichWithWorkflows(workflow);
} }
[Fact] [Fact]
@ -42,7 +42,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
new StatusInfo(Status.Published, StatusColors.Published) new StatusInfo(Status.Published, StatusColors.Published)
}; };
A.CallTo(() => contentWorkflow.GetNextAsync(content, content.Status, requestContext.User)) A.CallTo(() => workflow.GetNextAsync(content, content.Status, requestContext.User))
.Returns(nexts); .Returns(nexts);
await sut.EnrichAsync(requestContext, new[] { content }, null!); await sut.EnrichAsync(requestContext, new[] { content }, null!);
@ -59,7 +59,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
Assert.Equal(Status.Published, content.NextStatuses?.Single().Status); Assert.Equal(Status.Published, content.NextStatuses?.Single().Status);
A.CallTo(() => contentWorkflow.GetNextAsync(content, A<Status>._, requestContext.User)) A.CallTo(() => workflow.GetNextAsync(content, A<Status>._, requestContext.User))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -72,7 +72,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
Assert.Empty(content.NextStatuses); Assert.Empty(content.NextStatuses);
A.CallTo(() => contentWorkflow.GetNextAsync(content, A<Status>._, requestContext.User)) A.CallTo(() => workflow.GetNextAsync(content, A<Status>._, requestContext.User))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
@ -81,7 +81,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
var content = new ContentEntity { SchemaId = schemaId }; var content = new ContentEntity { SchemaId = schemaId };
A.CallTo(() => contentWorkflow.GetInfoAsync(content, content.Status)) A.CallTo(() => workflow.GetInfoAsync(content, content.Status))
.Returns(new StatusInfo(Status.Published, StatusColors.Published)); .Returns(new StatusInfo(Status.Published, StatusColors.Published));
await sut.EnrichAsync(requestContext, new[] { content }, null!); await sut.EnrichAsync(requestContext, new[] { content }, null!);
@ -94,7 +94,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
var content = new ContentEntity { SchemaId = schemaId, NewStatus = Status.Archived }; var content = new ContentEntity { SchemaId = schemaId, NewStatus = Status.Archived };
A.CallTo(() => contentWorkflow.GetInfoAsync(content, content.NewStatus.Value)) A.CallTo(() => workflow.GetInfoAsync(content, content.NewStatus.Value))
.Returns(new StatusInfo(Status.Published, StatusColors.Archived)); .Returns(new StatusInfo(Status.Published, StatusColors.Archived));
await sut.EnrichAsync(requestContext, new[] { content }, null!); await sut.EnrichAsync(requestContext, new[] { content }, null!);
@ -107,7 +107,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
var content = new ContentEntity { SchemaId = schemaId, ScheduleJob = ScheduleJob.Build(Status.Archived, user, default) }; var content = new ContentEntity { SchemaId = schemaId, ScheduleJob = ScheduleJob.Build(Status.Archived, user, default) };
A.CallTo(() => contentWorkflow.GetInfoAsync(content, content.ScheduleJob.Status)) A.CallTo(() => workflow.GetInfoAsync(content, content.ScheduleJob.Status))
.Returns(new StatusInfo(Status.Published, StatusColors.Archived)); .Returns(new StatusInfo(Status.Published, StatusColors.Archived));
await sut.EnrichAsync(requestContext, new[] { content }, null!); await sut.EnrichAsync(requestContext, new[] { content }, null!);
@ -120,7 +120,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
var content = new ContentEntity { SchemaId = schemaId }; var content = new ContentEntity { SchemaId = schemaId };
A.CallTo(() => contentWorkflow.GetInfoAsync(content, content.Status)) A.CallTo(() => workflow.GetInfoAsync(content, content.Status))
.Returns(Task.FromResult<StatusInfo>(null!)); .Returns(Task.FromResult<StatusInfo>(null!));
var ctx = requestContext.Clone(b => b.WithResolveFlow(false)); var ctx = requestContext.Clone(b => b.WithResolveFlow(false));
@ -135,7 +135,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
{ {
var content = new ContentEntity { SchemaId = schemaId }; var content = new ContentEntity { SchemaId = schemaId };
A.CallTo(() => contentWorkflow.CanUpdateAsync(content, content.Status, requestContext.User)) A.CallTo(() => workflow.CanUpdateAsync(content, content.Status, requestContext.User))
.Returns(true); .Returns(true);
var ctx = requestContext.Clone(b => b.WithResolveFlow(false)); var ctx = requestContext.Clone(b => b.WithResolveFlow(false));
@ -156,7 +156,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries
Assert.False(content.CanUpdate); Assert.False(content.CanUpdate);
A.CallTo(() => contentWorkflow.CanUpdateAsync(content, A<Status>._, requestContext.User)) A.CallTo(() => workflow.CanUpdateAsync(content, A<Status>._, requestContext.User))
.MustNotHaveHappened(); .MustNotHaveHappened();
} }
} }

26
backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/GuardRuleTests.cs

@ -41,15 +41,14 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards
[Fact] [Fact]
public async Task CanCreate_should_throw_exception_if_trigger_null() public async Task CanCreate_should_throw_exception_if_trigger_null()
{ {
var command = new CreateRule var command = CreateCommand(new CreateRule
{ {
Trigger = null!,
Action = new TestAction Action = new TestAction
{ {
Url = validUrl Url = validUrl
}, },
AppId = appId Trigger = null!,
}; });
await ValidationAssert.ThrowsAsync(() => GuardRule.CanCreate(command, appProvider), await ValidationAssert.ThrowsAsync(() => GuardRule.CanCreate(command, appProvider),
new ValidationError("Trigger is required.", "Trigger")); new ValidationError("Trigger is required.", "Trigger"));
@ -58,15 +57,14 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards
[Fact] [Fact]
public async Task CanCreate_should_throw_exception_if_action_null() public async Task CanCreate_should_throw_exception_if_action_null()
{ {
var command = new CreateRule var command = CreateCommand(new CreateRule
{ {
Trigger = new ContentChangedTriggerV2 Trigger = new ContentChangedTriggerV2
{ {
Schemas = ReadOnlyCollection.Empty<ContentChangedTriggerSchemaV2>() Schemas = ReadOnlyCollection.Empty<ContentChangedTriggerSchemaV2>()
}, },
Action = null!, Action = null!,
AppId = appId });
};
await ValidationAssert.ThrowsAsync(() => GuardRule.CanCreate(command, appProvider), await ValidationAssert.ThrowsAsync(() => GuardRule.CanCreate(command, appProvider),
new ValidationError("Action is required.", "Action")); new ValidationError("Action is required.", "Action"));
@ -75,7 +73,7 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards
[Fact] [Fact]
public async Task CanCreate_should_not_throw_exception_if_trigger_and_action_valid() public async Task CanCreate_should_not_throw_exception_if_trigger_and_action_valid()
{ {
var command = new CreateRule var command = CreateCommand(new CreateRule
{ {
Trigger = new ContentChangedTriggerV2 Trigger = new ContentChangedTriggerV2
{ {
@ -84,9 +82,8 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards
Action = new TestAction Action = new TestAction
{ {
Url = validUrl Url = validUrl
}, }
AppId = appId });
};
await GuardRule.CanCreate(command, appProvider); await GuardRule.CanCreate(command, appProvider);
} }
@ -150,6 +147,13 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards
GuardRule.CanDelete(command); GuardRule.CanDelete(command);
} }
private CreateRule CreateCommand(CreateRule command)
{
command.AppId = appId;
return command;
}
private IRuleEntity Rule() private IRuleEntity Rule()
{ {
var rule = A.Fake<IRuleEntity>(); var rule = A.Fake<IRuleEntity>();

15
backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleCommandMiddlewareTests.cs

@ -45,8 +45,9 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject
[Fact] [Fact]
public async Task Should_not_invoke_enricher_for_other_result() public async Task Should_not_invoke_enricher_for_other_result()
{ {
var command = CreateCommand(new MyCommand()); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new MyCommand());
context.Complete(12); context.Complete(12);
@ -61,8 +62,9 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject
{ {
var result = new RuleEntity(); var result = new RuleEntity();
var command = CreateCommand(new MyCommand()); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new MyCommand());
context.Complete(result); context.Complete(result);
@ -79,8 +81,9 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject
{ {
var result = A.Fake<IRuleEntity>(); var result = A.Fake<IRuleEntity>();
var command = CreateCommand(new MyCommand()); var context =
var context = CreateContextForCommand(command); CreateCommandContext(
new MyCommand());
context.Complete(result); context.Complete(result);

81
backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/Guards/GuardSchemaTests.cs

@ -36,7 +36,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_name_not_valid() public void CanCreate_should_throw_exception_if_name_not_valid()
{ {
var command = new CreateSchema { AppId = appId, Name = "INVALID NAME" }; var command = CreateCommand(new CreateSchema { Name = "INVALID NAME" });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("Name is not a valid slug.", "Name")); new ValidationError("Name is not a valid slug.", "Name"));
@ -45,9 +45,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_field_name_invalid() public void CanCreate_should_throw_exception_if_field_name_invalid()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
AppId = appId,
Fields = new[] Fields = new[]
{ {
new UpsertSchemaField new UpsertSchemaField
@ -58,7 +57,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
} }
}, },
Name = "new-schema" Name = "new-schema"
}; });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("Name is not a Javascript property name.", new ValidationError("Name is not a Javascript property name.",
@ -68,9 +67,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_field_properties_null() public void CanCreate_should_throw_exception_if_field_properties_null()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
AppId = appId,
Fields = new[] Fields = new[]
{ {
new UpsertSchemaField new UpsertSchemaField
@ -81,7 +79,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
} }
}, },
Name = "new-schema" Name = "new-schema"
}; });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("Properties is required.", new ValidationError("Properties is required.",
@ -91,9 +89,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_field_properties_not_valid() public void CanCreate_should_throw_exception_if_field_properties_not_valid()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
AppId = appId,
Fields = new[] Fields = new[]
{ {
new UpsertSchemaField new UpsertSchemaField
@ -104,7 +101,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
} }
}, },
Name = "new-schema" Name = "new-schema"
}; });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("Max length must be greater or equal to min length.", new ValidationError("Max length must be greater or equal to min length.",
@ -115,9 +112,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_field_partitioning_not_valid() public void CanCreate_should_throw_exception_if_field_partitioning_not_valid()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
AppId = appId,
Fields = new[] Fields = new[]
{ {
new UpsertSchemaField new UpsertSchemaField
@ -128,7 +124,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
} }
}, },
Name = "new-schema" Name = "new-schema"
}; });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("Partitioning is not a valid value.", new ValidationError("Partitioning is not a valid value.",
@ -138,9 +134,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_fields_contains_duplicate_name() public void CanCreate_should_throw_exception_if_fields_contains_duplicate_name()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
AppId = appId,
Fields = new[] Fields = new[]
{ {
new UpsertSchemaField new UpsertSchemaField
@ -157,7 +152,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
} }
}, },
Name = "new-schema" Name = "new-schema"
}; });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("Field 'field1' has been added twice.", new ValidationError("Field 'field1' has been added twice.",
@ -167,9 +162,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_nested_field_name_invalid() public void CanCreate_should_throw_exception_if_nested_field_name_invalid()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
AppId = appId,
Fields = new[] Fields = new[]
{ {
new UpsertSchemaField new UpsertSchemaField
@ -188,7 +182,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
} }
}, },
Name = "new-schema" Name = "new-schema"
}; });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("Name is not a Javascript property name.", new ValidationError("Name is not a Javascript property name.",
@ -198,9 +192,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_nested_field_properties_null() public void CanCreate_should_throw_exception_if_nested_field_properties_null()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
AppId = appId,
Fields = new[] Fields = new[]
{ {
new UpsertSchemaField new UpsertSchemaField
@ -219,7 +212,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
} }
}, },
Name = "new-schema" Name = "new-schema"
}; });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("Properties is required.", new ValidationError("Properties is required.",
@ -229,9 +222,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_nested_field_is_array() public void CanCreate_should_throw_exception_if_nested_field_is_array()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
AppId = appId,
Fields = new[] Fields = new[]
{ {
new UpsertSchemaField new UpsertSchemaField
@ -250,7 +242,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
} }
}, },
Name = "new-schema" Name = "new-schema"
}; });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("Nested field cannot be array fields.", new ValidationError("Nested field cannot be array fields.",
@ -260,9 +252,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_nested_field_properties_not_valid() public void CanCreate_should_throw_exception_if_nested_field_properties_not_valid()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
AppId = appId,
Fields = new[] Fields = new[]
{ {
new UpsertSchemaField new UpsertSchemaField
@ -281,7 +272,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
} }
}, },
Name = "new-schema" Name = "new-schema"
}; });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("Max length must be greater or equal to min length.", new ValidationError("Max length must be greater or equal to min length.",
@ -292,9 +283,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_nested_field_have_duplicate_names() public void CanCreate_should_throw_exception_if_nested_field_have_duplicate_names()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
AppId = appId,
Fields = new[] Fields = new[]
{ {
new UpsertSchemaField new UpsertSchemaField
@ -318,7 +308,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
} }
}, },
Name = "new-schema" Name = "new-schema"
}; });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("Field 'nested1' has been added twice.", new ValidationError("Field 'nested1' has been added twice.",
@ -328,9 +318,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_ui_field_is_invalid() public void CanCreate_should_throw_exception_if_ui_field_is_invalid()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
AppId = appId,
Fields = new[] Fields = new[]
{ {
new UpsertSchemaField new UpsertSchemaField
@ -345,7 +334,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
FieldsInLists = new FieldNames("field1"), FieldsInLists = new FieldNames("field1"),
FieldsInReferences = new FieldNames("field1"), FieldsInReferences = new FieldNames("field1"),
Name = "new-schema" Name = "new-schema"
}; });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("UI field cannot be hidden.", new ValidationError("UI field cannot be hidden.",
@ -361,7 +350,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_invalid_lists_field_are_used() public void CanCreate_should_throw_exception_if_invalid_lists_field_are_used()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
Fields = new[] Fields = new[]
{ {
@ -381,7 +370,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
FieldsInLists = new FieldNames(null!, null!, "field3", "field1", "field1", "field4"), FieldsInLists = new FieldNames(null!, null!, "field3", "field1", "field1", "field4"),
FieldsInReferences = null, FieldsInReferences = null,
Name = "new-schema" Name = "new-schema"
}; });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("Field is required.", new ValidationError("Field is required.",
@ -399,7 +388,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_invalid_references_field_are_used() public void CanCreate_should_throw_exception_if_invalid_references_field_are_used()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
Fields = new[] Fields = new[]
{ {
@ -419,7 +408,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
FieldsInLists = null, FieldsInLists = null,
FieldsInReferences = new FieldNames(null!, null!, "field3", "field1", "field1", "field4"), FieldsInReferences = new FieldNames(null!, null!, "field3", "field1", "field1", "field4"),
Name = "new-schema" Name = "new-schema"
}; });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("Field is required.", new ValidationError("Field is required.",
@ -437,12 +426,12 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_references_contains_meta_field() public void CanCreate_should_throw_exception_if_references_contains_meta_field()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
FieldsInLists = null, FieldsInLists = null,
FieldsInReferences = new FieldNames("meta.id"), FieldsInReferences = new FieldNames("meta.id"),
Name = "new-schema" Name = "new-schema"
}; });
ValidationAssert.Throws(() => GuardSchema.CanCreate(command), ValidationAssert.Throws(() => GuardSchema.CanCreate(command),
new ValidationError("Field is not part of the schema.", new ValidationError("Field is not part of the schema.",
@ -452,9 +441,8 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
[Fact] [Fact]
public void CanCreate_should_not_throw_exception_if_command_is_valid() public void CanCreate_should_not_throw_exception_if_command_is_valid()
{ {
var command = new CreateSchema var command = CreateCommand(new CreateSchema
{ {
AppId = appId,
Fields = new[] Fields = new[]
{ {
new UpsertSchemaField new UpsertSchemaField
@ -494,7 +482,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
FieldsInLists = new FieldNames("field1", "meta.id"), FieldsInLists = new FieldNames("field1", "meta.id"),
FieldsInReferences = new FieldNames("field1"), FieldsInReferences = new FieldNames("field1"),
Name = "new-schema" Name = "new-schema"
}; });
GuardSchema.CanCreate(command); GuardSchema.CanCreate(command);
} }
@ -706,6 +694,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards
GuardSchema.CanDelete(command); GuardSchema.CanDelete(command);
} }
private CreateSchema CreateCommand(CreateSchema command)
{
command.AppId = appId;
return command;
}
private static StringFieldProperties ValidProperties() private static StringFieldProperties ValidProperties()
{ {
return new StringFieldProperties { MinLength = 10, MaxLength = 20 }; return new StringFieldProperties { MinLength = 10, MaxLength = 20 };

2
backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs

@ -73,7 +73,7 @@ namespace Squidex.Domain.Apps.Entities.TestHelpers
.Invokes((IEnumerable<Envelope<IEvent>> events) => LastEvents = events); .Invokes((IEnumerable<Envelope<IEvent>> events) => LastEvents = events);
} }
protected CommandContext CreateContextForCommand<TCommand>(TCommand command) where TCommand : SquidexCommand protected CommandContext CreateCommandContext<TCommand>(TCommand command) where TCommand : SquidexCommand
{ {
return new CommandContext(CreateCommand(command), A.Dummy<ICommandBus>()); return new CommandContext(CreateCommand(command), A.Dummy<ICommandBus>());
} }

Loading…
Cancel
Save