diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Assets/AssetScripts.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Assets/AssetScripts.cs index 9d0bc3e07..8ca1320fb 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Assets/AssetScripts.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Assets/AssetScripts.cs @@ -20,4 +20,8 @@ public sealed record AssetScripts public string? Move { get; init; } public string? Delete { get; init; } + + public string? Query { get; init; } + + public string? QueryPre { get; init; } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOptions.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOptions.cs index 58cb1c91b..58d0d46d9 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOptions.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptOptions.cs @@ -7,16 +7,11 @@ namespace Squidex.Domain.Apps.Core.Scripting; -public struct ScriptOptions +public record struct ScriptOptions { public bool CanReject { get; set; } public bool CanDisallow { get; set; } public bool AsContext { get; set; } - - public override readonly string ToString() - { - return $"CanReject={CanReject}, CanDisallow={CanDisallow}, AsContext={AsContext}"; - } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs index 078703f64..58342ae64 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/ContentValidator.cs @@ -37,41 +37,45 @@ public sealed class ContentValidator this.partitionResolver = partitionResolver; } - public ValueTask ValidateInputPartialAsync(ContentData data) + public ValueTask ValidateInputPartialAsync(ContentData data, + CancellationToken ct = default) { Guard.NotNull(data); ValidateInputCore(data, true); - return context.Root.CompleteAsync(); + return context.Root.CompleteAsync(ct); } - public ValueTask ValidateInputAsync(ContentData data) + public ValueTask ValidateInputAsync(ContentData data, + CancellationToken ct = default) { Guard.NotNull(data); ValidateInputCore(data, false); - return context.Root.CompleteAsync(); + return context.Root.CompleteAsync(ct); } - public ValueTask ValidateInputAndContentAsync(ContentData data) + public ValueTask ValidateInputAndContentAsync(ContentData data, + CancellationToken ct = default) { Guard.NotNull(data); ValidateInputCore(data, false); ValidateContentCore(data); - return context.Root.CompleteAsync(); + return context.Root.CompleteAsync(ct); } - public ValueTask ValidateContentAsync(ContentData data) + public ValueTask ValidateContentAsync(ContentData data, + CancellationToken ct = default) { Guard.NotNull(data); ValidateContentCore(data); - return context.Root.CompleteAsync(); + return context.Root.CompleteAsync(ct); } private void ValidateInputCore(ContentData data, bool partial) diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/AtlasIndexDefinition.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/AtlasIndexDefinition.cs index 1ee2ea687..bce6d47eb 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/AtlasIndexDefinition.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Text/AtlasIndexDefinition.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Net; using System.Net.Http.Json; using Squidex.Hosting.Configuration; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetCommandMiddleware.cs index 71f870ebc..a52099eb7 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetCommandMiddleware.cs @@ -8,6 +8,7 @@ using System.Security.Cryptography; using Squidex.Assets; using Squidex.Domain.Apps.Entities.Assets.Commands; +using Squidex.Domain.Apps.Entities.Assets.Queries; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetDomainObject.cs index d2ab859ad..6f98e831d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetDomainObject.cs @@ -70,16 +70,16 @@ public partial class AssetDomainObject : DomainObject if (Version > EtagVersion.Empty && !IsDeleted(Snapshot)) { - await UpdateCore(c.AsUpdate(), operation); + await UpdateCore(c.AsUpdate(), operation, ct); } else { - await CreateCore(c.AsCreate(), operation); + await CreateCore(c.AsCreate(), operation, ct); } if (Is.OptionalChange(Snapshot.ParentId, c.ParentId)) { - await MoveCore(c.AsMove(c.ParentId.Value), operation); + await MoveCore(c.AsMove(c.ParentId.Value), operation, ct); } return Snapshot; @@ -90,11 +90,11 @@ public partial class AssetDomainObject : DomainObject { var operation = await AssetOperation.CreateAsync(serviceProvider, c, () => Snapshot); - await CreateCore(c, operation); + await CreateCore(c, operation, ct); if (Is.Change(Snapshot.ParentId, c.ParentId)) { - await MoveCore(c.AsMove(), operation); + await MoveCore(c.AsMove(), operation, ct); } return Snapshot; @@ -105,7 +105,7 @@ public partial class AssetDomainObject : DomainObject { var operation = await AssetOperation.CreateAsync(serviceProvider, c, () => Snapshot); - await AnnotateCore(c, operation); + await AnnotateCore(c, operation, ct); return Snapshot; }, ct); @@ -115,7 +115,7 @@ public partial class AssetDomainObject : DomainObject { var operation = await AssetOperation.CreateAsync(serviceProvider, c, () => Snapshot); - await UpdateCore(c, operation); + await UpdateCore(c, operation, ct); return Snapshot; }, ct); @@ -125,7 +125,7 @@ public partial class AssetDomainObject : DomainObject { var operation = await AssetOperation.CreateAsync(serviceProvider, c, () => Snapshot); - await MoveCore(c, operation); + await MoveCore(c, operation, ct); return Snapshot; }, ct); @@ -135,7 +135,7 @@ public partial class AssetDomainObject : DomainObject { var operation = await AssetOperation.CreateAsync(serviceProvider, c, () => Snapshot); - await DeleteCore(c, operation); + await DeleteCore(c, operation, ct); }, ct); case DeleteAsset delete: @@ -143,7 +143,7 @@ public partial class AssetDomainObject : DomainObject { var operation = await AssetOperation.CreateAsync(serviceProvider, c, () => Snapshot); - await DeleteCore(c, operation); + await DeleteCore(c, operation, ct); }, ct); default: @@ -152,16 +152,17 @@ public partial class AssetDomainObject : DomainObject } } - private async Task CreateCore(CreateAsset create, AssetOperation operation) + private async Task CreateCore(CreateAsset create, AssetOperation operation, + CancellationToken ct) { if (!create.OptimizeValidation) { - await operation.MustMoveToValidFolder(create.ParentId); + await operation.MustMoveToValidFolder(create.ParentId, ct); } if (!create.DoNotScript) { - await operation.ExecuteCreateScriptAsync(create); + await operation.ExecuteCreateScriptAsync(create, ct); } if (create.Tags != null) @@ -172,11 +173,12 @@ public partial class AssetDomainObject : DomainObject Create(create); } - private async Task AnnotateCore(AnnotateAsset annotate, AssetOperation operation) + private async Task AnnotateCore(AnnotateAsset annotate, AssetOperation operation, + CancellationToken ct) { if (!annotate.DoNotScript) { - await operation.ExecuteAnnotateScriptAsync(annotate); + await operation.ExecuteAnnotateScriptAsync(annotate, ct); } if (annotate.Tags != null) @@ -187,41 +189,44 @@ public partial class AssetDomainObject : DomainObject Annotate(annotate); } - private async Task UpdateCore(UpdateAsset update, AssetOperation operation) + private async Task UpdateCore(UpdateAsset update, AssetOperation operation, + CancellationToken ct) { if (!update.DoNotScript) { - await operation.ExecuteUpdateScriptAsync(update); + await operation.ExecuteUpdateScriptAsync(update, ct); } Update(update); } - private async Task MoveCore(MoveAsset move, AssetOperation operation) + private async Task MoveCore(MoveAsset move, AssetOperation operation, + CancellationToken ct) { if (!move.OptimizeValidation) { - await operation.MustMoveToValidFolder(move.ParentId); + await operation.MustMoveToValidFolder(move.ParentId, ct); } if (!move.DoNotScript) { - await operation.ExecuteMoveScriptAsync(move); + await operation.ExecuteMoveScriptAsync(move, ct); } Move(move); } - private async Task DeleteCore(DeleteAsset delete, AssetOperation operation) + private async Task DeleteCore(DeleteAsset delete, AssetOperation operation, + CancellationToken ct) { if (delete.CheckReferrers) { - await operation.CheckReferrersAsync(); + await operation.CheckReferrersAsync(ct); } if (!delete.DoNotScript) { - await operation.ExecuteDeleteScriptAsync(delete); + await operation.ExecuteDeleteScriptAsync(delete, ct); } Delete(delete); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetFolderDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetFolderDomainObject.cs index a6581697b..b889c3cc1 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetFolderDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetFolderDomainObject.cs @@ -56,7 +56,7 @@ public sealed partial class AssetFolderDomainObject : DomainObject { - await CreateCore(c, c); + await CreateCore(c, ct); return Snapshot; }, ct); @@ -64,7 +64,7 @@ public sealed partial class AssetFolderDomainObject : DomainObject { - await MoveCore(c); + await MoveCore(c, ct); return Snapshot; }, ct); @@ -89,7 +89,8 @@ public sealed partial class AssetFolderDomainObject : DomainObject Snapshot); @@ -97,19 +98,20 @@ public sealed partial class AssetFolderDomainObject : DomainObject Snapshot); if (!c.OptimizeValidation) { - await operation.MustMoveToValidFolder(c.ParentId); + await operation.MustMoveToValidFolder(c.ParentId, ct); } Move(c); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/Guards/ScriptingExtensions.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/Guards/ScriptingExtensions.cs index d1332627c..acf308a32 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/Guards/ScriptingExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/Guards/ScriptingExtensions.cs @@ -21,7 +21,8 @@ public static class ScriptingExtensions CanReject = true }; - public static async Task ExecuteCreateScriptAsync(this AssetOperation operation, CreateAsset create) + public static async Task ExecuteCreateScriptAsync(this AssetOperation operation, CreateAsset create, + CancellationToken ct) { var script = operation.App.AssetScripts?.Create; @@ -30,7 +31,7 @@ public static class ScriptingExtensions return; } - var parentPath = await GetPathAsync(operation, create.ParentId); + var parentPath = await GetPathAsync(operation, create.ParentId, ct); // Script vars are just wrappers over dictionaries for better performance. var vars = new AssetScriptVars @@ -51,10 +52,11 @@ public static class ScriptingExtensions Operation = "Create" }; - await ExecuteScriptAsync(operation, script, vars); + await ExecuteScriptAsync(operation, script, vars, ct); } - public static Task ExecuteUpdateScriptAsync(this AssetOperation operation, UpdateAsset update) + public static Task ExecuteUpdateScriptAsync(this AssetOperation operation, UpdateAsset update, + CancellationToken ct) { var script = operation.App.AssetScripts?.Update; @@ -79,10 +81,11 @@ public static class ScriptingExtensions Operation = "Update" }; - return ExecuteScriptAsync(operation, script, vars); + return ExecuteScriptAsync(operation, script, vars, ct); } - public static Task ExecuteAnnotateScriptAsync(this AssetOperation operation, AnnotateAsset annotate) + public static Task ExecuteAnnotateScriptAsync(this AssetOperation operation, AnnotateAsset annotate, + CancellationToken ct) { var script = operation.App.AssetScripts?.Annotate; @@ -106,10 +109,11 @@ public static class ScriptingExtensions Operation = "Annotate" }; - return ExecuteScriptAsync(operation, script, vars); + return ExecuteScriptAsync(operation, script, vars, ct); } - public static async Task ExecuteMoveScriptAsync(this AssetOperation operation, MoveAsset move) + public static async Task ExecuteMoveScriptAsync(this AssetOperation operation, MoveAsset move, + CancellationToken ct) { var script = operation.App.AssetScripts?.Move; @@ -118,7 +122,7 @@ public static class ScriptingExtensions return; } - var parentPath = await GetPathAsync(operation, move.ParentId); + var parentPath = await GetPathAsync(operation, move.ParentId, ct); // Script vars are just wrappers over dictionaries for better performance. var vars = new AssetScriptVars @@ -131,10 +135,11 @@ public static class ScriptingExtensions Operation = "Move" }; - await ExecuteScriptAsync(operation, script, vars); + await ExecuteScriptAsync(operation, script, vars, ct); } - public static Task ExecuteDeleteScriptAsync(this AssetOperation operation, DeleteAsset delete) + public static Task ExecuteDeleteScriptAsync(this AssetOperation operation, DeleteAsset delete, + CancellationToken ct) { var script = operation.App.AssetScripts?.Delete; @@ -153,14 +158,15 @@ public static class ScriptingExtensions Operation = "Delete" }; - return ExecuteScriptAsync(operation, script, vars); + return ExecuteScriptAsync(operation, script, vars, ct); } - private static async Task ExecuteScriptAsync(AssetOperation operation, string script, AssetScriptVars vars) + private static async Task ExecuteScriptAsync(AssetOperation operation, string script, AssetScriptVars vars, + CancellationToken ct) { var snapshot = operation.Snapshot; - var parentPath = await GetPathAsync(operation, snapshot.ParentId); + var parentPath = await GetPathAsync(operation, snapshot.ParentId, ct); // Script vars are just wrappers over dictionaries for better performance. var asset = new AssetEntityScriptVars @@ -186,10 +192,11 @@ public static class ScriptingExtensions var scriptEngine = operation.Resolve(); - await scriptEngine.ExecuteAsync(vars, script, Options); + await scriptEngine.ExecuteAsync(vars, script, Options, ct); } - private static async Task GetPathAsync(AssetOperation operation, DomainId parentId) + private static async Task GetPathAsync(AssetOperation operation, DomainId parentId, + CancellationToken ct) { if (parentId == default) { @@ -197,7 +204,7 @@ public static class ScriptingExtensions } var assetQuery = operation.Resolve(); - var assetPath = await assetQuery.FindAssetFolderAsync(operation.App.Id, parentId); + var assetPath = await assetQuery.FindAssetFolderAsync(operation.App.Id, parentId, ct); return assetPath.Select(x => new { id = x.Id, folderName = x.FolderName }).ToArray(); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/Guards/ValidationExtensions.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/Guards/ValidationExtensions.cs index a5f6d76d5..b31e1ae3e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/Guards/ValidationExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/Guards/ValidationExtensions.cs @@ -26,7 +26,8 @@ public static class ValidationExtensions operation.ThrowOnErrors(); } - public static async Task MustMoveToValidFolder(this AssetOperation operation, DomainId parentId) + public static async Task MustMoveToValidFolder(this AssetOperation operation, DomainId parentId, + CancellationToken ct) { // If moved to root folder or not moved at all, we can just skip the validation. if (parentId == DomainId.Empty || parentId == operation.Snapshot.ParentId) @@ -36,7 +37,7 @@ public static class ValidationExtensions var assetQuery = operation.Resolve(); - var path = await assetQuery.FindAssetFolderAsync(operation.App.Id, parentId); + var path = await assetQuery.FindAssetFolderAsync(operation.App.Id, parentId, ct); if (path.Count == 0) { @@ -46,7 +47,8 @@ public static class ValidationExtensions operation.ThrowOnErrors(); } - public static async Task MustMoveToValidFolder(this AssetFolderOperation operation, DomainId parentId) + public static async Task MustMoveToValidFolder(this AssetFolderOperation operation, DomainId parentId, + CancellationToken ct) { // If moved to root folder or not moved at all, we can just skip the validation. if (parentId == DomainId.Empty || parentId == operation.Snapshot.ParentId) @@ -56,7 +58,7 @@ public static class ValidationExtensions var assetQuery = operation.Resolve(); - var path = await assetQuery.FindAssetFolderAsync(operation.App.Id, parentId); + var path = await assetQuery.FindAssetFolderAsync(operation.App.Id, parentId, ct); if (path.Count == 0) { @@ -77,11 +79,12 @@ public static class ValidationExtensions operation.ThrowOnErrors(); } - public static async Task CheckReferrersAsync(this AssetOperation operation) + public static async Task CheckReferrersAsync(this AssetOperation operation, + CancellationToken ct) { var contentRepository = operation.Resolve(); - var hasReferrer = await contentRepository.HasReferrersAsync(operation.App.Id, operation.CommandId, SearchScope.All, default); + var hasReferrer = await contentRepository.HasReferrersAsync(operation.App.Id, operation.CommandId, SearchScope.All, ct); if (hasReferrer) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetEnricher.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetEnricher.cs index d64b5871e..5e4adcb64 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetEnricher.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetEnricher.cs @@ -5,32 +5,18 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Text; -using Squidex.Domain.Apps.Core; -using Squidex.Domain.Apps.Core.Tags; using Squidex.Infrastructure; -using Squidex.Infrastructure.Caching; -using Squidex.Infrastructure.Json; using Squidex.Infrastructure.Reflection; namespace Squidex.Domain.Apps.Entities.Assets.Queries; public sealed class AssetEnricher : IAssetEnricher { - private readonly ITagService tagService; - private readonly IEnumerable assetMetadataSources; - private readonly IRequestCache requestCache; - private readonly IUrlGenerator urlGenerator; - private readonly IJsonSerializer serializer; - - public AssetEnricher(ITagService tagService, IEnumerable assetMetadataSources, IRequestCache requestCache, - IUrlGenerator urlGenerator, IJsonSerializer serializer) + private readonly IEnumerable steps; + + public AssetEnricher(IEnumerable steps) { - this.tagService = tagService; - this.assetMetadataSources = assetMetadataSources; - this.requestCache = requestCache; - this.urlGenerator = urlGenerator; - this.serializer = serializer; + this.steps = steps; } public async Task EnrichAsync(IAssetEntity asset, Context context, @@ -52,108 +38,42 @@ public sealed class AssetEnricher : IAssetEnricher using (Telemetry.Activities.StartActivity("AssetEnricher/EnrichAsync")) { - var results = assets.Select(x => SimpleMapper.Map(x, new AssetEntity())).ToList(); + var results = new List(); - foreach (var asset in results) + if (context.App != null) { - requestCache.AddDependency(asset.UniqueId, asset.Version); + foreach (var step in steps) + { + await step.EnrichAsync(context, ct); + } } - if (!context.ShouldSkipAssetEnrichment()) + if (!assets.Any()) { - await EnrichTagsAsync(results, ct); - - EnrichWithMetadataText(results); - EnrichWithEditTokens(results); + return results; } - return results; - } - } - - private void EnrichWithEditTokens(IEnumerable assets) - { - var url = urlGenerator.Root(); - - foreach (var asset in assets) - { - // We have to use these short names here because they are later read like this. - var token = new + foreach (var asset in assets) { - a = asset.AppId.Name, - i = asset.Id.ToString(), - u = url - }; + var result = SimpleMapper.Map(asset, new AssetEntity()); - var json = serializer.Serialize(token); - - asset.EditToken = Convert.ToBase64String(Encoding.UTF8.GetBytes(json)); - } - } - - private void EnrichWithMetadataText(List results) - { - var sb = new StringBuilder(); - - void Append(string? text) - { - if (!string.IsNullOrWhiteSpace(text)) - { - sb.AppendIfNotEmpty(", "); - sb.Append(text); + results.Add(result); } - } - - foreach (var asset in results) - { - sb.Clear(); - foreach (var source in assetMetadataSources) + if (context.App != null) { - foreach (var metadata in source.Format(asset)) + foreach (var step in steps) { - Append(metadata); - } - } - - Append(asset.FileSize.ToReadableSize()); - - asset.MetadataText = sb.ToString(); - } - } - - private async Task EnrichTagsAsync(List assets, - CancellationToken ct) - { - foreach (var group in assets.GroupBy(x => x.AppId.Id)) - { - ct.ThrowIfCancellationRequested(); - - var tagsById = await CalculateTagsAsync(group, ct); + ct.ThrowIfCancellationRequested(); - foreach (var asset in group) - { - asset.TagNames = new HashSet(); - - if (asset.Tags != null) - { - foreach (var id in asset.Tags) + using (Telemetry.Activities.StartActivity(step.ToString()!)) { - if (tagsById.TryGetValue(id, out var name)) - { - asset.TagNames.Add(name); - } + await step.EnrichAsync(context, results, ct); } } } - } - } - private async Task> CalculateTagsAsync(IGrouping group, - CancellationToken ct) - { - var uniqueIds = group.Where(x => x.Tags != null).SelectMany(x => x.Tags).ToHashSet(); - - return await tagService.GetTagNamesAsync(group.Key, TagGroups.Assets, uniqueIds, ct); + return results; + } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetEnricher.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/IAssetEnricher.cs similarity index 92% rename from backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetEnricher.cs rename to backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/IAssetEnricher.cs index 14c9fc440..2917ee44d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetEnricher.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/IAssetEnricher.cs @@ -5,7 +5,7 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -namespace Squidex.Domain.Apps.Entities.Assets; +namespace Squidex.Domain.Apps.Entities.Assets.Queries; public interface IAssetEnricher { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/IAssetEnricherStep.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/IAssetEnricherStep.cs new file mode 100644 index 000000000..c9dc530a9 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/IAssetEnricherStep.cs @@ -0,0 +1,20 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Domain.Apps.Entities.Assets.Queries; + +public interface IAssetEnricherStep +{ + Task EnrichAsync(Context context, IEnumerable assets, + CancellationToken ct); + + Task EnrichAsync(Context context, + CancellationToken ct) + { + return Task.CompletedTask; + } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/CalculateTokens.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/CalculateTokens.cs new file mode 100644 index 000000000..ae15c4544 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/CalculateTokens.cs @@ -0,0 +1,52 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Text; +using Squidex.Domain.Apps.Core; +using Squidex.Infrastructure.Json; + +namespace Squidex.Domain.Apps.Entities.Assets.Queries.Steps; + +public sealed class CalculateTokens : IAssetEnricherStep +{ + private readonly IJsonSerializer serializer; + private readonly IUrlGenerator urlGenerator; + + public CalculateTokens(IUrlGenerator urlGenerator, IJsonSerializer serializer) + { + this.serializer = serializer; + this.urlGenerator = urlGenerator; + } + + public Task EnrichAsync(Context context, IEnumerable assets, + CancellationToken ct) + { + if (context.ShouldSkipAssetEnrichment()) + { + return Task.CompletedTask; + } + + var url = urlGenerator.Root(); + + foreach (var asset in assets) + { + // We have to use these short names here because they are later read like this. + var token = new + { + a = asset.AppId.Name, + i = asset.Id.ToString(), + u = url + }; + + var json = serializer.Serialize(token); + + asset.EditToken = Convert.ToBase64String(Encoding.UTF8.GetBytes(json)); + } + + return Task.CompletedTask; + } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/ConvertTags.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/ConvertTags.cs new file mode 100644 index 000000000..243cfc026 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/ConvertTags.cs @@ -0,0 +1,56 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Core.Tags; +using Squidex.Infrastructure; + +namespace Squidex.Domain.Apps.Entities.Assets.Queries.Steps; + +public sealed class ConvertTags : IAssetEnricherStep +{ + private readonly ITagService tagService; + + public ConvertTags(ITagService tagService) + { + this.tagService = tagService; + } + + public async Task EnrichAsync(Context context, IEnumerable assets, + CancellationToken ct) + { + if (context.ShouldSkipAssetEnrichment()) + { + return; + } + + var tagsById = await CalculateTagsAsync(context.App.Id, assets, ct); + + foreach (var asset in assets) + { + asset.TagNames = new HashSet(); + + if (asset.Tags != null) + { + foreach (var id in asset.Tags) + { + if (tagsById.TryGetValue(id, out var name)) + { + asset.TagNames.Add(name); + } + } + } + } + } + + private async Task> CalculateTagsAsync(DomainId appId, IEnumerable assets, + CancellationToken ct) + { + var uniqueIds = assets.Where(x => x.Tags != null).SelectMany(x => x.Tags).ToHashSet(); + + return await tagService.GetTagNamesAsync(appId, TagGroups.Assets, uniqueIds, ct); + } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/EnrichForCaching.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/EnrichForCaching.cs new file mode 100644 index 000000000..ccc81c3b5 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/EnrichForCaching.cs @@ -0,0 +1,42 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Entities.Contents; +using Squidex.Infrastructure.Caching; + +namespace Squidex.Domain.Apps.Entities.Assets.Queries.Steps; + +public sealed class EnrichForCaching : IAssetEnricherStep +{ + private readonly IRequestCache requestCache; + + public EnrichForCaching(IRequestCache requestCache) + { + this.requestCache = requestCache; + } + + public Task EnrichAsync(Context context, + CancellationToken ct) + { + context.AddCacheHeaders(requestCache); + + return Task.CompletedTask; + } + + public Task EnrichAsync(Context context, IEnumerable assets, + CancellationToken ct) + { + requestCache.AddDependency(context.App.Id, context.App.Version); + + foreach (var asset in assets) + { + requestCache.AddDependency(asset.UniqueId, asset.Version); + } + + return Task.CompletedTask; + } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/EnrichWithMetadataText.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/EnrichWithMetadataText.cs new file mode 100644 index 000000000..4e63c8c2d --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/EnrichWithMetadataText.cs @@ -0,0 +1,66 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Infrastructure; +using Squidex.Infrastructure.ObjectPool; + +namespace Squidex.Domain.Apps.Entities.Assets.Queries.Steps; + +public sealed class EnrichWithMetadataText : IAssetEnricherStep +{ + private readonly IEnumerable assetMetadataSources; + + public EnrichWithMetadataText(IEnumerable assetMetadataSources) + { + this.assetMetadataSources = assetMetadataSources; + } + + public Task EnrichAsync(Context context, IEnumerable assets, + CancellationToken ct) + { + if (context.ShouldSkipAssetEnrichment()) + { + return Task.CompletedTask; + } + + var sb = DefaultPools.StringBuilder.Get(); + try + { + void Append(string? text) + { + if (!string.IsNullOrWhiteSpace(text)) + { + sb.AppendIfNotEmpty(", "); + sb.Append(text); + } + } + + foreach (var asset in assets) + { + sb.Clear(); + + foreach (var source in assetMetadataSources) + { + foreach (var metadata in source.Format(asset)) + { + Append(metadata); + } + } + + Append(asset.FileSize.ToReadableSize()); + + asset.MetadataText = sb.ToString(); + } + } + finally + { + DefaultPools.StringBuilder.Return(sb); + } + + return Task.CompletedTask; + } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/ScriptAsset.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/ScriptAsset.cs new file mode 100644 index 000000000..41123e1f2 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/Steps/ScriptAsset.cs @@ -0,0 +1,107 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Core.Scripting; + +namespace Squidex.Domain.Apps.Entities.Assets.Queries.Steps; + +public sealed class ScriptAsset : IAssetEnricherStep +{ + private readonly IScriptEngine scriptEngine; + + public ScriptAsset(IScriptEngine scriptEngine) + { + this.scriptEngine = scriptEngine; + } + + public async Task EnrichAsync(Context context, IEnumerable assets, + CancellationToken ct) + { + if (!ShouldEnrich(context)) + { + return; + } + + var script = context.App.AssetScripts.Query; + + if (string.IsNullOrWhiteSpace(script)) + { + return; + } + + // Script vars are just wrappers over dictionaries for better performance. + var vars = new AssetScriptVars + { + AppId = context.App.Id, + AppName = context.App.Name, + User = context.UserPrincipal + }; + + var preScript = context.App.AssetScripts.QueryPre; + + if (!string.IsNullOrWhiteSpace(preScript)) + { + var options = new ScriptOptions + { + AsContext = true + }; + + await scriptEngine.ExecuteAsync(vars, preScript, options, ct); + } + + foreach (var asset in assets) + { + await ScriptAsync(vars, script, asset, ct); + } + } + + private async Task ScriptAsync(AssetScriptVars sharedVars, string script, AssetEntity asset, + CancellationToken ct) + { + // Script vars are just wrappers over dictionaries for better performance. + var vars = new AssetScriptVars + { + AssetId = asset.Id, + Asset = new AssetEntityScriptVars + { + Metadata = asset.Metadata, + FileHash = asset.FileHash, + FileName = asset.FileName, + FileSize = asset.FileSize, + FileSlug = asset.Slug, + FileVersion = asset.FileVersion, + IsProtected = asset.IsProtected, + MimeType = asset.MimeType, + ParentId = asset.ParentId, + ParentPath = null, + Tags = asset.Tags + } + }; + + foreach (var (key, value) in sharedVars) + { + if (!vars.ContainsKey(key)) + { + vars[key] = value; + } + } + + var options = new ScriptOptions + { + AsContext = true, + CanDisallow = true, + CanReject = true + }; + + await scriptEngine.ExecuteAsync(vars, script, options, ct); + } + + private static bool ShouldEnrich(Context context) + { + return !context.IsFrontendClient; + } +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs index ff088b87a..fb1e7c479 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs @@ -75,20 +75,20 @@ public partial class ContentDomainObject : DomainObject Snapshot); - await CreateCore(c, operation); + await CreateCore(c, operation, ct); if (operation.Schema.SchemaDef.Type == SchemaType.Singleton) { @@ -107,7 +107,7 @@ public partial class ContentDomainObject : DomainObject Snapshot); - await ValidateCore(operation); + await ValidateCore(operation, ct); return true; }, ct); @@ -148,7 +148,7 @@ public partial class ContentDomainObject : DomainObject Snapshot); - await PatchCore(c, operation); + await PatchCore(c, operation, ct); return Snapshot; }, ct); @@ -158,7 +158,7 @@ public partial class ContentDomainObject : DomainObject Snapshot); - await UpdateCore(c, operation); + await UpdateCore(c, operation, ct); return Snapshot; }, ct); @@ -186,7 +186,7 @@ public partial class ContentDomainObject : DomainObject Snapshot); - await ChangeCore(c, operation); + await ChangeCore(c, operation, ct); } } catch (Exception) @@ -209,7 +209,7 @@ public partial class ContentDomainObject : DomainObject Snapshot); - await DeleteCore(c, operation); + await DeleteCore(c, operation, ct); }, ct); case DeleteContent deleteContent: @@ -217,7 +217,7 @@ public partial class ContentDomainObject : DomainObject Snapshot); - await DeleteCore(c, operation); + await DeleteCore(c, operation, ct); }, ct); default: @@ -226,7 +226,8 @@ public partial class ContentDomainObject : DomainObject ExecuteCreateScriptAsync(this ContentOperation operation, ContentData data, Status status) + public static Task ExecuteCreateScriptAsync(this ContentOperation operation, ContentData data, Status status, + CancellationToken ct) { var script = operation.SchemaDef.Scripts.Create; @@ -40,10 +41,11 @@ public static class ScriptingExtensions StatusOld = default }); - return TransformAsync(operation, script, vars); + return TransformAsync(operation, script, vars, ct); } - public static Task ExecuteUpdateScriptAsync(this ContentOperation operation, ContentData data) + public static Task ExecuteUpdateScriptAsync(this ContentOperation operation, ContentData data, + CancellationToken ct) { var script = operation.SchemaDef.Scripts.Update; @@ -64,10 +66,11 @@ public static class ScriptingExtensions StatusOld = default }); - return TransformAsync(operation, script, vars); + return TransformAsync(operation, script, vars, ct); } - public static Task ExecuteChangeScriptAsync(this ContentOperation operation, Status status, StatusChange change) + public static Task ExecuteChangeScriptAsync(this ContentOperation operation, Status status, StatusChange change, + CancellationToken ct) { var script = operation.SchemaDef.Scripts.Change; @@ -89,10 +92,11 @@ public static class ScriptingExtensions Validate = Validate(operation, status) }); - return TransformAsync(operation, script, vars); + return TransformAsync(operation, script, vars, ct); } - public static Task ExecuteDeleteScriptAsync(this ContentOperation operation, bool permanent) + public static Task ExecuteDeleteScriptAsync(this ContentOperation operation, bool permanent, + CancellationToken ct) { var script = operation.SchemaDef.Scripts.Delete; @@ -114,17 +118,19 @@ public static class ScriptingExtensions StatusOld = default }); - return ExecuteAsync(operation, script, vars); + return ExecuteAsync(operation, script, vars, ct); } - private static async Task TransformAsync(ContentOperation operation, string script, ContentScriptVars vars) + private static async Task TransformAsync(ContentOperation operation, string script, ContentScriptVars vars, + CancellationToken ct) { - return await operation.Resolve().TransformAsync(vars, script, Options); + return await operation.Resolve().TransformAsync(vars, script, Options, ct); } - private static async Task ExecuteAsync(ContentOperation operation, string script, ContentScriptVars vars) + private static async Task ExecuteAsync(ContentOperation operation, string script, ContentScriptVars vars, + CancellationToken ct) { - await operation.Resolve().ExecuteAsync(vars, script, Options); + await operation.Resolve().ExecuteAsync(vars, script, Options, ct); } private static Action Validate(ContentOperation operation, Status status) @@ -135,7 +141,7 @@ public static class ScriptingExtensions { var snapshot = operation.Snapshot; - operation.ValidateContentAndInputAsync(snapshot.Data, false, snapshot.IsPublished() || status == Status.Published).Wait(); + operation.ValidateContentAndInputAsync(snapshot.Data, false, snapshot.IsPublished() || status == Status.Published, default).Wait(); } catch (AggregateException ex) when (ex.InnerException != null) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs index b0e95bbd8..6194fc746 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs @@ -47,38 +47,42 @@ public static class ValidationExtensions operation.ThrowOnErrors(); } - public static async Task ValidateInputAsync(this ContentOperation operation, ContentData data, bool optimize, bool published) + public static async Task ValidateInputAsync(this ContentOperation operation, ContentData data, bool optimize, bool published, + CancellationToken ct) { var validator = GetValidator(operation, optimize, published); - await validator.ValidateInputAsync(data); + await validator.ValidateInputAsync(data, ct); operation.AddErrors(validator.Errors).ThrowOnErrors(); } - public static async Task ValidateInputPartialAsync(this ContentOperation operation, ContentData data, bool optimize, bool published) + public static async Task ValidateInputPartialAsync(this ContentOperation operation, ContentData data, bool optimize, bool published, + CancellationToken ct) { var validator = GetValidator(operation, optimize, published); - await validator.ValidateInputPartialAsync(data); + await validator.ValidateInputPartialAsync(data, ct); operation.AddErrors(validator.Errors).ThrowOnErrors(); } - public static async Task ValidateContentAsync(this ContentOperation operation, ContentData data, bool optimize, bool published) + public static async Task ValidateContentAsync(this ContentOperation operation, ContentData data, bool optimize, bool published, + CancellationToken ct) { var validator = GetValidator(operation, optimize, published); - await validator.ValidateContentAsync(data); + await validator.ValidateContentAsync(data, ct); operation.AddErrors(validator.Errors).ThrowOnErrors(); } - public static async Task ValidateContentAndInputAsync(this ContentOperation operation, ContentData data, bool optimize, bool published) + public static async Task ValidateContentAndInputAsync(this ContentOperation operation, ContentData data, bool optimize, bool published, + CancellationToken ct) { var validator = GetValidator(operation, optimize, published); - await validator.ValidateInputAndContentAsync(data); + await validator.ValidateInputAndContentAsync(data, ct); operation.AddErrors(validator.Errors).ThrowOnErrors(); } @@ -88,11 +92,12 @@ public static class ValidationExtensions data.GenerateDefaultValues(operation.Schema.SchemaDef, operation.Partition()); } - public static async Task CheckReferrersAsync(this ContentOperation operation) + public static async Task CheckReferrersAsync(this ContentOperation operation, + CancellationToken ct) { var contentRepository = operation.Resolve(); - var hasReferrer = await contentRepository.HasReferrersAsync(operation.App.Id, operation.CommandId, SearchScope.All, default); + var hasReferrer = await contentRepository.HasReferrersAsync(operation.App.Id, operation.CommandId, SearchScope.All, ct); if (hasReferrer) { diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs index 9640f2e68..4a5e924b5 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs @@ -58,52 +58,54 @@ public sealed class ContentEnricher : IContentEnricher } } - if (contents.Any()) + if (!contents.Any()) { - foreach (var content in contents) - { - var result = SimpleMapper.Map(content, new ContentEntity()); + return results; + } + + foreach (var content in contents) + { + var result = SimpleMapper.Map(content, new ContentEntity()); - if (cloneData) + if (cloneData) + { + using (Telemetry.Activities.StartActivity("ContentEnricher/CloneData")) { - using (Telemetry.Activities.StartActivity("ContentEnricher/CloneData")) - { - result.Data = result.Data.Clone(); - } + result.Data = result.Data.Clone(); } - - results.Add(result); } - if (context.App != null) - { - var schemaCache = new Dictionary>(); + results.Add(result); + } - Task<(ISchemaEntity, ResolvedComponents)> GetSchema(DomainId id) + if (context.App != null) + { + var schemaCache = new Dictionary>(); + + Task<(ISchemaEntity, ResolvedComponents)> GetSchema(DomainId id) + { + return schemaCache.GetOrAdd(id, async x => { - return schemaCache.GetOrAdd(id, async x => + var schema = await appProvider.GetSchemaAsync(context.App.Id, x, false, ct); + + if (schema == null) { - var schema = await appProvider.GetSchemaAsync(context.App.Id, x, false, ct); + throw new DomainObjectNotFoundException(x.ToString()); + } - if (schema == null) - { - throw new DomainObjectNotFoundException(x.ToString()); - } + var components = await appProvider.GetComponentsAsync(schema, ct); - var components = await appProvider.GetComponentsAsync(schema, ct); + return (schema, components); + }); + } - return (schema, components); - }); - } + foreach (var step in steps) + { + ct.ThrowIfCancellationRequested(); - foreach (var step in steps) + using (Telemetry.Activities.StartActivity(step.ToString()!)) { - ct.ThrowIfCancellationRequested(); - - using (Telemetry.Activities.StartActivity(step.ToString()!)) - { - await step.EnrichAsync(context, results, GetSchema, ct); - } + await step.EnrichAsync(context, results, GetSchema, ct); } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs index d7ff4622d..293bf422e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ResolveAssets.cs @@ -36,25 +36,27 @@ public sealed class ResolveAssets : IContentEnricherStep public async Task EnrichAsync(Context context, IEnumerable contents, ProvideSchema schemas, CancellationToken ct) { - if (ShouldEnrich(context)) + if (!ShouldEnrich(context)) { - var ids = new HashSet(); + return; + } - foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) - { - var (schema, components) = await schemas(group.Key); + var ids = new HashSet(); - AddAssetIds(ids, schema, components, group); - } + foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) + { + var (schema, components) = await schemas(group.Key); - var assets = await GetAssetsAsync(context, ids, ct); + AddAssetIds(ids, schema, components, group); + } - foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) - { - var (schema, components) = await schemas(group.Key); + var assets = await GetAssetsAsync(context, ids, ct); - ResolveAssetsUrls(schema, components, group, assets); - } + foreach (var group in contents.GroupBy(x => x.SchemaId.Id)) + { + var (schema, components) = await schemas(group.Key); + + ResolveAssetsUrls(schema, components, group, assets); } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs index ab8593d5c..5d7bb16fe 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ScriptContent.cs @@ -37,6 +37,7 @@ public sealed class ScriptContent : IContentEnricherStep continue; } + // Script vars are just wrappers over dictionaries for better performance. var vars = new ContentScriptVars { AppId = schema.AppId.Id, @@ -68,6 +69,7 @@ public sealed class ScriptContent : IContentEnricherStep private async Task TransformAsync(ContentScriptVars sharedVars, string script, ContentEntity content, CancellationToken ct) { + // Script vars are just wrappers over dictionaries for better performance. var vars = new ContentScriptVars { ContentId = content.Id, @@ -87,7 +89,9 @@ public sealed class ScriptContent : IContentEnricherStep var options = new ScriptOptions { - AsContext = true + AsContext = true, + CanDisallow = true, + CanReject = true }; content.Data = await scriptEngine.TransformAsync(vars, script, options, ct); diff --git a/backend/src/Squidex.Web/Pipeline/AppResolver.cs b/backend/src/Squidex.Web/Pipeline/AppResolver.cs index 7b297f722..80777f084 100644 --- a/backend/src/Squidex.Web/Pipeline/AppResolver.cs +++ b/backend/src/Squidex.Web/Pipeline/AppResolver.cs @@ -44,7 +44,7 @@ public sealed class AppResolver : IAsyncActionFilter var isFrontend = user.IsInClient(DefaultClients.Frontend); - var app = await appProvider.GetAppAsync(appName, !isFrontend, default); + var app = await appProvider.GetAppAsync(appName, !isFrontend, context.HttpContext.RequestAborted); if (app == null) { diff --git a/backend/src/Squidex/Areas/Api/Config/OpenApi/OpenApiServices.cs b/backend/src/Squidex/Areas/Api/Config/OpenApi/OpenApiServices.cs index 9bb6364f8..934a48560 100644 --- a/backend/src/Squidex/Areas/Api/Config/OpenApi/OpenApiServices.cs +++ b/backend/src/Squidex/Areas/Api/Config/OpenApi/OpenApiServices.cs @@ -107,6 +107,7 @@ public static class OpenApiServices }; settings.AllowReferencesWithProperties = true; + settings.DefaultReferenceTypeNullHandling = ReferenceTypeNullHandling.NotNull; settings.FlattenInheritanceHierarchy = flatten; settings.SchemaNameGenerator = new SchemaNameGenerator(); settings.SchemaProcessors.Add(new DiscriminatorProcessor(typeRegistry)); diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AssetScriptsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AssetScriptsDto.cs index 503d0f550..66f1d3917 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AssetScriptsDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AssetScriptsDto.cs @@ -13,6 +13,16 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models; public sealed class AssetScriptsDto : Resource { + /// + /// The script that is executed for each asset when querying assets. + /// + public string? Query { get; set; } + + /// + /// The script that is executed for all assets when querying assets. + /// + public string? QueryPre { get; set; } + /// /// The script that is executed when creating an asset. /// diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateAssetScriptsDto.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateAssetScriptsDto.cs index 70cd0cd42..1fc54262e 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateAssetScriptsDto.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateAssetScriptsDto.cs @@ -13,6 +13,16 @@ namespace Squidex.Areas.Api.Controllers.Apps.Models; public sealed class UpdateAssetScriptsDto { + /// + /// The script that is executed for each asset when querying assets. + /// + public string? Query { get; set; } + + /// + /// The script that is executed for all assets when querying assets. + /// + public string? QueryPre { get; set; } + /// /// The script that is executed when creating an asset. /// diff --git a/backend/src/Squidex/Config/Domain/AssetServices.cs b/backend/src/Squidex/Config/Domain/AssetServices.cs index f8af431ba..04940d6f5 100644 --- a/backend/src/Squidex/Config/Domain/AssetServices.cs +++ b/backend/src/Squidex/Config/Domain/AssetServices.cs @@ -11,6 +11,7 @@ using Squidex.Assets; using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Assets.Queries; +using Squidex.Domain.Apps.Entities.Assets.Queries.Steps; using Squidex.Domain.Apps.Entities.History; using Squidex.Domain.Apps.Entities.Search; using Squidex.Hosting; @@ -72,6 +73,21 @@ public static class AssetServices services.AddSingletonAs() .As(); + services.AddSingletonAs() + .As(); + + services.AddSingletonAs() + .As(); + + services.AddSingletonAs() + .As(); + + services.AddSingletonAs() + .As(); + + services.AddSingletonAs() + .As(); + services.AddSingletonAs() .As(); diff --git a/backend/src/Squidex/Squidex.csproj b/backend/src/Squidex/Squidex.csproj index eaeaade11..df2c37be5 100644 --- a/backend/src/Squidex/Squidex.csproj +++ b/backend/src/Squidex/Squidex.csproj @@ -57,7 +57,7 @@ - + diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/AppProviderExtensionsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/AppProviderExtensionsTests.cs index 6327e3470..0c7aa5a13 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/AppProviderExtensionsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/AppProviderExtensionsTests.cs @@ -12,10 +12,8 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities; -public class AppProviderExtensionsTests +public class AppProviderExtensionsTests : GivenContext { - private readonly IAppProvider appProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly NamedId componentId1 = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly NamedId componentId2 = NamedId.Of(DomainId.NewGuid(), "my-schema"); @@ -23,13 +21,13 @@ public class AppProviderExtensionsTests [Fact] public async Task Should_do_nothing_if_no_component_found() { - var schema = Mocks.Schema(appId, schemaId); + var schema = Mocks.Schema(AppId, schemaId); - var components = await appProvider.GetComponentsAsync(schema); + var components = await AppProvider.GetComponentsAsync(schema, ct: CancellationToken); Assert.Empty(components); - A.CallTo(() => appProvider.GetSchemaAsync(A._, A._, false, A._)) + A.CallTo(() => AppProvider.GetSchemaAsync(A._, A._, false, A._)) .MustNotHaveHappened(); } @@ -37,39 +35,39 @@ public class AppProviderExtensionsTests public async Task Should_resolve_self_as_component() { var schema = - Mocks.Schema(appId, schemaId, + Mocks.Schema(AppId, schemaId, new Schema(schemaId.Name) .AddComponent(1, "1", Partitioning.Invariant, new ComponentFieldProperties { SchemaId = schemaId.Id })); - var components = await appProvider.GetComponentsAsync(schema); + var components = await AppProvider.GetComponentsAsync(schema, ct: CancellationToken); Assert.Single(components); Assert.Same(schema.SchemaDef, components[schemaId.Id]); - A.CallTo(() => appProvider.GetSchemaAsync(A._, A._, false, A._)) + A.CallTo(() => AppProvider.GetSchemaAsync(A._, A._, false, A._)) .MustNotHaveHappened(); } [Fact] public async Task Should_resolve_from_component() { - var component = Mocks.Schema(appId, componentId1); + var component = Mocks.Schema(AppId, componentId1); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, componentId1.Id, false, default)) + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, componentId1.Id, false, CancellationToken)) .Returns(component); var schema = - Mocks.Schema(appId, schemaId, + Mocks.Schema(AppId, schemaId, new Schema(schemaId.Name) .AddComponent(1, "1", Partitioning.Invariant, new ComponentFieldProperties { SchemaId = componentId1.Id })); - var components = await appProvider.GetComponentsAsync(schema); + var components = await AppProvider.GetComponentsAsync(schema, ct: CancellationToken); Assert.Single(components); Assert.Same(component.SchemaDef, components[componentId1.Id]); @@ -78,20 +76,20 @@ public class AppProviderExtensionsTests [Fact] public async Task Should_resolve_from_components() { - var component = Mocks.Schema(appId, componentId1); + var component = Mocks.Schema(AppId, componentId1); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, componentId1.Id, false, default)) + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, componentId1.Id, false, CancellationToken)) .Returns(component); var schema = - Mocks.Schema(appId, schemaId, + Mocks.Schema(AppId, schemaId, new Schema(schemaId.Name) .AddComponents(1, "1", Partitioning.Invariant, new ComponentsFieldProperties { SchemaId = componentId1.Id })); - var components = await appProvider.GetComponentsAsync(schema); + var components = await AppProvider.GetComponentsAsync(schema, ct: CancellationToken); Assert.Single(components); Assert.Same(component.SchemaDef, components[componentId1.Id]); @@ -100,13 +98,13 @@ public class AppProviderExtensionsTests [Fact] public async Task Should_resolve_from_array() { - var component = Mocks.Schema(appId, componentId1); + var component = Mocks.Schema(AppId, componentId1); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, componentId1.Id, false, default)) + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, componentId1.Id, false, CancellationToken)) .Returns(component); var schema = - Mocks.Schema(appId, schemaId, + Mocks.Schema(AppId, schemaId, new Schema(schemaId.Name) .AddArray(1, "1", Partitioning.Invariant, a => a .AddComponent(2, "2", new ComponentFieldProperties @@ -114,7 +112,7 @@ public class AppProviderExtensionsTests SchemaId = componentId1.Id }))); - var components = await appProvider.GetComponentsAsync(schema); + var components = await AppProvider.GetComponentsAsync(schema, ct: CancellationToken); Assert.Single(components); Assert.Same(component.SchemaDef, components[componentId1.Id]); @@ -124,25 +122,25 @@ public class AppProviderExtensionsTests public async Task Should_resolve_self_referencing_component() { var component = - Mocks.Schema(appId, componentId1, + Mocks.Schema(AppId, componentId1, new Schema(componentId1.Name) .AddComponent(1, "1", Partitioning.Invariant, new ComponentFieldProperties { SchemaId = componentId1.Id })); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, componentId1.Id, false, default)) + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, componentId1.Id, false, CancellationToken)) .Returns(component); var schema = - Mocks.Schema(appId, schemaId, + Mocks.Schema(AppId, schemaId, new Schema(schemaId.Name) .AddComponent(1, "1", Partitioning.Invariant, new ComponentFieldProperties { SchemaId = componentId1.Id })); - var components = await appProvider.GetComponentsAsync(schema); + var components = await AppProvider.GetComponentsAsync(schema, ct: CancellationToken); Assert.Single(components); Assert.Same(component.SchemaDef, components[componentId1.Id]); @@ -152,7 +150,7 @@ public class AppProviderExtensionsTests public async Task Should_resolve_component_of_component() { var component1 = - Mocks.Schema(appId, componentId1, + Mocks.Schema(AppId, componentId1, new Schema(componentId1.Name) .AddComponent(1, "1", Partitioning.Invariant, new ComponentFieldProperties { @@ -160,28 +158,28 @@ public class AppProviderExtensionsTests })); var component2 = - Mocks.Schema(appId, componentId2, + Mocks.Schema(AppId, componentId2, new Schema(componentId2.Name) .AddComponent(1, "1", Partitioning.Invariant, new ComponentFieldProperties { SchemaId = componentId2.Id })); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, componentId1.Id, false, default)) + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, componentId1.Id, false, CancellationToken)) .Returns(component1); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, componentId2.Id, false, default)) + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, componentId2.Id, false, CancellationToken)) .Returns(component2); var schema = - Mocks.Schema(appId, schemaId, + Mocks.Schema(AppId, schemaId, new Schema(schemaId.Name) .AddComponent(1, "1", Partitioning.Invariant, new ComponentFieldProperties { SchemaId = componentId1.Id })); - var components = await appProvider.GetComponentsAsync(schema); + var components = await AppProvider.GetComponentsAsync(schema, ct: CancellationToken); Assert.Equal(2, components.Count); Assert.Same(component1.SchemaDef, components[componentId1.Id]); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/AppProviderTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/AppProviderTests.cs index bc60ab4df..3e26d3dd0 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/AppProviderTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/AppProviderTests.cs @@ -20,55 +20,42 @@ using Squidex.Infrastructure.Security; namespace Squidex.Domain.Apps.Entities; -public class AppProviderTests +public class AppProviderTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IAppsIndex indexForApps = A.Fake(); private readonly IRulesIndex indexForRules = A.Fake(); private readonly ISchemasIndex indexForSchemas = A.Fake(); private readonly ITeamsIndex indexForTeams = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); - private readonly IAppEntity app; private readonly AppProvider sut; public AppProviderTests() { - ct = cts.Token; - - app = Mocks.App(appId); - sut = new AppProvider(indexForApps, indexForRules, indexForSchemas, indexForTeams, new AsyncLocalCache()); } [Fact] public async Task Should_get_app_with_schema_from_index() { - var schema = Mocks.Schema(app.NamedId(), schemaId); - - A.CallTo(() => indexForApps.GetAppAsync(app.Id, false, ct)) - .Returns(app); + A.CallTo(() => indexForApps.GetAppAsync(AppId.Id, false, CancellationToken)) + .Returns(App); - A.CallTo(() => indexForSchemas.GetSchemaAsync(app.Id, schema.Id, false, ct)) - .Returns(schema); + A.CallTo(() => indexForSchemas.GetSchemaAsync(AppId.Id, SchemaId.Id, false, CancellationToken)) + .Returns(Schema); - var actual = await sut.GetAppWithSchemaAsync(app.Id, schemaId.Id, false, ct); + var actual = await sut.GetAppWithSchemaAsync(AppId.Id, SchemaId.Id, false, CancellationToken); - Assert.Equal(schema, actual.Item2); + Assert.Equal(Schema, actual.Item2); } [Fact] public async Task Should_get_team_apps_from_index() { - var team = Mocks.Team(DomainId.NewGuid()); + A.CallTo(() => indexForApps.GetAppsForTeamAsync(TeamId, CancellationToken)) + .Returns(new List { App }); - A.CallTo(() => indexForApps.GetAppsForTeamAsync(team.Id, ct)) - .Returns(new List { app }); + var actual = await sut.GetTeamAppsAsync(TeamId, CancellationToken); - var actual = await sut.GetTeamAppsAsync(team.Id, ct); - - Assert.Equal(app, actual.Single()); + Assert.Equal(App, actual.Single()); } [Fact] @@ -76,99 +63,89 @@ public class AppProviderTests { var permissions = new PermissionSet("*"); - A.CallTo(() => indexForApps.GetAppsForUserAsync("user1", permissions, ct)) - .Returns(new List { app }); + A.CallTo(() => indexForApps.GetAppsForUserAsync("user1", permissions, CancellationToken)) + .Returns(new List { App }); - var actual = await sut.GetUserAppsAsync("user1", permissions, ct); + var actual = await sut.GetUserAppsAsync("user1", permissions, CancellationToken); - Assert.Equal(app, actual.Single()); + Assert.Equal(App, actual.Single()); } [Fact] public async Task Should_get_app_from_index() { - A.CallTo(() => indexForApps.GetAppAsync(app.Id, false, ct)) - .Returns(app); + A.CallTo(() => indexForApps.GetAppAsync(AppId.Id, false, CancellationToken)) + .Returns(App); - var actual = await sut.GetAppAsync(app.Id, false, ct); + var actual = await sut.GetAppAsync(AppId.Id, false, CancellationToken); - Assert.Equal(app, actual); + Assert.Equal(App, actual); } [Fact] public async Task Should_get_app_by_name_from_index() { - A.CallTo(() => indexForApps.GetAppAsync(app.Name, false, ct)) - .Returns(app); + A.CallTo(() => indexForApps.GetAppAsync(AppId.Name, false, CancellationToken)) + .Returns(App); - var actual = await sut.GetAppAsync(app.Name, false, ct); + var actual = await sut.GetAppAsync(AppId.Name, false, CancellationToken); - Assert.Equal(app, actual); + Assert.Equal(App, actual); } [Fact] public async Task Should_get_team_from_index() { - var team = Mocks.Team(DomainId.NewGuid()); - - A.CallTo(() => indexForTeams.GetTeamAsync(team.Id, ct)) - .Returns(team); + A.CallTo(() => indexForTeams.GetTeamAsync(TeamId, CancellationToken)) + .Returns(Team); - var actual = await sut.GetTeamAsync(team.Id, ct); + var actual = await sut.GetTeamAsync(TeamId, CancellationToken); - Assert.Equal(team, actual); + Assert.Equal(Team, actual); } [Fact] public async Task Should_get_teams_from_index() { - var team = Mocks.Team(DomainId.NewGuid()); + A.CallTo(() => indexForTeams.GetTeamsAsync("user1", CancellationToken)) + .Returns(new List { Team }); - A.CallTo(() => indexForTeams.GetTeamsAsync("user1", ct)) - .Returns(new List { team }); + var actual = await sut.GetUserTeamsAsync("user1", CancellationToken); - var actual = await sut.GetUserTeamsAsync("user1", ct); - - Assert.Equal(team, actual.Single()); + Assert.Equal(Team, actual.Single()); } [Fact] public async Task Should_get_schema_from_index() { - var schema = Mocks.Schema(app.NamedId(), schemaId); - - A.CallTo(() => indexForSchemas.GetSchemaAsync(app.Id, schema.Id, false, ct)) - .Returns(schema); + A.CallTo(() => indexForSchemas.GetSchemaAsync(AppId.Id, SchemaId.Id, false, CancellationToken)) + .Returns(Schema); - var actual = await sut.GetSchemaAsync(app.Id, schema.Id, false, ct); + var actual = await sut.GetSchemaAsync(AppId.Id, SchemaId.Id, false, CancellationToken); - Assert.Equal(schema, actual); + Assert.Equal(Schema, actual); } [Fact] public async Task Should_get_schema_by_name_from_index() { - var schema = Mocks.Schema(app.NamedId(), schemaId); + A.CallTo(() => indexForSchemas.GetSchemaAsync(AppId.Id, SchemaId.Name, false, CancellationToken)) + .Returns(Schema); - A.CallTo(() => indexForSchemas.GetSchemaAsync(app.Id, schemaId.Name, false, ct)) - .Returns(schema); + var actual = await sut.GetSchemaAsync(AppId.Id, SchemaId.Name, false, CancellationToken); - var actual = await sut.GetSchemaAsync(app.Id, schemaId.Name, false, ct); - - Assert.Equal(schema, actual); + Assert.Equal(Schema, actual); } [Fact] public async Task Should_get_schemas_from_index() { - var schema = Mocks.Schema(app.NamedId(), schemaId); - - A.CallTo(() => indexForSchemas.GetSchemasAsync(app.Id, ct)) - .Returns(new List { schema }); + A.CallTo(() => indexForSchemas.GetSchemasAsync(AppId.Id, CancellationToken)) + .Returns(new List { Schema }); - var actual = await sut.GetSchemasAsync(app.Id, ct); + var actual = await sut.GetSchemasAsync(AppId.Id, CancellationToken); - Assert.Equal(schema, actual.Single()); + Assert.Equal(Schema, actual.Single()); } [Fact] @@ -176,10 +153,10 @@ public class AppProviderTests { var rule = new RuleEntity(); - A.CallTo(() => indexForRules.GetRulesAsync(app.Id, ct)) + A.CallTo(() => indexForRules.GetRulesAsync(AppId.Id, CancellationToken)) .Returns(new List { rule }); - var actual = await sut.GetRulesAsync(app.Id, ct); + var actual = await sut.GetRulesAsync(AppId.Id, CancellationToken); Assert.Equal(rule, actual.Single()); } @@ -189,10 +166,10 @@ public class AppProviderTests { var rule = new RuleEntity { Id = DomainId.NewGuid() }; - A.CallTo(() => indexForRules.GetRulesAsync(app.Id, ct)) + A.CallTo(() => indexForRules.GetRulesAsync(AppId.Id, CancellationToken)) .Returns(new List { rule }); - var actual = await sut.GetRuleAsync(app.Id, rule.Id, ct); + var actual = await sut.GetRuleAsync(AppId.Id, rule.Id, CancellationToken); Assert.Equal(rule, actual); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppEventDeleterTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppEventDeleterTests.cs index b7fab9093..a00c1acc9 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppEventDeleterTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppEventDeleterTests.cs @@ -6,22 +6,17 @@ // ========================================================================== using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities.Apps; -public class AppEventDeleterTests +public class AppEventDeleterTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IEventStore eventStore = A.Fake(); private readonly AppEventDeleter sut; public AppEventDeleterTests() { - ct = cts.Token; - sut = new AppEventDeleter(eventStore); } @@ -36,11 +31,9 @@ public class AppEventDeleterTests [Fact] public async Task Should_remove_events_from_streams() { - var app = Mocks.App(NamedId.Of(DomainId.NewGuid(), "my-app")); - - await sut.DeleteAppAsync(app, ct); + await sut.DeleteAppAsync(App, CancellationToken); - A.CallTo(() => eventStore.DeleteAsync($"^[a-zA-Z0-9]-{app.Id}", A._)) + A.CallTo(() => eventStore.DeleteAsync($"^[a-zA-Z0-9]-{AppId.Id}", A._)) .MustNotHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppPermanentDeleterTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppPermanentDeleterTests.cs index 52b0efbb3..8ce75a73f 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppPermanentDeleterTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppPermanentDeleterTests.cs @@ -9,13 +9,12 @@ using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Apps.DomainObject; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events.Apps; -using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities.Apps; -public class AppPermanentDeleterTests +public class AppPermanentDeleterTests : GivenContext { private readonly IDomainObjectFactory domainObjectFactory = A.Fake(); private readonly IDeleter deleter1 = A.Fake(); @@ -90,24 +89,22 @@ public class AppPermanentDeleterTests [Fact] public async Task Should_call_deleters_when_contributor_removed() { - var app = Mocks.App(NamedId.Of(DomainId.NewGuid(), "my-app")); - await sut.On(Envelope.Create(new AppContributorRemoved { - AppId = app.NamedId(), ContributorId = "user1" + AppId = AppId, ContributorId = "user1" })); - A.CallTo(() => deleter1.DeleteContributorAsync(app.Id, "user1", default)) + A.CallTo(() => deleter1.DeleteContributorAsync(AppId.Id, "user1", default)) .MustHaveHappened(); - A.CallTo(() => deleter2.DeleteContributorAsync(app.Id, "user1", default)) + A.CallTo(() => deleter2.DeleteContributorAsync(AppId.Id, "user1", default)) .MustHaveHappened(); } [Fact] public async Task Should_call_deleters_when_app_deleted() { - var app = new AppDomainObject.State { Id = DomainId.NewGuid(), Name = "my-app" }; + var app = new AppDomainObject.State { Id = AppId.Id, Name = AppId.Name }; var domainObject = A.Fake(); @@ -119,7 +116,7 @@ public class AppPermanentDeleterTests await sut.On(Envelope.Create(new AppDeleted { - AppId = app.NamedId() + AppId = AppId })); A.CallTo(() => deleter1.DeleteAppAsync(app, default)) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppSettingsSearchSourceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppSettingsSearchSourceTests.cs index c81ef1fbd..6d549c3ab 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppSettingsSearchSourceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppSettingsSearchSourceTests.cs @@ -5,20 +5,16 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Security.Claims; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Entities.Search; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; using Squidex.Shared; -using Squidex.Shared.Identity; namespace Squidex.Domain.Apps.Entities.Apps; -public sealed class AppSettingsSearchSourceTests +public sealed class AppSettingsSearchSourceTests : GivenContext { private readonly IUrlGenerator urlGenerator = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly AppSettingsSearchSource sut; public AppSettingsSearchSourceTests() @@ -29,24 +25,20 @@ public sealed class AppSettingsSearchSourceTests [Fact] public async Task Should_return_empty_if_nothing_matching() { - var ctx = ContextWithPermission(); - - var actual = await sut.SearchAsync("xyz", ctx, default); + var actual = await sut.SearchAsync("xyz", ApiContext, CancellationToken); Assert.Empty(actual); } [Fact] - public async Task Should_return_dashboard_actual_if_matching_and_permission_given() + public async Task Should_return_dashboard_result_if_matching_and_permission_given() { - var permission = PermissionIds.ForApp(PermissionIds.AppUsage, appId.Name); - - var ctx = ContextWithPermission(permission.Id); + var requestContext = SetupContext(PermissionIds.AppUsage); - A.CallTo(() => urlGenerator.DashboardUI(appId)) + A.CallTo(() => urlGenerator.DashboardUI(AppId)) .Returns("dashboard-url"); - var actual = await sut.SearchAsync("dashboard", ctx, default); + var actual = await sut.SearchAsync("dashboard", requestContext, CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -54,26 +46,22 @@ public sealed class AppSettingsSearchSourceTests } [Fact] - public async Task Should_not_return_dashboard_actual_if_user_has_no_permission() + public async Task Should_not_return_dashboard_result_if_user_has_no_permission() { - var ctx = ContextWithPermission(); - - var actual = await sut.SearchAsync("assets", ctx, default); + var actual = await sut.SearchAsync("assets", ApiContext, CancellationToken); Assert.Empty(actual); } [Fact] - public async Task Should_return_languages_actual_if_matching_and_permission_given() + public async Task Should_return_languages_result_if_matching_and_permission_given() { - var permission = PermissionIds.ForApp(PermissionIds.AppLanguagesRead, appId.Name); - - var ctx = ContextWithPermission(permission.Id); + var requestContext = SetupContext(PermissionIds.AppLanguagesRead); - A.CallTo(() => urlGenerator.LanguagesUI(appId)) + A.CallTo(() => urlGenerator.LanguagesUI(AppId)) .Returns("languages-url"); - var actual = await sut.SearchAsync("languages", ctx, default); + var actual = await sut.SearchAsync("languages", requestContext, CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -81,36 +69,22 @@ public sealed class AppSettingsSearchSourceTests } [Fact] - public async Task Should_not_return_languages_actual_if_user_has_no_permission() - { - var ctx = ContextWithPermission(); - - var actual = await sut.SearchAsync("assets", ctx, default); - - Assert.Empty(actual); - } - - [Fact] - public async Task Should_not_return_patterns_actual_if_user_has_no_permission() + public async Task Should_not_return_languages_result_if_user_has_no_permission() { - var ctx = ContextWithPermission(); - - var actual = await sut.SearchAsync("patterns", ctx, default); + var actual = await sut.SearchAsync("assets", ApiContext, CancellationToken); Assert.Empty(actual); } [Fact] - public async Task Should_return_schemas_actual_if_matching_and_permission_given() + public async Task Should_return_schemas_result_if_matching_and_permission_given() { - var permission = PermissionIds.ForApp(PermissionIds.AppSchemasRead, appId.Name); + var requestContext = SetupContext(PermissionIds.AppSchemasRead); - var ctx = ContextWithPermission(permission.Id); - - A.CallTo(() => urlGenerator.SchemasUI(appId)) + A.CallTo(() => urlGenerator.SchemasUI(AppId)) .Returns("schemas-url"); - var actual = await sut.SearchAsync("schemas", ctx, default); + var actual = await sut.SearchAsync("schemas", requestContext, CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -118,26 +92,22 @@ public sealed class AppSettingsSearchSourceTests } [Fact] - public async Task Should_not_return_schemas_actual_if_user_has_no_permission() + public async Task Should_not_return_schemas_result_if_user_has_no_permission() { - var ctx = ContextWithPermission(); - - var actual = await sut.SearchAsync("schemas", ctx, default); + var actual = await sut.SearchAsync("schemas", ApiContext, CancellationToken); Assert.Empty(actual); } [Fact] - public async Task Should_return_assets_actual_if_matching_and_permission_given() + public async Task Should_return_assets_result_if_matching_and_permission_given() { - var permission = PermissionIds.ForApp(PermissionIds.AppAssetsRead, appId.Name); + var requestContext = SetupContext(PermissionIds.AppAssetsRead); - var ctx = ContextWithPermission(permission.Id); - - A.CallTo(() => urlGenerator.AssetsUI(appId, A._)) + A.CallTo(() => urlGenerator.AssetsUI(AppId, A._)) .Returns("assets-url"); - var actual = await sut.SearchAsync("assets", ctx, default); + var actual = await sut.SearchAsync("assets", requestContext, CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -145,26 +115,22 @@ public sealed class AppSettingsSearchSourceTests } [Fact] - public async Task Should_not_return_assets_actual_if_user_has_no_permission() + public async Task Should_not_return_assets_result_if_user_has_no_permission() { - var ctx = ContextWithPermission(); - - var actual = await sut.SearchAsync("assets", ctx, default); + var actual = await sut.SearchAsync("assets", ApiContext, CancellationToken); Assert.Empty(actual); } [Fact] - public async Task Should_return_backups_actual_if_matching_and_permission_given() + public async Task Should_return_backups_result_if_matching_and_permission_given() { - var permission = PermissionIds.ForApp(PermissionIds.AppBackupsRead, appId.Name); + var requestContext = SetupContext(PermissionIds.AppBackupsRead); - var ctx = ContextWithPermission(permission.Id); - - A.CallTo(() => urlGenerator.BackupsUI(appId)) + A.CallTo(() => urlGenerator.BackupsUI(AppId)) .Returns("backups-url"); - var actual = await sut.SearchAsync("backups", ctx, default); + var actual = await sut.SearchAsync("backups", requestContext, CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -172,26 +138,22 @@ public sealed class AppSettingsSearchSourceTests } [Fact] - public async Task Should_not_return_backups_actual_if_user_has_no_permission() + public async Task Should_not_return_backups_result_if_user_has_no_permission() { - var ctx = ContextWithPermission(); - - var actual = await sut.SearchAsync("backups", ctx, default); + var actual = await sut.SearchAsync("backups", ApiContext, CancellationToken); Assert.Empty(actual); } [Fact] - public async Task Should_return_clients_actual_if_matching_and_permission_given() + public async Task Should_return_clients_result_if_matching_and_permission_given() { - var permission = PermissionIds.ForApp(PermissionIds.AppClientsRead, appId.Name); + var requestContext = SetupContext(PermissionIds.AppClientsRead); - var ctx = ContextWithPermission(permission.Id); - - A.CallTo(() => urlGenerator.ClientsUI(appId)) + A.CallTo(() => urlGenerator.ClientsUI(AppId)) .Returns("clients-url"); - var actual = await sut.SearchAsync("clients", ctx, default); + var actual = await sut.SearchAsync("clients", requestContext, CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -199,26 +161,22 @@ public sealed class AppSettingsSearchSourceTests } [Fact] - public async Task Should_not_return_clients_actual_if_user_has_no_permission() + public async Task Should_not_return_clients_result_if_user_has_no_permission() { - var ctx = ContextWithPermission(); - - var actual = await sut.SearchAsync("clients", ctx, default); + var actual = await sut.SearchAsync("clients", ApiContext, CancellationToken); Assert.Empty(actual); } [Fact] - public async Task Should_return_contributors_actual_if_matching_and_permission_given() + public async Task Should_return_contributors_result_if_matching_and_permission_given() { - var permission = PermissionIds.ForApp(PermissionIds.AppContributorsRead, appId.Name); + var requestContext = SetupContext(PermissionIds.AppContributorsRead); - var ctx = ContextWithPermission(permission.Id); - - A.CallTo(() => urlGenerator.ContributorsUI(appId)) + A.CallTo(() => urlGenerator.ContributorsUI(AppId)) .Returns("contributors-url"); - var actual = await sut.SearchAsync("contributors", ctx, default); + var actual = await sut.SearchAsync("contributors", requestContext, CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -226,26 +184,22 @@ public sealed class AppSettingsSearchSourceTests } [Fact] - public async Task Should_not_contributors_clients_actual_if_user_has_no_permission() + public async Task Should_not_contributors_clients_result_if_user_has_no_permission() { - var ctx = ContextWithPermission(); - - var actual = await sut.SearchAsync("contributors", ctx, default); + var actual = await sut.SearchAsync("contributors", ApiContext, CancellationToken); Assert.Empty(actual); } [Fact] - public async Task Should_return_subscription_actual_if_matching_and_permission_given() + public async Task Should_return_subscription_result_if_matching_and_permission_given() { - var permission = PermissionIds.ForApp(PermissionIds.AppPlansRead, appId.Name); + var requestContext = SetupContext(PermissionIds.AppPlansRead); - var ctx = ContextWithPermission(permission.Id); - - A.CallTo(() => urlGenerator.PlansUI(appId)) + A.CallTo(() => urlGenerator.PlansUI(AppId)) .Returns("subscription-url"); - var actual = await sut.SearchAsync("subscription", ctx, default); + var actual = await sut.SearchAsync("subscription", requestContext, CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -253,26 +207,22 @@ public sealed class AppSettingsSearchSourceTests } [Fact] - public async Task Should_not_subscription_clients_actual_if_user_has_no_permission() + public async Task Should_not_subscription_clients_result_if_user_has_no_permission() { - var ctx = ContextWithPermission(); - - var actual = await sut.SearchAsync("subscription", ctx, default); + var actual = await sut.SearchAsync("subscription", ApiContext, CancellationToken); Assert.Empty(actual); } [Fact] - public async Task Should_return_roles_actual_if_matching_and_permission_given() + public async Task Should_return_roles_result_if_matching_and_permission_given() { - var permission = PermissionIds.ForApp(PermissionIds.AppRolesRead, appId.Name); + var requestContext = SetupContext(PermissionIds.AppRolesRead); - var ctx = ContextWithPermission(permission.Id); - - A.CallTo(() => urlGenerator.RolesUI(appId)) + A.CallTo(() => urlGenerator.RolesUI(AppId)) .Returns("roles-url"); - var actual = await sut.SearchAsync("roles", ctx, default); + var actual = await sut.SearchAsync("roles", requestContext, CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -280,26 +230,22 @@ public sealed class AppSettingsSearchSourceTests } [Fact] - public async Task Should_not_roles_clients_actual_if_user_has_no_permission() + public async Task Should_not_roles_clients_result_if_user_has_no_permission() { - var ctx = ContextWithPermission(); - - var actual = await sut.SearchAsync("roles", ctx, default); + var actual = await sut.SearchAsync("roles", ApiContext, CancellationToken); Assert.Empty(actual); } [Fact] - public async Task Should_return_rules_actual_if_matching_and_permission_given() + public async Task Should_return_rules_result_if_matching_and_permission_given() { - var permission = PermissionIds.ForApp(PermissionIds.AppRulesRead, appId.Name); + var requestContext = SetupContext(PermissionIds.AppRulesRead); - var ctx = ContextWithPermission(permission.Id); - - A.CallTo(() => urlGenerator.RulesUI(appId)) + A.CallTo(() => urlGenerator.RulesUI(AppId)) .Returns("rules-url"); - var actual = await sut.SearchAsync("rules", ctx, default); + var actual = await sut.SearchAsync("rules", requestContext, CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -307,26 +253,22 @@ public sealed class AppSettingsSearchSourceTests } [Fact] - public async Task Should_not_return_rules_actual_if_user_has_no_permission() + public async Task Should_not_return_rules_result_if_user_has_no_permission() { - var ctx = ContextWithPermission(); - - var actual = await sut.SearchAsync("assets", ctx, default); + var actual = await sut.SearchAsync("assets", ApiContext, CancellationToken); Assert.Empty(actual); } [Fact] - public async Task Should_return_workflows_actual_if_matching_and_permission_given() + public async Task Should_return_workflows_result_if_matching_and_permission_given() { - var permission = PermissionIds.ForApp(PermissionIds.AppWorkflowsRead, appId.Name); + var requestContext = SetupContext(PermissionIds.AppWorkflowsRead); - var ctx = ContextWithPermission(permission.Id); - - A.CallTo(() => urlGenerator.WorkflowsUI(appId)) + A.CallTo(() => urlGenerator.WorkflowsUI(AppId)) .Returns("workflows-url"); - var actual = await sut.SearchAsync("workflows", ctx, default); + var actual = await sut.SearchAsync("workflows", requestContext, CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -334,25 +276,15 @@ public sealed class AppSettingsSearchSourceTests } [Fact] - public async Task Should_not_return_workflows_actual_if_user_has_no_permission() + public async Task Should_not_return_workflows_result_if_user_has_no_permission() { - var ctx = ContextWithPermission(); - - var actual = await sut.SearchAsync("workflows", ctx, default); + var actual = await sut.SearchAsync("workflows", ApiContext, CancellationToken); Assert.Empty(actual); } - private Context ContextWithPermission(string? permission = null) + private Context SetupContext(string permission) { - var claimsIdentity = new ClaimsIdentity(); - var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); - - if (permission != null) - { - claimsIdentity.AddClaim(new Claim(SquidexClaimTypes.Permissions, permission)); - } - - return new Context(claimsPrincipal, Mocks.App(appId)); + return CreateContext(false, PermissionIds.ForApp(permission, AppId.Name).Id); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsTests.cs index 9ae53dd19..b9838a2e8 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUISettingsTests.cs @@ -8,27 +8,21 @@ using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.TestHelpers; namespace Squidex.Domain.Apps.Entities.Apps; -public sealed class AppUISettingsTests +public sealed class AppUISettingsTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly TestState state; - private readonly DomainId appId = DomainId.NewGuid(); private readonly string userId = Guid.NewGuid().ToString(); private readonly string stateId; private readonly AppUISettings sut; public AppUISettingsTests() { - ct = cts.Token; - - stateId = $"{appId}_{userId}"; + stateId = $"{AppId.Id}_{userId}"; state = new TestState(stateId); sut = new AppUISettings(state.PersistenceFactory); @@ -45,87 +39,85 @@ public sealed class AppUISettingsTests [Fact] public async Task Should_delete_contributor_state() { - await ((IDeleter)sut).DeleteContributorAsync(appId, userId, ct); + await ((IDeleter)sut).DeleteContributorAsync(AppId.Id, userId, CancellationToken); - A.CallTo(() => state.Persistence.DeleteAsync(ct)) + A.CallTo(() => state.Persistence.DeleteAsync(CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_delete_app_and_contributors() { - var app = Mocks.App(NamedId.Of(appId, "my-app")); - - A.CallTo(() => app.Contributors) + A.CallTo(() => App.Contributors) .Returns(Contributors.Empty.Assign(userId, Role.Owner)); - var rootState = new TestState(appId, state.PersistenceFactory); + var rootState = new TestState(AppId.Id, state.PersistenceFactory); - await ((IDeleter)sut).DeleteAppAsync(app, ct); + await ((IDeleter)sut).DeleteAppAsync(App, CancellationToken); - A.CallTo(() => state.Persistence.DeleteAsync(ct)) + A.CallTo(() => state.Persistence.DeleteAsync(CancellationToken)) .MustHaveHappened(); - A.CallTo(() => rootState.Persistence.DeleteAsync(ct)) + A.CallTo(() => rootState.Persistence.DeleteAsync(CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_set_setting() { - await sut.SetAsync(appId, userId, new JsonObject().Add("key", 42), ct); + await sut.SetAsync(AppId.Id, userId, new JsonObject().Add("key", 42), CancellationToken); - var actual = await sut.GetAsync(appId, userId, ct); + var actual = await sut.GetAsync(AppId.Id, userId, CancellationToken); var expected = new JsonObject().Add("key", 42); Assert.Equal(expected.ToString(), actual.ToString()); - A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, ct)) + A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_set_root_value() { - await sut.SetAsync(appId, userId, "key", 42, ct); + await sut.SetAsync(AppId.Id, userId, "key", 42, CancellationToken); - var actual = await sut.GetAsync(appId, userId, ct); + var actual = await sut.GetAsync(AppId.Id, userId, CancellationToken); var expected = new JsonObject().Add("key", 42); Assert.Equal(expected.ToString(), actual.ToString()); - A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, ct)) + A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_remove_root_value() { - await sut.SetAsync(appId, userId, "key", 42, ct); + await sut.SetAsync(AppId.Id, userId, "key", 42, CancellationToken); - await sut.RemoveAsync(appId, userId, "key", ct); - await sut.RemoveAsync(appId, userId, "key", ct); + await sut.RemoveAsync(AppId.Id, userId, "key", CancellationToken); + await sut.RemoveAsync(AppId.Id, userId, "key", CancellationToken); - var actual = await sut.GetAsync(appId, userId, ct); + var actual = await sut.GetAsync(AppId.Id, userId, CancellationToken); var expected = new JsonObject(); Assert.Equal(expected.ToString(), actual.ToString()); - A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, ct)) + A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, CancellationToken)) .MustHaveHappenedTwiceExactly(); } [Fact] public async Task Should_set_nested_value() { - await sut.SetAsync(appId, userId, "root.nested", 42, ct); + await sut.SetAsync(AppId.Id, userId, "root.nested", 42, CancellationToken); - var actual = await sut.GetAsync(appId, userId, ct); + var actual = await sut.GetAsync(AppId.Id, userId, CancellationToken); var expected = new JsonObject().Add("root", @@ -133,17 +125,17 @@ public sealed class AppUISettingsTests Assert.Equal(expected.ToString(), actual.ToString()); - A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, ct)) + A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_not_write_state_if_value_not_changed() { - await sut.SetAsync(appId, userId, "root.nested", 42, ct); - await sut.SetAsync(appId, userId, "root.nested", 42, ct); + await sut.SetAsync(AppId.Id, userId, "root.nested", 42, CancellationToken); + await sut.SetAsync(AppId.Id, userId, "root.nested", 42, CancellationToken); - var actual = await sut.GetAsync(appId, userId, ct); + var actual = await sut.GetAsync(AppId.Id, userId, CancellationToken); var expected = new JsonObject().Add("root", @@ -151,19 +143,19 @@ public sealed class AppUISettingsTests Assert.Equal(expected.ToString(), actual.ToString()); - A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, ct)) + A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, CancellationToken)) .MustHaveHappenedOnceExactly(); } [Fact] public async Task Should_remove_nested_value() { - await sut.SetAsync(appId, userId, "root.nested", 42, ct); + await sut.SetAsync(AppId.Id, userId, "root.nested", 42, CancellationToken); - await sut.RemoveAsync(appId, userId, "root.nested", ct); - await sut.RemoveAsync(appId, userId, "key", ct); + await sut.RemoveAsync(AppId.Id, userId, "root.nested", CancellationToken); + await sut.RemoveAsync(AppId.Id, userId, "key", CancellationToken); - var actual = await sut.GetAsync(appId, userId, ct); + var actual = await sut.GetAsync(AppId.Id, userId, CancellationToken); var expected = new JsonObject().Add("root", @@ -171,22 +163,22 @@ public sealed class AppUISettingsTests Assert.Equal(expected.ToString(), actual.ToString()); - A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, ct)) + A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, CancellationToken)) .MustHaveHappenedTwiceExactly(); } [Fact] public async Task Should_throw_exception_if_nested_not_an_object() { - await sut.SetAsync(appId, userId, "root.nested", 42, ct); + await sut.SetAsync(AppId.Id, userId, "root.nested", 42, CancellationToken); - await Assert.ThrowsAsync(() => sut.SetAsync(appId, userId, "root.nested.value", 42, ct)); + await Assert.ThrowsAsync(() => sut.SetAsync(AppId.Id, userId, "root.nested.value", 42, CancellationToken)); } [Fact] public async Task Should_do_nothing_if_deleting_and_nested_not_found() { - await sut.RemoveAsync(appId, userId, "root.nested", ct); + await sut.RemoveAsync(AppId.Id, userId, "root.nested", CancellationToken); A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, A._)) .MustNotHaveHappened(); @@ -195,7 +187,7 @@ public sealed class AppUISettingsTests [Fact] public async Task Should_do_nothing_if_deleting_and_key_not_found() { - await sut.RemoveAsync(appId, userId, "root", ct); + await sut.RemoveAsync(AppId.Id, userId, "root", CancellationToken); A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, A._)) .MustNotHaveHappened(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUsageDeleterTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUsageDeleterTests.cs index be0d08f98..f6fb10be8 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUsageDeleterTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppUsageDeleterTests.cs @@ -6,22 +6,17 @@ // ========================================================================== using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; using Squidex.Infrastructure.UsageTracking; namespace Squidex.Domain.Apps.Entities.Apps; -public class AppUsageDeleterTests +public class AppUsageDeleterTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IApiUsageTracker usageTracker = A.Fake(); private readonly AppUsageDeleter sut; public AppUsageDeleterTests() { - ct = cts.Token; - sut = new AppUsageDeleter(usageTracker); } @@ -36,11 +31,9 @@ public class AppUsageDeleterTests [Fact] public async Task Should_remove_events_from_streams() { - var app = Mocks.App(NamedId.Of(DomainId.NewGuid(), "my-app")); - - await sut.DeleteAppAsync(app, ct); + await sut.DeleteAppAsync(App, CancellationToken); - A.CallTo(() => usageTracker.DeleteAsync(app.Id.ToString(), ct)) + A.CallTo(() => usageTracker.DeleteAsync(AppId.Id.ToString(), CancellationToken)) .MustHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/BackupAppsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/BackupAppsTests.cs index dc6e99f67..ef1c82f76 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/BackupAppsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/BackupAppsTests.cs @@ -10,6 +10,7 @@ using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Apps.DomainObject; using Squidex.Domain.Apps.Entities.Apps.Indexes; using Squidex.Domain.Apps.Entities.Backup; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events.Apps; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; @@ -18,22 +19,16 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Entities.Apps; -public class BackupAppsTests +public class BackupAppsTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly Rebuilder rebuilder = A.Fake(); private readonly IAppsIndex appsIndex = A.Fake(); private readonly IAppUISettings appUISettings = A.Fake(); private readonly IAppImageStore appImageStore = A.Fake(); - private readonly DomainId appId = DomainId.NewGuid(); - private readonly RefToken actor = RefToken.User("123"); private readonly BackupApps sut; public BackupAppsTests() { - ct = cts.Token; - sut = new BackupApps(rebuilder, appImageStore, appsIndex, appUISettings); } @@ -46,62 +41,56 @@ public class BackupAppsTests [Fact] public async Task Should_reserve_app_name() { - const string appName = "my-app"; - var context = CreateRestoreContext(); - A.CallTo(() => appsIndex.ReserveAsync(appId, appName, A._)) + A.CallTo(() => appsIndex.ReserveAsync(AppId.Id, AppId.Name, A._)) .Returns("Reservation"); await sut.RestoreEventAsync(Envelope.Create(new AppCreated { - Name = appName - }), context, ct); + Name = AppId.Name + }), context, CancellationToken); - A.CallTo(() => appsIndex.ReserveAsync(appId, appName, A._)) + A.CallTo(() => appsIndex.ReserveAsync(AppId.Id, AppId.Name, A._)) .MustHaveHappened(); } [Fact] public async Task Should_complete_reservation_with_previous_token() { - const string appName = "my-app"; - var context = CreateRestoreContext(); - A.CallTo(() => appsIndex.ReserveAsync(appId, appName, ct)) + A.CallTo(() => appsIndex.ReserveAsync(AppId.Id, AppId.Name, CancellationToken)) .Returns("Reservation"); await sut.RestoreEventAsync(Envelope.Create(new AppCreated { - Name = appName - }), context, ct); + Name = AppId.Name + }), context, CancellationToken); - await sut.CompleteRestoreAsync(context, appName); + await sut.CompleteRestoreAsync(context, AppId.Name); A.CallTo(() => appsIndex.RemoveReservationAsync("Reservation", default)) .MustHaveHappened(); - A.CallTo(() => rebuilder.InsertManyAsync(A>.That.Is(appId), 1, default)) + A.CallTo(() => rebuilder.InsertManyAsync(A>.That.Is(AppId.Id), 1, default)) .MustHaveHappened(); } [Fact] public async Task Should_cleanup_reservation_with_previous_token() { - const string appName = "my-app"; - var context = CreateRestoreContext(); - A.CallTo(() => appsIndex.ReserveAsync(appId, appName, ct)) + A.CallTo(() => appsIndex.ReserveAsync(AppId.Id, AppId.Name, CancellationToken)) .Returns("Reservation"); await sut.RestoreEventAsync(Envelope.Create(new AppCreated { - Name = appName - }), context, ct); + Name = AppId.Name + }), context, CancellationToken); - await sut.CleanupRestoreErrorAsync(appId); + await sut.CleanupRestoreErrorAsync(AppId.Id); A.CallTo(() => appsIndex.RemoveReservationAsync("Reservation", default)) .MustHaveHappened(); @@ -110,25 +99,23 @@ public class BackupAppsTests [Fact] public async Task Should_throw_exception_if_no_reservation_token_returned() { - const string appName = "my-app"; - var context = CreateRestoreContext(); - A.CallTo(() => appsIndex.ReserveAsync(appId, appName, ct)) + A.CallTo(() => appsIndex.ReserveAsync(AppId.Id, AppId.Name, CancellationToken)) .Returns(Task.FromResult(null)); var @event = Envelope.Create(new AppCreated { - Name = appName + Name = AppId.Name }); - await Assert.ThrowsAsync(() => sut.RestoreEventAsync(@event, context, ct)); + await Assert.ThrowsAsync(() => sut.RestoreEventAsync(@event, context, CancellationToken)); } [Fact] public async Task Should_not_cleanup_reservation_if_no_reservation_token_hold() { - await sut.CleanupRestoreErrorAsync(appId); + await sut.CleanupRestoreErrorAsync(AppId.Id); A.CallTo(() => appsIndex.RemoveReservationAsync("Reservation", A._)) .MustNotHaveHappened(); @@ -141,12 +128,12 @@ public class BackupAppsTests var context = CreateBackupContext(); - A.CallTo(() => appUISettings.GetAsync(appId, null, ct)) + A.CallTo(() => appUISettings.GetAsync(AppId.Id, null, CancellationToken)) .Returns(settings); - await sut.BackupAsync(context, ct); + await sut.BackupAsync(context, CancellationToken); - A.CallTo(() => context.Writer.WriteJsonAsync(A._, settings, ct)) + A.CallTo(() => context.Writer.WriteJsonAsync(A._, settings, CancellationToken)) .MustHaveHappened(); } @@ -157,12 +144,12 @@ public class BackupAppsTests var context = CreateRestoreContext(); - A.CallTo(() => context.Reader.ReadJsonAsync(A._, ct)) + A.CallTo(() => context.Reader.ReadJsonAsync(A._, CancellationToken)) .Returns(settings); - await sut.RestoreAsync(context, ct); + await sut.RestoreAsync(context, CancellationToken); - A.CallTo(() => appUISettings.SetAsync(appId, null, settings, ct)) + A.CallTo(() => appUISettings.SetAsync(AppId.Id, null, settings, CancellationToken)) .MustHaveHappened(); } @@ -176,7 +163,7 @@ public class BackupAppsTests ContributorId = "found" }); - var actual = await sut.RestoreEventAsync(@event, context, ct); + var actual = await sut.RestoreEventAsync(@event, context, CancellationToken); Assert.True(actual); Assert.Equal("found_mapped", @event.Payload.ContributorId); @@ -192,7 +179,7 @@ public class BackupAppsTests ContributorId = "unknown" }); - var actual = await sut.RestoreEventAsync(@event, context, ct); + var actual = await sut.RestoreEventAsync(@event, context, CancellationToken); Assert.False(actual); Assert.Equal("unknown", @event.Payload.ContributorId); @@ -208,7 +195,7 @@ public class BackupAppsTests ContributorId = "found" }); - var actual = await sut.RestoreEventAsync(@event, context, ct); + var actual = await sut.RestoreEventAsync(@event, context, CancellationToken); Assert.True(actual); Assert.Equal("found_mapped", @event.Payload.ContributorId); @@ -224,7 +211,7 @@ public class BackupAppsTests ContributorId = "unknown" }); - var actual = await sut.RestoreEventAsync(@event, context, ct); + var actual = await sut.RestoreEventAsync(@event, context, CancellationToken); Assert.False(actual); Assert.Equal("unknown", @event.Payload.ContributorId); @@ -237,13 +224,13 @@ public class BackupAppsTests var context = CreateBackupContext(); - A.CallTo(() => context.Writer.OpenBlobAsync(A._, ct)) + A.CallTo(() => context.Writer.OpenBlobAsync(A._, CancellationToken)) .Returns(imageStream); - A.CallTo(() => appImageStore.DownloadAsync(appId, imageStream, ct)) + A.CallTo(() => appImageStore.DownloadAsync(AppId.Id, imageStream, CancellationToken)) .Throws(new AssetNotFoundException("Image")); - await sut.BackupEventAsync(Envelope.Create(new AppImageUploaded()), context, ct); + await sut.BackupEventAsync(Envelope.Create(new AppImageUploaded()), context, CancellationToken); } [Fact] @@ -253,12 +240,12 @@ public class BackupAppsTests var context = CreateBackupContext(); - A.CallTo(() => context.Writer.OpenBlobAsync(A._, ct)) + A.CallTo(() => context.Writer.OpenBlobAsync(A._, CancellationToken)) .Returns(imageStream); - await sut.BackupEventAsync(Envelope.Create(new AppImageUploaded()), context, ct); + await sut.BackupEventAsync(Envelope.Create(new AppImageUploaded()), context, CancellationToken); - A.CallTo(() => appImageStore.DownloadAsync(appId, imageStream, ct)) + A.CallTo(() => appImageStore.DownloadAsync(AppId.Id, imageStream, CancellationToken)) .MustHaveHappened(); } @@ -269,12 +256,12 @@ public class BackupAppsTests var context = CreateRestoreContext(); - A.CallTo(() => context.Reader.OpenBlobAsync(A._, ct)) + A.CallTo(() => context.Reader.OpenBlobAsync(A._, CancellationToken)) .Returns(imageStream); - await sut.RestoreEventAsync(Envelope.Create(new AppImageUploaded()), context, ct); + await sut.RestoreEventAsync(Envelope.Create(new AppImageUploaded()), context, CancellationToken); - A.CallTo(() => appImageStore.UploadAsync(appId, imageStream, ct)) + A.CallTo(() => appImageStore.UploadAsync(AppId.Id, imageStream, CancellationToken)) .MustHaveHappened(); } @@ -285,30 +272,31 @@ public class BackupAppsTests var context = CreateRestoreContext(); - A.CallTo(() => context.Reader.OpenBlobAsync(A._, ct)) + A.CallTo(() => context.Reader.OpenBlobAsync(A._, CancellationToken)) .Returns(imageStream); - A.CallTo(() => appImageStore.UploadAsync(appId, imageStream, ct)) + A.CallTo(() => appImageStore.UploadAsync(AppId.Id, imageStream, CancellationToken)) .Throws(new AssetAlreadyExistsException("Image")); - await sut.RestoreEventAsync(Envelope.Create(new AppImageUploaded()), context, ct); + await sut.RestoreEventAsync(Envelope.Create(new AppImageUploaded()), context, CancellationToken); } private BackupContext CreateBackupContext() { - return new BackupContext(appId, CreateUserMapping(), A.Fake()); + return new BackupContext(AppId.Id, CreateUserMapping(), A.Fake()); } private RestoreContext CreateRestoreContext() { - return new RestoreContext(appId, CreateUserMapping(), A.Fake(), DomainId.NewGuid()); + return new RestoreContext(AppId.Id, CreateUserMapping(), A.Fake(), DomainId.NewGuid()); } private IUserMapping CreateUserMapping() { var mapping = A.Fake(); - A.CallTo(() => mapping.Initiator).Returns(actor); + A.CallTo(() => mapping.Initiator) + .Returns(User); RefToken mapped; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppImageStoreTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppImageStoreTests.cs index 62caa82e8..8f71022ec 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppImageStoreTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppImageStoreTests.cs @@ -8,14 +8,13 @@ using Microsoft.Extensions.Options; using Squidex.Assets; using Squidex.Domain.Apps.Entities.Assets; -using Squidex.Infrastructure; +using Squidex.Domain.Apps.Entities.TestHelpers; namespace Squidex.Domain.Apps.Entities.Apps; -public class DefaultAppImageStoreTests +public class DefaultAppImageStoreTests : GivenContext { private readonly IAssetStore assetStore = A.Fake(); - private readonly DomainId appId = DomainId.NewGuid(); private readonly string fileNameDefault; private readonly string fileNameFolder; private readonly AssetOptions options = new AssetOptions(); @@ -23,8 +22,8 @@ public class DefaultAppImageStoreTests public DefaultAppImageStoreTests() { - fileNameDefault = appId.ToString(); - fileNameFolder = $"{appId}/thumbnail"; + fileNameDefault = AppId.Id.ToString(); + fileNameFolder = $"{AppId.Id}/thumbnail"; sut = new DefaultAppImageStore(assetStore, Options.Create(options)); } @@ -40,9 +39,9 @@ public class DefaultAppImageStoreTests var fileName = GetFileName(folderPerApp); - await sut.UploadAsync(appId, stream); + await sut.UploadAsync(AppId.Id, stream, CancellationToken); - A.CallTo(() => assetStore.UploadAsync(fileName, stream, true, default)) + A.CallTo(() => assetStore.UploadAsync(fileName, stream, true, CancellationToken)) .MustHaveHappened(); } @@ -57,9 +56,9 @@ public class DefaultAppImageStoreTests var fileName = GetFileName(folderPerApp); - await sut.DownloadAsync(appId, stream); + await sut.DownloadAsync(AppId.Id, stream, CancellationToken); - A.CallTo(() => assetStore.DownloadAsync(fileName, stream, default, default)) + A.CallTo(() => assetStore.DownloadAsync(fileName, stream, default, CancellationToken)) .MustHaveHappened(); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppLogStoreTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppLogStoreTests.cs index 0227e97ce..f7e9c58c7 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppLogStoreTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DefaultAppLogStoreTests.cs @@ -7,23 +7,17 @@ using System.Globalization; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; using Squidex.Infrastructure.Log; namespace Squidex.Domain.Apps.Entities.Apps; -public class DefaultAppLogStoreTests +public class DefaultAppLogStoreTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IRequestLogStore requestLogStore = A.Fake(); - private readonly DomainId appId = DomainId.NewGuid(); private readonly DefaultAppLogStore sut; public DefaultAppLogStoreTests() { - ct = cts.Token; - sut = new DefaultAppLogStore(requestLogStore); } @@ -38,11 +32,9 @@ public class DefaultAppLogStoreTests [Fact] public async Task Should_remove_events_from_streams() { - var app = Mocks.App(NamedId.Of(appId, "my-app")); - - await ((IDeleter)sut).DeleteAppAsync(app, ct); + await ((IDeleter)sut).DeleteAppAsync(App, CancellationToken); - A.CallTo(() => requestLogStore.DeleteAsync($"^[a-z]-{app.Id}", A._)) + A.CallTo(() => requestLogStore.DeleteAsync($"^[a-z]-{AppId.Id}", A._)) .MustNotHaveHappened(); } @@ -52,7 +44,7 @@ public class DefaultAppLogStoreTests A.CallTo(() => requestLogStore.IsEnabled) .Returns(false); - await sut.LogAsync(appId, default, ct); + await sut.LogAsync(AppId.Id, default, CancellationToken); A.CallTo(() => requestLogStore.LogAsync(A._, A._)) .MustNotHaveHappened(); @@ -66,7 +58,7 @@ public class DefaultAppLogStoreTests A.CallTo(() => requestLogStore.IsEnabled) .Returns(true); - A.CallTo(() => requestLogStore.LogAsync(A._, ct)) + A.CallTo(() => requestLogStore.LogAsync(A._, CancellationToken)) .Invokes(x => recordedRequest = x.GetArgument(0)!); var request = default(RequestLog); @@ -84,7 +76,7 @@ public class DefaultAppLogStoreTests request.UserClientId = "frontend"; request.UserId = "user1"; - await sut.LogAsync(appId, request, ct); + await sut.LogAsync(AppId.Id, request, CancellationToken); Assert.NotNull(recordedRequest); @@ -100,7 +92,7 @@ public class DefaultAppLogStoreTests Contains(request.UserClientId, recordedRequest); Contains(request.UserId, recordedRequest); - Assert.Equal(appId.ToString(), recordedRequest?.Key); + Assert.Equal(AppId.Id.ToString(), recordedRequest?.Key); } [Fact] @@ -109,7 +101,7 @@ public class DefaultAppLogStoreTests var dateFrom = DateTime.UtcNow.Date.AddDays(-30); var dateTo = DateTime.UtcNow.Date; - A.CallTo(() => requestLogStore.QueryAllAsync(appId.ToString(), dateFrom, dateTo, ct)) + A.CallTo(() => requestLogStore.QueryAllAsync(AppId.Id.ToString(), dateFrom, dateTo, CancellationToken)) .Returns(new[] { CreateRecord(), @@ -120,7 +112,7 @@ public class DefaultAppLogStoreTests var stream = new MemoryStream(); - await sut.ReadLogAsync(appId, dateFrom, dateTo, stream, ct); + await sut.ReadLogAsync(AppId.Id, dateFrom, dateTo, stream, CancellationToken); stream.Position = 0; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppCommandMiddlewareTests.cs index 28db0259f..6481d8d74 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppCommandMiddlewareTests.cs @@ -17,11 +17,8 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject; public class AppCommandMiddlewareTests : HandlerTestBase { private readonly IDomainObjectFactory domainObjectFactory = A.Fake(); - private readonly IContextProvider contextProvider = A.Fake(); private readonly IAppImageStore appImageStore = A.Fake(); private readonly IAssetThumbnailGenerator assetThumbnailGenerator = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly Context requestContext; private readonly AppCommandMiddleware sut; public sealed class MyCommand : SquidexCommand @@ -30,27 +27,22 @@ public class AppCommandMiddlewareTests : HandlerTestBase protected override DomainId Id { - get => appId.Id; + get => AppId.Id; } public AppCommandMiddlewareTests() { - requestContext = Context.Anonymous(Mocks.App(appId)); - - A.CallTo(() => contextProvider.Context) - .Returns(requestContext); - - sut = new AppCommandMiddleware(domainObjectFactory, appImageStore, assetThumbnailGenerator, contextProvider); + sut = new AppCommandMiddleware(domainObjectFactory, appImageStore, assetThumbnailGenerator, ApiContextProvider); } [Fact] public async Task Should_replace_context_app_with_domain_object_actual() { - var actual = A.Fake(); + var replaced = A.Fake(); - await HandleAsync(new UpdateApp(), actual); + await HandleAsync(new UpdateApp(), replaced); - Assert.Same(actual, requestContext.App); + Assert.Same(replaced, ApiContext.App); } [Fact] @@ -58,12 +50,12 @@ public class AppCommandMiddlewareTests : HandlerTestBase { var file = new NoopAssetFile(); - A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(A._, file.MimeType, default)) + A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(A._, file.MimeType, CancellationToken)) .Returns(new ImageInfo(100, 100, ImageOrientation.None, ImageFormat.PNG)); await HandleAsync(new UploadAppImage { File = file }, None.Value); - A.CallTo(() => appImageStore.UploadAsync(appId.Id, A._, A._)) + A.CallTo(() => appImageStore.UploadAsync(AppId.Id, A._, CancellationToken)) .MustHaveHappened(); } @@ -74,15 +66,15 @@ public class AppCommandMiddlewareTests : HandlerTestBase var command = new UploadAppImage { File = file }; - A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(A._, file.MimeType, default)) + A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(A._, file.MimeType, CancellationToken)) .Returns(Task.FromResult(null)); - await Assert.ThrowsAsync(() => HandleAsync(sut, command)); + await Assert.ThrowsAsync(() => HandleAsync(sut, command, CancellationToken)); } private Task HandleAsync(AppCommand command, object actual) { - command.AppId = appId; + command.AppId = AppId; var domainObject = A.Fake(); @@ -92,6 +84,6 @@ public class AppCommandMiddlewareTests : HandlerTestBase A.CallTo(() => domainObjectFactory.Create(command.AggregateId)) .Returns(domainObject); - return HandleAsync(sut, command); + return HandleAsync(sut, command, CancellationToken); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs index a186141cc..469fe7cd1 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs @@ -23,7 +23,6 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject; public class AppDomainObjectTests : HandlerTestBase { - private readonly IAppProvider appProvider = A.Fake(); private readonly IBillingPlans billingPlans = A.Fake(); private readonly IBillingManager billingManager = A.Fake(); private readonly IUser user; @@ -36,37 +35,33 @@ public class AppDomainObjectTests : HandlerTestBase private readonly string planIdPaid = "premium"; private readonly string planIdFree = "free"; private readonly InitialSettings initialSettings; - private readonly DomainId teamId = DomainId.NewGuid(); private readonly DomainId workflowId = DomainId.NewGuid(); private readonly AppDomainObject sut; protected override DomainId Id { - get => AppId; + get => AppId.Id; } public AppDomainObjectTests() { user = UserMocks.User(contributorId); - A.CallTo(() => userResolver.FindByIdOrEmailAsync(contributorId, default)) + A.CallTo(() => userResolver.FindByIdOrEmailAsync(contributorId, CancellationToken)) .Returns(user); - A.CallTo(() => usageGate.GetPlanForAppAsync(A.That.Matches(x => x.Plan != null && x.Plan.PlanId == planIdFree), false, default)) + A.CallTo(() => usageGate.GetPlanForAppAsync(A.That.Matches(x => x.Plan != null && x.Plan.PlanId == planIdFree), false, CancellationToken)) .Returns((new Plan { Id = planIdFree, MaxContributors = 10 }, planIdFree, null)); - A.CallTo(() => usageGate.GetPlanForAppAsync(A.That.Matches(x => x.Plan != null && x.Plan.PlanId == planIdPaid), false, default)) + A.CallTo(() => usageGate.GetPlanForAppAsync(A.That.Matches(x => x.Plan != null && x.Plan.PlanId == planIdPaid), false, CancellationToken)) .Returns((new Plan { Id = planIdPaid, MaxContributors = 30 }, planIdPaid, null)); A.CallTo(() => billingPlans.GetFreePlan()) .Returns(new Plan { Id = planIdFree, MaxContributors = 10 }); - A.CallTo(() => billingManager.MustRedirectToPortalAsync(Actor.Identifier, A._, A._, default)) + A.CallTo(() => billingManager.MustRedirectToPortalAsync(User.Identifier, A._, A._, CancellationToken)) .Returns(Task.FromResult(null)); - A.CallTo(() => appProvider.GetTeamAsync(teamId, default)) - .Returns(Mocks.Team(teamId, contributor: Actor.Identifier)); - // Create a non-empty setting, otherwise the event is not raised as it does not change the domain object. initialSettings = new InitialSettings { @@ -78,7 +73,7 @@ public class AppDomainObjectTests : HandlerTestBase var serviceProvider = new ServiceCollection() - .AddSingleton(appProvider) + .AddSingleton(AppProvider) .AddSingleton(billingManager) .AddSingleton(billingPlans) .AddSingleton(initialSettings) @@ -105,18 +100,18 @@ public class AppDomainObjectTests : HandlerTestBase [Fact] public async Task Create_should_create_events_and_set_intitial_state() { - var command = new CreateApp { Name = AppName, AppId = AppId }; + var command = new CreateApp { Name = AppId.Name, AppId = AppId.Id }; var actual = await PublishAsync(command); actual.ShouldBeEquivalent(sut.Snapshot); - Assert.Equal(AppName, sut.Snapshot.Name); + Assert.Equal(AppId.Name, sut.Snapshot.Name); LastEvents .ShouldHaveSameEvents( - CreateEvent(new AppCreated { Name = AppName }), - CreateEvent(new AppContributorAssigned { ContributorId = Actor.Identifier, Role = Role.Owner }), + CreateEvent(new AppCreated { Name = AppId.Name }), + CreateEvent(new AppContributorAssigned { ContributorId = User.Identifier, Role = Role.Owner }), CreateEvent(new AppSettingsUpdated { Settings = initialSettings.Settings }) ); } @@ -124,17 +119,17 @@ public class AppDomainObjectTests : HandlerTestBase [Fact] public async Task Create_should_not_assign_client_as_contributor() { - var command = new CreateApp { Name = AppName, Actor = ActorClient, AppId = AppId }; + var command = new CreateApp { Name = AppId.Name, Actor = Client, AppId = AppId.Id }; var actual = await PublishAsync(command); actual.ShouldBeEquivalent(sut.Snapshot); - Assert.Equal(AppName, sut.Snapshot.Name); + Assert.Equal(AppId.Name, sut.Snapshot.Name); LastEvents .ShouldHaveSameEvents( - CreateEvent(new AppCreated { Name = AppName }, true), // Must be with client actor. + CreateEvent(new AppCreated { Name = AppId.Name }, true), // Must be with client actor. CreateEvent(new AppSettingsUpdated { Settings = initialSettings.Settings }, true) ); } @@ -227,7 +222,7 @@ public class AppDomainObjectTests : HandlerTestBase { var command = new ChangePlan { PlanId = planIdPaid }; - A.CallTo(() => billingManager.MustRedirectToPortalAsync(Actor.Identifier, A._, planIdPaid, default)) + A.CallTo(() => billingManager.MustRedirectToPortalAsync(User.Identifier, A._, planIdPaid, default)) .Returns(Task.FromResult(null)); await ExecuteCreateAsync(); @@ -243,10 +238,10 @@ public class AppDomainObjectTests : HandlerTestBase CreateEvent(new AppPlanChanged { PlanId = planIdPaid }) ); - A.CallTo(() => billingManager.MustRedirectToPortalAsync(Actor.Identifier, A._, planIdPaid, default)) + A.CallTo(() => billingManager.MustRedirectToPortalAsync(User.Identifier, A._, planIdPaid, CancellationToken)) .MustHaveHappened(); - A.CallTo(() => billingManager.SubscribeAsync(Actor.Identifier, A._, planIdPaid, default)) + A.CallTo(() => billingManager.SubscribeAsync(User.Identifier, A._, planIdPaid, default)) .MustHaveHappened(); } @@ -320,7 +315,7 @@ public class AppDomainObjectTests : HandlerTestBase CreateEvent(new AppPlanReset()) ); - A.CallTo(() => billingManager.MustRedirectToPortalAsync(Actor.Identifier, A._, planIdPaid, default)) + A.CallTo(() => billingManager.MustRedirectToPortalAsync(User.Identifier, A._, planIdPaid, CancellationToken)) .MustHaveHappenedOnceExactly(); A.CallTo(() => billingManager.UnsubscribeAsync(A._, A._, A._)) @@ -332,7 +327,7 @@ public class AppDomainObjectTests : HandlerTestBase { var command = new ChangePlan { PlanId = planIdPaid }; - A.CallTo(() => billingManager.MustRedirectToPortalAsync(Actor.Identifier, A._, planIdPaid, default)) + A.CallTo(() => billingManager.MustRedirectToPortalAsync(User.Identifier, A._, planIdPaid, CancellationToken)) .Returns(new Uri("http://squidex.io")); await ExecuteCreateAsync(); @@ -357,10 +352,10 @@ public class AppDomainObjectTests : HandlerTestBase Assert.Equal(planIdPaid, sut.Snapshot.Plan?.PlanId); - A.CallTo(() => billingManager.MustRedirectToPortalAsync(Actor.Identifier, A._, planIdPaid, A._)) + A.CallTo(() => billingManager.MustRedirectToPortalAsync(User.Identifier, A._, planIdPaid, A._)) .MustNotHaveHappened(); - A.CallTo(() => billingManager.SubscribeAsync(Actor.Identifier, A._, planIdPaid, A._)) + A.CallTo(() => billingManager.SubscribeAsync(User.Identifier, A._, planIdPaid, A._)) .MustNotHaveHappened(); } @@ -426,7 +421,7 @@ public class AppDomainObjectTests : HandlerTestBase [Fact] public async Task Transfer_should_create_events_and_set_team() { - var command = new TransferToTeam { TeamId = teamId }; + var command = new TransferToTeam { TeamId = TeamId }; await ExecuteCreateAsync(); @@ -434,11 +429,11 @@ public class AppDomainObjectTests : HandlerTestBase actual.ShouldBeEquivalent(sut.Snapshot); - Assert.Equal(teamId, sut.Snapshot.TeamId); + Assert.Equal(TeamId, sut.Snapshot.TeamId); LastEvents .ShouldHaveSameEvents( - CreateEvent(new AppTransfered { TeamId = teamId }) + CreateEvent(new AppTransfered { TeamId = TeamId }) ); } @@ -720,7 +715,7 @@ public class AppDomainObjectTests : HandlerTestBase private Task ExecuteCreateAsync() { - return PublishAsync(new CreateApp { Name = AppName, AppId = AppId }); + return PublishAsync(new CreateApp { Name = AppId.Name, AppId = AppId.Id }); } private Task ExecuteUploadImage() @@ -760,7 +755,7 @@ public class AppDomainObjectTests : HandlerTestBase private Task ExecuteTransferAsync() { - return PublishAsync(new TransferToTeam { TeamId = teamId }); + return PublishAsync(new TransferToTeam { TeamId = TeamId }); } private Task ExecuteArchiveAsync() @@ -775,7 +770,7 @@ public class AppDomainObjectTests : HandlerTestBase private async Task PublishAsync(T command) where T : SquidexCommand, IAggregateCommand { - var actual = await sut.ExecuteAsync(CreateCommand(command), default); + var actual = await sut.ExecuteAsync(CreateCommand(command), CancellationToken); return actual.Payload; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppClientsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppClientsTests.cs index c2a0914fb..061f609a1 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppClientsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppClientsTests.cs @@ -12,21 +12,27 @@ using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Validation; -#pragma warning disable SA1310 // Field names must not contain underscore - namespace Squidex.Domain.Apps.Entities.Apps.DomainObject.Guards; -public class GuardAppClientsTests : IClassFixture +public class GuardAppClientsTests : GivenContext, IClassFixture { - private readonly AppClients clients_0 = AppClients.Empty; - private readonly Roles roles = Roles.Empty; + private AppClients clients = AppClients.Empty; + + public GuardAppClientsTests() + { + A.CallTo(() => App.Roles) + .Returns(Roles.Empty); + + A.CallTo(() => App.Clients) + .ReturnsLazily(() => clients); + } [Fact] public void CanAttach_should_throw_execption_if_client_id_is_null() { var command = new AttachClient(); - ValidationAssert.Throws(() => GuardAppClients.CanAttach(command, App(clients_0)), + ValidationAssert.Throws(() => GuardAppClients.CanAttach(command, App), new ValidationError("Client ID is required.", "Id")); } @@ -35,9 +41,9 @@ public class GuardAppClientsTests : IClassFixture { var command = new AttachClient { Id = "android" }; - var clients_1 = clients_0.Add("android", "secret"); + clients = clients.Add("android", "secret"); - ValidationAssert.Throws(() => GuardAppClients.CanAttach(command, App(clients_1)), + ValidationAssert.Throws(() => GuardAppClients.CanAttach(command, App), new ValidationError("A client with the same id already exists.")); } @@ -46,9 +52,9 @@ public class GuardAppClientsTests : IClassFixture { var command = new AttachClient { Id = "ios" }; - var clients_1 = clients_0.Add("android", "secret"); + clients = clients.Add("android", "secret"); - GuardAppClients.CanAttach(command, App(clients_1)); + GuardAppClients.CanAttach(command, App); } [Fact] @@ -56,7 +62,7 @@ public class GuardAppClientsTests : IClassFixture { var command = new RevokeClient(); - ValidationAssert.Throws(() => GuardAppClients.CanRevoke(command, App(clients_0)), + ValidationAssert.Throws(() => GuardAppClients.CanRevoke(command, App), new ValidationError("Client ID is required.", "Id")); } @@ -65,7 +71,7 @@ public class GuardAppClientsTests : IClassFixture { var command = new RevokeClient { Id = "ios" }; - Assert.Throws(() => GuardAppClients.CanRevoke(command, App(clients_0))); + Assert.Throws(() => GuardAppClients.CanRevoke(command, App)); } [Fact] @@ -73,9 +79,9 @@ public class GuardAppClientsTests : IClassFixture { var command = new RevokeClient { Id = "ios" }; - var clients_1 = clients_0.Add("ios", "secret"); + clients = clients.Add("ios", "secret"); - GuardAppClients.CanRevoke(command, App(clients_1)); + GuardAppClients.CanRevoke(command, App); } [Fact] @@ -83,7 +89,7 @@ public class GuardAppClientsTests : IClassFixture { var command = new UpdateClient { Name = "iOS" }; - ValidationAssert.Throws(() => GuardAppClients.CanUpdate(command, App(clients_0)), + ValidationAssert.Throws(() => GuardAppClients.CanUpdate(command, App), new ValidationError("Client ID is required.", "Id")); } @@ -92,7 +98,7 @@ public class GuardAppClientsTests : IClassFixture { var command = new UpdateClient { Id = "ios", Name = "iOS" }; - Assert.Throws(() => GuardAppClients.CanUpdate(command, App(clients_0))); + Assert.Throws(() => GuardAppClients.CanUpdate(command, App)); } [Fact] @@ -100,9 +106,9 @@ public class GuardAppClientsTests : IClassFixture { var command = new UpdateClient { Id = "ios", Role = "Invalid" }; - var clients_1 = clients_0.Add("ios", "secret"); + clients = clients.Add("ios", "secret"); - ValidationAssert.Throws(() => GuardAppClients.CanUpdate(command, App(clients_1)), + ValidationAssert.Throws(() => GuardAppClients.CanUpdate(command, App), new ValidationError("Role is not a valid value.", "Role")); } @@ -111,9 +117,9 @@ public class GuardAppClientsTests : IClassFixture { var command = new UpdateClient { Id = "ios", ApiCallsLimit = -10 }; - var clients_1 = clients_0.Add("ios", "secret"); + clients = clients.Add("ios", "secret"); - ValidationAssert.Throws(() => GuardAppClients.CanUpdate(command, App(clients_1)), + ValidationAssert.Throws(() => GuardAppClients.CanUpdate(command, App), new ValidationError("ApiCallsLimit must be greater or equal to 0.", "ApiCallsLimit")); } @@ -122,9 +128,9 @@ public class GuardAppClientsTests : IClassFixture { var command = new UpdateClient { Id = "ios", ApiTrafficLimit = -10 }; - var clients_1 = clients_0.Add("ios", "secret"); + clients = clients.Add("ios", "secret"); - ValidationAssert.Throws(() => GuardAppClients.CanUpdate(command, App(clients_1)), + ValidationAssert.Throws(() => GuardAppClients.CanUpdate(command, App), new ValidationError("ApiTrafficLimit must be greater or equal to 0.", "ApiTrafficLimit")); } @@ -133,9 +139,9 @@ public class GuardAppClientsTests : IClassFixture { var command = new UpdateClient { Id = "ios", Name = "ios" }; - var clients_1 = clients_0.Add("ios", "secret"); + clients = clients.Add("ios", "secret"); - GuardAppClients.CanUpdate(command, App(clients_1)); + GuardAppClients.CanUpdate(command, App); } [Fact] @@ -143,9 +149,9 @@ public class GuardAppClientsTests : IClassFixture { var command = new UpdateClient { Id = "ios", Role = Role.Editor }; - var clients_1 = clients_0.Add("ios", "secret"); + clients = clients.Add("ios", "secret"); - GuardAppClients.CanUpdate(command, App(clients_1)); + GuardAppClients.CanUpdate(command, App); } [Fact] @@ -153,18 +159,8 @@ public class GuardAppClientsTests : IClassFixture { var command = new UpdateClient { Id = "ios", Name = "iOS", Role = Role.Reader }; - var clients_1 = clients_0.Add("ios", "secret"); - - GuardAppClients.CanUpdate(command, App(clients_1)); - } - - private IAppEntity App(AppClients clients) - { - var app = A.Fake(); - - A.CallTo(() => app.Clients).Returns(clients); - A.CallTo(() => app.Roles).Returns(roles); + clients = clients.Add("ios", "secret"); - return app; + GuardAppClients.CanUpdate(command, App); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppContributorsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppContributorsTests.cs index 75168e0bf..7fc427594 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppContributorsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppContributorsTests.cs @@ -15,23 +15,26 @@ using Squidex.Infrastructure; using Squidex.Infrastructure.Validation; using Squidex.Shared.Users; -#pragma warning disable SA1310 // Field names must not contain underscore - namespace Squidex.Domain.Apps.Entities.Apps.DomainObject.Guards; -public class GuardAppContributorsTests : IClassFixture +public class GuardAppContributorsTests : GivenContext, IClassFixture { private readonly IUser user1 = UserMocks.User("1"); private readonly IUser user2 = UserMocks.User("2"); private readonly IUser user3 = UserMocks.User("3"); private readonly IUserResolver users = A.Fake(); - private readonly Contributors contributors_0 = Contributors.Empty; private readonly Plan planWithoutLimit = new Plan { MaxContributors = -1 }; private readonly Plan planWithLimit = new Plan { MaxContributors = 2 }; - private readonly Roles roles = Roles.Empty; + private Contributors contributors = Contributors.Empty; public GuardAppContributorsTests() { + A.CallTo(() => App.Roles) + .Returns(Roles.Empty); + + A.CallTo(() => App.Contributors) + .ReturnsLazily(() => contributors); + A.CallTo(() => user1.Id) .Returns("1"); @@ -59,7 +62,7 @@ public class GuardAppContributorsTests : IClassFixture { var command = new AssignContributor(); - await ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(command, App(contributors_0), users, planWithoutLimit), + await ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(command, App, users, planWithoutLimit), new ValidationError("Contributor ID or email is required.", "ContributorId")); } @@ -68,7 +71,7 @@ public class GuardAppContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "1", Role = "Invalid" }; - await ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(command, App(contributors_0), users, planWithoutLimit), + await ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(command, App, users, planWithoutLimit), new ValidationError("Role is not a valid value.", "Role")); } @@ -77,9 +80,9 @@ public class GuardAppContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "1", Role = Role.Owner }; - var contributors_1 = contributors_0.Assign("1", Role.Owner); + contributors = contributors.Assign("1", Role.Owner); - await GuardAppContributors.CanAssign(command, App(contributors_1), users, planWithoutLimit); + await GuardAppContributors.CanAssign(command, App, users, planWithoutLimit); } [Fact] @@ -87,9 +90,9 @@ public class GuardAppContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "1", Role = Role.Owner, IgnoreActor = true }; - var contributors_1 = contributors_0.Assign("1", Role.Owner); + contributors = contributors.Assign("1", Role.Owner); - await GuardAppContributors.CanAssign(command, App(contributors_1), users, planWithoutLimit); + await GuardAppContributors.CanAssign(command, App, users, planWithoutLimit); } [Fact] @@ -97,7 +100,7 @@ public class GuardAppContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "notfound", Role = Role.Owner }; - await Assert.ThrowsAsync(() => GuardAppContributors.CanAssign(command, App(contributors_0), users, planWithoutLimit)); + await Assert.ThrowsAsync(() => GuardAppContributors.CanAssign(command, App, users, planWithoutLimit)); } [Fact] @@ -105,7 +108,7 @@ public class GuardAppContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "3", Role = Role.Editor, Actor = RefToken.User("3") }; - await Assert.ThrowsAsync(() => GuardAppContributors.CanAssign(command, App(contributors_0), users, planWithoutLimit)); + await Assert.ThrowsAsync(() => GuardAppContributors.CanAssign(command, App, users, planWithoutLimit)); } [Fact] @@ -113,10 +116,9 @@ public class GuardAppContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "3" }; - var contributors_1 = contributors_0.Assign("1", Role.Owner); - var contributors_2 = contributors_1.Assign("2", Role.Editor); + contributors = contributors.Assign("1", Role.Owner).Assign("2", Role.Editor); - await ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(command, App(contributors_2), users, planWithLimit), + await ValidationAssert.ThrowsAsync(() => GuardAppContributors.CanAssign(command, App, users, planWithLimit), new ValidationError("You have reached the maximum number of contributors for your plan.")); } @@ -125,10 +127,9 @@ public class GuardAppContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "3", IgnorePlans = true }; - var contributors_1 = contributors_0.Assign("1", Role.Owner); - var contributors_2 = contributors_1.Assign("2", Role.Editor); + contributors = contributors.Assign("1", Role.Owner).Assign("2", Role.Editor); - await GuardAppContributors.CanAssign(command, App(contributors_2), users, planWithLimit); + await GuardAppContributors.CanAssign(command, App, users, planWithLimit); } [Fact] @@ -136,7 +137,7 @@ public class GuardAppContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "1" }; - await GuardAppContributors.CanAssign(command, App(contributors_0), users, planWithoutLimit); + await GuardAppContributors.CanAssign(command, App, users, planWithoutLimit); } [Fact] @@ -144,9 +145,9 @@ public class GuardAppContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "1" }; - var contributors_1 = contributors_0.Assign("1", Role.Developer); + contributors = contributors.Assign("1", Role.Developer); - await GuardAppContributors.CanAssign(command, App(contributors_1), users, planWithoutLimit); + await GuardAppContributors.CanAssign(command, App, users, planWithoutLimit); } [Fact] @@ -154,10 +155,9 @@ public class GuardAppContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "1" }; - var contributors_1 = contributors_0.Assign("1", Role.Developer); - var contributors_2 = contributors_1.Assign("2", Role.Developer); + contributors = contributors.Assign("1", Role.Developer).Assign("2", Role.Developer); - await GuardAppContributors.CanAssign(command, App(contributors_2), users, planWithLimit); + await GuardAppContributors.CanAssign(command, App, users, planWithLimit); } [Fact] @@ -165,10 +165,9 @@ public class GuardAppContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "3", IgnorePlans = true }; - var contributors_1 = contributors_0.Assign("1", Role.Editor); - var contributors_2 = contributors_1.Assign("2", Role.Editor); + contributors = contributors.Assign("1", Role.Editor).Assign("2", Role.Editor); - await GuardAppContributors.CanAssign(command, App(contributors_2), users, planWithoutLimit); + await GuardAppContributors.CanAssign(command, App, users, planWithoutLimit); } [Fact] @@ -176,7 +175,7 @@ public class GuardAppContributorsTests : IClassFixture { var command = new RemoveContributor(); - ValidationAssert.Throws(() => GuardAppContributors.CanRemove(command, App(contributors_0)), + ValidationAssert.Throws(() => GuardAppContributors.CanRemove(command, App), new ValidationError("Contributor ID or email is required.", "ContributorId")); } @@ -185,7 +184,7 @@ public class GuardAppContributorsTests : IClassFixture { var command = new RemoveContributor { ContributorId = "1" }; - Assert.Throws(() => GuardAppContributors.CanRemove(command, App(contributors_0))); + Assert.Throws(() => GuardAppContributors.CanRemove(command, App)); } [Fact] @@ -193,10 +192,9 @@ public class GuardAppContributorsTests : IClassFixture { var command = new RemoveContributor { ContributorId = "1" }; - var contributors_1 = contributors_0.Assign("1", Role.Owner); - var contributors_2 = contributors_1.Assign("2", Role.Editor); + contributors = contributors.Assign("1", Role.Owner).Assign("2", Role.Editor); - ValidationAssert.Throws(() => GuardAppContributors.CanRemove(command, App(contributors_2)), + ValidationAssert.Throws(() => GuardAppContributors.CanRemove(command, App), new ValidationError("Cannot remove the only owner.")); } @@ -205,19 +203,8 @@ public class GuardAppContributorsTests : IClassFixture { var command = new RemoveContributor { ContributorId = "1" }; - var contributors_1 = contributors_0.Assign("1", Role.Owner); - var contributors_2 = contributors_1.Assign("2", Role.Owner); - - GuardAppContributors.CanRemove(command, App(contributors_2)); - } - - private IAppEntity App(Contributors contributors) - { - var app = A.Fake(); - - A.CallTo(() => app.Contributors).Returns(contributors); - A.CallTo(() => app.Roles).Returns(roles); + contributors = contributors.Assign("1", Role.Owner).Assign("2", Role.Owner); - return app; + GuardAppContributors.CanRemove(command, App); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppLanguagesTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppLanguagesTests.cs index 108ff6193..bf960617c 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppLanguagesTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppLanguagesTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.TestHelpers; @@ -14,16 +13,14 @@ using Squidex.Infrastructure.Validation; namespace Squidex.Domain.Apps.Entities.Apps.DomainObject.Guards; -public class GuardAppLanguagesTests : IClassFixture +public class GuardAppLanguagesTests : GivenContext, IClassFixture { - private readonly LanguagesConfig languages = LanguagesConfig.English.Set(Language.DE); - [Fact] public void CanAddLanguage_should_throw_exception_if_language_is_null() { var command = new AddLanguage(); - ValidationAssert.Throws(() => GuardAppLanguages.CanAdd(command, App(languages)), + ValidationAssert.Throws(() => GuardAppLanguages.CanAdd(command, App), new ValidationError("Language code is required.", "Language")); } @@ -32,7 +29,7 @@ public class GuardAppLanguagesTests : IClassFixture { var command = new AddLanguage { Language = Language.EN }; - ValidationAssert.Throws(() => GuardAppLanguages.CanAdd(command, App(languages)), + ValidationAssert.Throws(() => GuardAppLanguages.CanAdd(command, App), new ValidationError("Language has already been added.")); } @@ -41,7 +38,7 @@ public class GuardAppLanguagesTests : IClassFixture { var command = new AddLanguage { Language = Language.IT }; - GuardAppLanguages.CanAdd(command, App(languages)); + GuardAppLanguages.CanAdd(command, App); } [Fact] @@ -49,7 +46,7 @@ public class GuardAppLanguagesTests : IClassFixture { var command = new RemoveLanguage(); - ValidationAssert.Throws(() => GuardAppLanguages.CanRemove(command, App(languages)), + ValidationAssert.Throws(() => GuardAppLanguages.CanRemove(command, App), new ValidationError("Language code is required.", "Language")); } @@ -58,7 +55,7 @@ public class GuardAppLanguagesTests : IClassFixture { var command = new RemoveLanguage { Language = Language.IT }; - Assert.Throws(() => GuardAppLanguages.CanRemove(command, App(languages))); + Assert.Throws(() => GuardAppLanguages.CanRemove(command, App)); } [Fact] @@ -66,7 +63,7 @@ public class GuardAppLanguagesTests : IClassFixture { var command = new RemoveLanguage { Language = Language.EN }; - ValidationAssert.Throws(() => GuardAppLanguages.CanRemove(command, App(languages)), + ValidationAssert.Throws(() => GuardAppLanguages.CanRemove(command, App), new ValidationError("Master language cannot be removed.")); } @@ -75,7 +72,7 @@ public class GuardAppLanguagesTests : IClassFixture { var command = new RemoveLanguage { Language = Language.DE }; - GuardAppLanguages.CanRemove(command, App(languages)); + GuardAppLanguages.CanRemove(command, App); } [Fact] @@ -83,7 +80,7 @@ public class GuardAppLanguagesTests : IClassFixture { var command = new UpdateLanguage(); - ValidationAssert.Throws(() => GuardAppLanguages.CanUpdate(command, App(languages)), + ValidationAssert.Throws(() => GuardAppLanguages.CanUpdate(command, App), new ValidationError("Language code is required.", "Language")); } @@ -92,7 +89,7 @@ public class GuardAppLanguagesTests : IClassFixture { var command = new UpdateLanguage { Language = Language.EN, IsOptional = true }; - ValidationAssert.Throws(() => GuardAppLanguages.CanUpdate(command, App(languages)), + ValidationAssert.Throws(() => GuardAppLanguages.CanUpdate(command, App), new ValidationError("Master language cannot be made optional.", "IsMaster")); } @@ -101,7 +98,7 @@ public class GuardAppLanguagesTests : IClassFixture { var command = new UpdateLanguage { Language = Language.EN, Fallback = new[] { Language.DE } }; - ValidationAssert.Throws(() => GuardAppLanguages.CanUpdate(command, App(languages)), + ValidationAssert.Throws(() => GuardAppLanguages.CanUpdate(command, App), new ValidationError("Master language cannot have fallback languages.", "Fallback")); } @@ -110,7 +107,7 @@ public class GuardAppLanguagesTests : IClassFixture { var command = new UpdateLanguage { Language = Language.DE, Fallback = new[] { Language.IT } }; - ValidationAssert.Throws(() => GuardAppLanguages.CanUpdate(command, App(languages)), + ValidationAssert.Throws(() => GuardAppLanguages.CanUpdate(command, App), new ValidationError("App does not have fallback language 'Italian'.", "Fallback")); } @@ -119,7 +116,7 @@ public class GuardAppLanguagesTests : IClassFixture { var command = new UpdateLanguage { Language = Language.IT }; - Assert.Throws(() => GuardAppLanguages.CanUpdate(command, App(languages))); + Assert.Throws(() => GuardAppLanguages.CanUpdate(command, App)); } [Fact] @@ -127,15 +124,6 @@ public class GuardAppLanguagesTests : IClassFixture { var command = new UpdateLanguage { Language = Language.DE, Fallback = new[] { Language.EN } }; - GuardAppLanguages.CanUpdate(command, App(languages)); - } - - private static IAppEntity App(LanguagesConfig languages) - { - var app = A.Fake(); - - A.CallTo(() => app.Languages).Returns(languages); - - return app; + GuardAppLanguages.CanUpdate(command, App); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppRolesTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppRolesTests.cs index 230a6055f..57928f047 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppRolesTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppRolesTests.cs @@ -13,34 +13,42 @@ using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Validation; -#pragma warning disable SA1310 // Field names must not contain underscore - namespace Squidex.Domain.Apps.Entities.Apps.DomainObject.Guards; -public class GuardAppRolesTests : IClassFixture +public class GuardAppRolesTests : GivenContext, IClassFixture { private readonly string roleName = "Role1"; - private readonly Roles roles_0 = Roles.Empty; - private readonly AppClients clients = AppClients.Empty.Add("client", "secret", "clientRole"); - private readonly Contributors contributors = Contributors.Empty.Assign("contributor", "contributorRole"); + private Roles roles = Roles.Empty; + + public GuardAppRolesTests() + { + A.CallTo(() => App.Contributors) + .Returns(Contributors.Empty.Assign(User.Identifier, "contributorRole")); + + A.CallTo(() => App.Clients) + .Returns(AppClients.Empty.Add(Client.Identifier, "secret", "clientRole")); + + A.CallTo(() => App.Roles) + .ReturnsLazily(() => roles); + } [Fact] public void CanAdd_should_throw_exception_if_name_empty() { var command = new AddRole { Name = null! }; - ValidationAssert.Throws(() => GuardAppRoles.CanAdd(command, App(roles_0)), + ValidationAssert.Throws(() => GuardAppRoles.CanAdd(command, App), new ValidationError("Name is required.", "Name")); } [Fact] public void CanAdd_should_throw_exception_if_name_exists() { - var roles_1 = roles_0.Add(roleName); + roles = roles.Add(roleName); var command = new AddRole { Name = roleName }; - ValidationAssert.Throws(() => GuardAppRoles.CanAdd(command, App(roles_1)), + ValidationAssert.Throws(() => GuardAppRoles.CanAdd(command, App), new ValidationError("A role with the same name already exists.")); } @@ -49,7 +57,7 @@ public class GuardAppRolesTests : IClassFixture { var command = new AddRole { Name = roleName }; - GuardAppRoles.CanAdd(command, App(roles_0)); + GuardAppRoles.CanAdd(command, App); } [Fact] @@ -57,7 +65,7 @@ public class GuardAppRolesTests : IClassFixture { var command = new DeleteRole { Name = null! }; - ValidationAssert.Throws(() => GuardAppRoles.CanDelete(command, App(roles_0)), + ValidationAssert.Throws(() => GuardAppRoles.CanDelete(command, App), new ValidationError("Name is required.", "Name")); } @@ -66,82 +74,82 @@ public class GuardAppRolesTests : IClassFixture { var command = new DeleteRole { Name = roleName }; - Assert.Throws(() => GuardAppRoles.CanDelete(command, App(roles_0))); + Assert.Throws(() => GuardAppRoles.CanDelete(command, App)); } [Fact] public void CanDelete_should_throw_exception_if_contributor_found() { - var roles_1 = roles_0.Add("contributorRole"); + roles = roles.Add("contributorRole"); var command = new DeleteRole { Name = "contributorRole" }; - ValidationAssert.Throws(() => GuardAppRoles.CanDelete(command, App(roles_1)), + ValidationAssert.Throws(() => GuardAppRoles.CanDelete(command, App), new ValidationError("Cannot remove a role when a contributor is assigned.")); } [Fact] public void CanDelete_should_throw_exception_if_client_found() { - var roles_1 = roles_0.Add("clientRole"); + roles = roles.Add("clientRole"); var command = new DeleteRole { Name = "clientRole" }; - ValidationAssert.Throws(() => GuardAppRoles.CanDelete(command, App(roles_1)), + ValidationAssert.Throws(() => GuardAppRoles.CanDelete(command, App), new ValidationError("Cannot remove a role when a client is assigned.")); } [Fact] public void CanDelete_should_throw_exception_if_default_role() { - var roles_1 = roles_0.Add(Role.Developer); + roles = roles.Add(Role.Developer); var command = new DeleteRole { Name = Role.Developer }; - ValidationAssert.Throws(() => GuardAppRoles.CanDelete(command, App(roles_1)), + ValidationAssert.Throws(() => GuardAppRoles.CanDelete(command, App), new ValidationError("Cannot delete a default role.")); } [Fact] public void CanDelete_should_not_throw_exception_if_command_is_valid() { - var roles_1 = roles_0.Add(roleName); + roles = roles.Add(roleName); var command = new DeleteRole { Name = roleName }; - GuardAppRoles.CanDelete(command, App(roles_1)); + GuardAppRoles.CanDelete(command, App); } [Fact] public void CanUpdate_should_throw_exception_if_name_empty() { - var roles_1 = roles_0.Add(roleName); + roles = roles.Add(roleName); var command = new UpdateRole { Name = null!, Permissions = new[] { "P1" } }; - ValidationAssert.Throws(() => GuardAppRoles.CanUpdate(command, App(roles_1)), + ValidationAssert.Throws(() => GuardAppRoles.CanUpdate(command, App), new ValidationError("Name is required.", "Name")); } [Fact] public void CanUpdate_should_throw_exception_if_permission_is_null() { - var roles_1 = roles_0.Add(roleName); + roles = roles.Add(roleName); var command = new UpdateRole { Name = roleName }; - ValidationAssert.Throws(() => GuardAppRoles.CanUpdate(command, App(roles_1)), + ValidationAssert.Throws(() => GuardAppRoles.CanUpdate(command, App), new ValidationError("Permissions is required.", "Permissions")); } [Fact] public void CanUpdate_should_throw_exception_if_default_role() { - var roles_1 = roles_0.Add(Role.Developer); + roles = roles.Add(Role.Developer); var command = new UpdateRole { Name = Role.Developer, Permissions = new[] { "P1" } }; - ValidationAssert.Throws(() => GuardAppRoles.CanUpdate(command, App(roles_1)), + ValidationAssert.Throws(() => GuardAppRoles.CanUpdate(command, App), new ValidationError("Cannot update a default role.")); } @@ -150,37 +158,26 @@ public class GuardAppRolesTests : IClassFixture { var command = new UpdateRole { Name = roleName, Permissions = new[] { "P1" } }; - Assert.Throws(() => GuardAppRoles.CanUpdate(command, App(roles_0))); + Assert.Throws(() => GuardAppRoles.CanUpdate(command, App)); } [Fact] public void CanUpdate_should_not_throw_exception_if_properties_is_null() { - var roles_1 = roles_0.Add(roleName); + roles = roles.Add(roleName); var command = new UpdateRole { Name = roleName, Permissions = new[] { "P1" } }; - GuardAppRoles.CanUpdate(command, App(roles_1)); + GuardAppRoles.CanUpdate(command, App); } [Fact] public void CanUpdate_should_not_throw_exception_if_role_exist_with_valid_command() { - var roles_1 = roles_0.Add(roleName); + roles = roles.Add(roleName); var command = new UpdateRole { Name = roleName, Permissions = new[] { "P1" } }; - GuardAppRoles.CanUpdate(command, App(roles_1)); - } - - private IAppEntity App(Roles roles) - { - var app = A.Fake(); - - A.CallTo(() => app.Contributors).Returns(contributors); - A.CallTo(() => app.Clients).Returns(clients); - A.CallTo(() => app.Roles).Returns(roles); - - return app; + GuardAppRoles.CanUpdate(command, App); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppTests.cs index 1aba4a3f5..e28c6155f 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppTests.cs @@ -10,7 +10,6 @@ using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Billing; -using Squidex.Domain.Apps.Entities.Teams; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Collections; @@ -19,9 +18,8 @@ using Squidex.Shared.Users; namespace Squidex.Domain.Apps.Entities.Apps.DomainObject.Guards; -public class GuardAppTests : IClassFixture +public class GuardAppTests : GivenContext, IClassFixture { - private readonly IAppProvider appProvider = A.Fake(); private readonly IUserResolver users = A.Fake(); private readonly IBillingPlans billingPlans = A.Fake(); private readonly RefToken actor = RefToken.User("42"); @@ -75,121 +73,104 @@ public class GuardAppTests : IClassFixture [Fact] public void CanChangePlan_should_throw_exception_if_plan_id_is_null() { - var command = new ChangePlan { Actor = RefToken.User("me") }; + var command = new ChangePlan { Actor = User }; - AssignedPlan? plan = null; - - ValidationAssert.Throws(() => GuardApp.CanChangePlan(command, App(plan), billingPlans), + ValidationAssert.Throws(() => GuardApp.CanChangePlan(command, App, billingPlans), new ValidationError("Plan ID is required.", "PlanId")); } [Fact] public void CanChangePlan_should_throw_exception_if_plan_not_found() { - var command = new ChangePlan { PlanId = "notfound", Actor = RefToken.User("me") }; - - AssignedPlan? plan = null; + var command = new ChangePlan { PlanId = "notfound", Actor = User }; - ValidationAssert.Throws(() => GuardApp.CanChangePlan(command, App(plan), billingPlans), + ValidationAssert.Throws(() => GuardApp.CanChangePlan(command, App, billingPlans), new ValidationError("A plan with this id does not exist.", "PlanId")); } [Fact] public void CanChangePlan_should_throw_exception_if_plan_was_configured_from_another_user() { - var command = new ChangePlan { PlanId = "basic", Actor = RefToken.User("me") }; + var command = new ChangePlan { PlanId = "basic", Actor = User }; - var plan = new AssignedPlan(RefToken.User("other"), "premium"); + A.CallTo(() => App.Plan) + .Returns(new AssignedPlan(RefToken.User("other"), "premium")); - ValidationAssert.Throws(() => GuardApp.CanChangePlan(command, App(plan), billingPlans), + ValidationAssert.Throws(() => GuardApp.CanChangePlan(command, App, billingPlans), new ValidationError("Plan can only changed from the user who configured the plan initially.")); } [Fact] public void CanChangePlan_should_throw_exception_if_assigned_to_team() { - var command = new ChangePlan { PlanId = "basic", Actor = RefToken.User("me") }; + var command = new ChangePlan { PlanId = "basic", Actor = User }; - var teamId = DomainId.NewGuid(); + A.CallTo(() => App.TeamId) + .Returns(DomainId.NewGuid()); - ValidationAssert.Throws(() => GuardApp.CanChangePlan(command, App(null, teamId), billingPlans), + ValidationAssert.Throws(() => GuardApp.CanChangePlan(command, App, billingPlans), new ValidationError("Plan is managed by the team.")); } [Fact] public void CanChangePlan_should_not_throw_exception_if_plan_is_the_same() { - var command = new ChangePlan { PlanId = "basic", Actor = RefToken.User("me") }; + var command = new ChangePlan { PlanId = "basic", Actor = User }; - var plan = new AssignedPlan(command.Actor, "basic"); + A.CallTo(() => App.Plan) + .Returns(new AssignedPlan(command.Actor, "premium")); - GuardApp.CanChangePlan(command, App(plan), billingPlans); + GuardApp.CanChangePlan(command, App, billingPlans); } [Fact] public void CanChangePlan_should_not_throw_exception_if_same_user_but_other_plan() { - var command = new ChangePlan { PlanId = "basic", Actor = RefToken.User("me") }; + var command = new ChangePlan { PlanId = "basic", Actor = User }; - var plan = new AssignedPlan(command.Actor, "premium"); + A.CallTo(() => App.Plan) + .Returns(new AssignedPlan(command.Actor, "premium")); - GuardApp.CanChangePlan(command, App(plan), billingPlans); + GuardApp.CanChangePlan(command, App, billingPlans); } [Fact] public async Task CanTransfer_should_not_throw_exception_if_team_exists() { - var team = Mocks.Team(DomainId.NewGuid(), contributor: actor.Identifier); - - A.CallTo(() => appProvider.GetTeamAsync(team.Id, default)) - .Returns(team); - - var command = new TransferToTeam { TeamId = team.Id, Actor = actor }; + var command = new TransferToTeam { TeamId = TeamId, Actor = User }; - await GuardApp.CanTransfer(command, App(null), appProvider, default); + await GuardApp.CanTransfer(command, App, AppProvider, default); } [Fact] public async Task CanTransfer_should_throw_exception_if_team_does_not_exist() { - var team = Mocks.Team(DomainId.NewGuid(), contributor: actor.Identifier); + Team = null!; - A.CallTo(() => appProvider.GetTeamAsync(team.Id, default)) - .Returns(Task.FromResult(null)); + var command = new TransferToTeam { TeamId = TeamId, Actor = actor }; - var command = new TransferToTeam { TeamId = team.Id, Actor = actor }; - - await ValidationAssert.ThrowsAsync(() => GuardApp.CanTransfer(command, App(null), appProvider, default), + await ValidationAssert.ThrowsAsync(() => GuardApp.CanTransfer(command, App, AppProvider, default), new ValidationError("The team does not exist.")); } [Fact] public async Task CanTransfer_should_throw_exception_if_actor_is_not_part_of_team() { - var team = Mocks.Team(DomainId.NewGuid()); - - A.CallTo(() => appProvider.GetTeamAsync(team.Id, default)) - .Returns(team); + var command = new TransferToTeam { TeamId = TeamId, Actor = actor }; - var command = new TransferToTeam { TeamId = team.Id, Actor = actor }; - - await ValidationAssert.ThrowsAsync(() => GuardApp.CanTransfer(command, App(null), appProvider, default), + await ValidationAssert.ThrowsAsync(() => GuardApp.CanTransfer(command, App, AppProvider, default), new ValidationError("The team does not exist.")); } [Fact] public async Task CanTransfer_should_throw_exception_if_app_has_plan() { - var team = Mocks.Team(DomainId.NewGuid(), contributor: actor.Identifier); - - A.CallTo(() => appProvider.GetTeamAsync(team.Id, default)) - .Returns(team); + var command = new TransferToTeam { TeamId = TeamId, Actor = User }; - var command = new TransferToTeam { TeamId = team.Id, Actor = actor }; + A.CallTo(() => App.Plan) + .Returns(new AssignedPlan(User, "premium")); - var plan = new AssignedPlan(RefToken.User("me"), "premium"); - - await ValidationAssert.ThrowsAsync(() => GuardApp.CanTransfer(command, App(plan), appProvider, default), + await ValidationAssert.ThrowsAsync(() => GuardApp.CanTransfer(command, App, AppProvider, default), new ValidationError("Subscription must be cancelled first before the app can be transfered.")); } @@ -312,17 +293,4 @@ public class GuardAppTests : IClassFixture GuardApp.CanUpdateSettings(command); } - - private static IAppEntity App(AssignedPlan? plan, DomainId? teamId = null) - { - var app = A.Fake(); - - A.CallTo(() => app.Plan) - .Returns(plan); - - A.CallTo(() => app.TeamId) - .Returns(teamId); - - return app; - } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppWorkflowTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppWorkflowTests.cs index 44c65aee6..b56f76d99 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppWorkflowTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/Guards/GuardAppWorkflowTests.cs @@ -15,7 +15,7 @@ using Squidex.Infrastructure.Validation; namespace Squidex.Domain.Apps.Entities.Apps.DomainObject.Guards; -public class GuardAppWorkflowTests : IClassFixture +public class GuardAppWorkflowTests : GivenContext, IClassFixture { private readonly DomainId workflowId = DomainId.NewGuid(); private readonly Workflows workflows; @@ -23,6 +23,9 @@ public class GuardAppWorkflowTests : IClassFixture public GuardAppWorkflowTests() { workflows = Workflows.Empty.Add(workflowId, "name"); + + A.CallTo(() => App.Workflows) + .Returns(workflows); } [Fact] @@ -51,7 +54,7 @@ public class GuardAppWorkflowTests : IClassFixture WorkflowId = DomainId.NewGuid() }; - Assert.Throws(() => GuardAppWorkflows.CanUpdate(command, App())); + Assert.Throws(() => GuardAppWorkflows.CanUpdate(command, App)); } [Fact] @@ -59,7 +62,7 @@ public class GuardAppWorkflowTests : IClassFixture { var command = new UpdateWorkflow { WorkflowId = workflowId }; - ValidationAssert.Throws(() => GuardAppWorkflows.CanUpdate(command, App()), + ValidationAssert.Throws(() => GuardAppWorkflows.CanUpdate(command, App), new ValidationError("Workflow is required.", "Workflow")); } @@ -77,7 +80,7 @@ public class GuardAppWorkflowTests : IClassFixture WorkflowId = workflowId }; - ValidationAssert.Throws(() => GuardAppWorkflows.CanUpdate(command, App()), + ValidationAssert.Throws(() => GuardAppWorkflows.CanUpdate(command, App), new ValidationError("Initial step is required.", "Workflow.Initial")); } @@ -95,7 +98,7 @@ public class GuardAppWorkflowTests : IClassFixture WorkflowId = workflowId }; - ValidationAssert.Throws(() => GuardAppWorkflows.CanUpdate(command, App()), + ValidationAssert.Throws(() => GuardAppWorkflows.CanUpdate(command, App), new ValidationError("Initial step cannot be published step.", "Workflow.Initial")); } @@ -113,7 +116,7 @@ public class GuardAppWorkflowTests : IClassFixture WorkflowId = workflowId }; - ValidationAssert.Throws(() => GuardAppWorkflows.CanUpdate(command, App()), + ValidationAssert.Throws(() => GuardAppWorkflows.CanUpdate(command, App), new ValidationError("Workflow must have a published step.", "Workflow.Steps")); } @@ -132,7 +135,7 @@ public class GuardAppWorkflowTests : IClassFixture WorkflowId = workflowId }; - ValidationAssert.Throws(() => GuardAppWorkflows.CanUpdate(command, App()), + ValidationAssert.Throws(() => GuardAppWorkflows.CanUpdate(command, App), new ValidationError("Step is required.", "Workflow.Steps.Published")); } @@ -156,7 +159,7 @@ public class GuardAppWorkflowTests : IClassFixture WorkflowId = workflowId }; - ValidationAssert.Throws(() => GuardAppWorkflows.CanUpdate(command, App()), + ValidationAssert.Throws(() => GuardAppWorkflows.CanUpdate(command, App), new ValidationError("Transition has an invalid target.", "Workflow.Steps.Published.Transitions.Archived")); } @@ -181,7 +184,7 @@ public class GuardAppWorkflowTests : IClassFixture WorkflowId = workflowId }; - ValidationAssert.Throws(() => GuardAppWorkflows.CanUpdate(command, App()), + ValidationAssert.Throws(() => GuardAppWorkflows.CanUpdate(command, App), new ValidationError("Transition is required.", "Workflow.Steps.Published.Transitions.Draft")); } @@ -190,7 +193,7 @@ public class GuardAppWorkflowTests : IClassFixture { var command = new UpdateWorkflow { Workflow = Workflow.Default, WorkflowId = workflowId }; - GuardAppWorkflows.CanUpdate(command, App()); + GuardAppWorkflows.CanUpdate(command, App); } [Fact] @@ -198,7 +201,7 @@ public class GuardAppWorkflowTests : IClassFixture { var command = new DeleteWorkflow { WorkflowId = DomainId.NewGuid() }; - Assert.Throws(() => GuardAppWorkflows.CanDelete(command, App())); + Assert.Throws(() => GuardAppWorkflows.CanDelete(command, App)); } [Fact] @@ -206,15 +209,6 @@ public class GuardAppWorkflowTests : IClassFixture { var command = new DeleteWorkflow { WorkflowId = workflowId }; - GuardAppWorkflows.CanDelete(command, App()); - } - - private IAppEntity App() - { - var app = A.Fake(); - - A.CallTo(() => app.Workflows).Returns(workflows); - - return app; + GuardAppWorkflows.CanDelete(command, App); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Indexes/AppsIndexTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Indexes/AppsIndexTests.cs index 342612583..6831ce0ee 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Indexes/AppsIndexTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Indexes/AppsIndexTests.cs @@ -11,6 +11,7 @@ using Squidex.Caching; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Apps.Commands; using Squidex.Domain.Apps.Entities.Apps.Repositories; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Security; @@ -21,23 +22,17 @@ using Squidex.Messaging; namespace Squidex.Domain.Apps.Entities.Apps.Indexes; -public class AppsIndexTests +public class AppsIndexTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly TestState state; private readonly IAppRepository appRepository = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly string userId = "user1"; private readonly AppsIndex sut; public AppsIndexTests() { state = new TestState("Apps"); - ct = cts.Token; - var replicatedCache = new ReplicatedCache(new MemoryCache(Options.Create(new MemoryCacheOptions())), A.Fake(), Options.Create(new ReplicatedCacheOptions { Enable = true })); @@ -48,129 +43,114 @@ public class AppsIndexTests [Fact] public async Task Should_resolve_app_by_name() { - var expected = CreateApp(); - - A.CallTo(() => appRepository.FindAsync(appId.Name, ct)) - .Returns(expected); + A.CallTo(() => appRepository.FindAsync(AppId.Name, CancellationToken)) + .Returns(App); - var actual1 = await sut.GetAppAsync(appId.Name, false, ct); - var actual2 = await sut.GetAppAsync(appId.Name, false, ct); + var actual1 = await sut.GetAppAsync(AppId.Name, false, CancellationToken); + var actual2 = await sut.GetAppAsync(AppId.Name, false, CancellationToken); - Assert.Same(expected, actual1); - Assert.Same(expected, actual2); + Assert.Same(App, actual1); + Assert.Same(App, actual2); - A.CallTo(() => appRepository.FindAsync(appId.Name, ct)) + A.CallTo(() => appRepository.FindAsync(AppId.Name, CancellationToken)) .MustHaveHappenedTwiceExactly(); } [Fact] public async Task Should_resolve_app_by_name_and_id_if_cached_before() { - var expected = CreateApp(); + A.CallTo(() => appRepository.FindAsync(AppId.Name, CancellationToken)) + .Returns(App); - A.CallTo(() => appRepository.FindAsync(appId.Name, ct)) - .Returns(expected); + var actual1 = await sut.GetAppAsync(AppId.Name, true, CancellationToken); + var actual2 = await sut.GetAppAsync(AppId.Name, true, CancellationToken); + var actual3 = await sut.GetAppAsync(AppId.Id, true, CancellationToken); - var actual1 = await sut.GetAppAsync(appId.Name, true, ct); - var actual2 = await sut.GetAppAsync(appId.Name, true, ct); - var actual3 = await sut.GetAppAsync(appId.Id, true, ct); + Assert.Same(App, actual1); + Assert.Same(App, actual2); + Assert.Same(App, actual3); - Assert.Same(expected, actual1); - Assert.Same(expected, actual2); - Assert.Same(expected, actual3); - - A.CallTo(() => appRepository.FindAsync(appId.Name, ct)) + A.CallTo(() => appRepository.FindAsync(AppId.Name, CancellationToken)) .MustHaveHappenedOnceExactly(); } [Fact] public async Task Should_resolve_app_by_id() { - var expected = CreateApp(); - - A.CallTo(() => appRepository.FindAsync(appId.Id, ct)) - .Returns(expected); + A.CallTo(() => appRepository.FindAsync(AppId.Id, CancellationToken)) + .Returns(App); - var actual1 = await sut.GetAppAsync(appId.Id, false, ct); - var actual2 = await sut.GetAppAsync(appId.Id, false, ct); + var actual1 = await sut.GetAppAsync(AppId.Id, false, CancellationToken); + var actual2 = await sut.GetAppAsync(AppId.Id, false, CancellationToken); - Assert.Same(expected, actual1); - Assert.Same(expected, actual2); + Assert.Same(App, actual1); + Assert.Same(App, actual2); - A.CallTo(() => appRepository.FindAsync(appId.Id, ct)) + A.CallTo(() => appRepository.FindAsync(AppId.Id, CancellationToken)) .MustHaveHappenedTwiceExactly(); } [Fact] public async Task Should_resolve_app_by_id_and_name_if_cached_before() { - var expected = CreateApp(); + A.CallTo(() => appRepository.FindAsync(AppId.Id, CancellationToken)) + .Returns(App); - A.CallTo(() => appRepository.FindAsync(appId.Id, ct)) - .Returns(expected); + var actual1 = await sut.GetAppAsync(AppId.Id, true, CancellationToken); + var actual2 = await sut.GetAppAsync(AppId.Id, true, CancellationToken); + var actual3 = await sut.GetAppAsync(AppId.Name, true, CancellationToken); - var actual1 = await sut.GetAppAsync(appId.Id, true, ct); - var actual2 = await sut.GetAppAsync(appId.Id, true, ct); - var actual3 = await sut.GetAppAsync(appId.Name, true, ct); + Assert.Same(App, actual1); + Assert.Same(App, actual2); + Assert.Same(App, actual3); - Assert.Same(expected, actual1); - Assert.Same(expected, actual2); - Assert.Same(expected, actual3); - - A.CallTo(() => appRepository.FindAsync(appId.Id, ct)) + A.CallTo(() => appRepository.FindAsync(AppId.Id, CancellationToken)) .MustHaveHappenedOnceExactly(); } [Fact] public async Task Should_resolve_all_apps_from_user_permissions() { - var expected = CreateApp(); - - A.CallTo(() => appRepository.QueryAllAsync(userId, A>.That.Is(appId.Name), ct)) - .Returns(new List { expected }); + A.CallTo(() => appRepository.QueryAllAsync(User.Identifier, A>.That.Is(AppId.Name), CancellationToken)) + .Returns(new List { App }); - var actual = await sut.GetAppsForUserAsync(userId, new PermissionSet($"squidex.apps.{appId.Name}"), ct); + var actual = await sut.GetAppsForUserAsync(User.Identifier, new PermissionSet($"squidex.apps.{AppId.Name}"), CancellationToken); - Assert.Same(expected, actual[0]); + Assert.Same(App, actual[0]); } [Fact] public async Task Should_resolve_all_apps_from_user() { - var expected = CreateApp(); + A.CallTo(() => appRepository.QueryAllAsync(User.Identifier, A>.That.IsEmpty(), CancellationToken)) + .Returns(new List { App }); - A.CallTo(() => appRepository.QueryAllAsync(userId, A>.That.IsEmpty(), ct)) - .Returns(new List { expected }); + var actual = await sut.GetAppsForUserAsync(User.Identifier, PermissionSet.Empty, CancellationToken); - var actual = await sut.GetAppsForUserAsync(userId, PermissionSet.Empty, ct); - - Assert.Same(expected, actual[0]); + Assert.Same(App, actual[0]); } [Fact] public async Task Should_resolve_all_apps_from_team() { - var teamId = DomainId.NewGuid(); - - var expected = CreateApp(); + A.CallTo(() => appRepository.QueryAllAsync(TeamId, CancellationToken)) + .Returns(new List { App }); - A.CallTo(() => appRepository.QueryAllAsync(teamId, ct)) - .Returns(new List { expected }); + var actual = await sut.GetAppsForTeamAsync(TeamId, CancellationToken); - var actual = await sut.GetAppsForTeamAsync(teamId, ct); - - Assert.Same(expected, actual[0]); + Assert.Same(App, actual[0]); } [Fact] public async Task Should_return_empty_apps_if_app_not_created() { - var expected = CreateApp(EtagVersion.Empty); + A.CallTo(() => App.Version) + .Returns(EtagVersion.Empty); - A.CallTo(() => appRepository.QueryAllAsync(userId, A>.That.IsEmpty(), ct)) - .Returns(new List { expected }); + A.CallTo(() => appRepository.QueryAllAsync(User.Identifier, A>.That.IsEmpty(), CancellationToken)) + .Returns(new List { App }); - var actual = await sut.GetAppsForUserAsync(userId, PermissionSet.Empty, ct); + var actual = await sut.GetAppsForUserAsync(User.Identifier, PermissionSet.Empty, CancellationToken); Assert.Empty(actual); } @@ -178,12 +158,13 @@ public class AppsIndexTests [Fact] public async Task Should_return_empty_apps_if_app_deleted() { - var expected = CreateApp(0, true); + A.CallTo(() => App.IsDeleted) + .Returns(true); - A.CallTo(() => appRepository.QueryAllAsync(userId, A>.That.IsEmpty(), ct)) - .Returns(new List { expected }); + A.CallTo(() => appRepository.QueryAllAsync(User.Identifier, A>.That.IsEmpty(), CancellationToken)) + .Returns(new List { App }); - var actual = await sut.GetAppsForUserAsync(userId, PermissionSet.Empty, ct); + var actual = await sut.GetAppsForUserAsync(User.Identifier, PermissionSet.Empty, CancellationToken); Assert.Empty(actual); } @@ -191,10 +172,10 @@ public class AppsIndexTests [Fact] public async Task Should_take_and_remove_reservation_if_created() { - A.CallTo(() => appRepository.FindAsync(appId.Name, ct)) + A.CallTo(() => appRepository.FindAsync(AppId.Name, CancellationToken)) .Returns(Task.FromResult(null)); - var command = Create(appId.Name); + var command = Create(AppId.Name); var context = new CommandContext(command, commandBus) @@ -207,21 +188,21 @@ public class AppsIndexTests madeReservation = state.Snapshot.Reservations.FirstOrDefault(); return Task.CompletedTask; - }, ct); + }, CancellationToken); Assert.Empty(state.Snapshot.Reservations); - Assert.Equal(appId.Id, madeReservation?.Id); - Assert.Equal(appId.Name, madeReservation?.Name); + Assert.Equal(AppId.Id, madeReservation?.Id); + Assert.Equal(AppId.Name, madeReservation?.Name); } [Fact] public async Task Should_clear_reservation_if_app_creation_failed() { - A.CallTo(() => appRepository.FindAsync(appId.Name, ct)) + A.CallTo(() => appRepository.FindAsync(AppId.Name, CancellationToken)) .Returns(Task.FromResult(null)); - var command = Create(appId.Name); + var command = Create(AppId.Name); var context = new CommandContext(command, commandBus) @@ -234,44 +215,44 @@ public class AppsIndexTests madeReservation = state.Snapshot.Reservations.FirstOrDefault(); throw new InvalidOperationException(); - }, ct)); + }, CancellationToken)); Assert.Empty(state.Snapshot.Reservations); - Assert.Equal(appId.Id, madeReservation?.Id); - Assert.Equal(appId.Name, madeReservation?.Name); + Assert.Equal(AppId.Id, madeReservation?.Id); + Assert.Equal(AppId.Name, madeReservation?.Name); } [Fact] public async Task Should_not_create_app_if_name_is_reserved() { - state.Snapshot.Reservations.Add(new NameReservation(RandomHash.Simple(), appId.Name, DomainId.NewGuid())); + state.Snapshot.Reservations.Add(new NameReservation(RandomHash.Simple(), AppId.Name, DomainId.NewGuid())); - A.CallTo(() => appRepository.FindAsync(appId.Name, ct)) + A.CallTo(() => appRepository.FindAsync(AppId.Name, CancellationToken)) .Returns(Task.FromResult(null)); - var command = Create(appId.Name); + var command = Create(AppId.Name); var context = new CommandContext(command, commandBus) .Complete(); - await Assert.ThrowsAsync(() => sut.HandleAsync(context, ct)); + await Assert.ThrowsAsync(() => sut.HandleAsync(context, CancellationToken)); } [Fact] public async Task Should_not_create_app_if_name_is_taken() { - A.CallTo(() => appRepository.FindAsync(appId.Name, ct)) - .Returns(CreateApp()); + A.CallTo(() => appRepository.FindAsync(AppId.Name, CancellationToken)) + .Returns(App); - var command = Create(appId.Name); + var command = Create(AppId.Name); var context = new CommandContext(command, commandBus) .Complete(); - await Assert.ThrowsAsync(() => sut.HandleAsync(context, ct)); + await Assert.ThrowsAsync(() => sut.HandleAsync(context, CancellationToken)); A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, A._)) .MustNotHaveHappened(); @@ -280,15 +261,13 @@ public class AppsIndexTests [Fact] public async Task Should_not_make_an_update_for_other_command() { - var app = CreateApp(); - - var command = new UpdateApp { AppId = appId }; + var command = new UpdateApp { AppId = AppId }; var context = new CommandContext(command, commandBus) - .Complete(app); + .Complete(App); - await sut.HandleAsync(context, ct); + await sut.HandleAsync(context, CancellationToken); A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, A._)) .MustNotHaveHappened(); @@ -296,18 +275,6 @@ public class AppsIndexTests private CreateApp Create(string name) { - return new CreateApp { AppId = appId.Id, Name = name }; - } - - private IAppEntity CreateApp(long version = 0, bool isDeleted = false) - { - var app = A.Fake(); - - A.CallTo(() => app.Id).Returns(appId.Id); - A.CallTo(() => app.Name).Returns(appId.Name); - A.CallTo(() => app.Version).Returns(version); - A.CallTo(() => app.IsDeleted).Returns(isDeleted); - - return app; + return new CreateApp { AppId = AppId.Id, Name = name }; } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Plans/RestrictAppsCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Plans/RestrictAppsCommandMiddlewareTests.cs index cb4404edd..981de8197 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Plans/RestrictAppsCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Plans/RestrictAppsCommandMiddlewareTests.cs @@ -8,6 +8,7 @@ using System.Security.Claims; using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Entities.Apps.Commands; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Validation; @@ -16,10 +17,8 @@ using Squidex.Shared.Users; namespace Squidex.Domain.Apps.Entities.Apps.Plans; -public sealed class RestrictAppsCommandMiddlewareTests +public sealed class RestrictAppsCommandMiddlewareTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IUserResolver userResolver = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); private readonly RestrictAppsOptions options = new RestrictAppsOptions(); @@ -27,8 +26,6 @@ public sealed class RestrictAppsCommandMiddlewareTests public RestrictAppsCommandMiddlewareTests() { - ct = cts.Token; - sut = new RestrictAppsCommandMiddleware(Options.Create(options), userResolver); } @@ -54,7 +51,7 @@ public sealed class RestrictAppsCommandMiddlewareTests A.CallTo(() => user.Claims) .Returns(Enumerable.Repeat(new Claim(SquidexClaimTypes.TotalApps, "5"), 1).ToList()); - A.CallTo(() => userResolver.FindByIdAsync(userId, ct)) + A.CallTo(() => userResolver.FindByIdAsync(userId, CancellationToken)) .Returns(user); var isNextCalled = false; @@ -64,7 +61,7 @@ public sealed class RestrictAppsCommandMiddlewareTests isNextCalled = true; return Task.CompletedTask; - }, ct)); + }, CancellationToken)); Assert.False(isNextCalled); } @@ -91,7 +88,7 @@ public sealed class RestrictAppsCommandMiddlewareTests A.CallTo(() => user.Claims) .Returns(Enumerable.Repeat(new Claim(SquidexClaimTypes.TotalApps, "5"), 1).ToList()); - A.CallTo(() => userResolver.FindByIdAsync(userId, ct)) + A.CallTo(() => userResolver.FindByIdAsync(userId, CancellationToken)) .Returns(user); await sut.HandleAsync(commandContext, (c, ct) => @@ -99,7 +96,7 @@ public sealed class RestrictAppsCommandMiddlewareTests c.Complete(true); return Task.CompletedTask; - }, ct); + }, CancellationToken); A.CallTo(() => userResolver.SetClaimAsync(userId, SquidexClaimTypes.TotalApps, "6", true, default)) .MustHaveHappened(); @@ -122,7 +119,7 @@ public sealed class RestrictAppsCommandMiddlewareTests c.Complete(true); return Task.CompletedTask; - }, ct); + }, CancellationToken); A.CallTo(() => userResolver.FindByIdAsync(A._, A._)) .MustNotHaveHappened(); @@ -145,7 +142,7 @@ public sealed class RestrictAppsCommandMiddlewareTests c.Complete(true); return Task.CompletedTask; - }, ct); + }, CancellationToken); A.CallTo(() => userResolver.FindByIdAsync(A._, A._)) .MustNotHaveHappened(); @@ -168,7 +165,7 @@ public sealed class RestrictAppsCommandMiddlewareTests c.Complete(true); return Task.CompletedTask; - }, ct); + }, CancellationToken); A.CallTo(() => userResolver.FindByIdAsync(A._, A._)) .MustNotHaveHappened(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/RolePermissionsProviderTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/RolePermissionsProviderTests.cs index 46e28f2a9..19ad56473 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/RolePermissionsProviderTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/RolePermissionsProviderTests.cs @@ -13,31 +13,26 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Apps; -public class RolePermissionsProviderTests +public class RolePermissionsProviderTests : GivenContext { - private readonly IAppEntity app; - private readonly IAppProvider appProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly RolePermissionsProvider sut; public RolePermissionsProviderTests() { - app = Mocks.App(appId); - - sut = new RolePermissionsProvider(appProvider); + sut = new RolePermissionsProvider(AppProvider); } [Fact] public async Task Should_provide_all_permissions() { - A.CallTo(() => appProvider.GetSchemasAsync(A._, default)) + A.CallTo(() => AppProvider.GetSchemasAsync(A._, default)) .Returns(new List { - Mocks.Schema(appId, NamedId.Of(DomainId.NewGuid(), "schema1")), - Mocks.Schema(appId, NamedId.Of(DomainId.NewGuid(), "schema2")) + Mocks.Schema(AppId, NamedId.Of(DomainId.NewGuid(), "schema1")), + Mocks.Schema(AppId, NamedId.Of(DomainId.NewGuid(), "schema2")) }); - var actual = await sut.GetPermissionsAsync(app); + var actual = await sut.GetPermissionsAsync(App); Assert.True(actual.Contains("*")); Assert.True(actual.Contains("clients.read")); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetChangedTriggerHandlerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetChangedTriggerHandlerTests.cs index 16504b2d4..b492f8cd0 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetChangedTriggerHandlerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetChangedTriggerHandlerTests.cs @@ -12,6 +12,7 @@ using Squidex.Domain.Apps.Core.Rules.Triggers; using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Assets.Repositories; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events.Assets; using Squidex.Domain.Apps.Events.Contents; @@ -20,10 +21,8 @@ using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities.Assets; -public class AssetChangedTriggerHandlerTests +public class AssetChangedTriggerHandlerTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IScriptEngine scriptEngine = A.Fake(); private readonly IAssetLoader assetLoader = A.Fake(); private readonly IAssetRepository assetRepository = A.Fake(); @@ -31,8 +30,6 @@ public class AssetChangedTriggerHandlerTests public AssetChangedTriggerHandlerTests() { - ct = cts.Token; - A.CallTo(() => scriptEngine.Evaluate(A._, "true", default)) .Returns(true); @@ -79,14 +76,14 @@ public class AssetChangedTriggerHandlerTests { var ctx = Context(); - A.CallTo(() => assetRepository.StreamAll(ctx.AppId.Id, ct)) + A.CallTo(() => assetRepository.StreamAll(ctx.AppId.Id, CancellationToken)) .Returns(new List { new AssetEntity(), new AssetEntity() }.ToAsyncEnumerable()); - var actual = await sut.CreateSnapshotEventsAsync(ctx, ct).ToListAsync(ct); + var actual = await sut.CreateSnapshotEventsAsync(ctx, CancellationToken).ToListAsync(CancellationToken); var typed = actual.OfType().ToList(); @@ -102,10 +99,10 @@ public class AssetChangedTriggerHandlerTests var envelope = Envelope.Create(@event).SetEventStreamNumber(12); - A.CallTo(() => assetLoader.GetAsync(ctx.AppId.Id, @event.AssetId, 12, ct)) + A.CallTo(() => assetLoader.GetAsync(ctx.AppId.Id, @event.AssetId, 12, CancellationToken)) .Returns(new AssetEntity()); - var actual = await sut.CreateEnrichedEventsAsync(envelope, ctx, ct).ToListAsync(ct); + var actual = await sut.CreateEnrichedEventsAsync(envelope, ctx, CancellationToken).ToListAsync(CancellationToken); var enrichedEvent = (EnrichedAssetEvent)actual.Single(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetPermanentDeleterTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetPermanentDeleterTests.cs index abc3bada8..bb9ae8054 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetPermanentDeleterTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetPermanentDeleterTests.cs @@ -7,16 +7,16 @@ using Squidex.Assets; using Squidex.Domain.Apps.Core.TestHelpers; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events.Assets; using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities.Assets; -public class AssetPermanentDeleterTests +public class AssetPermanentDeleterTests : GivenContext { private readonly IAssetFileStore assetFiletore = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly AssetPermanentDeleter sut; public AssetPermanentDeleterTests() @@ -75,31 +75,31 @@ public class AssetPermanentDeleterTests [Fact] public async Task Should_not_delete_assets_if_event_restored() { - var @event = new AssetDeleted { AppId = appId, AssetId = DomainId.NewGuid() }; + var @event = new AssetDeleted { AppId = AppId, AssetId = DomainId.NewGuid() }; await sut.On(Envelope.Create(@event).SetRestored()); - A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, A._)) + A.CallTo(() => assetFiletore.DeleteAsync(AppId.Id, @event.AssetId, A._)) .MustNotHaveHappened(); } [Fact] public async Task Should_delete_asset() { - var @event = new AssetDeleted { AppId = appId, AssetId = DomainId.NewGuid() }; + var @event = new AssetDeleted { AppId = AppId, AssetId = DomainId.NewGuid() }; await sut.On(Envelope.Create(@event)); - A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, A._)) + A.CallTo(() => assetFiletore.DeleteAsync(AppId.Id, @event.AssetId, A._)) .MustHaveHappened(); } [Fact] public async Task Should_ignore_not_found_assets() { - var @event = new AssetDeleted { AppId = appId, AssetId = DomainId.NewGuid() }; + var @event = new AssetDeleted { AppId = AppId, AssetId = DomainId.NewGuid() }; - A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, default)) + A.CallTo(() => assetFiletore.DeleteAsync(AppId.Id, @event.AssetId, default)) .Throws(new AssetNotFoundException("fileName")); await sut.On(Envelope.Create(@event)); @@ -108,9 +108,9 @@ public class AssetPermanentDeleterTests [Fact] public async Task Should_not_ignore_exceptions() { - var @event = new AssetDeleted { AppId = appId, AssetId = DomainId.NewGuid() }; + var @event = new AssetDeleted { AppId = AppId, AssetId = DomainId.NewGuid() }; - A.CallTo(() => assetFiletore.DeleteAsync(appId.Id, @event.AssetId, default)) + A.CallTo(() => assetFiletore.DeleteAsync(AppId.Id, @event.AssetId, default)) .Throws(new InvalidOperationException()); await Assert.ThrowsAsync(() => sut.On(Envelope.Create(@event))); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetTagsDeleterTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetTagsDeleterTests.cs index 8ec199b0e..463fd834e 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetTagsDeleterTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetTagsDeleterTests.cs @@ -7,21 +7,16 @@ using Squidex.Domain.Apps.Core.Tags; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Assets; -public class AssetTagsDeleterTests +public class AssetTagsDeleterTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly ITagService tagService = A.Fake(); private readonly AssetTagsDeleter sut; public AssetTagsDeleterTests() { - ct = cts.Token; - sut = new AssetTagsDeleter(tagService); } @@ -36,11 +31,9 @@ public class AssetTagsDeleterTests [Fact] public async Task Should_remove_events_from_streams() { - var app = Mocks.App(NamedId.Of(DomainId.NewGuid(), "my-app")); - - await sut.DeleteAppAsync(app, ct); + await sut.DeleteAppAsync(App, CancellationToken); - A.CallTo(() => tagService.ClearAsync(app.Id, TagGroups.Assets, ct)) + A.CallTo(() => tagService.ClearAsync(AppId.Id, TagGroups.Assets, CancellationToken)) .MustHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetUsageTrackerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetUsageTrackerTests.cs index f0c6bc312..9bde2831d 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetUsageTrackerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetUsageTrackerTests.cs @@ -8,6 +8,7 @@ using NodaTime; using Squidex.Domain.Apps.Core.Tags; using Squidex.Domain.Apps.Entities.Billing; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events.Assets; using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; @@ -15,20 +16,19 @@ using Squidex.Infrastructure.States; namespace Squidex.Domain.Apps.Entities.Assets; -public class AssetUsageTrackerTests +public class AssetUsageTrackerTests : GivenContext { private readonly IAssetLoader assetLoader = A.Fake(); private readonly ISnapshotStore store = A.Fake>(); private readonly ITagService tagService = A.Fake(); private readonly IUsageGate usageGate = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly DomainId assetId = DomainId.NewGuid(); private readonly DomainId assetKey; private readonly AssetUsageTracker sut; public AssetUsageTrackerTests() { - assetKey = DomainId.Combine(appId, assetId); + assetKey = DomainId.Combine(AppId, assetId); sut = new AssetUsageTracker(usageGate, assetLoader, tagService, store); } @@ -81,7 +81,7 @@ public class AssetUsageTrackerTests { var date = DateTime.UtcNow.Date.AddDays(13); - @event.AppId = appId; + @event.AppId = AppId; var envelope = Envelope.Create(@event) @@ -89,7 +89,7 @@ public class AssetUsageTrackerTests await sut.On(new[] { envelope }); - A.CallTo(() => usageGate.TrackAssetAsync(appId.Id, date, sizeDiff, countDiff, default)) + A.CallTo(() => usageGate.TrackAssetAsync(AppId.Id, date, sizeDiff, countDiff, default)) .MustHaveHappened(); } @@ -98,7 +98,7 @@ public class AssetUsageTrackerTests { var @event = new AssetCreated { - AppId = appId, + AppId = AppId, Tags = new HashSet { "tag1", @@ -113,7 +113,7 @@ public class AssetUsageTrackerTests Dictionary? update = null; - A.CallTo(() => tagService.UpdateAsync(appId.Id, TagGroups.Assets, A>._, default)) + A.CallTo(() => tagService.UpdateAsync(AppId.Id, TagGroups.Assets, A>._, default)) .Invokes(x => { update = x.GetArgument>(2); }); await sut.On(new[] { envelope }); @@ -130,7 +130,7 @@ public class AssetUsageTrackerTests { var @event1 = new AssetCreated { - AppId = appId, + AppId = AppId, Tags = new HashSet { "tag1", @@ -141,7 +141,7 @@ public class AssetUsageTrackerTests var @event2 = new AssetCreated { - AppId = appId, + AppId = AppId, Tags = new HashSet { "tag2", @@ -160,7 +160,7 @@ public class AssetUsageTrackerTests Dictionary? update = null; - A.CallTo(() => tagService.UpdateAsync(appId.Id, TagGroups.Assets, A>._, default)) + A.CallTo(() => tagService.UpdateAsync(AppId.Id, TagGroups.Assets, A>._, default)) .Invokes(x => { update = x.GetArgument>(2); }); await sut.On(new[] { envelope1, envelope2 }); @@ -181,7 +181,7 @@ public class AssetUsageTrackerTests { var @event1 = new AssetCreated { - AppId = appId, + AppId = AppId, Tags = new HashSet { "tag1", @@ -192,7 +192,7 @@ public class AssetUsageTrackerTests var @event2 = new AssetAnnotated { - AppId = appId, + AppId = AppId, Tags = new HashSet { "tag2", @@ -211,7 +211,7 @@ public class AssetUsageTrackerTests Dictionary? update = null; - A.CallTo(() => tagService.UpdateAsync(appId.Id, TagGroups.Assets, A>._, default)) + A.CallTo(() => tagService.UpdateAsync(AppId.Id, TagGroups.Assets, A>._, default)) .Invokes(x => { update = x.GetArgument>(2); }); await sut.On(new[] { envelope1, envelope2 }); @@ -229,7 +229,7 @@ public class AssetUsageTrackerTests { var @event1 = new AssetCreated { - AppId = appId, + AppId = AppId, Tags = new HashSet { "tag1", @@ -240,7 +240,7 @@ public class AssetUsageTrackerTests var @event2 = new AssetAnnotated { - AppId = appId, + AppId = AppId, Tags = new HashSet { "tag2", @@ -259,7 +259,7 @@ public class AssetUsageTrackerTests Dictionary? update = null; - A.CallTo(() => tagService.UpdateAsync(appId.Id, TagGroups.Assets, A>._, default)) + A.CallTo(() => tagService.UpdateAsync(AppId.Id, TagGroups.Assets, A>._, default)) .Invokes(x => { update = x.GetArgument>(2); }); await sut.On(new[] { envelope1 }); @@ -278,7 +278,7 @@ public class AssetUsageTrackerTests { var @event1 = new AssetCreated { - AppId = appId, + AppId = AppId, Tags = new HashSet { "tag1", @@ -287,7 +287,7 @@ public class AssetUsageTrackerTests AssetId = assetId }; - var @event2 = new AssetDeleted { AppId = appId, AssetId = assetId }; + var @event2 = new AssetDeleted { AppId = AppId, AssetId = assetId }; var envelope1 = Envelope.Create(@event1) @@ -299,7 +299,7 @@ public class AssetUsageTrackerTests Dictionary? update = null; - A.CallTo(() => tagService.UpdateAsync(appId.Id, TagGroups.Assets, A>._, default)) + A.CallTo(() => tagService.UpdateAsync(AppId.Id, TagGroups.Assets, A>._, default)) .Invokes(x => { update = x.GetArgument>(2); }); await sut.On(new[] { Envelope.Create(@event1), Envelope.Create(@event2) }); @@ -326,7 +326,7 @@ public class AssetUsageTrackerTests A.CallTo(() => store.ReadAsync(assetKey, default)) .Returns(new SnapshotResult(assetKey, state, 0)); - var @event = new AssetDeleted { AppId = appId, AssetId = assetId }; + var @event = new AssetDeleted { AppId = AppId, AssetId = assetId }; var envelope = Envelope.Create(@event) @@ -334,7 +334,7 @@ public class AssetUsageTrackerTests Dictionary? update = null; - A.CallTo(() => tagService.UpdateAsync(appId.Id, TagGroups.Assets, A>._, default)) + A.CallTo(() => tagService.UpdateAsync(AppId.Id, TagGroups.Assets, A>._, default)) .Invokes(x => { update = x.GetArgument>(2); }); await sut.On(new[] { envelope }); @@ -358,10 +358,10 @@ public class AssetUsageTrackerTests } }; - A.CallTo(() => assetLoader.GetAsync(appId.Id, assetId, 41, default)) + A.CallTo(() => assetLoader.GetAsync(AppId.Id, assetId, 41, default)) .Returns(asset); - var @event = new AssetDeleted { AppId = appId, AssetId = assetId }; + var @event = new AssetDeleted { AppId = AppId, AssetId = assetId }; var envelope = Envelope.Create(@event) @@ -370,7 +370,7 @@ public class AssetUsageTrackerTests Dictionary? update = null; - A.CallTo(() => tagService.UpdateAsync(appId.Id, TagGroups.Assets, A>._, default)) + A.CallTo(() => tagService.UpdateAsync(AppId.Id, TagGroups.Assets, A>._, default)) .Invokes(x => { update = x.GetArgument>(2); }); await sut.On(new[] { envelope }); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsFluidExtensionTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsFluidExtensionTests.cs index c5a08b725..e065c1a91 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsFluidExtensionTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsFluidExtensionTests.cs @@ -19,20 +19,18 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Entities.Assets; -public class AssetsFluidExtensionTests +public class AssetsFluidExtensionTests : GivenContext { - private readonly IAppProvider appProvider = A.Fake(); private readonly IAssetFileStore assetFileStore = A.Fake(); private readonly IAssetQueryService assetQuery = A.Fake(); private readonly IAssetThumbnailGenerator assetThumbnailGenerator = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly FluidTemplateEngine sut; public AssetsFluidExtensionTests() { var serviceProvider = new ServiceCollection() - .AddSingleton(appProvider) + .AddSingleton(AppProvider) .AddSingleton(assetFileStore) .AddSingleton(assetQuery) .AddSingleton(assetThumbnailGenerator) @@ -44,9 +42,6 @@ public class AssetsFluidExtensionTests new AssetsFluidExtension(serviceProvider) }; - A.CallTo(() => appProvider.GetAppAsync(appId.Id, false, default)) - .Returns(Mocks.App(appId)); - sut = new FluidTemplateEngine(extensions); } @@ -179,7 +174,7 @@ public class AssetsFluidExtensionTests Id = DomainId.NewGuid(), FileVersion = 0, FileSize = 100, - AppId = appId + AppId = AppId }; SetupText(@event.ToRef(), Encode(encoding, "hello+assets")); @@ -276,7 +271,7 @@ public class AssetsFluidExtensionTests AssetType = AssetType.Image, FileVersion = 0, FileSize = 100, - AppId = appId + AppId = AppId }; SetupBlurHash(@event.ToRef(), "Hash"); @@ -307,7 +302,7 @@ public class AssetsFluidExtensionTests private void SetupText(AssetRef asset, byte[] bytes) { - A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, asset.Id, asset.FileVersion, null, A._, A._, A._)) + A.CallTo(() => assetFileStore.DownloadAsync(AppId.Id, asset.Id, asset.FileVersion, null, A._, A._, A._)) .Invokes(x => x.GetArgument(4)?.Write(bytes)); } @@ -323,7 +318,7 @@ public class AssetsFluidExtensionTests .AddField("assets", new ContentFieldData() .AddInvariant(JsonValue.Array(assetId))), - AppId = appId + AppId = AppId }; A.CallTo(() => assetQuery.FindAsync(A._, assetId, EtagVersion.Any, A._)) @@ -351,7 +346,7 @@ public class AssetsFluidExtensionTests .AddField("assets", new ContentFieldData() .AddInvariant(JsonValue.Array(assetId1, assetId2))), - AppId = appId + AppId = AppId }; A.CallTo(() => assetQuery.FindAsync(A._, assetId1, EtagVersion.Any, A._)) @@ -372,7 +367,7 @@ public class AssetsFluidExtensionTests { return new AssetEntity { - AppId = appId, + AppId = AppId, Id = assetId, FileSize = fileSize, FileName = $"file{index}.jpg", diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsJintExtensionTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsJintExtensionTests.cs index b5c26edfc..19fa33947 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsJintExtensionTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsJintExtensionTests.cs @@ -22,20 +22,18 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Entities.Assets; -public class AssetsJintExtensionTests : IClassFixture +public class AssetsJintExtensionTests : GivenContext, IClassFixture { - private readonly IAppProvider appProvider = A.Fake(); private readonly IAssetFileStore assetFileStore = A.Fake(); private readonly IAssetQueryService assetQuery = A.Fake(); private readonly IAssetThumbnailGenerator assetThumbnailGenerator = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly JintScriptEngine sut; public AssetsJintExtensionTests() { var serviceProvider = new ServiceCollection() - .AddSingleton(appProvider) + .AddSingleton(AppProvider) .AddSingleton(assetFileStore) .AddSingleton(assetQuery) .AddSingleton(assetThumbnailGenerator) @@ -46,9 +44,6 @@ public class AssetsJintExtensionTests : IClassFixture new AssetsJintExtension(serviceProvider) }; - A.CallTo(() => appProvider.GetAppAsync(appId.Id, false, A._)) - .Returns(Mocks.App(appId)); - sut = new JintScriptEngine(new MemoryCache(Options.Create(new MemoryCacheOptions())), Options.Create(new JintScriptOptions { @@ -97,7 +92,7 @@ public class AssetsJintExtensionTests : IClassFixture complete(`${actual1}`); });"; - var actual = (await sut.ExecuteAsync(vars, script)).ToString(); + var actual = (await sut.ExecuteAsync(vars, script, ct: CancellationToken)).ToString(); Assert.Equal(Cleanup(expected), Cleanup(actual)); } @@ -120,7 +115,7 @@ public class AssetsJintExtensionTests : IClassFixture complete(`${actual1}\n${actual2}`); });"; - var actual = (await sut.ExecuteAsync(vars, script)).ToString(); + var actual = (await sut.ExecuteAsync(vars, script, ct: CancellationToken)).ToString(); Assert.Equal(Cleanup(expected), Cleanup(actual)); } @@ -146,7 +141,7 @@ public class AssetsJintExtensionTests : IClassFixture }}, '{encoding}'); }});"; - var actual = (await sut.ExecuteAsync(vars, script)).ToString(); + var actual = (await sut.ExecuteAsync(vars, script, ct: CancellationToken)).ToString(); Assert.Equal(Cleanup(expected), Cleanup(actual)); } @@ -169,7 +164,7 @@ public class AssetsJintExtensionTests : IClassFixture }); });"; - var actual = (await sut.ExecuteAsync(vars, script)).ToString(); + var actual = (await sut.ExecuteAsync(vars, script, ct: CancellationToken)).ToString(); Assert.Equal(Cleanup(expected), Cleanup(actual)); @@ -186,7 +181,7 @@ public class AssetsJintExtensionTests : IClassFixture Id = DomainId.NewGuid(), FileVersion = 0, FileSize = 100, - AppId = appId + AppId = AppId }; SetupText(@event.ToRef(), Encode(encoding, "hello+assets")); @@ -207,7 +202,7 @@ public class AssetsJintExtensionTests : IClassFixture complete(actual); }}, '{encoding}');"; - var actual = (await sut.ExecuteAsync(vars, script)).ToString(); + var actual = (await sut.ExecuteAsync(vars, script, ct: CancellationToken)).ToString(); Assert.Equal(Cleanup(expected), Cleanup(actual)); } @@ -232,7 +227,7 @@ public class AssetsJintExtensionTests : IClassFixture }); });"; - var actual = (await sut.ExecuteAsync(vars, script)).ToString(); + var actual = (await sut.ExecuteAsync(vars, script, ct: CancellationToken)).ToString(); Assert.Equal(Cleanup(expected), Cleanup(actual)); } @@ -257,7 +252,7 @@ public class AssetsJintExtensionTests : IClassFixture }); });"; - var actual = (await sut.ExecuteAsync(vars, script)).ToString(); + var actual = (await sut.ExecuteAsync(vars, script, ct: CancellationToken)).ToString(); Assert.Equal(Cleanup(expected), Cleanup(actual)); } @@ -282,7 +277,7 @@ public class AssetsJintExtensionTests : IClassFixture }); });"; - var actual = (await sut.ExecuteAsync(vars, script)).ToString(); + var actual = (await sut.ExecuteAsync(vars, script, ct: CancellationToken)).ToString(); Assert.Equal(Cleanup(expected), Cleanup(actual)); } @@ -296,7 +291,7 @@ public class AssetsJintExtensionTests : IClassFixture AssetType = AssetType.Image, FileVersion = 0, FileSize = 100, - AppId = appId + AppId = AppId }; SetupBlurHash(@event.ToRef(), "Hash"); @@ -317,7 +312,7 @@ public class AssetsJintExtensionTests : IClassFixture complete(actual); });"; - var actual = (await sut.ExecuteAsync(vars, script)).ToString(); + var actual = (await sut.ExecuteAsync(vars, script, ct: CancellationToken)).ToString(); Assert.Equal(Cleanup(expected), Cleanup(actual)); } @@ -330,7 +325,7 @@ public class AssetsJintExtensionTests : IClassFixture private void SetupText(AssetRef asset, byte[] bytes) { - A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, asset.Id, asset.FileVersion, null, A._, A._, A._)) + A.CallTo(() => assetFileStore.DownloadAsync(AppId.Id, asset.Id, asset.FileVersion, null, A._, A._, A._)) .Invokes(x => x.GetArgument(4)?.Write(bytes)); } @@ -348,14 +343,14 @@ public class AssetsJintExtensionTests : IClassFixture .AddInvariant(JsonValue.Array(assetIds))); A.CallTo(() => assetQuery.QueryAsync( - A.That.Matches(x => x.App.Id == appId.Id && x.UserPrincipal == user), null, A.That.HasIds(assetIds), A._)) + A.That.Matches(x => x.App == App && x.UserPrincipal == user), null, A.That.HasIds(assetIds), A._)) .Returns(ResultList.CreateFrom(2, assets)); var vars = new ScriptVars { ["data"] = data, - ["appId"] = appId.Id, - ["appName"] = appId.Name, + ["appId"] = AppId.Id, + ["appName"] = AppId.Name, ["user"] = user }; @@ -366,7 +361,7 @@ public class AssetsJintExtensionTests : IClassFixture { return new AssetEntity { - AppId = appId, + AppId = AppId, Id = DomainId.NewGuid(), FileSize = fileSize, FileName = $"file{index}.jpg", diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsSearchSourceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsSearchSourceTests.cs index d9b926e7f..cd2518899 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsSearchSourceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/AssetsSearchSourceTests.cs @@ -5,21 +5,18 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Security.Claims; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Entities.Search; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Shared; -using Squidex.Shared.Identity; namespace Squidex.Domain.Apps.Entities.Assets; -public class AssetsSearchSourceTests +public class AssetsSearchSourceTests : GivenContext { private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly IAssetQueryService assetQuery = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly AssetsSearchSource sut; public AssetsSearchSourceTests() @@ -30,9 +27,7 @@ public class AssetsSearchSourceTests [Fact] public async Task Should_return_empty_actuals_if_user_has_no_permission() { - var ctx = ContextWithPermission(); - - var actual = await sut.SearchAsync("logo", ctx, default); + var actual = await sut.SearchAsync("logo", ApiContext, default); Assert.Empty(actual); @@ -43,23 +38,23 @@ public class AssetsSearchSourceTests [Fact] public async Task Should_return_assets_actuals_if_found() { - var permission = PermissionIds.ForApp(PermissionIds.AppAssetsRead, appId.Name); + var permission = PermissionIds.ForApp(PermissionIds.AppAssetsRead, AppId.Name); - var ctx = ContextWithPermission(permission.Id); + var requestContext = CreateContext(false, permission.Id); var asset1 = CreateAsset("logo1.png"); var asset2 = CreateAsset("logo2.png"); - A.CallTo(() => urlGenerator.AssetsUI(appId, asset1.Id.ToString())) + A.CallTo(() => urlGenerator.AssetsUI(AppId, asset1.Id.ToString())) .Returns("assets-url1"); - A.CallTo(() => urlGenerator.AssetsUI(appId, asset2.Id.ToString())) + A.CallTo(() => urlGenerator.AssetsUI(AppId, asset2.Id.ToString())) .Returns("assets-url2"); - A.CallTo(() => assetQuery.QueryAsync(ctx, null, A.That.HasQuery("Filter: contains(fileName, 'logo'); Take: 5"), A._)) + A.CallTo(() => assetQuery.QueryAsync(requestContext, null, A.That.HasQuery("Filter: contains(fileName, 'logo'); Take: 5"), A._)) .Returns(ResultList.CreateFrom(2, asset1, asset2)); - var actual = await sut.SearchAsync("logo", ctx, default); + var actual = await sut.SearchAsync("logo", requestContext, default); actual.Should().BeEquivalentTo( new SearchResults() @@ -71,17 +66,4 @@ public class AssetsSearchSourceTests { return new AssetEntity { FileName = fileName, Id = DomainId.NewGuid() }; } - - private Context ContextWithPermission(string? permission = null) - { - var claimsIdentity = new ClaimsIdentity(); - var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); - - if (permission != null) - { - claimsIdentity.AddClaim(new Claim(SquidexClaimTypes.Permissions, permission)); - } - - return new Context(claimsPrincipal, Mocks.App(appId)); - } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/BackupAssetsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/BackupAssetsTests.cs index 61959e3b5..d1e0546bd 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/BackupAssetsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/BackupAssetsTests.cs @@ -9,6 +9,7 @@ using Squidex.Assets; using Squidex.Domain.Apps.Core.Tags; using Squidex.Domain.Apps.Entities.Assets.DomainObject; using Squidex.Domain.Apps.Entities.Backup; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events.Apps; using Squidex.Domain.Apps.Events.Assets; using Squidex.Infrastructure; @@ -17,21 +18,16 @@ using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities.Assets; -public class BackupAssetsTests +public class BackupAssetsTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly Rebuilder rebuilder = A.Fake(); private readonly IAssetFileStore assetFileStore = A.Fake(); private readonly ITagService tagService = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly RefToken actor = RefToken.User("123"); private readonly BackupAssets sut; public BackupAssetsTests() { - ct = cts.Token; - sut = new BackupAssets(rebuilder, assetFileStore, tagService); } @@ -51,12 +47,12 @@ public class BackupAssetsTests var context = CreateBackupContext(); - A.CallTo(() => tagService.GetExportableTagsAsync(context.AppId, TagGroups.Assets, ct)) + A.CallTo(() => tagService.GetExportableTagsAsync(context.AppId, TagGroups.Assets, CancellationToken)) .Returns(tags); - await sut.BackupAsync(context, ct); + await sut.BackupAsync(context, CancellationToken); - A.CallTo(() => context.Writer.WriteJsonAsync(A._, tags.Tags, ct)) + A.CallTo(() => context.Writer.WriteJsonAsync(A._, tags.Tags, CancellationToken)) .MustHaveHappened(); A.CallTo(() => context.Writer.WriteJsonAsync(A._, tags.Alias!, A._)) @@ -77,15 +73,15 @@ public class BackupAssetsTests var context = CreateBackupContext(); - A.CallTo(() => tagService.GetExportableTagsAsync(context.AppId, TagGroups.Assets, ct)) + A.CallTo(() => tagService.GetExportableTagsAsync(context.AppId, TagGroups.Assets, CancellationToken)) .Returns(tags); - await sut.BackupAsync(context, ct); + await sut.BackupAsync(context, CancellationToken); - A.CallTo(() => context.Writer.WriteJsonAsync(A._, tags.Tags, ct)) + A.CallTo(() => context.Writer.WriteJsonAsync(A._, tags.Tags, CancellationToken)) .MustHaveHappened(); - A.CallTo(() => context.Writer.WriteJsonAsync(A._, tags.Alias, ct)) + A.CallTo(() => context.Writer.WriteJsonAsync(A._, tags.Alias, CancellationToken)) .MustHaveHappened(); } @@ -99,18 +95,18 @@ public class BackupAssetsTests var envelope = new Envelope(new AppCreated { - AppId = appId + AppId = AppId }); - A.CallTo(() => context.Reader.HasFileAsync(A._, ct)) + A.CallTo(() => context.Reader.HasFileAsync(A._, CancellationToken)) .Returns(true); - A.CallTo(() => context.Reader.ReadJsonAsync>(A._, ct)) + A.CallTo(() => context.Reader.ReadJsonAsync>(A._, CancellationToken)) .Returns(tags); - await sut.RestoreEventAsync(envelope, context, ct); + await sut.RestoreEventAsync(envelope, context, CancellationToken); - A.CallTo(() => tagService.RebuildTagsAsync(appId.Id, TagGroups.Assets, A.That.Matches(x => x.Tags == tags), ct)) + A.CallTo(() => tagService.RebuildTagsAsync(AppId.Id, TagGroups.Assets, A.That.Matches(x => x.Tags == tags), CancellationToken)) .MustHaveHappened(); } @@ -124,18 +120,18 @@ public class BackupAssetsTests var envelope = new Envelope(new AppCreated { - AppId = appId + AppId = AppId }); - A.CallTo(() => context.Reader.HasFileAsync(A._, ct)) + A.CallTo(() => context.Reader.HasFileAsync(A._, CancellationToken)) .Returns(false).Once().Then.Returns(true); - A.CallTo(() => context.Reader.ReadJsonAsync>(A._, ct)) + A.CallTo(() => context.Reader.ReadJsonAsync>(A._, CancellationToken)) .Returns(alias); - await sut.RestoreEventAsync(envelope, context, ct); + await sut.RestoreEventAsync(envelope, context, CancellationToken); - A.CallTo(() => tagService.RebuildTagsAsync(appId.Id, TagGroups.Assets, A.That.Matches(x => x.Alias == alias), ct)) + A.CallTo(() => tagService.RebuildTagsAsync(AppId.Id, TagGroups.Assets, A.That.Matches(x => x.Alias == alias), CancellationToken)) .MustHaveHappened(); } @@ -149,16 +145,16 @@ public class BackupAssetsTests var envelope = new Envelope(new AppCreated { - AppId = appId + AppId = AppId }); - A.CallTo(() => context.Reader.HasFileAsync(A._, ct)) + A.CallTo(() => context.Reader.HasFileAsync(A._, CancellationToken)) .Returns(false); - A.CallTo(() => context.Reader.ReadJsonAsync>(A._, ct)) + A.CallTo(() => context.Reader.ReadJsonAsync>(A._, CancellationToken)) .Returns(alias); - await sut.RestoreEventAsync(envelope, context, ct); + await sut.RestoreEventAsync(envelope, context, CancellationToken); A.CallTo(() => context.Reader.ReadJsonAsync>(A._, A._)) .MustNotHaveHappened(); @@ -166,7 +162,7 @@ public class BackupAssetsTests A.CallTo(() => context.Reader.ReadJsonAsync>(A._, A._)) .MustNotHaveHappened(); - A.CallTo(() => tagService.RebuildTagsAsync(appId.Id, TagGroups.Assets, A.That.Matches(x => x.Alias == alias), A._)) + A.CallTo(() => tagService.RebuildTagsAsync(AppId.Id, TagGroups.Assets, A.That.Matches(x => x.Alias == alias), A._)) .MustNotHaveHappened(); } @@ -209,12 +205,12 @@ public class BackupAssetsTests var context = CreateBackupContext(); - A.CallTo(() => context.Writer.OpenBlobAsync($"{assetId}_{version}.asset", ct)) + A.CallTo(() => context.Writer.OpenBlobAsync($"{assetId}_{version}.asset", CancellationToken)) .Returns(assetStream); - await sut.BackupEventAsync(AppEvent(@event), context, ct); + await sut.BackupEventAsync(AppEvent(@event), context, CancellationToken); - A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, assetId, version, null, assetStream, default, ct)) + A.CallTo(() => assetFileStore.DownloadAsync(AppId.Id, assetId, version, null, assetStream, default, CancellationToken)) .MustHaveHappened(); } @@ -225,13 +221,13 @@ public class BackupAssetsTests var context = CreateBackupContext(); - A.CallTo(() => context.Writer.OpenBlobAsync($"{assetId}_{version}.asset", ct)) + A.CallTo(() => context.Writer.OpenBlobAsync($"{assetId}_{version}.asset", CancellationToken)) .Returns(assetStream); - A.CallTo(() => assetFileStore.DownloadAsync(appId.Id, assetId, version, null, assetStream, default, ct)) + A.CallTo(() => assetFileStore.DownloadAsync(AppId.Id, assetId, version, null, assetStream, default, CancellationToken)) .Throws(new AssetNotFoundException(assetId.ToString())); - await sut.BackupEventAsync(AppEvent(@event), context, ct); + await sut.BackupEventAsync(AppEvent(@event), context, CancellationToken); } [Fact] @@ -253,7 +249,7 @@ public class BackupAssetsTests [Fact] public async Task Should_restore_updated_asset() { - var @event = new AssetUpdated { AppId = appId, AssetId = DomainId.NewGuid(), FileVersion = 3 }; + var @event = new AssetUpdated { AppId = AppId, AssetId = DomainId.NewGuid(), FileVersion = 3 }; await TestRestoreAsync(@event, @event.FileVersion); } @@ -261,7 +257,7 @@ public class BackupAssetsTests [Fact] public async Task Should_restore_updated_asset_with_missing_file() { - var @event = new AssetUpdated { AppId = appId, AssetId = DomainId.NewGuid(), FileVersion = 3 }; + var @event = new AssetUpdated { AppId = AppId, AssetId = DomainId.NewGuid(), FileVersion = 3 }; await TestRestoreFailedAsync(@event, @event.FileVersion); } @@ -273,12 +269,12 @@ public class BackupAssetsTests var context = CreateRestoreContext(); - A.CallTo(() => context.Reader.OpenBlobAsync($"{assetId}_{version}.asset", ct)) + A.CallTo(() => context.Reader.OpenBlobAsync($"{assetId}_{version}.asset", CancellationToken)) .Returns(assetStream); - await sut.RestoreEventAsync(AppEvent(@event), context, ct); + await sut.RestoreEventAsync(AppEvent(@event), context, CancellationToken); - A.CallTo(() => assetFileStore.UploadAsync(appId.Id, assetId, version, null, assetStream, true, ct)) + A.CallTo(() => assetFileStore.UploadAsync(AppId.Id, assetId, version, null, assetStream, true, CancellationToken)) .MustHaveHappened(); } @@ -289,12 +285,12 @@ public class BackupAssetsTests var context = CreateRestoreContext(); - A.CallTo(() => context.Reader.OpenBlobAsync($"{assetId}_{version}.asset", ct)) + A.CallTo(() => context.Reader.OpenBlobAsync($"{assetId}_{version}.asset", CancellationToken)) .Throws(new FileNotFoundException()); - await sut.RestoreEventAsync(AppEvent(@event), context, ct); + await sut.RestoreEventAsync(AppEvent(@event), context, CancellationToken); - A.CallTo(() => assetFileStore.UploadAsync(appId.Id, assetId, version, null, assetStream, true, A._)) + A.CallTo(() => assetFileStore.UploadAsync(AppId.Id, assetId, version, null, assetStream, true, A._)) .MustNotHaveHappened(); } @@ -309,29 +305,29 @@ public class BackupAssetsTests await sut.RestoreEventAsync(AppEvent(new AssetCreated { AssetId = assetId1 - }), context, ct); + }), context, CancellationToken); await sut.RestoreEventAsync(AppEvent(new AssetCreated { AssetId = assetId2 - }), context, ct); + }), context, CancellationToken); await sut.RestoreEventAsync(AppEvent(new AssetDeleted { AssetId = assetId2 - }), context, ct); + }), context, CancellationToken); var rebuildAssets = new HashSet(); - A.CallTo(() => rebuilder.InsertManyAsync(A>._, A._, ct)) + A.CallTo(() => rebuilder.InsertManyAsync(A>._, A._, CancellationToken)) .Invokes(x => rebuildAssets.AddRange(x.GetArgument>(0)!)); - await sut.RestoreAsync(context, ct); + await sut.RestoreAsync(context, CancellationToken); Assert.Equal(new HashSet { - DomainId.Combine(appId, assetId1), - DomainId.Combine(appId, assetId2) + DomainId.Combine(AppId, assetId1), + DomainId.Combine(AppId, assetId2) }, rebuildAssets); } @@ -346,54 +342,54 @@ public class BackupAssetsTests await sut.RestoreEventAsync(AppEvent(new AssetFolderCreated { AssetFolderId = assetFolderId1 - }), context, ct); + }), context, CancellationToken); await sut.RestoreEventAsync(AppEvent(new AssetFolderCreated { AssetFolderId = assetFolderId2 - }), context, ct); + }), context, CancellationToken); await sut.RestoreEventAsync(AppEvent(new AssetFolderDeleted { AssetFolderId = assetFolderId2 - }), context, ct); + }), context, CancellationToken); var rebuildAssetFolders = new HashSet(); - A.CallTo(() => rebuilder.InsertManyAsync(A>._, A._, ct)) + A.CallTo(() => rebuilder.InsertManyAsync(A>._, A._, CancellationToken)) .Invokes(x => rebuildAssetFolders.AddRange(x.GetArgument>(0)!)); - await sut.RestoreAsync(context, ct); + await sut.RestoreAsync(context, CancellationToken); Assert.Equal(new HashSet { - DomainId.Combine(appId, assetFolderId1), - DomainId.Combine(appId, assetFolderId2) + DomainId.Combine(AppId, assetFolderId1), + DomainId.Combine(AppId, assetFolderId2) }, rebuildAssetFolders); } private BackupContext CreateBackupContext() { - return new BackupContext(appId.Id, CreateUserMapping(), A.Fake()); + return new BackupContext(AppId.Id, CreateUserMapping(), A.Fake()); } private RestoreContext CreateRestoreContext() { - return new RestoreContext(appId.Id, CreateUserMapping(), A.Fake(), DomainId.NewGuid()); + return new RestoreContext(AppId.Id, CreateUserMapping(), A.Fake(), DomainId.NewGuid()); } private Envelope AppEvent(AssetEvent @event) { - @event.AppId = appId; + @event.AppId = AppId; - return Envelope.Create(@event).SetAggregateId(DomainId.Combine(appId, @event.AssetId)); + return Envelope.Create(@event).SetAggregateId(DomainId.Combine(AppId, @event.AssetId)); } private Envelope AppEvent(AssetFolderEvent @event) { - @event.AppId = appId; + @event.AppId = AppId; - return Envelope.Create(@event).SetAggregateId(DomainId.Combine(appId, @event.AssetFolderId)); + return Envelope.Create(@event).SetAggregateId(DomainId.Combine(AppId, @event.AssetFolderId)); } private IUserMapping CreateUserMapping() diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DefaultAssetFileStoreTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DefaultAssetFileStoreTests.cs index cd41a7bdf..46528796f 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DefaultAssetFileStoreTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DefaultAssetFileStoreTests.cs @@ -14,13 +14,10 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Assets; -public class DefaultAssetFileStoreTests +public class DefaultAssetFileStoreTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IAssetRepository assetRepository = A.Fake(); private readonly IAssetStore assetStore = A.Fake(); - private readonly DomainId appId = DomainId.NewGuid(); private readonly DomainId assetId = DomainId.NewGuid(); private readonly long assetFileVersion = 21; private readonly AssetOptions options = new AssetOptions(); @@ -28,8 +25,6 @@ public class DefaultAssetFileStoreTests public DefaultAssetFileStoreTests() { - ct = cts.Token; - sut = new DefaultAssetFileStore(assetStore, assetRepository, Options.Create(options)); } @@ -60,7 +55,7 @@ public class DefaultAssetFileStoreTests A.CallTo(() => assetStore.GeneratePublicUrl(fullName)) .Returns(url); - var actual = sut.GeneratePublicUrl(appId, assetId, assetFileVersion, suffix); + var actual = sut.GeneratePublicUrl(AppId.Id, assetId, assetFileVersion, suffix); Assert.Equal(url, actual); } @@ -75,10 +70,10 @@ public class DefaultAssetFileStoreTests var size = 1024L; - A.CallTo(() => assetStore.GetSizeAsync(fullName, ct)) + A.CallTo(() => assetStore.GetSizeAsync(fullName, CancellationToken)) .Returns(size); - var actual = await sut.GetFileSizeAsync(appId, assetId, assetFileVersion, suffix, ct); + var actual = await sut.GetFileSizeAsync(AppId.Id, assetId, assetFileVersion, suffix, CancellationToken); Assert.Equal(size, actual); } @@ -91,13 +86,13 @@ public class DefaultAssetFileStoreTests var size = 1024L; - A.CallTo(() => assetStore.GetSizeAsync(A._, ct)) + A.CallTo(() => assetStore.GetSizeAsync(A._, CancellationToken)) .Throws(new AssetNotFoundException(assetId.ToString())); - A.CallTo(() => assetStore.GetSizeAsync(fullName, ct)) + A.CallTo(() => assetStore.GetSizeAsync(fullName, CancellationToken)) .Returns(size); - var actual = await sut.GetFileSizeAsync(appId, assetId, assetFileVersion, suffix, ct); + var actual = await sut.GetFileSizeAsync(AppId.Id, assetId, assetFileVersion, suffix, CancellationToken); Assert.Equal(size, actual); } @@ -107,9 +102,9 @@ public class DefaultAssetFileStoreTests { var stream = new MemoryStream(); - await sut.UploadAsync("Temp", stream, ct); + await sut.UploadAsync("Temp", stream, CancellationToken); - A.CallTo(() => assetStore.UploadAsync("Temp", stream, false, ct)) + A.CallTo(() => assetStore.UploadAsync("Temp", stream, false, CancellationToken)) .MustHaveHappened(); } @@ -123,9 +118,9 @@ public class DefaultAssetFileStoreTests var stream = new MemoryStream(); - await sut.UploadAsync(appId, assetId, assetFileVersion, suffix, stream, true, ct); + await sut.UploadAsync(AppId.Id, assetId, assetFileVersion, suffix, stream, true, CancellationToken); - A.CallTo(() => assetStore.UploadAsync(fullName, stream, true, ct)) + A.CallTo(() => assetStore.UploadAsync(fullName, stream, true, CancellationToken)) .MustHaveHappened(); } @@ -139,9 +134,9 @@ public class DefaultAssetFileStoreTests var stream = new MemoryStream(); - await sut.DownloadAsync(appId, assetId, assetFileVersion, suffix, stream, default, ct); + await sut.DownloadAsync(AppId.Id, assetId, assetFileVersion, suffix, stream, default, CancellationToken); - A.CallTo(() => assetStore.DownloadAsync(fullName, stream, default, ct)) + A.CallTo(() => assetStore.DownloadAsync(fullName, stream, default, CancellationToken)) .MustHaveHappened(); } @@ -152,12 +147,12 @@ public class DefaultAssetFileStoreTests var stream = new MemoryStream(); - A.CallTo(() => assetStore.DownloadAsync(A._, stream, default, ct)) + A.CallTo(() => assetStore.DownloadAsync(A._, stream, default, CancellationToken)) .Throws(new AssetNotFoundException(assetId.ToString())).Once(); - await Assert.ThrowsAsync(() => sut.DownloadAsync(appId, assetId, assetFileVersion, null, stream, default, ct)); + await Assert.ThrowsAsync(() => sut.DownloadAsync(AppId.Id, assetId, assetFileVersion, null, stream, default, CancellationToken)); - A.CallTo(() => assetStore.DownloadAsync(A._, stream, default, ct)) + A.CallTo(() => assetStore.DownloadAsync(A._, stream, default, CancellationToken)) .MustHaveHappenedOnceExactly(); } @@ -169,12 +164,12 @@ public class DefaultAssetFileStoreTests var stream = new MemoryStream(); - A.CallTo(() => assetStore.DownloadAsync(A.That.Matches(x => x != fileName), stream, default, ct)) + A.CallTo(() => assetStore.DownloadAsync(A.That.Matches(x => x != fileName), stream, default, CancellationToken)) .Throws(new AssetNotFoundException(assetId.ToString())).Once(); - await sut.DownloadAsync(appId, assetId, assetFileVersion, suffix, stream, default, ct); + await sut.DownloadAsync(AppId.Id, assetId, assetFileVersion, suffix, stream, default, CancellationToken); - A.CallTo(() => assetStore.DownloadAsync(fullName, stream, default, ct)) + A.CallTo(() => assetStore.DownloadAsync(fullName, stream, default, CancellationToken)) .MustHaveHappened(); } @@ -186,30 +181,30 @@ public class DefaultAssetFileStoreTests options.FolderPerApp = folderPerApp; - await sut.CopyAsync("Temp", appId, assetId, assetFileVersion, suffix, ct); + await sut.CopyAsync("Temp", AppId.Id, assetId, assetFileVersion, suffix, CancellationToken); - A.CallTo(() => assetStore.CopyAsync("Temp", fullName, ct)) + A.CallTo(() => assetStore.CopyAsync("Temp", fullName, CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_delete_temporary_file_from_store() { - await sut.DeleteAsync("Temp", ct); + await sut.DeleteAsync("Temp", CancellationToken); - A.CallTo(() => assetStore.DeleteAsync("Temp", ct)) + A.CallTo(() => assetStore.DeleteAsync("Temp", CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_delete_file_from_store() { - await sut.DeleteAsync(appId, assetId, ct); + await sut.DeleteAsync(AppId.Id, assetId, CancellationToken); - A.CallTo(() => assetStore.DeleteByPrefixAsync($"{appId}_{assetId}", ct)) + A.CallTo(() => assetStore.DeleteByPrefixAsync($"{AppId.Id}_{assetId}", CancellationToken)) .MustHaveHappened(); - A.CallTo(() => assetStore.DeleteByPrefixAsync(assetId.ToString(), ct)) + A.CallTo(() => assetStore.DeleteByPrefixAsync(assetId.ToString(), CancellationToken)) .MustHaveHappened(); } @@ -218,9 +213,9 @@ public class DefaultAssetFileStoreTests { options.FolderPerApp = true; - await sut.DeleteAsync(appId, assetId, ct); + await sut.DeleteAsync(AppId.Id, assetId, CancellationToken); - A.CallTo(() => assetStore.DeleteByPrefixAsync($"{appId}/{assetId}", ct)) + A.CallTo(() => assetStore.DeleteByPrefixAsync($"{AppId.Id}/{assetId}", CancellationToken)) .MustHaveHappened(); } @@ -230,23 +225,21 @@ public class DefaultAssetFileStoreTests var asset1 = new AssetEntity { Id = DomainId.NewGuid() }; var asset2 = new AssetEntity { Id = DomainId.NewGuid() }; - A.CallTo(() => assetRepository.StreamAll(appId, ct)) + A.CallTo(() => assetRepository.StreamAll(AppId.Id, CancellationToken)) .Returns(new[] { asset1, asset2 }.ToAsyncEnumerable()); - var app = Mocks.App(NamedId.Of(appId, "my-app")); - - await ((IDeleter)sut).DeleteAppAsync(app, ct); + await ((IDeleter)sut).DeleteAppAsync(App, CancellationToken); - A.CallTo(() => assetStore.DeleteByPrefixAsync($"{appId}_{asset1.Id}", ct)) + A.CallTo(() => assetStore.DeleteByPrefixAsync($"{AppId.Id}_{asset1.Id}", CancellationToken)) .MustHaveHappened(); - A.CallTo(() => assetStore.DeleteByPrefixAsync($"{appId}_{asset2.Id}", ct)) + A.CallTo(() => assetStore.DeleteByPrefixAsync($"{AppId.Id}_{asset2.Id}", CancellationToken)) .MustHaveHappened(); - A.CallTo(() => assetStore.DeleteByPrefixAsync(asset1.Id.ToString(), ct)) + A.CallTo(() => assetStore.DeleteByPrefixAsync(asset1.Id.ToString(), CancellationToken)) .MustHaveHappened(); - A.CallTo(() => assetStore.DeleteByPrefixAsync(asset2.Id.ToString(), ct)) + A.CallTo(() => assetStore.DeleteByPrefixAsync(asset2.Id.ToString(), CancellationToken)) .MustHaveHappened(); } @@ -255,18 +248,16 @@ public class DefaultAssetFileStoreTests { options.FolderPerApp = true; - var app = Mocks.App(NamedId.Of(appId, "my-app")); - - await ((IDeleter)sut).DeleteAppAsync(app, ct); + await ((IDeleter)sut).DeleteAppAsync(App, CancellationToken); - A.CallTo(() => assetStore.DeleteByPrefixAsync($"{appId}/", ct)) + A.CallTo(() => assetStore.DeleteByPrefixAsync($"{AppId.Id}/", CancellationToken)) .MustHaveHappened(); } private string GetFullName(string fileName) { return fileName - .Replace("{appId}", appId.ToString(), StringComparison.Ordinal) + .Replace("{appId}", AppId.Id.ToString(), StringComparison.Ordinal) .Replace("{assetId}", assetId.ToString(), StringComparison.Ordinal) .Replace("{assetFileVersion}", assetFileVersion.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetCommandMiddlewareTests.cs index 7506a008b..01165fcb1 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetCommandMiddlewareTests.cs @@ -7,6 +7,7 @@ using Squidex.Assets; using Squidex.Domain.Apps.Entities.Assets.Commands; +using Squidex.Domain.Apps.Entities.Assets.Queries; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; @@ -15,18 +16,14 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject; public class AssetCommandMiddlewareTests : HandlerTestBase { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IDomainObjectCache domainObjectCache = A.Fake(); private readonly IDomainObjectFactory domainObjectFactory = A.Fake(); private readonly IAssetEnricher assetEnricher = A.Fake(); private readonly IAssetFileStore assetFileStore = A.Fake(); private readonly IAssetMetadataSource assetMetadataSource = A.Fake(); private readonly IAssetQueryService assetQuery = A.Fake(); - private readonly IContextProvider contextProvider = A.Fake(); private readonly DomainId assetId = DomainId.NewGuid(); private readonly AssetFile file = new NoopAssetFile(); - private readonly Context requestContext; private readonly AssetCommandMiddleware sut; public sealed class MyCommand : SquidexCommand @@ -35,21 +32,14 @@ public class AssetCommandMiddlewareTests : HandlerTestBase DomainId.Combine(AppId, assetId); + get => DomainId.Combine(AppId.Id, assetId); } public AssetCommandMiddlewareTests() { - ct = cts.Token; - file = new NoopAssetFile(); - requestContext = Context.Anonymous(Mocks.App(AppNamedId)); - - A.CallTo(() => contextProvider.Context) - .Returns(requestContext); - - A.CallTo(() => assetQuery.FindByHashAsync(A._, A._, A._, A._, ct)) + A.CallTo(() => assetQuery.FindByHashAsync(A._, A._, A._, A._, CancellationToken)) .Returns(Task.FromResult(null)); sut = new AssetCommandMiddleware( @@ -58,7 +48,7 @@ public class AssetCommandMiddlewareTests : HandlerTestBase assetEnricher.EnrichAsync(A._, requestContext, A._)) + A.CallTo(() => assetEnricher.EnrichAsync(A._, ApiContext, A._)) .MustNotHaveHappened(); } @@ -79,7 +69,7 @@ public class AssetCommandMiddlewareTests : HandlerTestBase assetEnricher.EnrichAsync(A._, requestContext, A._)) + A.CallTo(() => assetEnricher.EnrichAsync(A._, ApiContext, A._)) .MustNotHaveHappened(); } @@ -90,7 +80,7 @@ public class AssetCommandMiddlewareTests : HandlerTestBase assetEnricher.EnrichAsync(actual, requestContext, ct)) + A.CallTo(() => assetEnricher.EnrichAsync(actual, ApiContext, CancellationToken)) .Returns(enriched); var context = @@ -130,7 +120,7 @@ public class AssetCommandMiddlewareTests : HandlerTestBase assetFileStore.UploadAsync(A._, A._, ct)) + A.CallTo(() => assetFileStore.UploadAsync(A._, A._, CancellationToken)) .MustHaveHappened(); - A.CallTo(() => assetFileStore.CopyAsync(A._, AppId, assetId, fileVersion, null, ct)) + A.CallTo(() => assetFileStore.CopyAsync(A._, AppId.Id, assetId, fileVersion, null, CancellationToken)) .MustHaveHappened(); - A.CallTo(() => assetFileStore.DeleteAsync(A._, ct)) + A.CallTo(() => assetFileStore.DeleteAsync(A._, CancellationToken)) .MustHaveHappened(); } @@ -235,13 +225,13 @@ public class AssetCommandMiddlewareTests : HandlerTestBase assetQuery.FindByHashAsync(requestContext, A._, fileName, fileSize, ct)) + A.CallTo(() => assetQuery.FindByHashAsync(ApiContext, A._, fileName, fileSize, CancellationToken)) .Returns(duplicate); } private void AssertMetadataEnriched() { - A.CallTo(() => assetMetadataSource.EnhanceAsync(A._, ct)) + A.CallTo(() => assetMetadataSource.EnhanceAsync(A._, CancellationToken)) .MustHaveHappened(); } @@ -253,17 +243,17 @@ public class AssetCommandMiddlewareTests : HandlerTestBase(); - A.CallTo(() => domainObject.ExecuteAsync(A._, ct)) + A.CallTo(() => domainObject.ExecuteAsync(A._, CancellationToken)) .Returns(new CommandResult(command.AggregateId, 1, 0, actual)); A.CallTo(() => domainObjectFactory.Create(command.AggregateId)) .Returns(domainObject); - return HandleAsync(sut, command, ct); + return HandleAsync(sut, command, CancellationToken); } private IAssetEntity CreateAsset(long fileVersion = 0) { - return new AssetEntity { AppId = AppNamedId, Id = assetId, FileVersion = fileVersion }; + return new AssetEntity { AppId = AppId, Id = assetId, FileVersion = fileVersion }; } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetDomainObjectTests.cs index b40f640e3..f577dcaf7 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetDomainObjectTests.cs @@ -11,7 +11,6 @@ using Squidex.Assets; using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Core.Tags; -using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Contents; using Squidex.Domain.Apps.Entities.Contents.Repositories; @@ -23,8 +22,6 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject; public class AssetDomainObjectTests : HandlerTestBase { - private readonly IAppEntity app; - private readonly IAppProvider appProvider = A.Fake(); private readonly IAssetQueryService assetQuery = A.Fake(); private readonly IContentRepository contentRepository = A.Fake(); private readonly IScriptEngine scriptEngine = A.Fake(); @@ -41,8 +38,6 @@ public class AssetDomainObjectTests : HandlerTestBase public AssetDomainObjectTests() { - app = Mocks.App(AppNamedId, Language.DE); - var scripts = new AssetScripts { Annotate = "", @@ -52,23 +47,20 @@ public class AssetDomainObjectTests : HandlerTestBase Update = "" }; - A.CallTo(() => app.AssetScripts) + A.CallTo(() => App.AssetScripts) .Returns(scripts); - A.CallTo(() => appProvider.GetAppAsync(AppId, false, default)) - .Returns(app); - - A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId, parentId, A._)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId.Id, parentId, A._)) .Returns(new List { A.Fake() }); - A.CallTo(() => tagService.GetTagIdsAsync(AppId, TagGroups.Assets, A>._, default)) + A.CallTo(() => tagService.GetTagIdsAsync(AppId.Id, TagGroups.Assets, A>._, default)) .ReturnsLazily(x => Task.FromResult(x.GetArgument>(2)?.ToDictionary(x => x) ?? new Dictionary())); var log = A.Fake>(); var serviceProvider = new ServiceCollection() - .AddSingleton(appProvider) + .AddSingleton(AppProvider) .AddSingleton(assetQuery) .AddSingleton(contentRepository) .AddSingleton(log) @@ -117,7 +109,7 @@ public class AssetDomainObjectTests : HandlerTestBase }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -170,7 +162,7 @@ public class AssetDomainObjectTests : HandlerTestBase }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -200,7 +192,7 @@ public class AssetDomainObjectTests : HandlerTestBase }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -230,7 +222,7 @@ public class AssetDomainObjectTests : HandlerTestBase }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -252,7 +244,7 @@ public class AssetDomainObjectTests : HandlerTestBase CreateAssetEvent(new AssetAnnotated { FileName = command.FileName }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -274,7 +266,7 @@ public class AssetDomainObjectTests : HandlerTestBase CreateAssetEvent(new AssetAnnotated { Slug = command.Slug }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -296,7 +288,7 @@ public class AssetDomainObjectTests : HandlerTestBase CreateAssetEvent(new AssetAnnotated { IsProtected = command.IsProtected }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -318,7 +310,7 @@ public class AssetDomainObjectTests : HandlerTestBase CreateAssetEvent(new AssetAnnotated { Metadata = command.Metadata }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustNotHaveHappened(); } @@ -338,7 +330,7 @@ public class AssetDomainObjectTests : HandlerTestBase CreateAssetEvent(new AssetAnnotated { Tags = new HashSet { "tag1" } }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -360,7 +352,7 @@ public class AssetDomainObjectTests : HandlerTestBase CreateAssetEvent(new AssetMoved { ParentId = parentId }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -383,7 +375,7 @@ public class AssetDomainObjectTests : HandlerTestBase CreateAssetEvent(new AssetDeleted { DeletedSize = 2048, OldTags = new HashSet() }) ); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -394,7 +386,7 @@ public class AssetDomainObjectTests : HandlerTestBase await ExecuteCreateAsync(); - A.CallTo(() => contentRepository.HasReferrersAsync(AppId, Id, SearchScope.All, A._)) + A.CallTo(() => contentRepository.HasReferrersAsync(AppId.Id, Id, SearchScope.All, A._)) .Returns(false); var actual = await PublishAsync(command); @@ -404,7 +396,7 @@ public class AssetDomainObjectTests : HandlerTestBase Assert.Equal(EtagVersion.Empty, sut.Snapshot.Version); Assert.Empty(LastEvents); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -415,12 +407,12 @@ public class AssetDomainObjectTests : HandlerTestBase await ExecuteCreateAsync(); - A.CallTo(() => contentRepository.HasReferrersAsync(AppId, Id, SearchScope.All, A._)) + A.CallTo(() => contentRepository.HasReferrersAsync(AppId.Id, Id, SearchScope.All, A._)) .Returns(true); await Assert.ThrowsAsync(() => PublishAsync(command)); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustNotHaveHappened(); } @@ -431,12 +423,12 @@ public class AssetDomainObjectTests : HandlerTestBase await ExecuteCreateAsync(); - A.CallTo(() => contentRepository.HasReferrersAsync(AppId, Id, SearchScope.All, A._)) + A.CallTo(() => contentRepository.HasReferrersAsync(AppId.Id, Id, SearchScope.All, A._)) .Returns(true); await PublishAsync(command); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -481,7 +473,7 @@ public class AssetDomainObjectTests : HandlerTestBase private async Task PublishAsync(AssetCommand command) { - var actual = await sut.ExecuteAsync(CreateAssetCommand(command), default); + var actual = await sut.ExecuteAsync(CreateAssetCommand(command), CancellationToken); return actual.Payload; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetFolderDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetFolderDomainObjectTests.cs index 2f104431f..a038a5902 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetFolderDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetFolderDomainObjectTests.cs @@ -7,7 +7,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Domain.Apps.Entities.TestHelpers; @@ -18,8 +17,6 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject; public class AssetFolderDomainObjectTests : HandlerTestBase { - private readonly IAppEntity app; - private readonly IAppProvider appProvider = A.Fake(); private readonly IAssetQueryService assetQuery = A.Fake(); private readonly IContentRepository contentRepository = A.Fake(); private readonly DomainId parentId = DomainId.NewGuid(); @@ -33,19 +30,14 @@ public class AssetFolderDomainObjectTests : HandlerTestBase appProvider.GetAppAsync(AppId, false, default)) - .Returns(app); - - A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId, parentId, A._)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId.Id, parentId, A._)) .Returns(new List { A.Fake() }); var log = A.Fake>(); var serviceProvider = new ServiceCollection() - .AddSingleton(appProvider) + .AddSingleton(AppProvider) .AddSingleton(assetQuery) .AddSingleton(contentRepository) .AddSingleton(log) @@ -175,7 +167,7 @@ public class AssetFolderDomainObjectTests : HandlerTestBase PublishAsync(AssetFolderCommand command) { - var actual = await sut.ExecuteAsync(CreateAssetFolderCommand(command), default); + var actual = await sut.ExecuteAsync(CreateAssetFolderCommand(command), CancellationToken); return actual.Payload; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetsBulkUpdateCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetsBulkUpdateCommandMiddlewareTests.cs index 320ee6192..778059719 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetsBulkUpdateCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/AssetsBulkUpdateCommandMiddlewareTests.cs @@ -5,30 +5,23 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Security.Claims; using Microsoft.Extensions.Logging; using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Shared; -using Squidex.Shared.Identity; namespace Squidex.Domain.Apps.Entities.Assets.DomainObject; -public class AssetsBulkUpdateCommandMiddlewareTests +public class AssetsBulkUpdateCommandMiddlewareTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IContextProvider contextProvider = A.Fake(); private readonly ICommandBus commandBus = A.Dummy(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly AssetsBulkUpdateCommandMiddleware sut; public AssetsBulkUpdateCommandMiddlewareTests() { - ct = cts.Token; - var log = A.Fake>(); sut = new AssetsBulkUpdateCommandMiddleware(contextProvider, log); @@ -68,7 +61,7 @@ public class AssetsBulkUpdateCommandMiddlewareTests Assert.Single(actual); Assert.Single(actual, x => x.JobIndex == 0 && x.Id == id && x.Exception == null); - A.CallTo(() => commandBus.PublishAsync(A.That.Matches(x => x.AssetId == id && x.FileName == "file"), ct)) + A.CallTo(() => commandBus.PublishAsync(A.That.Matches(x => x.AssetId == id && x.FileName == "file"), CancellationToken)) .MustHaveHappened(); } @@ -104,7 +97,7 @@ public class AssetsBulkUpdateCommandMiddlewareTests Assert.Single(actual); Assert.Single(actual, x => x.JobIndex == 0 && x.Id == id && x.Exception == null); - A.CallTo(() => commandBus.PublishAsync(A.That.Matches(x => x.AssetId == id), ct)) + A.CallTo(() => commandBus.PublishAsync(A.That.Matches(x => x.AssetId == id), CancellationToken)) .MustHaveHappened(); } @@ -141,7 +134,7 @@ public class AssetsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id == id && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.AssetId == id), ct)) + A.That.Matches(x => x.AssetId == id), CancellationToken)) .MustHaveHappened(); } @@ -167,7 +160,7 @@ public class AssetsBulkUpdateCommandMiddlewareTests { var context = new CommandContext(command, commandBus); - await sut.HandleAsync(context, ct); + await sut.HandleAsync(context, CancellationToken); return (context.PlainResult as BulkUpdateResult)!; } @@ -176,7 +169,7 @@ public class AssetsBulkUpdateCommandMiddlewareTests { return new BulkUpdateAssets { - AppId = appId, + AppId = AppId, Jobs = new[] { new BulkUpdateJob @@ -191,14 +184,7 @@ public class AssetsBulkUpdateCommandMiddlewareTests private Context SetupContext(string id) { - var permission = PermissionIds.ForApp(id, appId.Name).Id; - - var claimsIdentity = new ClaimsIdentity(); - var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); - - claimsIdentity.AddClaim(new Claim(SquidexClaimTypes.Permissions, permission)); - - var requestContext = new Context(claimsPrincipal, Mocks.App(appId)); + var requestContext = CreateContext(false, PermissionIds.ForApp(id, AppId.Name).Id); A.CallTo(() => contextProvider.Context) .Returns(requestContext); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/GuardAssetFolderTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/GuardAssetFolderTests.cs index 71de1dbb4..a2c9c2610 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/GuardAssetFolderTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/GuardAssetFolderTests.cs @@ -15,10 +15,9 @@ using Squidex.Infrastructure.Validation; namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards; -public class GuardAssetFolderTests : IClassFixture +public class GuardAssetFolderTests : GivenContext, IClassFixture { private readonly IAssetQueryService assetQuery = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly RefToken actor = RefToken.User("123"); [Fact] @@ -45,10 +44,10 @@ public class GuardAssetFolderTests : IClassFixture var operation = Operation(CreateAssetFolder()); - A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, parentId, A._)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId.Id, parentId, CancellationToken)) .Returns(new List()); - await ValidationAssert.ThrowsAsync(() => operation.MustMoveToValidFolder(parentId), + await ValidationAssert.ThrowsAsync(() => operation.MustMoveToValidFolder(parentId, CancellationToken), new ValidationError("Asset folder does not exist.", "ParentId")); } @@ -59,10 +58,10 @@ public class GuardAssetFolderTests : IClassFixture var operation = Operation(CreateAssetFolder()); - A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, parentId, A._)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId.Id, parentId, CancellationToken)) .Returns(new List { CreateAssetFolder() }); - await operation.MustMoveToValidFolder(parentId); + await operation.MustMoveToValidFolder(parentId, CancellationToken); } [Fact] @@ -72,9 +71,9 @@ public class GuardAssetFolderTests : IClassFixture var operation = Operation(CreateAssetFolder(default, parentId)); - await operation.MustMoveToValidFolder(parentId); + await operation.MustMoveToValidFolder(parentId, CancellationToken); - A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, parentId, A._)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId.Id, parentId, CancellationToken)) .MustNotHaveHappened(); } @@ -85,9 +84,9 @@ public class GuardAssetFolderTests : IClassFixture var operation = Operation(CreateAssetFolder()); - await operation.MustMoveToValidFolder(parentId); + await operation.MustMoveToValidFolder(parentId, CancellationToken); - A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, A._, A._)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId.Id, A._, A._)) .MustNotHaveHappened(); } @@ -98,14 +97,14 @@ public class GuardAssetFolderTests : IClassFixture var operation = Operation(CreateAssetFolder()); - A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, parentId, A._)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId.Id, parentId, CancellationToken)) .Returns(new List { CreateAssetFolder(operation.CommandId), CreateAssetFolder(parentId, operation.CommandId) }); - await ValidationAssert.ThrowsAsync(() => operation.MustMoveToValidFolder(parentId), + await ValidationAssert.ThrowsAsync(() => operation.MustMoveToValidFolder(parentId, CancellationToken), new ValidationError("Cannot add folder to its own child.", "ParentId")); } @@ -123,7 +122,7 @@ public class GuardAssetFolderTests : IClassFixture return new AssetFolderOperation(serviceProvider, () => assetFolder) { - App = Mocks.App(appId), + App = App, CommandId = assetFolder.Id, Command = new CreateAssetFolder { User = currentUser, Actor = actor } }; @@ -136,7 +135,7 @@ public class GuardAssetFolderTests : IClassFixture A.CallTo(() => assetFolder.Id) .Returns(OrNew(id)); A.CallTo(() => assetFolder.AppId) - .Returns(appId); + .Returns(AppId); A.CallTo(() => assetFolder.ParentId) .Returns(OrNew(parentId)); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/GuardAssetTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/GuardAssetTests.cs index 47635bd8c..9cb247d0d 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/GuardAssetTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/GuardAssetTests.cs @@ -17,12 +17,10 @@ using Squidex.Infrastructure.Validation; namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards; -public class GuardAssetTests : IClassFixture +public class GuardAssetTests : GivenContext, IClassFixture { private readonly IAssetQueryService assetQuery = A.Fake(); private readonly IContentRepository contentRepository = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly RefToken actor = RefToken.User("123"); [Fact] public async Task Should_throw_exception_if_moving_to_invalid_folder() @@ -31,10 +29,10 @@ public class GuardAssetTests : IClassFixture var operation = Operation(CreateAsset()); - A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, parentId, default)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId.Id, parentId, CancellationToken)) .Returns(new List()); - await ValidationAssert.ThrowsAsync(() => operation.MustMoveToValidFolder(parentId), + await ValidationAssert.ThrowsAsync(() => operation.MustMoveToValidFolder(parentId, CancellationToken), new ValidationError("Asset folder does not exist.", "ParentId")); } @@ -45,10 +43,10 @@ public class GuardAssetTests : IClassFixture var operation = Operation(CreateAsset()); - A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, parentId, default)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId.Id, parentId, CancellationToken)) .Returns(new List { CreateAssetFolder() }); - await operation.MustMoveToValidFolder(parentId); + await operation.MustMoveToValidFolder(parentId, CancellationToken); } [Fact] @@ -58,9 +56,9 @@ public class GuardAssetTests : IClassFixture var operation = Operation(CreateAsset(default, parentId)); - await operation.MustMoveToValidFolder(parentId); + await operation.MustMoveToValidFolder(parentId, CancellationToken); - A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, parentId, A._)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId.Id, parentId, A._)) .MustNotHaveHappened(); } @@ -71,9 +69,9 @@ public class GuardAssetTests : IClassFixture var operation = Operation(CreateAsset(parentId)); - await operation.MustMoveToValidFolder(parentId); + await operation.MustMoveToValidFolder(parentId, CancellationToken); - A.CallTo(() => assetQuery.FindAssetFolderAsync(appId.Id, parentId, A._)) + A.CallTo(() => assetQuery.FindAssetFolderAsync(AppId.Id, parentId, A._)) .MustNotHaveHappened(); } @@ -82,10 +80,10 @@ public class GuardAssetTests : IClassFixture { var operation = Operation(CreateAsset()); - A.CallTo(() => contentRepository.HasReferrersAsync(appId.Id, operation.CommandId, SearchScope.All, default)) + A.CallTo(() => contentRepository.HasReferrersAsync(AppId.Id, operation.CommandId, SearchScope.All, CancellationToken)) .Returns(true); - await Assert.ThrowsAsync(() => operation.CheckReferrersAsync()); + await Assert.ThrowsAsync(() => operation.CheckReferrersAsync(CancellationToken)); } [Fact] @@ -93,10 +91,10 @@ public class GuardAssetTests : IClassFixture { var operation = Operation(CreateAsset()); - A.CallTo(() => contentRepository.HasReferrersAsync(appId.Id, operation.CommandId, SearchScope.All, default)) + A.CallTo(() => contentRepository.HasReferrersAsync(AppId.Id, operation.CommandId, SearchScope.All, CancellationToken)) .Returns(true); - await Assert.ThrowsAsync(() => operation.CheckReferrersAsync()); + await Assert.ThrowsAsync(() => operation.CheckReferrersAsync(CancellationToken)); } private AssetOperation Operation(AssetEntity asset) @@ -114,9 +112,9 @@ public class GuardAssetTests : IClassFixture return new AssetOperation(serviceProvider, () => asset) { - App = Mocks.App(appId), + App = App, CommandId = asset.Id, - Command = new CreateAsset { User = currentUser, Actor = actor } + Command = new CreateAsset { User = currentUser, Actor = User } }; } @@ -125,9 +123,9 @@ public class GuardAssetTests : IClassFixture return new AssetEntity { Id = OrNew(id), - AppId = appId, + AppId = AppId, Created = default, - CreatedBy = actor, + CreatedBy = User, ParentId = OrNew(parentId) }; } @@ -139,7 +137,7 @@ public class GuardAssetTests : IClassFixture A.CallTo(() => assetFolder.Id) .Returns(OrNew(id)); A.CallTo(() => assetFolder.AppId) - .Returns(appId); + .Returns(AppId); A.CallTo(() => assetFolder.ParentId) .Returns(OrNew(parentId)); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/ScriptingExtensionsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/ScriptingExtensionsTests.cs index 244519950..cd756e346 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/ScriptingExtensionsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/DomainObject/Guards/ScriptingExtensionsTests.cs @@ -17,11 +17,8 @@ using Squidex.Infrastructure.Validation; namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards; -public sealed class ScriptingExtensionsTests +public sealed class ScriptingExtensionsTests : GivenContext { - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly RefToken actor = RefToken.User("123"); - [Fact] public async Task Should_add_tag_in_script() { @@ -31,7 +28,7 @@ public sealed class ScriptingExtensionsTests var operation = Operation(script, CreateAsset(), command); - await operation.ExecuteAnnotateScriptAsync(command); + await operation.ExecuteAnnotateScriptAsync(command, CancellationToken); Assert.Contains("tag", command.Tags); } @@ -45,7 +42,7 @@ public sealed class ScriptingExtensionsTests var operation = Operation(script, CreateAsset(), command); - await operation.ExecuteAnnotateScriptAsync(command); + await operation.ExecuteAnnotateScriptAsync(command, CancellationToken); Assert.Equal(JsonValue.Create(42), command.Metadata["foo"]); } @@ -59,7 +56,7 @@ public sealed class ScriptingExtensionsTests var operation = Operation(script, CreateAsset(), command); - await Assert.ThrowsAsync(() => operation.ExecuteAnnotateScriptAsync(command)); + await Assert.ThrowsAsync(() => operation.ExecuteAnnotateScriptAsync(command, CancellationToken)); } [Fact] @@ -71,7 +68,7 @@ public sealed class ScriptingExtensionsTests var operation = Operation(script, CreateAsset(), command); - await Assert.ThrowsAsync(() => operation.ExecuteAnnotateScriptAsync(command)); + await Assert.ThrowsAsync(() => operation.ExecuteAnnotateScriptAsync(command, CancellationToken)); } private AssetOperation Operation(string script, AssetEntity asset, AnnotateAsset command) @@ -81,9 +78,7 @@ public sealed class ScriptingExtensionsTests Annotate = script }; - var app = Mocks.App(appId); - - A.CallTo(() => app.AssetScripts) + A.CallTo(() => App.AssetScripts) .Returns(scripts); var serviceProvider = @@ -94,12 +89,12 @@ public sealed class ScriptingExtensionsTests .AddSingleton() .BuildServiceProvider(); - command.Actor = actor; + command.Actor = User; command.User = Mocks.FrontendUser(); return new AssetOperation(serviceProvider, () => asset) { - App = app, + App = App, CommandId = asset.Id, Command = command }; @@ -110,9 +105,9 @@ public sealed class ScriptingExtensionsTests return new AssetEntity { Id = DomainId.NewGuid(), - AppId = appId, + AppId = AppId, Created = default, - CreatedBy = actor, + CreatedBy = User, Metadata = new AssetMetadata(), Tags = new HashSet() }; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs index 3f2f93825..2e8e1ea20 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/ImageAssetMetadataSourceTests.cs @@ -8,14 +8,13 @@ using Squidex.Assets; using Squidex.Domain.Apps.Core.Assets; using Squidex.Domain.Apps.Entities.Assets.Commands; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Entities.Assets; -public class ImageAssetMetadataSourceTests +public class ImageAssetMetadataSourceTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IAssetThumbnailGenerator assetThumbnailGenerator = A.Fake(); private readonly MemoryStream stream = new MemoryStream(); private readonly AssetFile file; @@ -23,8 +22,6 @@ public class ImageAssetMetadataSourceTests public ImageAssetMetadataSourceTests() { - ct = cts.Token; - file = new DelegateAssetFile("MyImage.png", "image/png", 1024, () => stream); sut = new ImageAssetMetadataSource(assetThumbnailGenerator); @@ -35,9 +32,9 @@ public class ImageAssetMetadataSourceTests { var command = new CreateAsset { File = file, Type = AssetType.Image }; - await sut.EnhanceAsync(command, ct); + await sut.EnhanceAsync(command, CancellationToken); - A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(A._, file.MimeType, ct)) + A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(A._, file.MimeType, CancellationToken)) .MustHaveHappened(); } @@ -46,7 +43,7 @@ public class ImageAssetMetadataSourceTests { var command = new CreateAsset { File = file }; - await sut.EnhanceAsync(command, ct); + await sut.EnhanceAsync(command, CancellationToken); Assert.Empty(command.Tags); } @@ -56,10 +53,10 @@ public class ImageAssetMetadataSourceTests { var command = new CreateAsset { File = file }; - A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(stream, file.MimeType, ct)) + A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(stream, file.MimeType, CancellationToken)) .Returns(new ImageInfo(800, 600, ImageOrientation.None, ImageFormat.PNG)); - await sut.EnhanceAsync(command, ct); + await sut.EnhanceAsync(command, CancellationToken); Assert.Equal(800, command.Metadata.GetPixelWidth()); Assert.Equal(600, command.Metadata.GetPixelHeight()); @@ -74,19 +71,19 @@ public class ImageAssetMetadataSourceTests { var command = new CreateAsset { File = file }; - A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(A._, file.MimeType, ct)) + A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(A._, file.MimeType, CancellationToken)) .Returns(new ImageInfo(800, 600, ImageOrientation.None, ImageFormat.PNG)); - A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(stream, file.MimeType, ct)) + A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(stream, file.MimeType, CancellationToken)) .Returns(new ImageInfo(600, 800, ImageOrientation.BottomRight, ImageFormat.PNG)).Once(); - await sut.EnhanceAsync(command, ct); + await sut.EnhanceAsync(command, CancellationToken); Assert.Equal(800, command.Metadata.GetPixelWidth()); Assert.Equal(600, command.Metadata.GetPixelHeight()); Assert.Equal(AssetType.Image, command.Type); - A.CallTo(() => assetThumbnailGenerator.FixOrientationAsync(stream, file.MimeType, A._, ct)) + A.CallTo(() => assetThumbnailGenerator.FixOrientationAsync(stream, file.MimeType, A._, CancellationToken)) .MustHaveHappened(); } @@ -98,7 +95,7 @@ public class ImageAssetMetadataSourceTests command.Metadata.SetPixelWidth(100); command.Metadata.SetPixelWidth(100); - await sut.EnhanceAsync(command, ct); + await sut.EnhanceAsync(command, CancellationToken); Assert.Contains("image", command.Tags); Assert.Contains("image/small", command.Tags); @@ -112,7 +109,7 @@ public class ImageAssetMetadataSourceTests command.Metadata.SetPixelWidth(800); command.Metadata.SetPixelWidth(600); - await sut.EnhanceAsync(command, ct); + await sut.EnhanceAsync(command, CancellationToken); Assert.Contains("image", command.Tags); Assert.Contains("image/medium", command.Tags); @@ -126,7 +123,7 @@ public class ImageAssetMetadataSourceTests command.Metadata.SetPixelWidth(1200); command.Metadata.SetPixelWidth(1400); - await sut.EnhanceAsync(command, ct); + await sut.EnhanceAsync(command, CancellationToken); Assert.Contains("image", command.Tags); Assert.Contains("image/large", command.Tags); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetEnricherTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetEnricherTests.cs index e0ae346d1..a8c4322eb 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetEnricherTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetEnricherTests.cs @@ -5,200 +5,65 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Domain.Apps.Core; -using Squidex.Domain.Apps.Core.Tags; -using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; -using Squidex.Infrastructure.Caching; -using Squidex.Infrastructure.Json; namespace Squidex.Domain.Apps.Entities.Assets.Queries; -public class AssetEnricherTests +public class AssetEnricherTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; - private readonly ITagService tagService = A.Fake(); - private readonly IRequestCache requestCache = A.Fake(); - private readonly IUrlGenerator urlGenerator = A.Fake(); - private readonly IAssetMetadataSource assetMetadataSource1 = A.Fake(); - private readonly IAssetMetadataSource assetMetadataSource2 = A.Fake(); - private readonly IJsonSerializer serializer = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly Context requestContext; - private readonly AssetEnricher sut; - - public AssetEnricherTests() - { - ct = cts.Token; - - var assetMetadataSources = new[] - { - assetMetadataSource1, - assetMetadataSource2 - }; - - requestContext = Context.Anonymous(Mocks.App(appId)); - - sut = new AssetEnricher(tagService, assetMetadataSources, requestCache, urlGenerator, serializer); - } - [Fact] - public async Task Should_not_enrich_if_asset_contains_null_tags() + public async Task Should_only_invoke_pre_enrich_for_empty_assets() { - var source = new AssetEntity { AppId = appId }; + var assets = Array.Empty(); - var actual = await sut.EnrichAsync(source, requestContext, ct); - - Assert.Empty(actual.TagNames); - } + var step1 = A.Fake(); + var step2 = A.Fake(); - [Fact] - public async Task Should_enrich_with_cache_dependencies() - { - var source = new AssetEntity { AppId = appId, Id = DomainId.NewGuid(), Version = 13 }; + var sut = new AssetEnricher(new[] { step1, step2 }); - var actual = await sut.EnrichAsync(source, requestContext, ct); + await sut.EnrichAsync(assets, ApiContext, CancellationToken); - A.CallTo(() => requestCache.AddDependency(actual.UniqueId, actual.Version)) + A.CallTo(() => step1.EnrichAsync(ApiContext, CancellationToken)) .MustHaveHappened(); - } - [Fact] - public async Task Should_enrich_asset_with_tag_names() - { - var source = new AssetEntity - { - Tags = new HashSet - { - "id1", - "id2" - }, - AppId = appId - }; - - A.CallTo(() => tagService.GetTagNamesAsync(appId.Id, TagGroups.Assets, A>.That.Is("id1", "id2"), ct)) - .Returns(new Dictionary - { - ["id1"] = "name1", - ["id2"] = "name2" - }); - - var actual = await sut.EnrichAsync(source, requestContext, ct); - - Assert.Equal(new HashSet { "name1", "name2" }, actual.TagNames); - } + A.CallTo(() => step2.EnrichAsync(ApiContext, CancellationToken)) + .MustHaveHappened(); - [Fact] - public async Task Should_not_enrich_asset_with_tag_names_if_disabled() - { - var source = new AssetEntity - { - Tags = new HashSet - { - "id1", - "id2" - }, - AppId = appId - }; - - var actual = await sut.EnrichAsync(source, requestContext.Clone(b => b.WithoutAssetEnrichment()), ct); - - Assert.Null(actual.TagNames); - } + A.CallTo(() => step1.EnrichAsync(ApiContext, A>._, A._)) + .MustNotHaveHappened(); - [Fact] - public async Task Should_enrich_asset_with_metadata() - { - var source = new AssetEntity - { - FileSize = 2 * 1024, - Tags = new HashSet - { - "id1", - "id2" - }, - AppId = appId - }; - - A.CallTo(() => assetMetadataSource1.Format(A._)) - .Returns(new[] { "metadata1" }); - - A.CallTo(() => assetMetadataSource2.Format(A._)) - .Returns(new[] { "metadata2", "metadata3" }); - - var actual = await sut.EnrichAsync(source, requestContext, ct); - - Assert.Equal("metadata1, metadata2, metadata3, 2 kB", actual.MetadataText); + A.CallTo(() => step2.EnrichAsync(ApiContext, A>._, A._)) + .MustNotHaveHappened(); } [Fact] - public async Task Should_enrich_multiple_assets_with_tag_names() + public async Task Should_invoke_steps() { - var source1 = new AssetEntity - { - Tags = new HashSet - { - "id1", - "id2" - }, - AppId = appId - }; - - var source2 = new AssetEntity - { - Tags = new HashSet - { - "id2", - "id3" - }, - AppId = appId - }; - - A.CallTo(() => tagService.GetTagNamesAsync(appId.Id, TagGroups.Assets, A>.That.Is("id1", "id2", "id3"), ct)) - .Returns(new Dictionary - { - ["id1"] = "name1", - ["id2"] = "name2", - ["id3"] = "name3" - }); - - var actual = await sut.EnrichAsync(new[] { source1, source2 }, requestContext, ct); - - Assert.Equal(new HashSet { "name1", "name2" }, actual[0].TagNames); - Assert.Equal(new HashSet { "name2", "name3" }, actual[1].TagNames); - } + var source = CreateAsset(); - [Fact] - public async Task Should_also_compute_ui_tokens_for_frontend() - { - var source = new AssetEntity - { - AppId = appId - }; + var step1 = A.Fake(); + var step2 = A.Fake(); - var actual = await sut.EnrichAsync(new[] { source }, new Context(Mocks.FrontendUser(), Mocks.App(appId)), ct); + var sut = new AssetEnricher(new[] { step1, step2 }); - Assert.NotNull(actual[0].EditToken); + await sut.EnrichAsync(source, ApiContext, CancellationToken); - A.CallTo(() => urlGenerator.Root()) + A.CallTo(() => step1.EnrichAsync(ApiContext, CancellationToken)) .MustHaveHappened(); - } - [Fact] - public async Task Should_compute_ui_tokens() - { - var source = new AssetEntity - { - AppId = appId - }; - - var actual = await sut.EnrichAsync(new[] { source }, requestContext, ct); + A.CallTo(() => step2.EnrichAsync(ApiContext, CancellationToken)) + .MustHaveHappened(); - Assert.NotNull(actual[0].EditToken); + A.CallTo(() => step1.EnrichAsync(ApiContext, A>._, CancellationToken)) + .MustHaveHappened(); - A.CallTo(() => urlGenerator.Root()) + A.CallTo(() => step2.EnrichAsync(ApiContext, A>._, CancellationToken)) .MustHaveHappened(); } + + private AssetEntity CreateAsset() + { + return new AssetEntity { Id = DomainId.NewGuid(), AppId = AppId }; + } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetLoaderTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetLoaderTests.cs index 690673a29..081375a70 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetLoaderTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetLoaderTests.cs @@ -6,30 +6,26 @@ // ========================================================================== using Squidex.Domain.Apps.Entities.Assets.DomainObject; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; namespace Squidex.Domain.Apps.Entities.Assets.Queries; -public class AssetLoaderTests +public class AssetLoaderTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IDomainObjectFactory domainObjectFactory = A.Fake(); private readonly IDomainObjectCache domainObjectCache = A.Fake(); private readonly AssetDomainObject domainObject = A.Fake(); - private readonly DomainId appId = DomainId.NewGuid(); private readonly DomainId id = DomainId.NewGuid(); private readonly DomainId uniqueId; private readonly AssetLoader sut; public AssetLoaderTests() { - ct = cts.Token; + uniqueId = DomainId.Combine(AppId.Id, id); - uniqueId = DomainId.Combine(appId, id); - - A.CallTo(() => domainObjectCache.GetAsync(A._, A._, ct)) + A.CallTo(() => domainObjectCache.GetAsync(A._, A._, CancellationToken)) .Returns(Task.FromResult(null!)); A.CallTo(() => domainObjectFactory.Create(uniqueId)) @@ -43,10 +39,10 @@ public class AssetLoaderTests { var asset = (AssetDomainObject.State)null!; - A.CallTo(() => domainObject.GetSnapshotAsync(10, ct)) + A.CallTo(() => domainObject.GetSnapshotAsync(10, CancellationToken)) .Returns(asset); - Assert.Null(await sut.GetAsync(appId, id, 10, ct)); + Assert.Null(await sut.GetAsync(AppId.Id, id, 10, CancellationToken)); } [Fact] @@ -54,10 +50,10 @@ public class AssetLoaderTests { var asset = new AssetDomainObject.State { Version = EtagVersion.Empty }; - A.CallTo(() => domainObject.GetSnapshotAsync(10, ct)) + A.CallTo(() => domainObject.GetSnapshotAsync(10, CancellationToken)) .Returns(asset); - Assert.Null(await sut.GetAsync(appId, id, 10, ct)); + Assert.Null(await sut.GetAsync(AppId.Id, id, 10, CancellationToken)); } [Fact] @@ -65,10 +61,10 @@ public class AssetLoaderTests { var asset = new AssetDomainObject.State { Version = 5 }; - A.CallTo(() => domainObject.GetSnapshotAsync(10, ct)) + A.CallTo(() => domainObject.GetSnapshotAsync(10, CancellationToken)) .Returns(asset); - Assert.Null(await sut.GetAsync(appId, id, 10, ct)); + Assert.Null(await sut.GetAsync(AppId.Id, id, 10, CancellationToken)); } [Fact] @@ -76,10 +72,10 @@ public class AssetLoaderTests { var asset = new AssetDomainObject.State { Version = 5 }; - A.CallTo(() => domainObject.GetSnapshotAsync(EtagVersion.Any, ct)) + A.CallTo(() => domainObject.GetSnapshotAsync(EtagVersion.Any, CancellationToken)) .Returns(asset); - var actual = await sut.GetAsync(appId, id, EtagVersion.Any, ct); + var actual = await sut.GetAsync(AppId.Id, id, EtagVersion.Any, CancellationToken); Assert.Same(asset, actual); } @@ -89,10 +85,10 @@ public class AssetLoaderTests { var asset = new AssetDomainObject.State { Version = 10 }; - A.CallTo(() => domainObject.GetSnapshotAsync(10, ct)) + A.CallTo(() => domainObject.GetSnapshotAsync(10, CancellationToken)) .Returns(asset); - var actual = await sut.GetAsync(appId, id, 10, ct); + var actual = await sut.GetAsync(AppId.Id, id, 10, CancellationToken); Assert.Same(asset, actual); } @@ -102,10 +98,10 @@ public class AssetLoaderTests { var content = new AssetDomainObject.State { Version = 10 }; - A.CallTo(() => domainObjectCache.GetAsync(DomainId.Combine(appId, id), 10, ct)) + A.CallTo(() => domainObjectCache.GetAsync(DomainId.Combine(AppId.Id, id), 10, CancellationToken)) .Returns(content); - var actual = await sut.GetAsync(appId, id, 10, ct); + var actual = await sut.GetAsync(AppId.Id, id, 10, CancellationToken); Assert.Same(content, actual); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryParserTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryParserTests.cs index 27fdc4dba..bdb727ed5 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryParserTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryParserTests.cs @@ -9,23 +9,18 @@ using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Core.Tags; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; using Squidex.Infrastructure.Queries; using Squidex.Infrastructure.Validation; namespace Squidex.Domain.Apps.Entities.Assets.Queries; -public class AssetQueryParserTests +public class AssetQueryParserTests : GivenContext { private readonly ITagService tagService = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly Context requestContext; private readonly AssetQueryParser sut; public AssetQueryParserTests() { - requestContext = new Context(Mocks.FrontendUser(), Mocks.App(appId)); - var options = Options.Create(new AssetOptions { DefaultPageSize = 30 }); sut = new AssetQueryParser(TestUtils.DefaultSerializer, tagService, options); @@ -34,7 +29,7 @@ public class AssetQueryParserTests [Fact] public async Task Should_skip_total_if_set_in_context() { - var q = await sut.ParseAsync(requestContext.Clone(b => b.WithoutTotal()), Q.Empty); + var q = await sut.ParseAsync(ApiContext.Clone(b => b.WithoutTotal()), Q.Empty, CancellationToken); Assert.True(q.NoTotal); } @@ -44,7 +39,7 @@ public class AssetQueryParserTests { var query = Q.Empty.WithODataQuery("$filter=invalid"); - await Assert.ThrowsAsync(() => sut.ParseAsync(requestContext, query)); + await Assert.ThrowsAsync(() => sut.ParseAsync(ApiContext, query, CancellationToken)); } [Fact] @@ -52,7 +47,7 @@ public class AssetQueryParserTests { var query = Q.Empty.WithJsonQuery("invalid"); - await Assert.ThrowsAsync(() => sut.ParseAsync(requestContext, query)); + await Assert.ThrowsAsync(() => sut.ParseAsync(ApiContext, query, CancellationToken)); } [Fact] @@ -60,7 +55,7 @@ public class AssetQueryParserTests { var query = Q.Empty.WithODataQuery("$top=100&$orderby=fileName asc&$search=Hello World"); - var q = await sut.ParseAsync(requestContext, query); + var q = await sut.ParseAsync(ApiContext, query, CancellationToken); Assert.Equal("FullText: 'Hello World'; Take: 100; Sort: fileName Ascending, id Ascending", q.Query.ToString()); } @@ -70,7 +65,7 @@ public class AssetQueryParserTests { var query = Q.Empty.WithODataQuery("$top=200&$filter=fileName eq 'ABC'"); - var q = await sut.ParseAsync(requestContext, query); + var q = await sut.ParseAsync(ApiContext, query, CancellationToken); Assert.Equal("Filter: fileName == 'ABC'; Take: 200; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -80,7 +75,7 @@ public class AssetQueryParserTests { var query = Q.Empty.WithJsonQuery("{ \"filter\": { \"path\": \"fileName\", \"op\": \"eq\", \"value\": \"ABC\" } }"); - var q = await sut.ParseAsync(requestContext, query); + var q = await sut.ParseAsync(ApiContext, query, CancellationToken); Assert.Equal("Filter: fileName == 'ABC'; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -90,7 +85,7 @@ public class AssetQueryParserTests { var query = Q.Empty.WithJsonQuery("{ \"fullText\": \"Hello\" }"); - var q = await sut.ParseAsync(requestContext, query); + var q = await sut.ParseAsync(ApiContext, query, CancellationToken); Assert.Equal("FullText: 'Hello'; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -104,7 +99,7 @@ public class AssetQueryParserTests { var query = Q.Empty.WithQuery(new ClrQuery { Take = take }); - var q = await sut.ParseAsync(requestContext, query); + var q = await sut.ParseAsync(ApiContext, query, CancellationToken); Assert.Equal("Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -114,7 +109,7 @@ public class AssetQueryParserTests { var query = Q.Empty.WithIds("1, 2, 3"); - var q = await sut.ParseAsync(requestContext, query); + var q = await sut.ParseAsync(ApiContext, query, CancellationToken); Assert.Equal("Take: 3; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -124,7 +119,7 @@ public class AssetQueryParserTests { var query = Q.Empty.WithIds("1, 2, 3").WithQuery(new ClrQuery { Take = 20 }); - var q = await sut.ParseAsync(requestContext, query); + var q = await sut.ParseAsync(ApiContext, query, CancellationToken); Assert.Equal("Take: 20; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -134,7 +129,7 @@ public class AssetQueryParserTests { var query = Q.Empty.WithODataQuery("$top=300&$skip=20"); - var q = await sut.ParseAsync(requestContext, query); + var q = await sut.ParseAsync(ApiContext, query, CancellationToken); Assert.Equal("Skip: 20; Take: 200; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -144,7 +139,7 @@ public class AssetQueryParserTests { var query = Q.Empty.WithODataQuery("$top=300&$skip=20&$orderby=id desc"); - var q = await sut.ParseAsync(requestContext, query); + var q = await sut.ParseAsync(ApiContext, query, CancellationToken); Assert.Equal("Skip: 20; Take: 200; Sort: id Descending", q.Query.ToString()); } @@ -152,12 +147,12 @@ public class AssetQueryParserTests [Fact] public async Task Should_denormalize_tags() { - A.CallTo(() => tagService.GetTagIdsAsync(appId.Id, TagGroups.Assets, A>.That.Contains("name1"), default)) + A.CallTo(() => tagService.GetTagIdsAsync(AppId.Id, TagGroups.Assets, A>.That.Contains("name1"), CancellationToken)) .Returns(new Dictionary { ["name1"] = "id1" }); var query = Q.Empty.WithODataQuery("$filter=tags eq 'name1'"); - var q = await sut.ParseAsync(requestContext, query); + var q = await sut.ParseAsync(ApiContext, query, CancellationToken); Assert.Equal("Filter: tags == 'id1'; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -165,12 +160,12 @@ public class AssetQueryParserTests [Fact] public async Task Should_not_fail_if_tags_not_found() { - A.CallTo(() => tagService.GetTagIdsAsync(appId.Id, TagGroups.Assets, A>.That.Contains("name1"), default)) + A.CallTo(() => tagService.GetTagIdsAsync(AppId.Id, TagGroups.Assets, A>.That.Contains("name1"), CancellationToken)) .Returns(new Dictionary()); var query = Q.Empty.WithODataQuery("$filter=tags eq 'name1'"); - var q = await sut.ParseAsync(requestContext, query); + var q = await sut.ParseAsync(ApiContext, query, CancellationToken); Assert.Equal("Filter: tags == 'name1'; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -180,11 +175,11 @@ public class AssetQueryParserTests { var query = Q.Empty.WithODataQuery("$filter=fileSize eq 123"); - var q = await sut.ParseAsync(requestContext, query); + var q = await sut.ParseAsync(ApiContext, query, CancellationToken); Assert.Equal("Filter: fileSize == 123; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); - A.CallTo(() => tagService.GetTagIdsAsync(appId.Id, A._, A>._, A._)) + A.CallTo(() => tagService.GetTagIdsAsync(AppId.Id, A._, A>._, A._)) .MustNotHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryServiceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryServiceTests.cs index 347eb5745..fd03cfd2f 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryServiceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/AssetQueryServiceTests.cs @@ -13,28 +13,20 @@ using Squidex.Infrastructure.Reflection; namespace Squidex.Domain.Apps.Entities.Assets.Queries; -public class AssetQueryServiceTests +public class AssetQueryServiceTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IAssetEnricher assetEnricher = A.Fake(); private readonly IAssetRepository assetRepository = A.Fake(); private readonly IAssetLoader assetLoader = A.Fake(); private readonly IAssetFolderRepository assetFolderRepository = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly Context requestContext; private readonly AssetQueryParser queryParser = A.Fake(); private readonly AssetQueryService sut; public AssetQueryServiceTests() { - ct = cts.Token; - - requestContext = new Context(Mocks.FrontendUser(), Mocks.App(appId)); - SetupEnricher(); - A.CallTo(() => queryParser.ParseAsync(requestContext, A._, ct)) + A.CallTo(() => queryParser.ParseAsync(ApiContext, A._, CancellationToken)) .ReturnsLazily(c => Task.FromResult(c.GetArgument(1)!)); var options = Options.Create(new AssetOptions()); @@ -53,10 +45,10 @@ public class AssetQueryServiceTests { var asset = CreateAsset(DomainId.NewGuid()); - A.CallTo(() => assetRepository.FindAssetBySlugAsync(appId.Id, "slug", A._)) + A.CallTo(() => assetRepository.FindAssetBySlugAsync(AppId.Id, "slug", A._)) .Returns(asset); - var actual = await sut.FindBySlugAsync(requestContext, "slug", ct); + var actual = await sut.FindBySlugAsync(ApiContext, "slug", CancellationToken); AssertAsset(asset, actual); } @@ -66,10 +58,10 @@ public class AssetQueryServiceTests { var asset = CreateAsset(DomainId.NewGuid()); - A.CallTo(() => assetRepository.FindAssetBySlugAsync(appId.Id, "slug", A._)) + A.CallTo(() => assetRepository.FindAssetBySlugAsync(AppId.Id, "slug", A._)) .Returns(Task.FromResult(null)); - var actual = await sut.FindBySlugAsync(requestContext, "slug", ct); + var actual = await sut.FindBySlugAsync(ApiContext, "slug", CancellationToken); Assert.Null(actual); } @@ -79,10 +71,10 @@ public class AssetQueryServiceTests { var asset = CreateAsset(DomainId.NewGuid()); - A.CallTo(() => assetRepository.FindAssetAsync(appId.Id, asset.Id, A._)) + A.CallTo(() => assetRepository.FindAssetAsync(AppId.Id, asset.Id, A._)) .Returns(asset); - var actual = await sut.FindAsync(requestContext, asset.Id, ct: ct); + var actual = await sut.FindAsync(ApiContext, asset.Id, ct: CancellationToken); AssertAsset(asset, actual); } @@ -92,10 +84,10 @@ public class AssetQueryServiceTests { var asset = CreateAsset(DomainId.NewGuid()); - A.CallTo(() => assetRepository.FindAssetAsync(appId.Id, asset.Id, A._)) + A.CallTo(() => assetRepository.FindAssetAsync(AppId.Id, asset.Id, A._)) .Returns(Task.FromResult(null)); - var actual = await sut.FindAsync(requestContext, asset.Id, ct: ct); + var actual = await sut.FindAsync(ApiContext, asset.Id, ct: CancellationToken); Assert.Null(actual); } @@ -105,10 +97,10 @@ public class AssetQueryServiceTests { var asset = CreateAsset(DomainId.NewGuid()); - A.CallTo(() => assetLoader.GetAsync(appId.Id, asset.Id, 2, A._)) + A.CallTo(() => assetLoader.GetAsync(AppId.Id, asset.Id, 2, A._)) .Returns(asset); - var actual = await sut.FindAsync(requestContext, asset.Id, 2, ct); + var actual = await sut.FindAsync(ApiContext, asset.Id, 2, CancellationToken); AssertAsset(asset, actual); } @@ -118,10 +110,10 @@ public class AssetQueryServiceTests { var asset = CreateAsset(DomainId.NewGuid()); - A.CallTo(() => assetLoader.GetAsync(appId.Id, asset.Id, 2, A._)) + A.CallTo(() => assetLoader.GetAsync(AppId.Id, asset.Id, 2, A._)) .Returns(Task.FromResult(null)); - var actual = await sut.FindAsync(requestContext, asset.Id, 2, ct); + var actual = await sut.FindAsync(ApiContext, asset.Id, 2, CancellationToken); Assert.Null(actual); } @@ -134,7 +126,7 @@ public class AssetQueryServiceTests A.CallTo(() => assetRepository.FindAssetAsync(asset.Id, A._)) .Returns(asset); - var actual = await sut.FindGlobalAsync(requestContext, asset.Id, ct); + var actual = await sut.FindGlobalAsync(ApiContext, asset.Id, CancellationToken); AssertAsset(asset, actual); } @@ -147,7 +139,7 @@ public class AssetQueryServiceTests A.CallTo(() => assetRepository.FindAssetAsync(asset.Id, A._)) .Returns(Task.FromResult(null)); - var actual = await sut.FindGlobalAsync(requestContext, asset.Id, ct); + var actual = await sut.FindGlobalAsync(ApiContext, asset.Id, CancellationToken); Assert.Null(actual); } @@ -157,10 +149,10 @@ public class AssetQueryServiceTests { var asset = CreateAsset(DomainId.NewGuid()); - A.CallTo(() => assetRepository.FindAssetByHashAsync(appId.Id, "hash", "name", 123, A._)) + A.CallTo(() => assetRepository.FindAssetByHashAsync(AppId.Id, "hash", "name", 123, A._)) .Returns(asset); - var actual = await sut.FindByHashAsync(requestContext, "hash", "name", 123, ct); + var actual = await sut.FindByHashAsync(ApiContext, "hash", "name", 123, CancellationToken); AssertAsset(asset, actual); } @@ -170,10 +162,10 @@ public class AssetQueryServiceTests { var asset = CreateAsset(DomainId.NewGuid()); - A.CallTo(() => assetRepository.FindAssetByHashAsync(appId.Id, "hash", "name", 123, A._)) + A.CallTo(() => assetRepository.FindAssetByHashAsync(AppId.Id, "hash", "name", 123, A._)) .Returns(Task.FromResult(null)); - var actual = await sut.FindByHashAsync(requestContext, "hash", "name", 123, ct); + var actual = await sut.FindByHashAsync(ApiContext, "hash", "name", 123, CancellationToken); Assert.Null(actual); } @@ -188,10 +180,10 @@ public class AssetQueryServiceTests var q = Q.Empty.WithODataQuery("fileName eq 'Name'"); - A.CallTo(() => assetRepository.QueryAsync(appId.Id, parentId, q, A._)) + A.CallTo(() => assetRepository.QueryAsync(AppId.Id, parentId, q, A._)) .Returns(ResultList.CreateFrom(8, asset1, asset2)); - var actual = await sut.QueryAsync(requestContext, parentId, q, ct); + var actual = await sut.QueryAsync(ApiContext, parentId, q, CancellationToken); Assert.Equal(8, actual.Total); @@ -206,10 +198,10 @@ public class AssetQueryServiceTests var assetFolders = ResultList.CreateFrom(10); - A.CallTo(() => assetFolderRepository.QueryAsync(appId.Id, parentId, A._)) + A.CallTo(() => assetFolderRepository.QueryAsync(AppId.Id, parentId, A._)) .Returns(assetFolders); - var actual = await sut.QueryAssetFoldersAsync(requestContext, parentId, ct); + var actual = await sut.QueryAssetFoldersAsync(ApiContext, parentId, CancellationToken); Assert.Same(assetFolders, actual); } @@ -221,10 +213,10 @@ public class AssetQueryServiceTests var assetFolders = ResultList.CreateFrom(10); - A.CallTo(() => assetFolderRepository.QueryAsync(appId.Id, parentId, A._)) + A.CallTo(() => assetFolderRepository.QueryAsync(AppId.Id, parentId, A._)) .Returns(assetFolders); - var actual = await sut.QueryAssetFoldersAsync(appId.Id, parentId, ct); + var actual = await sut.QueryAssetFoldersAsync(AppId.Id, parentId, CancellationToken); Assert.Same(assetFolders, actual); } @@ -235,10 +227,10 @@ public class AssetQueryServiceTests var folderId1 = DomainId.NewGuid(); var folder1 = CreateFolder(folderId1); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1, A._)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(AppId.Id, folderId1, A._)) .Returns(folder1); - var actual = await sut.FindAssetFolderAsync(appId.Id, folderId1, ct); + var actual = await sut.FindAssetFolderAsync(AppId.Id, folderId1, CancellationToken); Assert.Equal(actual, new[] { folder1 }); } @@ -254,16 +246,16 @@ public class AssetQueryServiceTests var folder2 = CreateFolder(folderId2, folderId1); var folder3 = CreateFolder(folderId3, folderId2); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1, A._)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(AppId.Id, folderId1, A._)) .Returns(folder1); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId2, A._)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(AppId.Id, folderId2, A._)) .Returns(folder2); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId3, A._)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(AppId.Id, folderId3, A._)) .Returns(folder3); - var actual = await sut.FindAssetFolderAsync(appId.Id, folderId3, ct); + var actual = await sut.FindAssetFolderAsync(AppId.Id, folderId3, CancellationToken); Assert.Equal(actual, new[] { folder1, folder2, folder3 }); } @@ -273,10 +265,10 @@ public class AssetQueryServiceTests { var folderId1 = DomainId.NewGuid(); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1, A._)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(AppId.Id, folderId1, A._)) .Returns(Task.FromResult(null)); - var actual = await sut.FindAssetFolderAsync(appId.Id, folderId1, ct); + var actual = await sut.FindAssetFolderAsync(AppId.Id, folderId1, CancellationToken); Assert.Empty(actual); } @@ -290,13 +282,13 @@ public class AssetQueryServiceTests var folder1 = CreateFolder(folderId1); var folder2 = CreateFolder(folderId2, folderId1); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1, A._)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(AppId.Id, folderId1, A._)) .Returns(Task.FromResult(null)); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId2, A._)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(AppId.Id, folderId2, A._)) .Returns(folder2); - var actual = await sut.FindAssetFolderAsync(appId.Id, folderId2, ct); + var actual = await sut.FindAssetFolderAsync(AppId.Id, folderId2, CancellationToken); Assert.Empty(actual); } @@ -310,13 +302,13 @@ public class AssetQueryServiceTests var folder1 = CreateFolder(folderId1, folderId2); var folder2 = CreateFolder(folderId2, folderId1); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId1, A._)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(AppId.Id, folderId1, A._)) .Returns(Task.FromResult(null)); - A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(appId.Id, folderId2, A._)) + A.CallTo(() => assetFolderRepository.FindAssetFolderAsync(AppId.Id, folderId2, A._)) .Returns(folder2); - var actual = await sut.FindAssetFolderAsync(appId.Id, folderId2, ct); + var actual = await sut.FindAssetFolderAsync(AppId.Id, folderId2, CancellationToken); Assert.Empty(actual); } @@ -345,7 +337,7 @@ public class AssetQueryServiceTests private void SetupEnricher() { - A.CallTo(() => assetEnricher.EnrichAsync(A>._, A._, ct)) + A.CallTo(() => assetEnricher.EnrichAsync(A>._, A._, CancellationToken)) .ReturnsLazily(x => { var input = x.GetArgument>(0)!; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/CalculateTokensTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/CalculateTokensTests.cs new file mode 100644 index 000000000..3f795ba65 --- /dev/null +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/CalculateTokensTests.cs @@ -0,0 +1,66 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Core; +using Squidex.Domain.Apps.Entities.Assets.Queries.Steps; +using Squidex.Domain.Apps.Entities.TestHelpers; +using Squidex.Infrastructure.Json; + +namespace Squidex.Domain.Apps.Entities.Assets.Queries; + +public class CalculateTokensTests : GivenContext +{ + private readonly IJsonSerializer serializer = A.Fake(); + private readonly IUrlGenerator urlGenerator = A.Fake(); + private readonly CalculateTokens sut; + + public CalculateTokensTests() + { + sut = new CalculateTokens(urlGenerator, serializer); + } + + [Fact] + public async Task Should_not_enrich_asset_edit_tokens_if_disabled() + { + var asset = CreateAsset(); + + await sut.EnrichAsync(ApiContext.Clone(b => b.WithoutAssetEnrichment()), Enumerable.Repeat(asset, 1), default); + + Assert.Null(asset.EditToken); + } + + [Fact] + public async Task Should_compute_ui_tokens() + { + var asset = CreateAsset(); + + await sut.EnrichAsync(ApiContext, new[] { asset }, CancellationToken); + + Assert.NotNull(asset.EditToken); + + A.CallTo(() => urlGenerator.Root()) + .MustHaveHappened(); + } + + [Fact] + public async Task Should_also_compute_ui_tokens_for_frontend() + { + var asset = CreateAsset(); + + await sut.EnrichAsync(FrontendContext, new[] { asset }, CancellationToken); + + Assert.NotNull(asset.EditToken); + + A.CallTo(() => urlGenerator.Root()) + .MustHaveHappened(); + } + + private AssetEntity CreateAsset() + { + return new AssetEntity { AppId = AppId }; + } +} diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/ConvertTagsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/ConvertTagsTests.cs new file mode 100644 index 000000000..4842ea7ae --- /dev/null +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/ConvertTagsTests.cs @@ -0,0 +1,107 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Core.Tags; +using Squidex.Domain.Apps.Core.TestHelpers; +using Squidex.Domain.Apps.Entities.Assets.Queries.Steps; +using Squidex.Domain.Apps.Entities.TestHelpers; +using Squidex.Infrastructure; + +namespace Squidex.Domain.Apps.Entities.Assets.Queries; + +public class ConvertTagsTests : GivenContext +{ + private readonly ITagService tagService = A.Fake(); + private readonly ConvertTags sut; + + public ConvertTagsTests() + { + sut = new ConvertTags(tagService); + } + + [Fact] + public async Task Should_not_enrich_if_asset_has_null_tags() + { + var asset = new AssetEntity(); + + await sut.EnrichAsync(ApiContext, Enumerable.Repeat(asset, 1), CancellationToken); + + Assert.Empty(asset.TagNames); + } + + [Fact] + public async Task Should_not_enrich_asset_with_tag_names_if_disabled() + { + var asset = new AssetEntity(); + + await sut.EnrichAsync(ApiContext.Clone(b => b.WithoutAssetEnrichment()), Enumerable.Repeat(asset, 1), CancellationToken); + + Assert.Null(asset.TagNames); + } + + [Fact] + public async Task Should_enrich_asset_with_tag_names() + { + var asset = new AssetEntity + { + Tags = new HashSet + { + "id1", + "id2" + }, + AppId = AppId + }; + + A.CallTo(() => tagService.GetTagNamesAsync(AppId.Id, TagGroups.Assets, A>.That.Is("id1", "id2"), CancellationToken)) + .Returns(new Dictionary + { + ["id1"] = "name1", + ["id2"] = "name2" + }); + + await sut.EnrichAsync(ApiContext, Enumerable.Repeat(asset, 1), CancellationToken); + + Assert.Equal(new HashSet { "name1", "name2" }, asset.TagNames); + } + + [Fact] + public async Task Should_enrich_multiple_assets_with_tag_names() + { + var asset1 = new AssetEntity + { + Tags = new HashSet + { + "id1", + "id2" + }, + AppId = AppId + }; + + var asset2 = new AssetEntity + { + Tags = new HashSet + { + "id2", + "id3" + }, + AppId = AppId + }; + + A.CallTo(() => tagService.GetTagNamesAsync(AppId.Id, TagGroups.Assets, A>.That.Is("id1", "id2", "id3"), CancellationToken)) + .Returns(new Dictionary + { + ["id1"] = "name1", + ["id2"] = "name2", + ["id3"] = "name3" + }); + + await sut.EnrichAsync(ApiContext, new[] { asset1, asset2 }, CancellationToken); + + Assert.Equal(new HashSet { "name1", "name2" }, asset1.TagNames); + Assert.Equal(new HashSet { "name2", "name3" }, asset2.TagNames); + } +} diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/EnrichForCachingTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/EnrichForCachingTests.cs new file mode 100644 index 000000000..acb65e0f1 --- /dev/null +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/EnrichForCachingTests.cs @@ -0,0 +1,66 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Entities.Assets.Queries.Steps; +using Squidex.Domain.Apps.Entities.TestHelpers; +using Squidex.Infrastructure; +using Squidex.Infrastructure.Caching; + +namespace Squidex.Domain.Apps.Entities.Assets.Queries; + +public class EnrichForCachingTests : GivenContext +{ + private readonly IRequestCache requestCache = A.Fake(); + private readonly EnrichForCaching sut; + + public EnrichForCachingTests() + { + sut = new EnrichForCaching(requestCache); + } + + [Fact] + public async Task Should_add_cache_headers() + { + var headers = new List(); + + A.CallTo(() => requestCache.AddHeader(A._)) + .Invokes(new Action(header => headers.Add(header))); + + await sut.EnrichAsync(ApiContext, CancellationToken); + + Assert.Equal(new List + { + "X-Flatten", + "X-Languages", + "X-NoCleanup", + "X-NoEnrichment", + "X-NoResolveLanguages", + "X-ResolveFlow", + "X-Resolve-Urls", + "X-Unpublished" + }, headers); + } + + [Fact] + public async Task Should_add_app_version_as_dependency() + { + var asset = CreateAsset(); + + await sut.EnrichAsync(ApiContext, Enumerable.Repeat(asset, 1), CancellationToken); + + A.CallTo(() => requestCache.AddDependency(asset.UniqueId, asset.Version)) + .MustHaveHappened(); + + A.CallTo(() => requestCache.AddDependency(App.UniqueId, App.Version)) + .MustHaveHappened(); + } + + private AssetEntity CreateAsset() + { + return new AssetEntity { AppId = AppId, Id = DomainId.NewGuid(), Version = 13 }; + } +} diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/EnrichWithMetadataTextTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/EnrichWithMetadataTextTests.cs new file mode 100644 index 000000000..fa99707b5 --- /dev/null +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/EnrichWithMetadataTextTests.cs @@ -0,0 +1,68 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Entities.Assets.Queries.Steps; +using Squidex.Domain.Apps.Entities.TestHelpers; + +namespace Squidex.Domain.Apps.Entities.Assets.Queries; + +public class EnrichWithMetadataTextTests : GivenContext +{ + private readonly IAssetMetadataSource assetMetadataSource1 = A.Fake(); + private readonly IAssetMetadataSource assetMetadataSource2 = A.Fake(); + private readonly EnrichWithMetadataText sut; + + public EnrichWithMetadataTextTests() + { + var assetMetadataSources = new[] + { + assetMetadataSource1, + assetMetadataSource2 + }; + + sut = new EnrichWithMetadataText(assetMetadataSources); + } + + [Fact] + public async Task Should_not_enrich_if_disabled() + { + var asset = new AssetEntity(); + + await sut.EnrichAsync(ApiContext.Clone(b => b.WithoutAssetEnrichment()), Enumerable.Repeat(asset, 1), CancellationToken); + + A.CallTo(() => assetMetadataSource1.Format(A._)) + .MustNotHaveHappened(); + + A.CallTo(() => assetMetadataSource2.Format(A._)) + .MustNotHaveHappened(); + } + + [Fact] + public async Task Should_enrich_asset_with_metadata() + { + var asset = new AssetEntity + { + FileSize = 2 * 1024, + Tags = new HashSet + { + "id1", + "id2" + }, + AppId = AppId + }; + + A.CallTo(() => assetMetadataSource1.Format(A._)) + .Returns(new[] { "metadata1" }); + + A.CallTo(() => assetMetadataSource2.Format(A._)) + .Returns(new[] { "metadata2", "metadata3" }); + + await sut.EnrichAsync(FrontendContext, Enumerable.Repeat(asset, 1), CancellationToken); + + Assert.Equal("metadata1, metadata2, metadata3, 2 kB", asset.MetadataText); + } +} diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/ScriptAssetTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/ScriptAssetTests.cs new file mode 100644 index 000000000..ca23df09c --- /dev/null +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/ScriptAssetTests.cs @@ -0,0 +1,107 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Core.Assets; +using Squidex.Domain.Apps.Core.Scripting; +using Squidex.Domain.Apps.Entities.Assets.Queries.Steps; +using Squidex.Domain.Apps.Entities.TestHelpers; +using Squidex.Infrastructure; + +namespace Squidex.Domain.Apps.Entities.Assets.Queries; + +public class ScriptAssetTests : GivenContext +{ + private readonly IScriptEngine scriptEngine = A.Fake(); + private readonly ScriptAsset sut; + + public ScriptAssetTests() + { + sut = new ScriptAsset(scriptEngine); + } + + [Fact] + public async Task Should_not_call_script_engine_if_no_script_configured() + { + var asset = new AssetEntity(); + + await sut.EnrichAsync(ApiContext, new[] { asset }, CancellationToken); + + A.CallTo(() => scriptEngine.ExecuteAsync(A._, A._, ScriptOptions(), A._)) + .MustNotHaveHappened(); + } + + [Fact] + public async Task Should_not_call_script_engine_for_frontend_user() + { + A.CallTo(() => App.AssetScripts) + .Returns(new AssetScripts { Query = "my-query" }); + + var asset = new AssetEntity(); + + await sut.EnrichAsync(FrontendContext, new[] { asset }, CancellationToken); + + A.CallTo(() => scriptEngine.ExecuteAsync(A._, A._, ScriptOptions(), A._)) + .MustNotHaveHappened(); + } + + [Fact] + public async Task Should_call_script_engine() + { + A.CallTo(() => App.AssetScripts) + .Returns(new AssetScripts { Query = "my-query" }); + + var asset = new AssetEntity { Id = DomainId.NewGuid() }; + + await sut.EnrichAsync(ApiContext, new[] { asset }, CancellationToken); + + A.CallTo(() => scriptEngine.ExecuteAsync( + A.That.Matches(x => + Equals(x["assetId"], asset.Id) && + Equals(x["appId"], AppId.Id) && + Equals(x["appName"], AppId.Name) && + Equals(x["user"], ApiContext.UserPrincipal)), + "my-query", + ScriptOptions(), CancellationToken)) + .MustHaveHappened(); + } + + [Fact] + public async Task Should_make_test_with_pre_query_script() + { + A.CallTo(() => App.AssetScripts) + .Returns(new AssetScripts { Query = "my-query", QueryPre = "my-pre-query" }); + + var asset = new AssetEntity { Id = DomainId.NewGuid() }; + + await sut.EnrichAsync(ApiContext, new[] { asset }, CancellationToken); + + A.CallTo(() => scriptEngine.ExecuteAsync( + A.That.Matches(x => + Equals(x.GetValue("assetId"), null) && + Equals(x["appId"], AppId.Id) && + Equals(x["appName"], AppId.Name) && + Equals(x["user"], ApiContext.UserPrincipal)), + "my-pre-query", + ScriptOptions(), CancellationToken)) + .MustHaveHappened(); + + A.CallTo(() => scriptEngine.ExecuteAsync( + A.That.Matches(x => + Equals(x.GetValue("assetId"), asset.Id) && + Equals(x["appId"], AppId.Id) && + Equals(x["appName"], AppId.Name) && + Equals(x["user"], ApiContext.UserPrincipal)), + "my-query", + ScriptOptions(), CancellationToken)) + .MustHaveHappened(); + } + + private static ScriptOptions ScriptOptions() + { + return A.That.Matches(x => x.AsContext); + } +} diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RecursiveDeleterTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RecursiveDeleterTests.cs index 0aa3a90b2..bfa4c048e 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RecursiveDeleterTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RecursiveDeleterTests.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Assets.Commands; using Squidex.Domain.Apps.Entities.Assets.Repositories; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events.Assets; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; @@ -16,13 +17,12 @@ using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities.Assets; -public class RecursiveDeleterTests +public class RecursiveDeleterTests : GivenContext { private readonly ILogger log = A.Fake>(); private readonly IAssetRepository assetRepository = A.Fake(); private readonly IAssetFolderRepository assetFolderRepository = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly RecursiveDeleter sut; public RecursiveDeleterTests() @@ -57,7 +57,7 @@ public class RecursiveDeleterTests [Fact] public async Task Should_Not_invoke_delete_commands_if_event_restored() { - var @event = new AssetFolderDeleted { AppId = appId, AssetFolderId = DomainId.NewGuid() }; + var @event = new AssetFolderDeleted { AppId = AppId, AssetFolderId = DomainId.NewGuid() }; await sut.On(Envelope.Create(@event).SetRestored()); @@ -68,12 +68,12 @@ public class RecursiveDeleterTests [Fact] public async Task Should_invoke_delete_commands_for_all_subfolders() { - var @event = new AssetFolderDeleted { AppId = appId, AssetFolderId = DomainId.NewGuid() }; + var @event = new AssetFolderDeleted { AppId = AppId, AssetFolderId = DomainId.NewGuid() }; var childFolderId1 = DomainId.NewGuid(); var childFolderId2 = DomainId.NewGuid(); - A.CallTo(() => assetFolderRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId, default)) + A.CallTo(() => assetFolderRepository.QueryChildIdsAsync(AppId.Id, @event.AssetFolderId, default)) .Returns(new List { childFolderId1, childFolderId2 }); await sut.On(Envelope.Create(@event)); @@ -88,12 +88,12 @@ public class RecursiveDeleterTests [Fact] public async Task Should_invoke_delete_commands_for_all_assets() { - var @event = new AssetFolderDeleted { AppId = appId, AssetFolderId = DomainId.NewGuid() }; + var @event = new AssetFolderDeleted { AppId = AppId, AssetFolderId = DomainId.NewGuid() }; var childId1 = DomainId.NewGuid(); var childId2 = DomainId.NewGuid(); - A.CallTo(() => assetRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId, default)) + A.CallTo(() => assetRepository.QueryChildIdsAsync(AppId.Id, @event.AssetFolderId, default)) .Returns(new List { childId1, childId2 }); await sut.On(Envelope.Create(@event)); @@ -108,7 +108,7 @@ public class RecursiveDeleterTests [Fact] public async Task Should_ignore_exceptions() { - var @event = new AssetFolderDeleted { AppId = appId, AssetFolderId = DomainId.NewGuid() }; + var @event = new AssetFolderDeleted { AppId = AppId, AssetFolderId = DomainId.NewGuid() }; var childId1 = DomainId.NewGuid(); var childId2 = DomainId.NewGuid(); @@ -116,7 +116,7 @@ public class RecursiveDeleterTests A.CallTo(() => commandBus.PublishAsync(A.That.Matches(x => x.AssetId == childId1), default)) .Throws(new InvalidOperationException()); - A.CallTo(() => assetRepository.QueryChildIdsAsync(appId.Id, @event.AssetFolderId, default)) + A.CallTo(() => assetRepository.QueryChildIdsAsync(AppId.Id, @event.AssetFolderId, default)) .Returns(new List { childId1, childId2 }); await sut.On(Envelope.Create(@event)); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RepairFilesTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RepairFilesTests.cs index 150898b0b..ba81142fd 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RepairFilesTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/RepairFilesTests.cs @@ -6,18 +6,18 @@ // ========================================================================== using Squidex.Assets; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events.Assets; using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities.Assets; -public class RepairFilesTests +public class RepairFilesTests : GivenContext { private readonly IEventStore eventStore = A.Fake(); private readonly IEventFormatter eventFormatter = A.Fake(); private readonly IAssetFileStore assetFileStore = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly RebuildFiles sut; public RepairFilesTests() @@ -28,64 +28,64 @@ public class RepairFilesTests [Fact] public async Task Should_repair_created_asset_if_not_found() { - var @event = new AssetCreated { AppId = appId, AssetId = DomainId.NewGuid() }; + var @event = new AssetCreated { AppId = AppId, AssetId = DomainId.NewGuid() }; SetupEvent(@event); - A.CallTo(() => assetFileStore.GetFileSizeAsync(appId.Id, @event.AssetId, 0, null, default)) + A.CallTo(() => assetFileStore.GetFileSizeAsync(AppId.Id, @event.AssetId, 0, null, CancellationToken)) .Throws(new AssetNotFoundException("file")); - await sut.RepairAsync(); + await sut.RepairAsync(CancellationToken); - A.CallTo(() => assetFileStore.UploadAsync(appId.Id, @event.AssetId, 0, null, A._, true, default)) + A.CallTo(() => assetFileStore.UploadAsync(AppId.Id, @event.AssetId, 0, null, A._, true, CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_not_repair_created_asset_if_found() { - var @event = new AssetCreated { AppId = appId, AssetId = DomainId.NewGuid() }; + var @event = new AssetCreated { AppId = AppId, AssetId = DomainId.NewGuid() }; SetupEvent(@event); - A.CallTo(() => assetFileStore.GetFileSizeAsync(appId.Id, @event.AssetId, 0, null, default)) + A.CallTo(() => assetFileStore.GetFileSizeAsync(AppId.Id, @event.AssetId, 0, null, CancellationToken)) .Returns(100); - await sut.RepairAsync(); + await sut.RepairAsync(CancellationToken); - A.CallTo(() => assetFileStore.UploadAsync(appId.Id, @event.AssetId, 0, null, A._, true, A._)) + A.CallTo(() => assetFileStore.UploadAsync(AppId.Id, @event.AssetId, 0, null, A._, true, A._)) .MustNotHaveHappened(); } [Fact] public async Task Should_repair_updated_asset_if_not_found() { - var @event = new AssetUpdated { AppId = appId, AssetId = DomainId.NewGuid(), FileVersion = 3 }; + var @event = new AssetUpdated { AppId = AppId, AssetId = DomainId.NewGuid(), FileVersion = 3 }; SetupEvent(@event); - A.CallTo(() => assetFileStore.GetFileSizeAsync(appId.Id, @event.AssetId, 3, null, A._)) + A.CallTo(() => assetFileStore.GetFileSizeAsync(AppId.Id, @event.AssetId, 3, null, CancellationToken)) .Throws(new AssetNotFoundException("file")); - await sut.RepairAsync(); + await sut.RepairAsync(CancellationToken); - A.CallTo(() => assetFileStore.UploadAsync(appId.Id, @event.AssetId, 3, null, A._, true, default)) + A.CallTo(() => assetFileStore.UploadAsync(AppId.Id, @event.AssetId, 3, null, A._, true, CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_not_repair_updated_asset_if_found() { - var @event = new AssetUpdated { AppId = appId, AssetId = DomainId.NewGuid(), FileVersion = 3 }; + var @event = new AssetUpdated { AppId = AppId, AssetId = DomainId.NewGuid(), FileVersion = 3 }; SetupEvent(@event); - A.CallTo(() => assetFileStore.GetFileSizeAsync(appId.Id, @event.AssetId, 3, null, default)) + A.CallTo(() => assetFileStore.GetFileSizeAsync(AppId.Id, @event.AssetId, 3, null, CancellationToken)) .Returns(100); - await sut.RepairAsync(); + await sut.RepairAsync(CancellationToken); - A.CallTo(() => assetFileStore.UploadAsync(appId.Id, @event.AssetId, 3, null, A._, true, A._)) + A.CallTo(() => assetFileStore.UploadAsync(AppId.Id, @event.AssetId, 3, null, A._, true, A._)) .MustNotHaveHappened(); } @@ -94,7 +94,7 @@ public class RepairFilesTests { SetupEvent(null); - await sut.RepairAsync(); + await sut.RepairAsync(CancellationToken); A.CallTo(() => assetFileStore.GetFileSizeAsync(A._, A._, A._, null, A._)) .MustNotHaveHappened(); @@ -122,7 +122,7 @@ public class RepairFilesTests .Returns(null); } - A.CallTo(() => eventStore.QueryAllAsync("^asset\\-", null, int.MaxValue, default)) + A.CallTo(() => eventStore.QueryAllAsync("^asset\\-", null, int.MaxValue, CancellationToken)) .Returns(storedEvents.ToAsyncEnumerable()); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/BackupServiceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/BackupServiceTests.cs index 8090a6ac5..d5850fb39 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/BackupServiceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/BackupServiceTests.cs @@ -14,20 +14,18 @@ using Squidex.Messaging; namespace Squidex.Domain.Apps.Entities.Backup; -public class BackupServiceTests +public class BackupServiceTests : GivenContext { private readonly TestState stateBackup; private readonly TestState stateRestore; private readonly IMessageBus messaging = A.Fake(); - private readonly DomainId appId = DomainId.NewGuid(); private readonly DomainId backupId = DomainId.NewGuid(); - private readonly RefToken actor = RefToken.User("me"); private readonly BackupService sut; public BackupServiceTests() { stateRestore = new TestState("Default"); - stateBackup = new TestState(appId); + stateBackup = new TestState(AppId.Id); sut = new BackupService( stateRestore.PersistenceFactory, @@ -40,36 +38,36 @@ public class BackupServiceTests var restoreUrl = new Uri("http://squidex.io"); var restoreAppName = "New App"; - await sut.StartRestoreAsync(actor, restoreUrl, restoreAppName); + await sut.StartRestoreAsync(User, restoreUrl, restoreAppName, CancellationToken); - A.CallTo(() => messaging.PublishAsync(new BackupRestore(actor, restoreUrl, restoreAppName), null, default)) + A.CallTo(() => messaging.PublishAsync(new BackupRestore(User, restoreUrl, restoreAppName), null, CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_send_message_to_start_backup() { - await sut.StartBackupAsync(appId, actor); + await sut.StartBackupAsync(AppId.Id, User, CancellationToken); - A.CallTo(() => messaging.PublishAsync(new BackupStart(appId, actor), null, default)) + A.CallTo(() => messaging.PublishAsync(new BackupStart(AppId.Id, User), null, CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_send_message_to_delete_backup() { - await sut.DeleteBackupAsync(appId, backupId); + await sut.DeleteBackupAsync(AppId.Id, backupId, CancellationToken); - A.CallTo(() => messaging.PublishAsync(new BackupDelete(appId, backupId), null, default)) + A.CallTo(() => messaging.PublishAsync(new BackupDelete(AppId.Id, backupId), null, CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_send_message_to_clear_backups() { - await ((IDeleter)sut).DeleteAppAsync(Mocks.App(NamedId.Of(appId, "my-app")), default); + await ((IDeleter)sut).DeleteAppAsync(App, CancellationToken); - A.CallTo(() => messaging.PublishAsync(new BackupClear(appId), null, default)) + A.CallTo(() => messaging.PublishAsync(new BackupClear(AppId.Id), null, CancellationToken)) .MustHaveHappened(); } @@ -86,7 +84,7 @@ public class BackupServiceTests var restoreUrl = new Uri("http://squidex.io"); - await Assert.ThrowsAnyAsync(() => sut.StartRestoreAsync(actor, restoreUrl, null)); + await Assert.ThrowsAnyAsync(() => sut.StartRestoreAsync(User, restoreUrl, null, CancellationToken)); } [Fact] @@ -97,7 +95,7 @@ public class BackupServiceTests stateBackup.Snapshot.Jobs.Add(new BackupJob()); } - await Assert.ThrowsAnyAsync(() => sut.StartBackupAsync(appId, actor)); + await Assert.ThrowsAnyAsync(() => sut.StartBackupAsync(AppId.Id, User, CancellationToken)); } [Fact] @@ -108,7 +106,7 @@ public class BackupServiceTests stateBackup.Snapshot.Jobs.Add(new BackupJob { Status = JobStatus.Started }); } - await Assert.ThrowsAnyAsync(() => sut.StartBackupAsync(appId, actor)); + await Assert.ThrowsAnyAsync(() => sut.StartBackupAsync(AppId.Id, User, CancellationToken)); } [Fact] @@ -122,7 +120,7 @@ public class BackupServiceTests } }; - var actual = await sut.GetRestoreAsync(); + var actual = await sut.GetRestoreAsync(CancellationToken); actual.Should().BeEquivalentTo(stateRestore.Snapshot.Job); } @@ -139,7 +137,7 @@ public class BackupServiceTests stateBackup.Snapshot.Jobs.Add(job); - var actual = await sut.GetBackupsAsync(appId); + var actual = await sut.GetBackupsAsync(AppId.Id, CancellationToken); actual.Should().BeEquivalentTo(stateBackup.Snapshot.Jobs); } @@ -156,7 +154,7 @@ public class BackupServiceTests stateBackup.Snapshot.Jobs.Add(job); - var actual = await sut.GetBackupAsync(appId, backupId); + var actual = await sut.GetBackupAsync(AppId.Id, backupId, CancellationToken); actual.Should().BeEquivalentTo(job); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/DefaultBackupArchiveStoreTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/DefaultBackupArchiveStoreTests.cs index 819ac7ba9..2854f321a 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/DefaultBackupArchiveStoreTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/DefaultBackupArchiveStoreTests.cs @@ -6,14 +6,13 @@ // ========================================================================== using Squidex.Assets; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Backup; -public class DefaultBackupArchiveStoreTests +public class DefaultBackupArchiveStoreTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IAssetStore assetStore = A.Fake(); private readonly DomainId backupId = DomainId.NewGuid(); private readonly string fileName; @@ -21,8 +20,6 @@ public class DefaultBackupArchiveStoreTests public DefaultBackupArchiveStoreTests() { - ct = cts.Token; - fileName = $"{backupId}_0"; sut = new DefaultBackupArchiveStore(assetStore); @@ -33,9 +30,9 @@ public class DefaultBackupArchiveStoreTests { var stream = new MemoryStream(); - await sut.UploadAsync(backupId, stream, ct); + await sut.UploadAsync(backupId, stream, CancellationToken); - A.CallTo(() => assetStore.UploadAsync(fileName, stream, true, ct)) + A.CallTo(() => assetStore.UploadAsync(fileName, stream, true, CancellationToken)) .MustHaveHappened(); } @@ -44,18 +41,18 @@ public class DefaultBackupArchiveStoreTests { var stream = new MemoryStream(); - await sut.DownloadAsync(backupId, stream, ct); + await sut.DownloadAsync(backupId, stream, CancellationToken); - A.CallTo(() => assetStore.DownloadAsync(fileName, stream, default, ct)) + A.CallTo(() => assetStore.DownloadAsync(fileName, stream, default, CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_invoke_asset_store_to_delete_archive_using_suffix_for_compatibility() { - await sut.DeleteAsync(backupId, ct); + await sut.DeleteAsync(backupId, CancellationToken); - A.CallTo(() => assetStore.DeleteAsync(fileName, ct)) + A.CallTo(() => assetStore.DeleteAsync(fileName, CancellationToken)) .MustHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/UserMappingTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/UserMappingTests.cs index ba670b44c..65b36560b 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/UserMappingTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Backup/UserMappingTests.cs @@ -6,22 +6,19 @@ // ========================================================================== using Squidex.Domain.Apps.Core.TestHelpers; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Shared.Users; namespace Squidex.Domain.Apps.Entities.Backup; -public class UserMappingTests +public class UserMappingTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; - private readonly RefToken initiator = Subject("me"); + private readonly RefToken initiator = RefToken.User("me"); private readonly UserMapping sut; public UserMappingTests() { - ct = cts.Token; - sut = new UserMapping(initiator); } @@ -29,9 +26,9 @@ public class UserMappingTests public async Task Should_backup_users_but_no_clients() { sut.Backup("1"); - sut.Backup(Subject("2")); + sut.Backup(RefToken.User("2")); - sut.Backup(Client("client")); + sut.Backup(RefToken.Client("client")); var user1 = UserMocks.User("1", "1@email.com"); var user2 = UserMocks.User("2", "1@email.com"); @@ -44,17 +41,17 @@ public class UserMappingTests var userResolver = A.Fake(); - A.CallTo(() => userResolver.QueryManyAsync(A.That.Is(user1.Id, user2.Id), ct)) + A.CallTo(() => userResolver.QueryManyAsync(A.That.Is(user1.Id, user2.Id), CancellationToken)) .Returns(users); var writer = A.Fake(); Dictionary? storedUsers = null; - A.CallTo(() => writer.WriteJsonAsync(A._, A._, ct)) + A.CallTo(() => writer.WriteJsonAsync(A._, A._, CancellationToken)) .Invokes(x => storedUsers = x.GetArgument>(1)); - await sut.StoreAsync(writer, userResolver, ct); + await sut.StoreAsync(writer, userResolver, CancellationToken); Assert.Equal(new Dictionary { @@ -73,25 +70,25 @@ public class UserMappingTests var userResolver = A.Fake(); - A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user1.Email, false, ct)) + A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user1.Email, false, CancellationToken)) .Returns((user1, false)); - A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user2.Email, false, ct)) + A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user2.Email, false, CancellationToken)) .Returns((user2, true)); - await sut.RestoreAsync(reader, userResolver, ct); + await sut.RestoreAsync(reader, userResolver, CancellationToken); Assert.True(sut.TryMap("1_old", out var mapped1)); - Assert.True(sut.TryMap(Subject("2_old"), out var mapped2)); + Assert.True(sut.TryMap(RefToken.User("2_old"), out var mapped2)); - Assert.Equal(Subject("1"), mapped1); - Assert.Equal(Subject("2"), mapped2); + Assert.Equal(RefToken.User("1"), mapped1); + Assert.Equal(RefToken.User("2"), mapped2); } [Fact] public void Should_return_initiator_if_user_not_found() { - var user = Subject("user1"); + var user = RefToken.User("user1"); Assert.False(sut.TryMap(user, out var mapped)); Assert.Same(initiator, mapped); @@ -100,7 +97,7 @@ public class UserMappingTests [Fact] public void Should_create_same_token_if_mapping_client() { - var client = Client("client1"); + var client = RefToken.Client("client1"); Assert.True(sut.TryMap(client, out var mapped)); Assert.Same(client, mapped); @@ -112,19 +109,9 @@ public class UserMappingTests var reader = A.Fake(); - A.CallTo(() => reader.ReadJsonAsync>(A._, ct)) + A.CallTo(() => reader.ReadJsonAsync>(A._, CancellationToken)) .Returns(storedUsers); return reader; } - - private static RefToken Client(string identifier) - { - return RefToken.Client(identifier); - } - - private static RefToken Subject(string identifier) - { - return RefToken.User(identifier); - } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Billing/UsageGateTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Billing/UsageGateTests.cs index 1c44f7796..357d12cc8 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Billing/UsageGateTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Billing/UsageGateTests.cs @@ -7,7 +7,6 @@ using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Apps; -using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Assets; using Squidex.Domain.Apps.Entities.Teams; using Squidex.Domain.Apps.Entities.TestHelpers; @@ -17,20 +16,14 @@ using Squidex.Messaging; namespace Squidex.Domain.Apps.Entities.Billing; -public class UsageGateTests +public class UsageGateTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IMessageBus messaging = A.Fake(); private readonly IApiUsageTracker apiUsageTracker = A.Fake(); - private readonly IAppEntity appWithoutTeam; - private readonly IAppEntity appWithTeam; - private readonly IAppProvider appProvider = A.Fake(); private readonly IBillingPlans billingPlans = A.Fake(); private readonly IUsageTracker usageTracker = A.Fake(); private readonly string clientId = Guid.NewGuid().ToString(); private readonly DomainId teamId = DomainId.NewGuid(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly DateTime today = new DateTime(2020, 10, 3); private readonly Plan planFree = new Plan { Id = "free" }; private readonly Plan planPaid = new Plan { Id = "paid" }; @@ -38,14 +31,6 @@ public class UsageGateTests public UsageGateTests() { - appWithoutTeam = Mocks.App(appId); - appWithTeam = Mocks.App(appId); - - ct = cts.Token; - - A.CallTo(() => appWithTeam.TeamId) - .Returns(teamId); - A.CallTo(() => billingPlans.GetActualPlan(A._)) .ReturnsLazily(x => (planFree, planFree.Id)); @@ -55,31 +40,31 @@ public class UsageGateTests A.CallTo(() => usageTracker.FallbackCategory) .Returns("*"); - sut = new UsageGate(appProvider, apiUsageTracker, billingPlans, messaging, usageTracker); + sut = new UsageGate(AppProvider, apiUsageTracker, billingPlans, messaging, usageTracker); } [Fact] public async Task Should_delete_app_asset_usage() { - await sut.DeleteAssetUsageAsync(appId.Id, ct); + await sut.DeleteAssetUsageAsync(AppId.Id, CancellationToken); - A.CallTo(() => usageTracker.DeleteAsync($"{appId.Id}_Assets", ct)) + A.CallTo(() => usageTracker.DeleteAsync($"{AppId.Id}_Assets", CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_delete_assets_usage() { - await sut.DeleteAssetsUsageAsync(ct); + await sut.DeleteAssetsUsageAsync(CancellationToken); - A.CallTo(() => usageTracker.DeleteByKeyPatternAsync("^([a-zA-Z0-9]+)_Assets", ct)) + A.CallTo(() => usageTracker.DeleteByKeyPatternAsync("^([a-zA-Z0-9]+)_Assets", CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_get_free_plan_for_app() { - var plan = await sut.GetPlanForAppAsync(appWithoutTeam, false, ct); + var plan = await sut.GetPlanForAppAsync(App, false, CancellationToken); Assert.Equal((planFree, planFree.Id, null), plan); } @@ -89,13 +74,16 @@ public class UsageGateTests { var team = A.Fake(); - A.CallTo(() => appProvider.GetTeamAsync(teamId, ct)) + A.CallTo(() => AppProvider.GetTeamAsync(teamId, CancellationToken)) .Returns(team); A.CallTo(() => team.Id) .Returns(teamId); - var plan = await sut.GetPlanForAppAsync(appWithTeam, false, ct); + A.CallTo(() => App.TeamId) + .Returns(teamId); + + var plan = await sut.GetPlanForAppAsync(App, false, CancellationToken); Assert.Equal((planFree, planFree.Id, teamId), plan); } @@ -103,10 +91,10 @@ public class UsageGateTests [Fact] public async Task Should_get_paid_plan_for_app() { - A.CallTo(() => appWithoutTeam.Plan) + A.CallTo(() => App.Plan) .Returns(new AssignedPlan(RefToken.User("1"), planPaid.Id)); - var plan = await sut.GetPlanForAppAsync(appWithoutTeam, false, ct); + var plan = await sut.GetPlanForAppAsync(App, false, CancellationToken); Assert.Equal((planPaid, planPaid.Id, null), plan); } @@ -114,13 +102,10 @@ public class UsageGateTests [Fact] public async Task Should_get_paid_plan_for_app_id() { - A.CallTo(() => appProvider.GetAppAsync(appWithoutTeam.Id, true, ct)) - .Returns(appWithoutTeam); - - A.CallTo(() => appWithoutTeam.Plan) + A.CallTo(() => App.Plan) .Returns(new AssignedPlan(RefToken.User("1"), planPaid.Id)); - var plan = await sut.GetPlanForAppAsync(appWithoutTeam.Id, false, ct); + var plan = await sut.GetPlanForAppAsync(AppId.Id, false, CancellationToken); Assert.Equal((planPaid, planPaid.Id, null), plan); } @@ -130,7 +115,7 @@ public class UsageGateTests { var team = A.Fake(); - A.CallTo(() => appProvider.GetTeamAsync(teamId, ct)) + A.CallTo(() => AppProvider.GetTeamAsync(teamId, CancellationToken)) .Returns(team); A.CallTo(() => team.Id) @@ -139,7 +124,10 @@ public class UsageGateTests A.CallTo(() => team.Plan) .Returns(new AssignedPlan(RefToken.User("1"), planPaid.Id)); - var plan = await sut.GetPlanForAppAsync(appWithTeam, false, ct); + A.CallTo(() => App.TeamId) + .Returns(teamId); + + var plan = await sut.GetPlanForAppAsync(App, false, CancellationToken); Assert.Equal((planPaid, planPaid.Id, teamId), plan); } @@ -152,17 +140,17 @@ public class UsageGateTests A.CallTo(() => billingPlans.GetActualPlan(A._)) .ReturnsLazily(x => (plan, plan.Id)); - A.CallTo(() => appWithoutTeam.Clients) + A.CallTo(() => App.Clients) .Returns(AppClients.Empty.Add(clientId, clientId).Update(clientId, apiCallsLimit: 1000)); - A.CallTo(() => apiUsageTracker.GetMonthCallsAsync(appId.Id.ToString(), today, A._, ct)) + A.CallTo(() => apiUsageTracker.GetMonthCallsAsync(AppId.Id.ToString(), today, A._, CancellationToken)) .Returns(1000); - var isBlocked = await sut.IsBlockedAsync(appWithoutTeam, clientId, today, ct); + var isBlocked = await sut.IsBlockedAsync(App, clientId, today, CancellationToken); Assert.True(isBlocked); - A.CallTo(() => messaging.PublishAsync(A._, null, ct)) + A.CallTo(() => messaging.PublishAsync(A._, null, CancellationToken)) .MustHaveHappened(); } @@ -174,14 +162,14 @@ public class UsageGateTests A.CallTo(() => billingPlans.GetActualPlan(A._)) .ReturnsLazily(x => (plan, plan.Id)); - A.CallTo(() => apiUsageTracker.GetMonthCallsAsync(appId.Id.ToString(), today, A._, ct)) + A.CallTo(() => apiUsageTracker.GetMonthCallsAsync(AppId.Id.ToString(), today, A._, CancellationToken)) .Returns(1000); - var isBlocked = await sut.IsBlockedAsync(appWithoutTeam, clientId, today, ct); + var isBlocked = await sut.IsBlockedAsync(App, clientId, today, CancellationToken); Assert.True(isBlocked); - A.CallTo(() => messaging.PublishAsync(A._, null, ct)) + A.CallTo(() => messaging.PublishAsync(A._, null, CancellationToken)) .MustHaveHappened(); } @@ -193,10 +181,10 @@ public class UsageGateTests A.CallTo(() => billingPlans.GetActualPlan(A._)) .ReturnsLazily(x => (plan, plan.Id)); - A.CallTo(() => apiUsageTracker.GetMonthCallsAsync(appId.Id.ToString(), today, A._, ct)) + A.CallTo(() => apiUsageTracker.GetMonthCallsAsync(AppId.Id.ToString(), today, A._, CancellationToken)) .Returns(100); - var isBlocked = await sut.IsBlockedAsync(appWithoutTeam, clientId, today, ct); + var isBlocked = await sut.IsBlockedAsync(App, clientId, today, CancellationToken); Assert.False(isBlocked); @@ -212,14 +200,14 @@ public class UsageGateTests A.CallTo(() => billingPlans.GetActualPlan(A._)) .ReturnsLazily(x => (plan, plan.Id)); - A.CallTo(() => apiUsageTracker.GetMonthCallsAsync(appId.Id.ToString(), today, A._, ct)) + A.CallTo(() => apiUsageTracker.GetMonthCallsAsync(AppId.Id.ToString(), today, A._, CancellationToken)) .Returns(1200); // in 10 days = 4000 / month - var isBlocked = await sut.IsBlockedAsync(appWithoutTeam, clientId, today, ct); + var isBlocked = await sut.IsBlockedAsync(App, clientId, today, CancellationToken); Assert.False(isBlocked); - A.CallTo(() => messaging.PublishAsync(A._, null, ct)) + A.CallTo(() => messaging.PublishAsync(A._, null, CancellationToken)) .MustHaveHappened(); } @@ -231,14 +219,14 @@ public class UsageGateTests A.CallTo(() => billingPlans.GetActualPlan(A._)) .ReturnsLazily(x => (plan, plan.Id)); - A.CallTo(() => apiUsageTracker.GetMonthCallsAsync(appId.Id.ToString(), today, A._, ct)) + A.CallTo(() => apiUsageTracker.GetMonthCallsAsync(AppId.Id.ToString(), today, A._, CancellationToken)) .Returns(1200); // in 10 days = 4000 / month - var isBlocked = await sut.IsBlockedAsync(appWithoutTeam, clientId, today, ct); + var isBlocked = await sut.IsBlockedAsync(App, clientId, today, CancellationToken); Assert.False(isBlocked); - A.CallTo(() => messaging.PublishAsync(A._, null, ct)) + A.CallTo(() => messaging.PublishAsync(A._, null, CancellationToken)) .MustHaveHappened(); } @@ -250,13 +238,13 @@ public class UsageGateTests A.CallTo(() => billingPlans.GetActualPlan(A._)) .ReturnsLazily(x => (plan, plan.Id)); - A.CallTo(() => apiUsageTracker.GetMonthCallsAsync(appId.Id.ToString(), today, A._, ct)) + A.CallTo(() => apiUsageTracker.GetMonthCallsAsync(AppId.Id.ToString(), today, A._, CancellationToken)) .Returns(1200); // in 10 days = 4000 / month - await sut.IsBlockedAsync(appWithoutTeam, clientId, today, ct); - await sut.IsBlockedAsync(appWithoutTeam, clientId, today, ct); + await sut.IsBlockedAsync(App, clientId, today, CancellationToken); + await sut.IsBlockedAsync(App, clientId, today, CancellationToken); - A.CallTo(() => messaging.PublishAsync(A._, null, ct)) + A.CallTo(() => messaging.PublishAsync(A._, null, CancellationToken)) .MustHaveHappenedOnceExactly(); } @@ -270,11 +258,11 @@ public class UsageGateTests A.CallTo(() => billingPlans.GetActualPlan(A._)) .ReturnsLazily(x => (plan, plan.Id)); - A.CallTo(() => apiUsageTracker.GetMonthCallsAsync(appId.Id.ToString(), now, A._, ct)) + A.CallTo(() => apiUsageTracker.GetMonthCallsAsync(AppId.Id.ToString(), now, A._, CancellationToken)) .Returns(220); // in 3 days = 3300 / month - await sut.IsBlockedAsync(appWithoutTeam, clientId, now, ct); - await sut.IsBlockedAsync(appWithoutTeam, clientId, now, ct); + await sut.IsBlockedAsync(App, clientId, now, CancellationToken); + await sut.IsBlockedAsync(App, clientId, now, CancellationToken); A.CallTo(() => messaging.PublishAsync(A._, null, A._)) .MustNotHaveHappened(); @@ -283,10 +271,10 @@ public class UsageGateTests [Fact] public async Task Should_get_app_asset_total_size_from_summary_date() { - A.CallTo(() => usageTracker.GetAsync($"{appId.Id}_Assets", default, default, null, ct)) + A.CallTo(() => usageTracker.GetAsync($"{AppId.Id}_Assets", default, default, null, CancellationToken)) .Returns(new Counters { ["TotalSize"] = 2048 }); - var size = await sut.GetTotalSizeByAppAsync(appId.Id, ct); + var size = await sut.GetTotalSizeByAppAsync(AppId.Id, CancellationToken); Assert.Equal(2048, size); } @@ -294,10 +282,10 @@ public class UsageGateTests [Fact] public async Task Should_get_team_asset_total_size_from_summary_date() { - A.CallTo(() => usageTracker.GetAsync($"{appId.Id}_TeamAssets", default, default, null, ct)) + A.CallTo(() => usageTracker.GetAsync($"{AppId.Id}_TeamAssets", default, default, null, CancellationToken)) .Returns(new Counters { ["TotalSize"] = 2048 }); - var size = await sut.GetTotalSizeByTeamAsync(appId.Id, ct); + var size = await sut.GetTotalSizeByTeamAsync(AppId.Id, CancellationToken); Assert.Equal(2048, size); } @@ -305,27 +293,30 @@ public class UsageGateTests [Fact] public async Task Should_track_request_async() { - await sut.TrackRequestAsync(appWithoutTeam, "client", today, 42, 50, 512, ct); + await sut.TrackRequestAsync(App, "client", today, 42, 50, 512, CancellationToken); - A.CallTo(() => apiUsageTracker.TrackAsync(today, appWithoutTeam.Id.ToString(), "client", 42, 50, 512, ct)) + A.CallTo(() => apiUsageTracker.TrackAsync(today, AppId.Id.ToString(), "client", 42, 50, 512, CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_track_request_for_team_async() { - await sut.TrackRequestAsync(appWithTeam, "client", today, 42, 50, 512, ct); + A.CallTo(() => App.TeamId) + .Returns(teamId); + + await sut.TrackRequestAsync(App, "client", today, 42, 50, 512, CancellationToken); - A.CallTo(() => apiUsageTracker.TrackAsync(today, appWithTeam.TeamId!.ToString()!, appWithTeam.Name, 42, 50, 512, ct)) + A.CallTo(() => apiUsageTracker.TrackAsync(today, App.TeamId!.ToString()!, AppId.Name, 42, 50, 512, CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_get_app_asset_counters_from_categories() { - SetupAssetQuery($"{appId.Id}_Assets"); + SetupAssetQuery($"{AppId.Id}_Assets"); - var actual = await sut.QueryByAppAsync(appId.Id, today, today.AddDays(3), ct); + var actual = await sut.QueryByAppAsync(AppId.Id, today, today.AddDays(3), CancellationToken); actual.Should().BeEquivalentTo(new List { @@ -338,9 +329,9 @@ public class UsageGateTests [Fact] public async Task Should_get_team_asset_counters_from_categories() { - SetupAssetQuery($"{appId.Id}_TeamAssets"); + SetupAssetQuery($"{AppId.Id}_TeamAssets"); - var actual = await sut.QueryByTeamAsync(appId.Id, today, today.AddDays(3), ct); + var actual = await sut.QueryByTeamAsync(AppId.Id, today, today.AddDays(3), CancellationToken); actual.Should().BeEquivalentTo(new List { @@ -352,7 +343,7 @@ public class UsageGateTests private void SetupAssetQuery(string key) { - A.CallTo(() => usageTracker.QueryAsync(key, today, today.AddDays(3), ct)) + A.CallTo(() => usageTracker.QueryAsync(key, today, today.AddDays(3), CancellationToken)) .Returns(new Dictionary> { [usageTracker.FallbackCategory] = new List<(DateTime, Counters)> @@ -382,13 +373,13 @@ public class UsageGateTests Counters? countersSummary = null; Counters? countersDate = null; - A.CallTo(() => usageTracker.TrackAsync(default, $"{appId.Id}_Assets", null, A._, ct)) + A.CallTo(() => usageTracker.TrackAsync(default, $"{AppId.Id}_Assets", null, A._, CancellationToken)) .Invokes(x => countersSummary = x.GetArgument(3)); - A.CallTo(() => usageTracker.TrackAsync(today, $"{appId.Id}_Assets", null, A._, ct)) + A.CallTo(() => usageTracker.TrackAsync(today, $"{AppId.Id}_Assets", null, A._, CancellationToken)) .Invokes(x => countersDate = x.GetArgument(3)); - await sut.TrackAssetAsync(appWithoutTeam.Id, today, 512, 3, ct); + await sut.TrackAssetAsync(AppId.Id, today, 512, 3, CancellationToken); var expected = new Counters { @@ -411,19 +402,19 @@ public class UsageGateTests A.CallTo(() => team.Id) .Returns(teamId); - A.CallTo(() => appProvider.GetAppAsync(appWithTeam.Id, true, ct)) - .Returns(appWithTeam); + A.CallTo(() => App.TeamId) + .Returns(teamId); - A.CallTo(() => appProvider.GetTeamAsync(teamId, ct)) + A.CallTo(() => AppProvider.GetTeamAsync(teamId, CancellationToken)) .Returns(team); - A.CallTo(() => usageTracker.TrackAsync(default, $"{teamId}_TeamAssets", null, A._, ct)) + A.CallTo(() => usageTracker.TrackAsync(default, $"{teamId}_TeamAssets", null, A._, CancellationToken)) .Invokes(x => countersSummary = x.GetArgument(3)); - A.CallTo(() => usageTracker.TrackAsync(today, $"{teamId}_TeamAssets", null, A._, ct)) + A.CallTo(() => usageTracker.TrackAsync(today, $"{teamId}_TeamAssets", null, A._, CancellationToken)) .Invokes(x => countersDate = x.GetArgument(3)); - await sut.TrackAssetAsync(appWithTeam.Id, today, 512, 3, ct); + await sut.TrackAssetAsync(AppId.Id, today, 512, 3, CancellationToken); var expected = new Counters { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Billing/UsageNotifierWorkerTest.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Billing/UsageNotifierWorkerTest.cs index e1d2c8ddc..6bc29b1e4 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Billing/UsageNotifierWorkerTest.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Billing/UsageNotifierWorkerTest.cs @@ -16,29 +16,24 @@ using Squidex.Shared.Users; namespace Squidex.Domain.Apps.Entities.Billing; -public class UsageNotifierWorkerTest +public class UsageNotifierWorkerTest : GivenContext { private readonly TestState state = new TestState("Default"); private readonly IClock clock = A.Fake(); - private readonly IAppProvider appProvider = A.Fake(); private readonly IUserNotifications notificationSender = A.Fake(); private readonly IUserResolver userResolver = A.Fake(); - private readonly IAppEntity app = Mocks.App(NamedId.Of(DomainId.NewGuid(), "my-app")); private readonly UsageNotifierWorker sut; private Instant time = SystemClock.Instance.GetCurrentInstant(); public UsageNotifierWorkerTest() { - A.CallTo(() => appProvider.GetAppAsync(app.Id, true, default)) - .Returns(app); - A.CallTo(() => clock.GetCurrentInstant()) .ReturnsLazily(() => time); A.CallTo(() => notificationSender.IsActive) .Returns(true); - sut = new UsageNotifierWorker(state.PersistenceFactory, appProvider, notificationSender, userResolver) + sut = new UsageNotifierWorker(state.PersistenceFactory, AppProvider, notificationSender, userResolver) { Clock = clock }; @@ -61,7 +56,7 @@ public class UsageNotifierWorkerTest var message = new UsageTrackingCheck { - AppId = app.Id, + AppId = AppId.Id, Usage = 1000, UsageLimit = 3000, Users = new[] { "1", "2" } @@ -82,7 +77,7 @@ public class UsageNotifierWorkerTest var message = new UsageTrackingCheck { - AppId = app.Id, + AppId = AppId.Id, Usage = 1000, UsageLimit = 3000, Users = new[] { "1", "2", "3" } @@ -90,13 +85,13 @@ public class UsageNotifierWorkerTest await sut.HandleAsync(message, default); - A.CallTo(() => notificationSender.SendUsageAsync(user1!, app, 1000, 3000, default)) + A.CallTo(() => notificationSender.SendUsageAsync(user1!, App, 1000, 3000, default)) .MustHaveHappened(); - A.CallTo(() => notificationSender.SendUsageAsync(user2!, app, 1000, 3000, default)) + A.CallTo(() => notificationSender.SendUsageAsync(user2!, App, 1000, 3000, default)) .MustHaveHappened(); - A.CallTo(() => notificationSender.SendUsageAsync(user3!, app, 1000, 3000, default)) + A.CallTo(() => notificationSender.SendUsageAsync(user3!, App, 1000, 3000, default)) .MustNotHaveHappened(); } @@ -107,7 +102,7 @@ public class UsageNotifierWorkerTest var message = new UsageTrackingCheck { - AppId = app.Id, + AppId = AppId.Id, Usage = 1000, UsageLimit = 3000, Users = new[] { "1" } @@ -116,7 +111,7 @@ public class UsageNotifierWorkerTest await sut.HandleAsync(message, default); await sut.HandleAsync(message, default); - A.CallTo(() => notificationSender.SendUsageAsync(user!, app, 1000, 3000, default)) + A.CallTo(() => notificationSender.SendUsageAsync(user!, App, 1000, 3000, default)) .MustHaveHappenedOnceExactly(); } @@ -127,7 +122,7 @@ public class UsageNotifierWorkerTest var message = new UsageTrackingCheck { - AppId = app.Id, + AppId = AppId.Id, Usage = 1000, UsageLimit = 3000, Users = new[] { "1" } @@ -139,7 +134,7 @@ public class UsageNotifierWorkerTest await sut.HandleAsync(message, default); - A.CallTo(() => notificationSender.SendUsageAsync(user!, app, 1000, 3000, default)) + A.CallTo(() => notificationSender.SendUsageAsync(user!, App, 1000, 3000, default)) .MustHaveHappenedTwiceExactly(); } @@ -155,7 +150,7 @@ public class UsageNotifierWorkerTest var message = new UsageTrackingCheck { - AppId = app.Id, + AppId = AppId.Id, Usage = 1000, UsageLimit = 3000, Users = new[] { "1" } @@ -167,7 +162,7 @@ public class UsageNotifierWorkerTest await sut.HandleAsync(message, default); - A.CallTo(() => notificationSender.SendUsageAsync(user!, app, 1000, 3000, default)) + A.CallTo(() => notificationSender.SendUsageAsync(user!, App, 1000, 3000, default)) .MustHaveHappenedOnceExactly(); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsLoaderTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsLoaderTests.cs index fda228dfb..f00bf2395 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsLoaderTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/CommentsLoaderTests.cs @@ -6,22 +6,19 @@ // ========================================================================== using Squidex.Domain.Apps.Entities.Comments.DomainObject; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; namespace Squidex.Domain.Apps.Entities.Comments; -public sealed class CommentsLoaderTests +public sealed class CommentsLoaderTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IDomainObjectFactory domainObjectFactory = A.Fake(); private readonly CommentsLoader sut; public CommentsLoaderTests() { - ct = cts.Token; - sut = new CommentsLoader(domainObjectFactory); } @@ -39,11 +36,11 @@ public sealed class CommentsLoaderTests A.CallTo(() => domainObject.GetComments(11)) .Returns(comments); - var actual = await sut.GetCommentsAsync(commentsId, 11, ct); + var actual = await sut.GetCommentsAsync(commentsId, 11, CancellationToken); Assert.Same(comments, actual); - A.CallTo(() => domainObject.LoadAsync(ct)) + A.CallTo(() => domainObject.LoadAsync(CancellationToken)) .MustHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/DomainObject/CommentsCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/DomainObject/CommentsCommandMiddlewareTests.cs index cea8a034a..0a609eab8 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/DomainObject/CommentsCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/DomainObject/CommentsCommandMiddlewareTests.cs @@ -7,29 +7,24 @@ using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Comments.Commands; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Shared.Users; namespace Squidex.Domain.Apps.Entities.Comments.DomainObject; -public class CommentsCommandMiddlewareTests +public class CommentsCommandMiddlewareTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IDomainObjectFactory domainObjectFactory = A.Fake(); private readonly IUserResolver userResolver = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); - private readonly RefToken actor = RefToken.User("me"); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly DomainId commentsId = DomainId.NewGuid(); private readonly DomainId commentId = DomainId.NewGuid(); private readonly CommentsCommandMiddleware sut; public CommentsCommandMiddlewareTests() { - ct = cts.Token; - A.CallTo(() => userResolver.FindByIdOrEmailAsync(A._, default)) .Returns(Task.FromResult(null)); @@ -44,7 +39,7 @@ public class CommentsCommandMiddlewareTests var domainObject = A.Fake(); - A.CallTo(() => domainObject.ExecuteAsync(command, ct)) + A.CallTo(() => domainObject.ExecuteAsync(command, CancellationToken)) .Returns(CommandResult.Empty(commentsId, 0, 0)); A.CallTo(() => domainObjectFactory.Create(commentsId)) @@ -57,7 +52,7 @@ public class CommentsCommandMiddlewareTests isNextCalled = true; return Task.CompletedTask; - }, ct); + }, CancellationToken); Assert.True(isNextCalled); } @@ -76,7 +71,7 @@ public class CommentsCommandMiddlewareTests var context = CrateCommandContext(command); - await sut.HandleAsync(context, ct); + await sut.HandleAsync(context, CancellationToken); Assert.Equal(command.Mentions, new[] { "id1", "id2" }); } @@ -95,7 +90,7 @@ public class CommentsCommandMiddlewareTests var context = CrateCommandContext(command); - await sut.HandleAsync(context, ct); + await sut.HandleAsync(context, CancellationToken); A.CallTo(() => commandBus.PublishAsync(A._, A._)) .MustNotHaveHappened(); @@ -112,7 +107,7 @@ public class CommentsCommandMiddlewareTests var context = CrateCommandContext(command); - await sut.HandleAsync(context, ct); + await sut.HandleAsync(context, CancellationToken); A.CallTo(() => userResolver.FindByIdOrEmailAsync(A._, A._)) .MustNotHaveHappened(); @@ -129,7 +124,7 @@ public class CommentsCommandMiddlewareTests var context = CrateCommandContext(command); - await sut.HandleAsync(context, ct); + await sut.HandleAsync(context, CancellationToken); A.CallTo(() => userResolver.FindByIdOrEmailAsync(A._, A._)) .MustNotHaveHappened(); @@ -150,10 +145,10 @@ public class CommentsCommandMiddlewareTests private T CreateCommentsCommand(T command) where T : CommentCommand { - command.Actor = actor; - command.AppId = appId; + command.AppId = AppId; command.CommentsId = commentsId; command.CommentId = commentId; + command.Actor = User; return command; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/WatchingServiceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/WatchingServiceTests.cs index cfced1d49..e96a39a9a 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/WatchingServiceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Comments/WatchingServiceTests.cs @@ -6,19 +6,16 @@ // ========================================================================== using NodaTime; -using Squidex.Infrastructure; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure.TestHelpers; namespace Squidex.Domain.Apps.Entities.Comments; -public class WatchingServiceTests +public class WatchingServiceTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly TestState state1; private readonly TestState state2; private readonly IClock clock = A.Fake(); - private readonly DomainId appId = DomainId.NewGuid(); private readonly string resource1 = "resource1"; private readonly string resource2 = "resource2"; private readonly WatchingService sut; @@ -26,13 +23,11 @@ public class WatchingServiceTests public WatchingServiceTests() { - ct = cts.Token; - A.CallTo(() => clock.GetCurrentInstant()) .ReturnsLazily(() => now); - state1 = new TestState($"{appId}_{resource1}"); - state2 = new TestState($"{appId}_{resource2}", state1.PersistenceFactory); + state1 = new TestState($"{AppId.Id}_{resource1}"); + state2 = new TestState($"{AppId.Id}_{resource2}", state1.PersistenceFactory); sut = new WatchingService(state1.PersistenceFactory) { @@ -43,7 +38,7 @@ public class WatchingServiceTests [Fact] public async Task Should_only_return_self_if_no_one_watching() { - var watching = await sut.GetWatchingUsersAsync(appId, resource1, "user1", ct); + var watching = await sut.GetWatchingUsersAsync(AppId.Id, resource1, "user1", CancellationToken); Assert.Equal(new[] { "user1" }, watching); } @@ -51,11 +46,11 @@ public class WatchingServiceTests [Fact] public async Task Should_return_users_watching_on_same_resource() { - await sut.GetWatchingUsersAsync(appId, resource1, "user1", ct); - await sut.GetWatchingUsersAsync(appId, resource2, "user2", ct); + await sut.GetWatchingUsersAsync(AppId.Id, resource1, "user1", CancellationToken); + await sut.GetWatchingUsersAsync(AppId.Id, resource2, "user2", CancellationToken); - var watching1 = await sut.GetWatchingUsersAsync(appId, resource1, "user3", ct); - var watching2 = await sut.GetWatchingUsersAsync(appId, resource2, "user4", ct); + var watching1 = await sut.GetWatchingUsersAsync(AppId.Id, resource1, "user3", CancellationToken); + var watching2 = await sut.GetWatchingUsersAsync(AppId.Id, resource2, "user4", CancellationToken); Assert.Equal(new[] { "user1", "user3" }, watching1); Assert.Equal(new[] { "user2", "user4" }, watching2); @@ -64,24 +59,24 @@ public class WatchingServiceTests [Fact] public async Task Should_cleanup_old_users() { - await sut.GetWatchingUsersAsync(appId, resource1, "user1", ct); - await sut.GetWatchingUsersAsync(appId, resource2, "user2", ct); + await sut.GetWatchingUsersAsync(AppId.Id, resource1, "user1", CancellationToken); + await sut.GetWatchingUsersAsync(AppId.Id, resource2, "user2", CancellationToken); now = now.Plus(Duration.FromMinutes(2)); - await sut.GetWatchingUsersAsync(appId, resource1, "user3", ct); - await sut.GetWatchingUsersAsync(appId, resource2, "user4", ct); + await sut.GetWatchingUsersAsync(AppId.Id, resource1, "user3", CancellationToken); + await sut.GetWatchingUsersAsync(AppId.Id, resource2, "user4", CancellationToken); - var watching1 = await sut.GetWatchingUsersAsync(appId, resource1, "user5", ct); - var watching2 = await sut.GetWatchingUsersAsync(appId, resource2, "user6", ct); + var watching1 = await sut.GetWatchingUsersAsync(AppId.Id, resource1, "user5", CancellationToken); + var watching2 = await sut.GetWatchingUsersAsync(AppId.Id, resource2, "user6", CancellationToken); Assert.Equal(new[] { "user3", "user5" }, watching1); Assert.Equal(new[] { "user4", "user6" }, watching2); - A.CallTo(() => state1.Persistence.WriteSnapshotAsync(A._, ct)) + A.CallTo(() => state1.Persistence.WriteSnapshotAsync(A._, CancellationToken)) .MustHaveHappened(); - A.CallTo(() => state2.Persistence.WriteSnapshotAsync(A._, ct)) + A.CallTo(() => state2.Persistence.WriteSnapshotAsync(A._, CancellationToken)) .MustHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BackupContentsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BackupContentsTests.cs index 453f13eed..19b5233b7 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BackupContentsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BackupContentsTests.cs @@ -9,6 +9,7 @@ using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Backup; using Squidex.Domain.Apps.Entities.Contents.DomainObject; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events.Apps; using Squidex.Domain.Apps.Events.Contents; using Squidex.Domain.Apps.Events.Schemas; @@ -19,19 +20,14 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Entities.Contents; -public class BackupContentsTests +public class BackupContentsTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly Rebuilder rebuilder = A.Fake(); private readonly BackupContents sut; public BackupContentsTests() { - ct = cts.Token; - sut = new BackupContents(rebuilder, urlGenerator); } @@ -52,22 +48,22 @@ public class BackupContentsTests A.CallTo(() => urlGenerator.AssetContentBase()) .Returns(assetsUrl); - A.CallTo(() => urlGenerator.AssetContentBase(appId.Name)) + A.CallTo(() => urlGenerator.AssetContentBase(AppId.Name)) .Returns(assetsUrlApp); var writer = A.Fake(); - var context = new BackupContext(appId.Id, new UserMapping(me), writer); + var context = new BackupContext(AppId.Id, new UserMapping(me), writer); await sut.BackupEventAsync(Envelope.Create(new AppCreated { - Name = appId.Name - }), context, ct); + Name = AppId.Name + }), context, CancellationToken); A.CallTo(() => writer.WriteJsonAsync(A._, A.That.Matches(x => x.Assets == assetsUrl && - x.AssetsApp == assetsUrlApp), ct)) + x.AssetsApp == assetsUrlApp), CancellationToken)) .MustHaveHappened(); } @@ -87,10 +83,10 @@ public class BackupContentsTests A.CallTo(() => urlGenerator.AssetContentBase()) .Returns(newAssetsUrl); - A.CallTo(() => urlGenerator.AssetContentBase(appId.Name)) + A.CallTo(() => urlGenerator.AssetContentBase(AppId.Name)) .Returns(newAssetsUrlApp); - A.CallTo(() => reader.ReadJsonAsync(A._, ct)) + A.CallTo(() => reader.ReadJsonAsync(A._, CancellationToken)) .Returns(new BackupContents.Urls { Assets = oldAssetsUrl, @@ -131,17 +127,17 @@ public class BackupContentsTests new JsonObject() .Add("asset", $"Asset: {newAssetsUrlApp}/my-asset.jpg."))); - var context = new RestoreContext(appId.Id, new UserMapping(me), reader, DomainId.NewGuid()); + var context = new RestoreContext(AppId.Id, new UserMapping(me), reader, DomainId.NewGuid()); await sut.RestoreEventAsync(Envelope.Create(new AppCreated { - Name = appId.Name - }), context, ct); + Name = AppId.Name + }), context, CancellationToken); await sut.RestoreEventAsync(Envelope.Create(new ContentUpdated { Data = data - }), context, ct); + }), context, CancellationToken); Assert.Equal(updateData, data); } @@ -158,55 +154,55 @@ public class BackupContentsTests var contentId2 = DomainId.NewGuid(); var contentId3 = DomainId.NewGuid(); - var context = new RestoreContext(appId.Id, new UserMapping(me), A.Fake(), DomainId.NewGuid()); + var context = new RestoreContext(AppId.Id, new UserMapping(me), A.Fake(), DomainId.NewGuid()); await sut.RestoreEventAsync(ContentEvent(new ContentCreated { ContentId = contentId1, SchemaId = schemaId1 - }), context, ct); + }), context, CancellationToken); await sut.RestoreEventAsync(ContentEvent(new ContentCreated { ContentId = contentId2, SchemaId = schemaId1 - }), context, ct); + }), context, CancellationToken); await sut.RestoreEventAsync(ContentEvent(new ContentCreated { ContentId = contentId3, SchemaId = schemaId2 - }), context, ct); + }), context, CancellationToken); await sut.RestoreEventAsync(ContentEvent(new ContentDeleted { ContentId = contentId2, SchemaId = schemaId1 - }), context, ct); + }), context, CancellationToken); await sut.RestoreEventAsync(Envelope.Create(new SchemaDeleted { SchemaId = schemaId2 - }), context, ct); + }), context, CancellationToken); var rebuildContents = new HashSet(); - A.CallTo(() => rebuilder.InsertManyAsync(A>._, A._, ct)) + A.CallTo(() => rebuilder.InsertManyAsync(A>._, A._, CancellationToken)) .Invokes(x => rebuildContents.AddRange(x.GetArgument>(0)!)); - await sut.RestoreAsync(context, ct); + await sut.RestoreAsync(context, CancellationToken); Assert.Equal(new HashSet { - DomainId.Combine(appId, contentId1), - DomainId.Combine(appId, contentId2) + DomainId.Combine(AppId, contentId1), + DomainId.Combine(AppId, contentId2) }, rebuildContents); } private Envelope ContentEvent(ContentEvent @event) { - @event.AppId = appId; + @event.AppId = AppId; - return Envelope.Create(@event).SetAggregateId(DomainId.Combine(appId, @event.ContentId)); + return Envelope.Create(@event).SetAggregateId(DomainId.Combine(AppId, @event.ContentId)); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentChangedTriggerHandlerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentChangedTriggerHandlerTests.cs index f72321d7d..28ba4768c 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentChangedTriggerHandlerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentChangedTriggerHandlerTests.cs @@ -13,6 +13,7 @@ using Squidex.Domain.Apps.Core.Rules.Triggers; using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Contents.Repositories; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events.Assets; using Squidex.Domain.Apps.Events.Contents; @@ -23,10 +24,8 @@ using Squidex.Infrastructure.Reflection; namespace Squidex.Domain.Apps.Entities.Contents; -public class ContentChangedTriggerHandlerTests +public class ContentChangedTriggerHandlerTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IScriptEngine scriptEngine = A.Fake(); private readonly IContentLoader contentLoader = A.Fake(); private readonly IContentRepository contentRepository = A.Fake(); @@ -36,8 +35,6 @@ public class ContentChangedTriggerHandlerTests public ContentChangedTriggerHandlerTests() { - ct = cts.Token; - A.CallTo(() => scriptEngine.Evaluate(A._, "true", default)) .Returns(true); @@ -128,14 +125,14 @@ public class ContentChangedTriggerHandlerTests { var ctx = Context(); - A.CallTo(() => contentRepository.StreamAll(ctx.AppId.Id, null, ct)) + A.CallTo(() => contentRepository.StreamAll(ctx.AppId.Id, null, CancellationToken)) .Returns(new List { new ContentEntity { SchemaId = schemaMatch }, new ContentEntity { SchemaId = schemaNonMatch } }.ToAsyncEnumerable()); - var actual = await sut.CreateSnapshotEventsAsync(ctx, ct).ToListAsync(ct); + var actual = await sut.CreateSnapshotEventsAsync(ctx, CancellationToken).ToListAsync(CancellationToken); var typed = actual.OfType().ToList(); @@ -160,14 +157,14 @@ public class ContentChangedTriggerHandlerTests var ctx = Context(trigger); - A.CallTo(() => contentRepository.StreamAll(ctx.AppId.Id, A>.That.Is(schemaMatch.Id), ct)) + A.CallTo(() => contentRepository.StreamAll(ctx.AppId.Id, A>.That.Is(schemaMatch.Id), CancellationToken)) .Returns(new List { new ContentEntity { SchemaId = schemaMatch }, new ContentEntity { SchemaId = schemaMatch } }.ToAsyncEnumerable()); - var actual = await sut.CreateSnapshotEventsAsync(ctx, ct).ToListAsync(ct); + var actual = await sut.CreateSnapshotEventsAsync(ctx, CancellationToken).ToListAsync(CancellationToken); var typed = actual.OfType().ToList(); @@ -186,10 +183,10 @@ public class ContentChangedTriggerHandlerTests var envelope = Envelope.Create(@event).SetEventStreamNumber(12); - A.CallTo(() => contentLoader.GetAsync(ctx.AppId.Id, @event.ContentId, 12, ct)) + A.CallTo(() => contentLoader.GetAsync(ctx.AppId.Id, @event.ContentId, 12, CancellationToken)) .Returns(SimpleMapper.Map(@event, new ContentEntity())); - var actual = await sut.CreateEnrichedEventsAsync(envelope, ctx, ct).ToListAsync(ct); + var actual = await sut.CreateEnrichedEventsAsync(envelope, ctx, CancellationToken).ToListAsync(CancellationToken); var enrichedEvent = (EnrichedContentEvent)actual.Single(); @@ -213,13 +210,13 @@ public class ContentChangedTriggerHandlerTests var dataNow = new ContentData(); var dataOld = new ContentData(); - A.CallTo(() => contentLoader.GetAsync(ctx.AppId.Id, @event.ContentId, 12, ct)) + A.CallTo(() => contentLoader.GetAsync(ctx.AppId.Id, @event.ContentId, 12, CancellationToken)) .Returns(new ContentEntity { AppId = ctx.AppId, SchemaId = schemaMatch, Version = 12, Data = dataNow, Id = @event.ContentId }); - A.CallTo(() => contentLoader.GetAsync(ctx.AppId.Id, @event.ContentId, 11, ct)) + A.CallTo(() => contentLoader.GetAsync(ctx.AppId.Id, @event.ContentId, 11, CancellationToken)) .Returns(new ContentEntity { AppId = ctx.AppId, SchemaId = schemaMatch, Version = 11, Data = dataOld }); - var actual = await sut.CreateEnrichedEventsAsync(envelope, ctx, ct).ToListAsync(ct); + var actual = await sut.CreateEnrichedEventsAsync(envelope, ctx, CancellationToken).ToListAsync(CancellationToken); var enrichedEvent = actual.Single() as EnrichedContentEvent; @@ -388,13 +385,13 @@ public class ContentChangedTriggerHandlerTests } } - private static RuleContext Context(RuleTrigger? trigger = null) + private RuleContext Context(RuleTrigger? trigger = null) { trigger ??= new ContentChangedTriggerV2(); return new RuleContext { - AppId = NamedId.Of(DomainId.NewGuid(), "my-app"), + AppId = AppId, Rule = new Rule(trigger, A.Fake()), RuleId = DomainId.NewGuid() }; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentSchedulerProcessTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentSchedulerProcessTests.cs index b802740eb..8bc9c6945 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentSchedulerProcessTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentSchedulerProcessTests.cs @@ -10,17 +10,17 @@ using NodaTime; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Repositories; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; namespace Squidex.Domain.Apps.Entities.Contents; -public class ContentSchedulerProcessTests +public class ContentSchedulerProcessTests : GivenContext { private readonly IContentRepository contentRepository = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); private readonly IClock clock = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly ContentSchedulerProcess sut; public ContentSchedulerProcessTests() @@ -38,14 +38,14 @@ public class ContentSchedulerProcessTests var content1 = new ContentEntity { - AppId = appId, + AppId = AppId, Id = DomainId.NewGuid(), ScheduleJob = new ScheduleJob(DomainId.NewGuid(), Status.Archived, null!, now) }; var content2 = new ContentEntity { - AppId = appId, + AppId = AppId, Id = DomainId.NewGuid(), ScheduleJob = new ScheduleJob(DomainId.NewGuid(), Status.Draft, null!, now) }; @@ -53,10 +53,10 @@ public class ContentSchedulerProcessTests A.CallTo(() => clock.GetCurrentInstant()) .Returns(now); - A.CallTo(() => contentRepository.QueryScheduledWithoutDataAsync(now, default)) + A.CallTo(() => contentRepository.QueryScheduledWithoutDataAsync(now, CancellationToken)) .Returns(new[] { content1, content2 }.ToAsyncEnumerable()); - await sut.PublishAsync(); + await sut.PublishAsync(CancellationToken); A.CallTo(() => commandBus.PublishAsync( A.That.Matches(x => @@ -82,7 +82,7 @@ public class ContentSchedulerProcessTests var content1 = new ContentEntity { - AppId = appId, + AppId = AppId, Id = DomainId.NewGuid(), ScheduleJob = null }; @@ -90,10 +90,10 @@ public class ContentSchedulerProcessTests A.CallTo(() => clock.GetCurrentInstant()) .Returns(now); - A.CallTo(() => contentRepository.QueryScheduledWithoutDataAsync(now, default)) + A.CallTo(() => contentRepository.QueryScheduledWithoutDataAsync(now, CancellationToken)) .Returns(new[] { content1 }.ToAsyncEnumerable()); - await sut.PublishAsync(); + await sut.PublishAsync(CancellationToken); A.CallTo(() => commandBus.PublishAsync(A._, A._)) .MustNotHaveHappened(); @@ -106,7 +106,7 @@ public class ContentSchedulerProcessTests var content1 = new ContentEntity { - AppId = appId, + AppId = AppId, Id = DomainId.NewGuid(), ScheduleJob = new ScheduleJob(DomainId.NewGuid(), Status.Archived, null!, now) }; @@ -114,13 +114,13 @@ public class ContentSchedulerProcessTests A.CallTo(() => clock.GetCurrentInstant()) .Returns(now); - A.CallTo(() => contentRepository.QueryScheduledWithoutDataAsync(now, default)) + A.CallTo(() => contentRepository.QueryScheduledWithoutDataAsync(now, CancellationToken)) .Returns(new[] { content1 }.ToAsyncEnumerable()); A.CallTo(() => commandBus.PublishAsync(A._, default)) .Throws(new DomainObjectNotFoundException(content1.Id.ToString())); - await sut.PublishAsync(); + await sut.PublishAsync(CancellationToken); A.CallTo(() => contentRepository.ResetScheduledAsync(content1.UniqueId, default)) .MustHaveHappened(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentsSearchSourceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentsSearchSourceTests.cs index dd5a4653a..e4420ed96 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentsSearchSourceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentsSearchSourceTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Security.Claims; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; @@ -15,19 +14,14 @@ using Squidex.Domain.Apps.Entities.Search; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Shared; -using Squidex.Shared.Identity; namespace Squidex.Domain.Apps.Entities.Contents; -public class ContentsSearchSourceTests +public class ContentsSearchSourceTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; - private readonly IAppProvider appProvider = A.Fake(); private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly ITextIndex contentIndex = A.Fake(); private readonly IContentQueryService contentQuery = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly NamedId schemaId1 = NamedId.Of(DomainId.NewGuid(), "my-schema1"); private readonly NamedId schemaId2 = NamedId.Of(DomainId.NewGuid(), "my-schema2"); private readonly NamedId schemaId3 = NamedId.Of(DomainId.NewGuid(), "my-schema3"); @@ -35,17 +29,15 @@ public class ContentsSearchSourceTests public ContentsSearchSourceTests() { - ct = cts.Token; - - A.CallTo(() => appProvider.GetSchemasAsync(appId.Id, ct)) + A.CallTo(() => AppProvider.GetSchemasAsync(AppId.Id, CancellationToken)) .Returns(new List { - Mocks.Schema(appId, schemaId1), - Mocks.Schema(appId, schemaId2), - Mocks.Schema(appId, schemaId3) + Mocks.Schema(AppId, schemaId1), + Mocks.Schema(AppId, schemaId2), + Mocks.Schema(AppId, schemaId3) }); - sut = new ContentsSearchSource(appProvider, contentQuery, contentIndex, urlGenerator); + sut = new ContentsSearchSource(AppProvider, contentQuery, contentIndex, urlGenerator); } [Fact] @@ -152,50 +144,50 @@ public class ContentsSearchSourceTests [Fact] public async Task Should_not_invoke_content_index_if_user_has_no_permission() { - var ctx = ContextWithPermissions(); + var requestContext = ContextWithPermissions(); - var actual = await sut.SearchAsync("query", ctx, ct); + var actual = await sut.SearchAsync("query", requestContext, CancellationToken); Assert.Empty(actual); - A.CallTo(() => contentIndex.SearchAsync(ctx.App, A._, A._, A._)) + A.CallTo(() => contentIndex.SearchAsync(App, A._, A._, A._)) .MustNotHaveHappened(); } [Fact] public async Task Should_not_invoke_context_query_if_no_id_found() { - var ctx = ContextWithPermissions(schemaId1, schemaId2); + var requestContext = ContextWithPermissions(schemaId1, schemaId2); - A.CallTo(() => contentIndex.SearchAsync(ctx.App, A.That.Matches(x => x.Text == "query~"), ctx.Scope(), ct)) + A.CallTo(() => contentIndex.SearchAsync(App, A.That.Matches(x => x.Text == "query~"), ApiContext.Scope(), CancellationToken)) .Returns(new List()); - var actual = await sut.SearchAsync("query", ctx, ct); + var actual = await sut.SearchAsync("query", requestContext, CancellationToken); Assert.Empty(actual); - A.CallTo(() => contentQuery.QueryAsync(ctx, A._, A._)) + A.CallTo(() => contentQuery.QueryAsync(requestContext, A._, A._)) .MustNotHaveHappened(); } private async Task TestContentAsync(ContentEntity content, string expectedName) { - content.AppId = appId; + content.AppId = AppId; - var ctx = ContextWithPermissions(schemaId1, schemaId2); + var requestContext = ContextWithPermissions(schemaId1, schemaId2); var ids = new List { content.Id }; - A.CallTo(() => contentIndex.SearchAsync(ctx.App, A.That.Matches(x => x.Text == "query~"), ctx.Scope(), ct)) + A.CallTo(() => contentIndex.SearchAsync(App, A.That.Matches(x => x.Text == "query~"), ApiContext.Scope(), CancellationToken)) .Returns(ids); - A.CallTo(() => contentQuery.QueryAsync(ctx, A.That.HasIds(ids), ct)) + A.CallTo(() => contentQuery.QueryAsync(requestContext, A.That.HasIds(ids), CancellationToken)) .Returns(ResultList.CreateFrom(1, content)); - A.CallTo(() => urlGenerator.ContentUI(appId, schemaId1, content.Id)) + A.CallTo(() => urlGenerator.ContentUI(AppId, schemaId1, content.Id)) .Returns("content-url"); - var actual = await sut.SearchAsync("query", ctx, ct); + var actual = await sut.SearchAsync("query", requestContext, CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -204,16 +196,13 @@ public class ContentsSearchSourceTests private Context ContextWithPermissions(params NamedId[] allowedSchemas) { - var claimsIdentity = new ClaimsIdentity(); - var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); + var permissions = new List(); foreach (var schemaId in allowedSchemas) { - var permission = PermissionIds.ForApp(PermissionIds.AppContentsReadOwn, appId.Name, schemaId.Name).Id; - - claimsIdentity.AddClaim(new Claim(SquidexClaimTypes.Permissions, permission)); + permissions.Add(PermissionIds.ForApp(PermissionIds.AppContentsReadOwn, AppId.Name, schemaId.Name).Id); } - return new Context(claimsPrincipal, Mocks.App(appId)); + return CreateContext(false, permissions.ToArray()); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterJintExtensionTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterJintExtensionTests.cs index c04506a5e..d188c771c 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterJintExtensionTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterJintExtensionTests.cs @@ -8,11 +8,11 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Core.Scripting; -using Squidex.Infrastructure; +using Squidex.Domain.Apps.Entities.TestHelpers; namespace Squidex.Domain.Apps.Entities.Contents.Counter; -public class CounterJintExtensionTests +public class CounterJintExtensionTests : GivenContext { private readonly ICounterService counterService = A.Fake(); private readonly JintScriptEngine sut; @@ -35,9 +35,7 @@ public class CounterJintExtensionTests [Fact] public void Should_reset_counter() { - var appId = DomainId.NewGuid(); - - A.CallTo(() => counterService.ResetAsync(appId, "my", 4, default)) + A.CallTo(() => counterService.ResetAsync(AppId.Id, "my", 4, default)) .Returns(3); const string script = @" @@ -46,7 +44,7 @@ public class CounterJintExtensionTests var vars = new ScriptVars { - ["appId"] = appId + ["appId"] = AppId.Id }; var actual = sut.Execute(vars, script).ToString(); @@ -57,9 +55,7 @@ public class CounterJintExtensionTests [Fact] public async Task Should_reset_counter_with_callback() { - var appId = DomainId.NewGuid(); - - A.CallTo(() => counterService.ResetAsync(appId, "my", 4, A._)) + A.CallTo(() => counterService.ResetAsync(AppId.Id, "my", 4, A._)) .Returns(3); const string script = @" @@ -70,7 +66,7 @@ public class CounterJintExtensionTests var vars = new ScriptVars { - ["appId"] = appId + ["appId"] = AppId.Id }; var actual = (await sut.ExecuteAsync(vars, script)).ToString(); @@ -81,9 +77,7 @@ public class CounterJintExtensionTests [Fact] public void Should_increment_counter() { - var appId = DomainId.NewGuid(); - - A.CallTo(() => counterService.IncrementAsync(appId, "my", A._)) + A.CallTo(() => counterService.IncrementAsync(AppId.Id, "my", A._)) .Returns(3); const string script = @" @@ -92,7 +86,7 @@ public class CounterJintExtensionTests var vars = new ScriptVars { - ["appId"] = appId + ["appId"] = AppId.Id }; var actual = sut.Execute(vars, script).ToString(); @@ -103,9 +97,7 @@ public class CounterJintExtensionTests [Fact] public async Task Should_increment_counter_with_callback() { - var appId = DomainId.NewGuid(); - - A.CallTo(() => counterService.IncrementAsync(appId, "my", A._)) + A.CallTo(() => counterService.IncrementAsync(AppId.Id, "my", A._)) .Returns(3); const string script = @" @@ -116,7 +108,7 @@ public class CounterJintExtensionTests var vars = new ScriptVars { - ["appId"] = appId + ["appId"] = AppId.Id }; var actual = (await sut.ExecuteAsync(vars, script)).ToString(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterServiceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterServiceTests.cs index d375caa0f..85e8a64c4 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterServiceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Counter/CounterServiceTests.cs @@ -6,24 +6,18 @@ // ========================================================================== using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; using Squidex.Infrastructure.TestHelpers; namespace Squidex.Domain.Apps.Entities.Contents.Counter; -public class CounterServiceTests +public class CounterServiceTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly TestState state; - private readonly DomainId appId = DomainId.NewGuid(); private readonly CounterService sut; public CounterServiceTests() { - ct = cts.Token; - - state = new TestState(appId); + state = new TestState(AppId.Id); sut = new CounterService(state.PersistenceFactory); } @@ -39,36 +33,36 @@ public class CounterServiceTests [Fact] public async Task Should_delete_state_when_app_deleted() { - await ((IDeleter)sut).DeleteAppAsync(Mocks.App(NamedId.Of(appId, "my-app")), ct); + await ((IDeleter)sut).DeleteAppAsync(App, CancellationToken); - A.CallTo(() => state.Persistence.DeleteAsync(ct)) + A.CallTo(() => state.Persistence.DeleteAsync(CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_increment_counters() { - Assert.Equal(1, await sut.IncrementAsync(appId, "Counter1", ct)); - Assert.Equal(2, await sut.IncrementAsync(appId, "Counter1", ct)); + Assert.Equal(1, await sut.IncrementAsync(AppId.Id, "Counter1", CancellationToken)); + Assert.Equal(2, await sut.IncrementAsync(AppId.Id, "Counter1", CancellationToken)); - Assert.Equal(1, await sut.IncrementAsync(appId, "Counter2", ct)); - Assert.Equal(2, await sut.IncrementAsync(appId, "Counter2", ct)); + Assert.Equal(1, await sut.IncrementAsync(AppId.Id, "Counter2", CancellationToken)); + Assert.Equal(2, await sut.IncrementAsync(AppId.Id, "Counter2", CancellationToken)); - A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, ct)) + A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, CancellationToken)) .MustHaveHappened(4, Times.Exactly); } [Fact] public async Task Should_reset_counter() { - Assert.Equal(1, await sut.IncrementAsync(appId, "Counter1", ct)); - Assert.Equal(2, await sut.IncrementAsync(appId, "Counter1", ct)); + Assert.Equal(1, await sut.IncrementAsync(AppId.Id, "Counter1", CancellationToken)); + Assert.Equal(2, await sut.IncrementAsync(AppId.Id, "Counter1", CancellationToken)); - Assert.Equal(1, await sut.ResetAsync(appId, "Counter1", 1, ct)); + Assert.Equal(1, await sut.ResetAsync(AppId.Id, "Counter1", 1, CancellationToken)); - Assert.Equal(2, await sut.IncrementAsync(appId, "Counter1", ct)); + Assert.Equal(2, await sut.IncrementAsync(AppId.Id, "Counter1", CancellationToken)); - A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, ct)) + A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, CancellationToken)) .MustHaveHappened(4, Times.Exactly); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultWorkflowsValidatorTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultWorkflowsValidatorTests.cs index a8aecf473..3083d2e37 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultWorkflowsValidatorTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultWorkflowsValidatorTests.cs @@ -6,33 +6,20 @@ // ========================================================================== using Squidex.Domain.Apps.Core.Contents; -using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.TestHelpers; -using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Collections; namespace Squidex.Domain.Apps.Entities.Contents; -public class DefaultWorkflowsValidatorTests : IClassFixture +public class DefaultWorkflowsValidatorTests : GivenContext, IClassFixture { - private readonly IAppProvider appProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly DefaultWorkflowsValidator sut; public DefaultWorkflowsValidatorTests() { - var schema = Mocks.Schema(appId, schemaId, new Schema(schemaId.Name)); - - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A._, false, default)) - .Returns(Task.FromResult(null)); - - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false, default)) - .Returns(schema); - - sut = new DefaultWorkflowsValidator(appProvider); + sut = new DefaultWorkflowsValidator(AppProvider); } [Fact] @@ -42,7 +29,7 @@ public class DefaultWorkflowsValidatorTests : IClassFixture .Add(DomainId.NewGuid(), "workflow1") .Add(DomainId.NewGuid(), "workflow2"); - var errors = await sut.ValidateAsync(appId.Id, workflows); + var errors = await sut.ValidateAsync(AppId.Id, workflows); Assert.Equal(new[] { "Multiple workflows cover all schemas." }, errors.ToArray()); } @@ -56,10 +43,10 @@ public class DefaultWorkflowsValidatorTests : IClassFixture var workflows = Workflows.Empty .Add(id1, "workflow1") .Add(id2, "workflow2") - .Update(id1, new Workflow(default, null, ReadonlyList.Create(schemaId.Id))) - .Update(id2, new Workflow(default, null, ReadonlyList.Create(schemaId.Id))); + .Update(id1, new Workflow(default, null, ReadonlyList.Create(SchemaId.Id))) + .Update(id2, new Workflow(default, null, ReadonlyList.Create(SchemaId.Id))); - var errors = await sut.ValidateAsync(appId.Id, workflows); + var errors = await sut.ValidateAsync(AppId.Id, workflows); Assert.Equal(new[] { "The schema 'my-schema' is covered by multiple workflows." }, errors.ToArray()); } @@ -67,18 +54,18 @@ public class DefaultWorkflowsValidatorTests : IClassFixture [Fact] public async Task Should_not_generate_error_if_schema_deleted() { + Schema = null!; + var id1 = DomainId.NewGuid(); var id2 = DomainId.NewGuid(); - var oldSchemaId = DomainId.NewGuid(); - var workflows = Workflows.Empty .Add(id1, "workflow1") .Add(id2, "workflow2") - .Update(id1, new Workflow(default, null, ReadonlyList.Create(oldSchemaId))) - .Update(id2, new Workflow(default, null, ReadonlyList.Create(oldSchemaId))); + .Update(id1, new Workflow(default, null, ReadonlyList.Create(SchemaId.Id))) + .Update(id2, new Workflow(default, null, ReadonlyList.Create(SchemaId.Id))); - var errors = await sut.ValidateAsync(appId.Id, workflows); + var errors = await sut.ValidateAsync(AppId.Id, workflows); Assert.Empty(errors); } @@ -92,9 +79,9 @@ public class DefaultWorkflowsValidatorTests : IClassFixture var workflows = Workflows.Empty .Add(id1, "workflow1") .Add(id2, "workflow2") - .Update(id1, new Workflow(default, null, ReadonlyList.Create(schemaId.Id))); + .Update(id1, new Workflow(default, null, ReadonlyList.Create(SchemaId.Id))); - var errors = await sut.ValidateAsync(appId.Id, workflows); + var errors = await sut.ValidateAsync(AppId.Id, workflows); Assert.Empty(errors); } @@ -102,7 +89,7 @@ public class DefaultWorkflowsValidatorTests : IClassFixture [Fact] public async Task Should_not_generate_errors_for_empty_workflows() { - var errors = await sut.ValidateAsync(appId.Id, Workflows.Empty); + var errors = await sut.ValidateAsync(AppId.Id, Workflows.Empty); Assert.Empty(errors); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentCommandMiddlewareTests.cs index b44fdfba6..c7c89fe77 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentCommandMiddlewareTests.cs @@ -18,9 +18,7 @@ public sealed class ContentCommandMiddlewareTests : HandlerTestBase(); private readonly IDomainObjectFactory domainObjectFactory = A.Fake(); private readonly IContentEnricher contentEnricher = A.Fake(); - private readonly IContextProvider contextProvider = A.Fake(); private readonly DomainId contentId = DomainId.NewGuid(); - private readonly Context requestContext; private readonly ContentCommandMiddleware sut; public sealed class MyCommand : SquidexCommand @@ -34,16 +32,11 @@ public sealed class ContentCommandMiddlewareTests : HandlerTestBase contextProvider.Context) - .Returns(requestContext); - sut = new ContentCommandMiddleware( domainObjectFactory, domainObjectCache, contentEnricher, - contextProvider); + ApiContextProvider); } [Fact] @@ -51,7 +44,7 @@ public sealed class ContentCommandMiddlewareTests : HandlerTestBase contentEnricher.EnrichAsync(A._, A._, requestContext, A._)) + A.CallTo(() => contentEnricher.EnrichAsync(A._, A._, ApiContext, A._)) .MustNotHaveHappened(); } @@ -66,7 +59,7 @@ public sealed class ContentCommandMiddlewareTests : HandlerTestBase()); - A.CallTo(() => contentEnricher.EnrichAsync(A._, A._, requestContext, A._)) + A.CallTo(() => contentEnricher.EnrichAsync(A._, A._, ApiContext, A._)) .MustNotHaveHappened(); } @@ -77,7 +70,7 @@ public sealed class ContentCommandMiddlewareTests : HandlerTestBase contentEnricher.EnrichAsync(actual, true, requestContext, A._)) + A.CallTo(() => contentEnricher.EnrichAsync(actual, true, ApiContext, CancellationToken)) .Returns(enriched); var context = @@ -95,12 +88,12 @@ public sealed class ContentCommandMiddlewareTests : HandlerTestBase(); - A.CallTo(() => domainObject.ExecuteAsync(A._, A._)) + A.CallTo(() => domainObject.ExecuteAsync(A._, CancellationToken)) .Returns(new CommandResult(command.AggregateId, 1, 0, actual)); A.CallTo(() => domainObjectFactory.Create(command.AggregateId)) .Returns(domainObject); - return HandleAsync(sut, command); + return HandleAsync(sut, command, CancellationToken); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs index 65311589a..ccbb4b34b 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentDomainObjectTests.cs @@ -14,10 +14,8 @@ using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Core.ValidateContent; -using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Repositories; -using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events.Contents; using Squidex.Infrastructure; @@ -29,11 +27,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject; public class ContentDomainObjectTests : HandlerTestBase { private readonly DomainId contentId = DomainId.NewGuid(); - private readonly IAppEntity app; - private readonly IAppProvider appProvider = A.Fake(); private readonly IContentWorkflow contentWorkflow = A.Fake(x => x.Wrapping(new DefaultContentWorkflow())); private readonly IContentRepository contentRepository = A.Fake(); - private readonly ISchemaEntity schema; private readonly IScriptEngine scriptEngine = A.Fake(); private readonly ContentData invalidData = @@ -72,8 +67,6 @@ public class ContentDomainObjectTests : HandlerTestBase appProvider.GetAppAsync(AppName, false, default)) - .Returns(app); - - A.CallTo(() => appProvider.GetAppWithSchemaAsync(AppId, SchemaId, false, default)) - .Returns((app, schema)); + A.CallTo(() => Schema.SchemaDef) + .Returns(schemaDef); - A.CallTo(() => scriptEngine.TransformAsync(A._, A._, ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(A._, A._, ScriptOptions(), CancellationToken)) .ReturnsLazily(x => Task.FromResult(x.GetArgument(0)!.Data!)); patched = patch.MergeInto(data); @@ -107,7 +95,7 @@ public class ContentDomainObjectTests : HandlerTestBase>()) .AddSingleton(log) .AddSingleton(contentWorkflow) @@ -148,9 +136,9 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustNotHaveHappened(); } @@ -171,9 +159,9 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustNotHaveHappened(); } @@ -195,9 +183,9 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); - A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Archived, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Archived, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -248,9 +236,9 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustNotHaveHappened(); } @@ -271,9 +259,9 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); - A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustNotHaveHappened(); } @@ -295,9 +283,9 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); - A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Archived, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Archived, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -319,7 +307,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(otherData, data, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(otherData, data, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -341,7 +329,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(patched, data, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(patched, data, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -363,7 +351,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(otherData, data, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(otherData, data, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -387,9 +375,9 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(otherData, data, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(otherData, data, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); - A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(otherData, null, Status.Archived, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(otherData, null, Status.Archived, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -443,7 +431,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(otherData, data, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(otherData, data, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -467,7 +455,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(otherData, data, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(otherData, data, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -484,7 +472,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(A._, "", ScriptOptions(), CancellationToken)) .MustNotHaveHappened(); } @@ -516,7 +504,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(patched, data, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(patched, data, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -540,7 +528,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(patched, data, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(patched, data, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -557,7 +545,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(A._, "", ScriptOptions(), CancellationToken)) .MustNotHaveHappened(); } @@ -579,7 +567,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Archived, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Archived, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -601,7 +589,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Archived, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Archived, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -624,7 +612,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft, Status.Published), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft, Status.Published), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -633,7 +621,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft, Status.Published), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft, Status.Published), "", ScriptOptions(), CancellationToken)) .Returns(otherData); await ExecuteCreateAsync(); @@ -652,7 +640,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft, Status.Published), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Draft, Status.Published), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -676,7 +664,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Archived, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Archived, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -700,7 +688,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Published, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(DataScriptVars(data, null, Status.Published, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -727,7 +715,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustNotHaveHappened(); } @@ -741,7 +729,7 @@ public class ContentDomainObjectTests : HandlerTestBase contentWorkflow.CanMoveToAsync(A._, Status.Draft, Status.Archived, User)) + A.CallTo(() => contentWorkflow.CanMoveToAsync(A._, Status.Draft, Status.Archived, ApiContext.UserPrincipal)) .Returns(true); var actual = await PublishAsync(command); @@ -755,7 +743,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.TransformAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.TransformAsync(A._, "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -769,7 +757,7 @@ public class ContentDomainObjectTests : HandlerTestBase contentWorkflow.CanMoveToAsync(A._, Status.Draft, Status.Published, User)) + A.CallTo(() => contentWorkflow.CanMoveToAsync(A._, Status.Draft, Status.Published, ApiContext.UserPrincipal)) .Returns(false); var actual = await PublishAsync(command); @@ -783,7 +771,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(A._, "", ScriptOptions(), CancellationToken)) .MustNotHaveHappened(); } @@ -795,7 +783,7 @@ public class ContentDomainObjectTests : HandlerTestBase contentRepository.HasReferrersAsync(AppId, contentId, SearchScope.All, A._)) + A.CallTo(() => contentRepository.HasReferrersAsync(AppId.Id, contentId, SearchScope.All, A._)) .Returns(true); await Assert.ThrowsAsync(() => PublishAsync(command)); @@ -809,7 +797,7 @@ public class ContentDomainObjectTests : HandlerTestBase contentRepository.HasReferrersAsync(AppId, contentId, SearchScope.Published, A._)) + A.CallTo(() => contentRepository.HasReferrersAsync(AppId.Id, contentId, SearchScope.Published, A._)) .Returns(true); await PublishAsync(command); @@ -865,7 +853,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.ExecuteAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -883,7 +871,7 @@ public class ContentDomainObjectTests : HandlerTestBase scriptEngine.ExecuteAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), default)) + A.CallTo(() => scriptEngine.ExecuteAsync(DataScriptVars(data, null, Status.Draft), "", ScriptOptions(), CancellationToken)) .MustHaveHappened(); } @@ -894,7 +882,7 @@ public class ContentDomainObjectTests : HandlerTestBase contentRepository.HasReferrersAsync(AppId, contentId, SearchScope.All, A._)) + A.CallTo(() => contentRepository.HasReferrersAsync(AppId.Id, contentId, SearchScope.All, A._)) .Returns(true); await Assert.ThrowsAsync(() => PublishAsync(command)); @@ -907,7 +895,7 @@ public class ContentDomainObjectTests : HandlerTestBase contentRepository.HasReferrersAsync(AppId, contentId, SearchScope.All, A._)) + A.CallTo(() => contentRepository.HasReferrersAsync(AppId.Id, contentId, SearchScope.All, A._)) .Returns(true); await PublishAsync(command); @@ -1007,7 +995,7 @@ public class ContentDomainObjectTests : HandlerTestBase(T @event) where T : ContentEvent @@ -1026,7 +1014,7 @@ public class ContentDomainObjectTests : HandlerTestBase PublishAsync(ContentCommand command) { - var actual = await sut.ExecuteAsync(CreateContentCommand(command), default); + var actual = await sut.ExecuteAsync(CreateContentCommand(command), CancellationToken); return actual.Payload; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentsBulkUpdateCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentsBulkUpdateCommandMiddlewareTests.cs index 8425d8647..c9c3a78a0 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentsBulkUpdateCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/ContentsBulkUpdateCommandMiddlewareTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Security.Claims; using Microsoft.Extensions.Logging; using NodaTime; using Squidex.Domain.Apps.Core.Contents; @@ -16,18 +15,14 @@ using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Queries; using Squidex.Shared; -using Squidex.Shared.Identity; namespace Squidex.Domain.Apps.Entities.Contents.DomainObject; -public class ContentsBulkUpdateCommandMiddlewareTests +public class ContentsBulkUpdateCommandMiddlewareTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IContentQueryService contentQuery = A.Fake(); private readonly IContextProvider contextProvider = A.Fake(); private readonly ICommandBus commandBus = A.Dummy(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly NamedId schemaCustomId = NamedId.Of(DomainId.NewGuid(), "my-schema2"); private readonly Instant time = Instant.FromDateTimeUtc(DateTime.UtcNow); @@ -35,8 +30,6 @@ public class ContentsBulkUpdateCommandMiddlewareTests public ContentsBulkUpdateCommandMiddlewareTests() { - ct = cts.Token; - var log = A.Fake>(); sut = new ContentsBulkUpdateCommandMiddleware(contentQuery, contextProvider, log); @@ -92,7 +85,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests x.ShouldSkipCleanup() && x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), - schemaId.Name, A.That.Matches(x => x.JsonQuery == query), ct)) + schemaId.Name, A.That.Matches(x => x.JsonQuery == query), CancellationToken)) .Returns(ResultList.CreateFrom(2, CreateContent(id), CreateContent(id))); var command = BulkCommand(BulkUpdateContentType.ChangeStatus, new BulkUpdateJob { Query = query }); @@ -118,7 +111,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests x.ShouldSkipCleanup() && x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), - schemaId.Name, A.That.Matches(x => x.JsonQuery == query), ct)) + schemaId.Name, A.That.Matches(x => x.JsonQuery == query), CancellationToken)) .Returns(ResultList.CreateFrom(1, CreateContent(id))); var command = BulkCommand(BulkUpdateContentType.Upsert, new BulkUpdateJob { Query = query, Data = data }); @@ -129,7 +122,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id == id && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.Data == data && x.ContentId == id), ct)) + A.That.Matches(x => x.Data == data && x.ContentId == id), CancellationToken)) .MustHaveHappenedOnceExactly(); } @@ -148,7 +141,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests x.ShouldSkipCleanup() && x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), - schemaId.Name, A.That.Matches(x => x.JsonQuery == query), ct)) + schemaId.Name, A.That.Matches(x => x.JsonQuery == query), CancellationToken)) .Returns(ResultList.CreateFrom(2, CreateContent(id1), CreateContent(id2))); @@ -164,11 +157,11 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id == id2 && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.Data == data && x.ContentId == id1), ct)) + A.That.Matches(x => x.Data == data && x.ContentId == id1), CancellationToken)) .MustHaveHappenedOnceExactly(); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.Data == data && x.ContentId == id2), ct)) + A.That.Matches(x => x.Data == data && x.ContentId == id2), CancellationToken)) .MustHaveHappenedOnceExactly(); } @@ -187,7 +180,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id != default && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.Data == data && x.ContentId != default), ct)) + A.That.Matches(x => x.Data == data && x.ContentId != default), CancellationToken)) .MustHaveHappenedOnceExactly(); } @@ -206,7 +199,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id != default && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.Data == data && x.ContentId != default), ct)) + A.That.Matches(x => x.Data == data && x.ContentId != default), CancellationToken)) .MustHaveHappenedOnceExactly(); } @@ -225,7 +218,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id != default && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.Data == data && x.ContentId == id), ct)) + A.That.Matches(x => x.Data == data && x.ContentId == id), CancellationToken)) .MustHaveHappenedOnceExactly(); } @@ -244,7 +237,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id != default && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.Data == data && x.ContentId == id), ct)) + A.That.Matches(x => x.Data == data && x.ContentId == id), CancellationToken)) .MustHaveHappenedOnceExactly(); } @@ -263,7 +256,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id == id && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.ContentId == id && x.Data == data), ct)) + A.That.Matches(x => x.ContentId == id && x.Data == data), CancellationToken)) .MustHaveHappened(); } @@ -300,7 +293,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id == id && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.ContentId == id && x.Data == data), ct)) + A.That.Matches(x => x.ContentId == id && x.Data == data), CancellationToken)) .MustHaveHappened(); } @@ -337,7 +330,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id == id && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.ContentId == id && x.Data == data), ct)) + A.That.Matches(x => x.ContentId == id && x.Data == data), CancellationToken)) .MustHaveHappened(); } @@ -374,7 +367,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id == id && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.ContentId == id && x.DueTime == null), ct)) + A.That.Matches(x => x.ContentId == id && x.DueTime == null), CancellationToken)) .MustHaveHappened(); } @@ -393,7 +386,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id == id && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.ContentId == id && x.DueTime == time), ct)) + A.That.Matches(x => x.ContentId == id && x.DueTime == time), CancellationToken)) .MustHaveHappened(); } @@ -430,7 +423,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id == id && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.ContentId == id), ct)) + A.That.Matches(x => x.ContentId == id), CancellationToken)) .MustHaveHappened(); } @@ -467,7 +460,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id == id && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.ContentId == id), ct)) + A.That.Matches(x => x.ContentId == id), CancellationToken)) .MustHaveHappened(); } @@ -494,8 +487,8 @@ public class ContentsBulkUpdateCommandMiddlewareTests { SetupContext(PermissionIds.AppContentsDeleteOwn); - A.CallTo(() => contentQuery.GetSchemaOrThrowAsync(A._, schemaCustomId.Name, ct)) - .Returns(Mocks.Schema(appId, schemaCustomId)); + A.CallTo(() => contentQuery.GetSchemaOrThrowAsync(A._, schemaCustomId.Name, CancellationToken)) + .Returns(Mocks.Schema(AppId, schemaCustomId)); var (id, _, _) = CreateTestData(false); @@ -507,7 +500,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id == id && x.Exception == null); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.SchemaId == schemaCustomId), ct)) + A.That.Matches(x => x.SchemaId == schemaCustomId), CancellationToken)) .MustHaveHappened(); } @@ -529,7 +522,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests Assert.Single(actual, x => x.JobIndex == 0 && x.Id == id && x.Exception is DomainObjectNotFoundException); A.CallTo(() => commandBus.PublishAsync( - A.That.Matches(x => x.SchemaId == schemaCustomId), ct)) + A.That.Matches(x => x.SchemaId == schemaCustomId), CancellationToken)) .MustNotHaveHappened(); } @@ -537,7 +530,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests { var context = new CommandContext(command, commandBus); - await sut.HandleAsync(context, ct); + await sut.HandleAsync(context, CancellationToken); return (context.PlainResult as BulkUpdateResult)!; } @@ -550,7 +543,7 @@ public class ContentsBulkUpdateCommandMiddlewareTests return new BulkUpdateContents { - AppId = appId, + AppId = AppId, Jobs = new[] { job @@ -561,18 +554,9 @@ public class ContentsBulkUpdateCommandMiddlewareTests private Context SetupContext(string id) { - var claimsIdentity = new ClaimsIdentity(); - var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); - - claimsIdentity.AddClaim( - new Claim(SquidexClaimTypes.Permissions, - PermissionIds.ForApp(id, appId.Name, schemaId.Name).Id)); - - claimsIdentity.AddClaim( - new Claim(SquidexClaimTypes.Permissions, - PermissionIds.ForApp(id, appId.Name, schemaCustomId.Name).Id)); - - var requestContext = new Context(claimsPrincipal, Mocks.App(appId)); + var requestContext = CreateContext(false, + PermissionIds.ForApp(id, AppId.Name, schemaId.Name).Id, + PermissionIds.ForApp(id, AppId.Name, schemaCustomId.Name).Id); A.CallTo(() => contextProvider.Context) .Returns(requestContext); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/Guards/GuardContentTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/Guards/GuardContentTests.cs index bd5ef7f4e..18fc31046 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/Guards/GuardContentTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DomainObject/Guards/GuardContentTests.cs @@ -22,35 +22,32 @@ using Squidex.Shared; namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards; -public class GuardContentTests : IClassFixture +public class GuardContentTests : GivenContext, IClassFixture { private readonly IContentWorkflow contentWorkflow = A.Fake(); private readonly IContentRepository contentRepository = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly ISchemaEntity normalSchema; private readonly ISchemaEntity normalUnpublishedSchema; private readonly ISchemaEntity singletonSchema; private readonly ISchemaEntity singletonUnpublishedSchema; private readonly ISchemaEntity componentSchema; - private readonly RefToken actor = RefToken.User("123"); public GuardContentTests() { normalUnpublishedSchema = - Mocks.Schema(appId, schemaId, new Schema(schemaId.Name)); + Mocks.Schema(AppId, SchemaId, new Schema(SchemaId.Name)); normalSchema = - Mocks.Schema(appId, schemaId, new Schema(schemaId.Name).Publish()); + Mocks.Schema(AppId, SchemaId, new Schema(SchemaId.Name).Publish()); singletonUnpublishedSchema = - Mocks.Schema(appId, schemaId, new Schema(schemaId.Name, type: SchemaType.Singleton)); + Mocks.Schema(AppId, SchemaId, new Schema(SchemaId.Name, type: SchemaType.Singleton)); singletonSchema = - Mocks.Schema(appId, schemaId, new Schema(schemaId.Name, type: SchemaType.Singleton).Publish()); + Mocks.Schema(AppId, SchemaId, new Schema(SchemaId.Name, type: SchemaType.Singleton).Publish()); componentSchema = - Mocks.Schema(appId, schemaId, new Schema(schemaId.Name, type: SchemaType.Component).Publish()); + Mocks.Schema(AppId, SchemaId, new Schema(SchemaId.Name, type: SchemaType.Component).Publish()); } [Fact] @@ -315,7 +312,7 @@ public class GuardContentTests : IClassFixture [Fact] public void Should_not_throw_exception_if_content_is_from_another_user_but_user_has_permission() { - var userPermission = PermissionIds.ForApp(PermissionIds.AppContentsDelete, appId.Name, schemaId.Name).Id; + var userPermission = PermissionIds.ForApp(PermissionIds.AppContentsDelete, AppId.Name, SchemaId.Name).Id; var userObject = Mocks.FrontendUser(permission: userPermission); var operation = Operation(CreateContent(Status.Draft), normalSchema, userObject); @@ -330,7 +327,7 @@ public class GuardContentTests : IClassFixture { var operation = Operation(CreateContent(Status.Draft), normalSchema); - ((ContentEntity)operation.Snapshot).CreatedBy = actor; + ((ContentEntity)operation.Snapshot).CreatedBy = User; operation.MustHavePermission(PermissionIds.AppContentsDelete); } @@ -360,10 +357,10 @@ public class GuardContentTests : IClassFixture { var operation = Operation(CreateContent(Status.Draft), normalSchema); - A.CallTo(() => contentRepository.HasReferrersAsync(appId.Id, operation.CommandId, SearchScope.All, default)) + A.CallTo(() => contentRepository.HasReferrersAsync(AppId.Id, operation.CommandId, SearchScope.All, CancellationToken)) .Returns(true); - await Assert.ThrowsAsync(() => operation.CheckReferrersAsync()); + await Assert.ThrowsAsync(() => operation.CheckReferrersAsync(CancellationToken)); } [Fact] @@ -371,10 +368,10 @@ public class GuardContentTests : IClassFixture { var operation = Operation(CreateContent(Status.Draft), normalSchema); - A.CallTo(() => contentRepository.HasReferrersAsync(appId.Id, operation.CommandId, SearchScope.All, default)) + A.CallTo(() => contentRepository.HasReferrersAsync(AppId.Id, operation.CommandId, SearchScope.All, CancellationToken)) .Returns(true); - await Assert.ThrowsAsync(() => operation.CheckReferrersAsync()); + await Assert.ThrowsAsync(() => operation.CheckReferrersAsync(CancellationToken)); } private ContentOperation Operation(ContentEntity content, ISchemaEntity operationSchema) @@ -392,8 +389,8 @@ public class GuardContentTests : IClassFixture return new ContentOperation(serviceProvider, () => content) { - App = Mocks.App(appId), - Command = new CreateContent { User = currentUser, Actor = actor }, + App = App, + Command = new CreateContent { User = currentUser, Actor = User }, CommandId = content.Id, Schema = operationSchema }; @@ -412,10 +409,10 @@ public class GuardContentTests : IClassFixture private ContentEntity CreateContentCore(ContentEntity content, DomainId? id = null) { content.Id = id ?? DomainId.NewGuid(); - content.AppId = appId; + content.AppId = AppId; content.Created = default; - content.CreatedBy = actor; - content.SchemaId = schemaId; + content.CreatedBy = User; + content.SchemaId = SchemaId; return content; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DynamicContentWorkflowTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DynamicContentWorkflowTests.cs index 3df2683cd..50c6867a5 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DynamicContentWorkflowTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DynamicContentWorkflowTests.cs @@ -10,7 +10,6 @@ using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Scripting; -using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; @@ -18,12 +17,8 @@ using Squidex.Infrastructure.Collections; namespace Squidex.Domain.Apps.Entities.Contents; -public class DynamicContentWorkflowTests +public class DynamicContentWorkflowTests : GivenContext { - private readonly IAppEntity app; - private readonly IAppProvider appProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly NamedId simpleSchemaId = NamedId.Of(DomainId.NewGuid(), "my-simple-schema"); private readonly DynamicContentWorkflow sut; @@ -58,8 +53,6 @@ public class DynamicContentWorkflowTests public DynamicContentWorkflowTests() { - app = Mocks.App(appId); - var simpleWorkflow = new Workflow( Status.Draft, new Dictionary @@ -83,10 +76,7 @@ public class DynamicContentWorkflowTests var workflows = Workflows.Empty.Set(workflow).Set(DomainId.NewGuid(), simpleWorkflow); - A.CallTo(() => appProvider.GetAppAsync(appId.Id, false, default)) - .Returns(app); - - A.CallTo(() => app.Workflows) + A.CallTo(() => App.Workflows) .Returns(workflows); var scriptEngine = new JintScriptEngine(new MemoryCache(Options.Create(new MemoryCacheOptions())), @@ -96,7 +86,7 @@ public class DynamicContentWorkflowTests TimeoutExecution = TimeSpan.FromSeconds(10) })); - sut = new DynamicContentWorkflow(scriptEngine, appProvider); + sut = new DynamicContentWorkflow(scriptEngine, AppProvider); } [Fact] @@ -122,7 +112,7 @@ public class DynamicContentWorkflowTests [Fact] public async Task Should_return_draft_as_initial_status() { - var actual = await sut.GetInitialStatusAsync(Mocks.Schema(appId, schemaId)); + var actual = await sut.GetInitialStatusAsync(Schema); Assert.Equal(Status.Draft, actual); } @@ -130,7 +120,7 @@ public class DynamicContentWorkflowTests [Fact] public async Task Should_allow_publish_on_create() { - var actual = await sut.CanPublishInitialAsync(Mocks.Schema(appId, schemaId), Mocks.FrontendUser("Editor")); + var actual = await sut.CanPublishInitialAsync(Schema, Mocks.FrontendUser("Editor")); Assert.True(actual); } @@ -138,7 +128,7 @@ public class DynamicContentWorkflowTests [Fact] public async Task Should_not_allow_publish_on_create_if_role_not_allowed() { - var actual = await sut.CanPublishInitialAsync(Mocks.Schema(appId, schemaId), Mocks.FrontendUser("Developer")); + var actual = await sut.CanPublishInitialAsync(Schema, Mocks.FrontendUser("Developer")); Assert.False(actual); } @@ -148,7 +138,7 @@ public class DynamicContentWorkflowTests { var content = CreateContent(Status.Draft, 2); - var actual = await sut.CanMoveToAsync(Mocks.Schema(appId, schemaId), content.Status, Status.Published, content.Data, Mocks.FrontendUser("Editor")); + var actual = await sut.CanMoveToAsync(Schema, content.Status, Status.Published, content.Data, Mocks.FrontendUser("Editor")); Assert.True(actual); } @@ -350,7 +340,7 @@ public class DynamicContentWorkflowTests new StatusInfo(Status.Published, StatusColors.Published) }; - var actual = await sut.GetAllAsync(Mocks.Schema(appId, schemaId)); + var actual = await sut.GetAllAsync(Schema); actual.Should().BeEquivalentTo(expected); } @@ -364,7 +354,7 @@ public class DynamicContentWorkflowTests new StatusInfo(Status.Published, StatusColors.Published) }; - var actual = await sut.GetAllAsync(Mocks.Schema(appId, simpleSchemaId)); + var actual = await sut.GetAllAsync(Mocks.Schema(AppId, simpleSchemaId)); actual.Should().BeEquivalentTo(expected); } @@ -372,7 +362,8 @@ public class DynamicContentWorkflowTests [Fact] public async Task Should_return_all_statuses_for_default_workflow_if_no_workflow_configured() { - A.CallTo(() => app.Workflows).Returns(Workflows.Empty); + A.CallTo(() => App.Workflows) + .Returns(Workflows.Empty); var expected = new[] { @@ -381,7 +372,7 @@ public class DynamicContentWorkflowTests new StatusInfo(Status.Published, StatusColors.Published) }; - var actual = await sut.GetAllAsync(Mocks.Schema(appId, simpleSchemaId)); + var actual = await sut.GetAllAsync(Mocks.Schema(AppId, simpleSchemaId)); actual.Should().BeEquivalentTo(expected); } @@ -389,7 +380,7 @@ public class DynamicContentWorkflowTests [Fact] public async Task Should_not_validate_when_not_publishing() { - var actual = await sut.ShouldValidateAsync(Mocks.Schema(appId, schemaId), Status.Draft); + var actual = await sut.ShouldValidateAsync(Schema, Status.Draft); Assert.False(actual); } @@ -413,7 +404,7 @@ public class DynamicContentWorkflowTests [Fact] public async Task Should_validate_when_enabled_in_step() { - var actual = await sut.ShouldValidateAsync(Mocks.Schema(appId, schemaId), Status.Archived); + var actual = await sut.ShouldValidateAsync(Schema, Status.Archived); Assert.True(actual); } @@ -425,12 +416,12 @@ public class DynamicContentWorkflowTests ValidateOnPublish = validateOnPublish }); - return Mocks.Schema(appId, simpleSchemaId, schema); + return Mocks.Schema(AppId, simpleSchemaId, schema); } private ContentEntity CreateContent(Status status, int value, bool simple = false) { - var content = new ContentEntity { AppId = appId, Status = status }; + var content = new ContentEntity { AppId = AppId, Status = status }; if (simple) { @@ -438,7 +429,7 @@ public class DynamicContentWorkflowTests } else { - content.SchemaId = schemaId; + content.SchemaId = SchemaId; } content.Data = diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs index 8d5d9cce7..0215496a4 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs @@ -8,7 +8,6 @@ using System.Globalization; using LoremNET; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MongoDB.Bson; using MongoDB.Driver; @@ -18,9 +17,7 @@ using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Contents.DomainObject; -using Squidex.Domain.Apps.Entities.MongoDb.Assets; using Squidex.Domain.Apps.Entities.MongoDb.Contents; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/CalculateTokensTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/CalculateTokensTests.cs index 27ff886b0..cabc27e57 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/CalculateTokensTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/CalculateTokensTests.cs @@ -8,42 +8,30 @@ using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Contents.Queries.Steps; -using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; using Squidex.Infrastructure.Json; namespace Squidex.Domain.Apps.Entities.Contents.Queries; -public class CalculateTokensTests +public class CalculateTokensTests : GivenContext { - private readonly ISchemaEntity schema; private readonly IJsonSerializer serializer = A.Fake(); private readonly IUrlGenerator urlGenerator = A.Fake(); - private readonly Context requestContext; - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); - private readonly ProvideSchema schemaProvider; private readonly CalculateTokens sut; public CalculateTokensTests() { - requestContext = new Context(Mocks.ApiUser(), Mocks.App(appId)); - - schema = Mocks.Schema(appId, schemaId); - schemaProvider = x => Task.FromResult((schema, ResolvedComponents.Empty)); - sut = new CalculateTokens(urlGenerator, serializer); } [Fact] public async Task Should_compute_ui_tokens() { - var source = CreateContent(); + var content = CreateContent(); - await sut.EnrichAsync(requestContext, new[] { source }, schemaProvider, default); + await sut.EnrichAsync(ApiContext, new[] { content }, SchemaProvider(), CancellationToken); - Assert.NotNull(source.EditToken); + Assert.NotNull(content.EditToken); A.CallTo(() => urlGenerator.Root()) .MustHaveHappened(); @@ -52,11 +40,11 @@ public class CalculateTokensTests [Fact] public async Task Should_also_compute_ui_tokens_for_frontend() { - var source = CreateContent(); + var content = CreateContent(); - await sut.EnrichAsync(new Context(Mocks.FrontendUser(), Mocks.App(appId)), new[] { source }, schemaProvider, default); + await sut.EnrichAsync(FrontendContext, new[] { content }, SchemaProvider(), CancellationToken); - Assert.NotNull(source.EditToken); + Assert.NotNull(content.EditToken); A.CallTo(() => urlGenerator.Root()) .MustHaveHappened(); @@ -64,6 +52,11 @@ public class CalculateTokensTests private ContentEntity CreateContent() { - return new ContentEntity { AppId = appId, SchemaId = schemaId }; + return new ContentEntity { AppId = AppId, SchemaId = SchemaId }; + } + + private ProvideSchema SchemaProvider() + { + return x => Task.FromResult((Schema, ResolvedComponents.Empty)); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentEnricherTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentEnricherTests.cs index 17f1716d1..7f1752e9b 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentEnricherTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentEnricherTests.cs @@ -8,20 +8,11 @@ using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Queries; -public class ContentEnricherTests +public class ContentEnricherTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; - private readonly IAppProvider appProvider = A.Fake(); - private readonly ISchemaEntity schema; - private readonly Context requestContext; - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); - private sealed class ResolveSchema : IContentEnricherStep { public ISchemaEntity Schema { get; private set; } @@ -36,40 +27,28 @@ public class ContentEnricherTests } } - public ContentEnricherTests() - { - ct = cts.Token; - - requestContext = new Context(Mocks.ApiUser(), Mocks.App(appId)); - - schema = Mocks.Schema(appId, schemaId); - - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false, ct)) - .Returns(schema); - } - [Fact] - public async Task Should_only_invoke_pre_enrich_for_empty_actuals() + public async Task Should_only_invoke_pre_enrich_for_empty_contents() { var source = Array.Empty(); var step1 = A.Fake(); var step2 = A.Fake(); - var sut = new ContentEnricher(new[] { step1, step2 }, appProvider); + var sut = new ContentEnricher(new[] { step1, step2 }, AppProvider); - await sut.EnrichAsync(source, requestContext, ct); + await sut.EnrichAsync(source, ApiContext, CancellationToken); - A.CallTo(() => step1.EnrichAsync(requestContext, ct)) + A.CallTo(() => step1.EnrichAsync(ApiContext, CancellationToken)) .MustHaveHappened(); - A.CallTo(() => step2.EnrichAsync(requestContext, ct)) + A.CallTo(() => step2.EnrichAsync(ApiContext, CancellationToken)) .MustHaveHappened(); - A.CallTo(() => step1.EnrichAsync(requestContext, A>._, A._, A._)) + A.CallTo(() => step1.EnrichAsync(ApiContext, A>._, A._, A._)) .MustNotHaveHappened(); - A.CallTo(() => step2.EnrichAsync(requestContext, A>._, A._, A._)) + A.CallTo(() => step2.EnrichAsync(ApiContext, A>._, A._, A._)) .MustNotHaveHappened(); } @@ -81,20 +60,20 @@ public class ContentEnricherTests var step1 = A.Fake(); var step2 = A.Fake(); - var sut = new ContentEnricher(new[] { step1, step2 }, appProvider); + var sut = new ContentEnricher(new[] { step1, step2 }, AppProvider); - await sut.EnrichAsync(source, false, requestContext, ct); + await sut.EnrichAsync(source, false, ApiContext, CancellationToken); - A.CallTo(() => step1.EnrichAsync(requestContext, ct)) + A.CallTo(() => step1.EnrichAsync(ApiContext, CancellationToken)) .MustHaveHappened(); - A.CallTo(() => step2.EnrichAsync(requestContext, ct)) + A.CallTo(() => step2.EnrichAsync(ApiContext, CancellationToken)) .MustHaveHappened(); - A.CallTo(() => step1.EnrichAsync(requestContext, A>._, A._, ct)) + A.CallTo(() => step1.EnrichAsync(ApiContext, A>._, A._, CancellationToken)) .MustHaveHappened(); - A.CallTo(() => step2.EnrichAsync(requestContext, A>._, A._, ct)) + A.CallTo(() => step2.EnrichAsync(ApiContext, A>._, A._, CancellationToken)) .MustHaveHappened(); } @@ -106,14 +85,14 @@ public class ContentEnricherTests var step1 = new ResolveSchema(); var step2 = new ResolveSchema(); - var sut = new ContentEnricher(new[] { step1, step2 }, appProvider); + var sut = new ContentEnricher(new[] { step1, step2 }, AppProvider); - await sut.EnrichAsync(source, false, requestContext, ct); + await sut.EnrichAsync(source, false, ApiContext, CancellationToken); - Assert.Same(schema, step1.Schema); - Assert.Same(schema, step1.Schema); + Assert.Same(Schema, step1.Schema); + Assert.Same(Schema, step1.Schema); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false, ct)) + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, SchemaId.Id, false, CancellationToken)) .MustHaveHappenedOnceExactly(); } @@ -122,9 +101,9 @@ public class ContentEnricherTests { var source = CreateContent(new ContentData()); - var sut = new ContentEnricher(Enumerable.Empty(), appProvider); + var sut = new ContentEnricher(Enumerable.Empty(), AppProvider); - var actual = await sut.EnrichAsync(source, true, requestContext, ct); + var actual = await sut.EnrichAsync(source, true, ApiContext, CancellationToken); Assert.NotSame(source.Data, actual.Data); } @@ -134,15 +113,15 @@ public class ContentEnricherTests { var source = CreateContent(new ContentData()); - var sut = new ContentEnricher(Enumerable.Empty(), appProvider); + var sut = new ContentEnricher(Enumerable.Empty(), AppProvider); - var actual = await sut.EnrichAsync(source, false, requestContext, ct); + var actual = await sut.EnrichAsync(source, false, ApiContext, CancellationToken); Assert.Same(source.Data, actual.Data); } private ContentEntity CreateContent(ContentData? data = null) { - return new ContentEntity { SchemaId = schemaId, Data = data! }; + return new ContentEntity { SchemaId = SchemaId, Data = data! }; } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentLoaderTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentLoaderTests.cs index 9c6f33609..d0de8045c 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentLoaderTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentLoaderTests.cs @@ -6,30 +6,26 @@ // ========================================================================== using Squidex.Domain.Apps.Entities.Contents.DomainObject; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; namespace Squidex.Domain.Apps.Entities.Contents.Queries; -public class ContentLoaderTests +public class ContentLoaderTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IDomainObjectFactory domainObjectFactory = A.Fake(); private readonly IDomainObjectCache domainObjectCache = A.Fake(); private readonly ContentDomainObject domainObject = A.Fake(); - private readonly DomainId appId = DomainId.NewGuid(); private readonly DomainId id = DomainId.NewGuid(); private readonly DomainId unqiueId; private readonly ContentLoader sut; public ContentLoaderTests() { - ct = cts.Token; + unqiueId = DomainId.Combine(AppId.Id, id); - unqiueId = DomainId.Combine(appId, id); - - A.CallTo(() => domainObjectCache.GetAsync(A._, A._, ct)) + A.CallTo(() => domainObjectCache.GetAsync(A._, A._, CancellationToken)) .Returns(Task.FromResult(null!)); A.CallTo(() => domainObjectFactory.Create(unqiueId)) @@ -43,10 +39,10 @@ public class ContentLoaderTests { var content = (ContentDomainObject.State)null!; - A.CallTo(() => domainObject.GetSnapshotAsync(10, ct)) + A.CallTo(() => domainObject.GetSnapshotAsync(10, CancellationToken)) .Returns(content); - Assert.Null(await sut.GetAsync(appId, id, 10, ct)); + Assert.Null(await sut.GetAsync(AppId.Id, id, 10, CancellationToken)); } [Fact] @@ -54,10 +50,10 @@ public class ContentLoaderTests { var content = new ContentDomainObject.State { Version = EtagVersion.Empty }; - A.CallTo(() => domainObject.GetSnapshotAsync(10, ct)) + A.CallTo(() => domainObject.GetSnapshotAsync(10, CancellationToken)) .Returns(content); - Assert.Null(await sut.GetAsync(appId, id, 10, ct)); + Assert.Null(await sut.GetAsync(AppId.Id, id, 10, CancellationToken)); } [Fact] @@ -65,10 +61,10 @@ public class ContentLoaderTests { var content = new ContentDomainObject.State { Version = 5 }; - A.CallTo(() => domainObject.GetSnapshotAsync(10, ct)) + A.CallTo(() => domainObject.GetSnapshotAsync(10, CancellationToken)) .Returns(content); - Assert.Null(await sut.GetAsync(appId, id, 10, ct)); + Assert.Null(await sut.GetAsync(AppId.Id, id, 10, CancellationToken)); } [Fact] @@ -76,10 +72,10 @@ public class ContentLoaderTests { var content = new ContentDomainObject.State { Version = 5 }; - A.CallTo(() => domainObject.GetSnapshotAsync(EtagVersion.Any, ct)) + A.CallTo(() => domainObject.GetSnapshotAsync(EtagVersion.Any, CancellationToken)) .Returns(content); - var actual = await sut.GetAsync(appId, id, EtagVersion.Any, ct); + var actual = await sut.GetAsync(AppId.Id, id, EtagVersion.Any, CancellationToken); Assert.Same(content, actual); } @@ -89,10 +85,10 @@ public class ContentLoaderTests { var content = new ContentDomainObject.State { Version = 10 }; - A.CallTo(() => domainObject.GetSnapshotAsync(10, ct)) + A.CallTo(() => domainObject.GetSnapshotAsync(10, CancellationToken)) .Returns(content); - var actual = await sut.GetAsync(appId, id, 10, ct); + var actual = await sut.GetAsync(AppId.Id, id, 10, CancellationToken); Assert.Same(content, actual); } @@ -102,10 +98,10 @@ public class ContentLoaderTests { var content = new ContentDomainObject.State { Version = 10 }; - A.CallTo(() => domainObjectCache.GetAsync(DomainId.Combine(appId, id), 10, ct)) + A.CallTo(() => domainObjectCache.GetAsync(DomainId.Combine(AppId.Id, id), 10, CancellationToken)) .Returns(content); - var actual = await sut.GetAsync(appId, id, 10, ct); + var actual = await sut.GetAsync(AppId.Id, id, 10, CancellationToken); Assert.Same(content, actual); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs index 665862f62..42ef1cf2d 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryParserTests.cs @@ -11,7 +11,6 @@ using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Contents.Text; -using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; @@ -20,38 +19,32 @@ using Squidex.Infrastructure.Validation; namespace Squidex.Domain.Apps.Entities.Contents.Queries; -public class ContentQueryParserTests +public class ContentQueryParserTests : GivenContext { - private readonly IAppProvider appProvider = A.Fake(); private readonly ITextIndex textIndex = A.Fake(); - private readonly ISchemaEntity schema; - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly Context requestContext; private readonly ContentQueryParser sut; public ContentQueryParserTests() { var options = Options.Create(new ContentOptions { DefaultPageSize = 30 }); - requestContext = new Context(Mocks.FrontendUser(), Mocks.App(appId)); - var schemaDef = - new Schema(schemaId.Name) + new Schema(SchemaId.Name) .AddString(1, "firstName", Partitioning.Invariant) .AddGeolocation(2, "geo", Partitioning.Invariant); - schema = Mocks.Schema(appId, schemaId, schemaDef); + A.CallTo(() => Schema.SchemaDef) + .Returns(schemaDef); var cache = new MemoryCache(Options.Create(new MemoryCacheOptions())); - sut = new ContentQueryParser(appProvider, textIndex, options, cache, TestUtils.DefaultSerializer); + sut = new ContentQueryParser(AppProvider, textIndex, options, cache, TestUtils.DefaultSerializer); } [Fact] public async Task Should_skip_total_if_set_in_context() { - var q = await sut.ParseAsync(requestContext.Clone(b => b.WithoutTotal()), Q.Empty); + var q = await sut.ParseAsync(ApiContext.Clone(b => b.WithoutTotal()), Q.Empty, ct: CancellationToken); Assert.True(q.NoTotal); } @@ -61,7 +54,7 @@ public class ContentQueryParserTests { var query = Q.Empty.WithODataQuery("$filter=invalid"); - await Assert.ThrowsAsync(() => sut.ParseAsync(requestContext, query, schema)); + await Assert.ThrowsAsync(() => sut.ParseAsync(ApiContext, query, Schema, CancellationToken)); } [Fact] @@ -69,7 +62,7 @@ public class ContentQueryParserTests { var query = Q.Empty.WithJsonQuery("invalid"); - await Assert.ThrowsAsync(() => sut.ParseAsync(requestContext, query, schema)); + await Assert.ThrowsAsync(() => sut.ParseAsync(ApiContext, query, Schema, CancellationToken)); } [Fact] @@ -77,7 +70,7 @@ public class ContentQueryParserTests { var query = Q.Empty.WithODataQuery("$filter=status eq 'Draft'"); - var q = await sut.ParseAsync(requestContext, query); + var q = await sut.ParseAsync(ApiContext, query, ct: CancellationToken); Assert.Equal("Filter: status == 'Draft'; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -87,7 +80,7 @@ public class ContentQueryParserTests { var query = Q.Empty.WithJsonQuery("{ \"filter\": { \"path\": \"status\", \"op\": \"eq\", \"value\": \"Draft\" } }"); - var q = await sut.ParseAsync(requestContext, query); + var q = await sut.ParseAsync(ApiContext, query, ct: CancellationToken); Assert.Equal("Filter: status == 'Draft'; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -97,27 +90,27 @@ public class ContentQueryParserTests { var query = Q.Empty.WithODataQuery("$top=100&$orderby=data/firstName/iv asc&$filter=status eq 'Draft'"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Filter: status == 'Draft'; Take: 100; Sort: data.firstName.iv Ascending, id Ascending", q.Query.ToString()); } [Fact] - public async Task Should_parse_odata_query_and_enrich_with_defaults() + public async Task Should_parse_odata_query_and_enrich_with_CancellationTokens() { var query = Q.Empty.WithODataQuery("$top=200&$filter=data/firstName/iv eq 'ABC'"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Filter: data.firstName.iv == 'ABC'; Take: 200; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } [Fact] - public async Task Should_parse_json_query_and_enrich_with_defaults() + public async Task Should_parse_json_query_and_enrich_with_CancellationTokens() { var query = Q.Empty.WithJsonQuery("{ \"filter\": { \"path\": \"data.firstName.iv\", \"op\": \"eq\", \"value\": \"ABC\" } }"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Filter: data.firstName.iv == 'ABC'; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -125,12 +118,12 @@ public class ContentQueryParserTests [Fact] public async Task Should_convert_full_text_query_to_filter_with_other_filter() { - A.CallTo(() => textIndex.SearchAsync(requestContext.App, A.That.Matches(x => x.Text == "Hello"), requestContext.Scope(), default)) + A.CallTo(() => textIndex.SearchAsync(ApiContext.App, A.That.Matches(x => x.Text == "Hello"), ApiContext.Scope(), CancellationToken)) .Returns(new List { DomainId.Create("1"), DomainId.Create("2") }); var query = Q.Empty.WithODataQuery("$search=Hello&$filter=data/firstName/iv eq 'ABC'"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Filter: (data.firstName.iv == 'ABC' && id in ['1', '2']); Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -138,12 +131,12 @@ public class ContentQueryParserTests [Fact] public async Task Should_convert_full_text_query_to_filter() { - A.CallTo(() => textIndex.SearchAsync(requestContext.App, A.That.Matches(x => x.Text == "Hello"), requestContext.Scope(), default)) + A.CallTo(() => textIndex.SearchAsync(ApiContext.App, A.That.Matches(x => x.Text == "Hello"), ApiContext.Scope(), CancellationToken)) .Returns(new List { DomainId.Create("1"), DomainId.Create("2") }); var query = Q.Empty.WithODataQuery("$search=Hello"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Filter: id in ['1', '2']; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -151,12 +144,12 @@ public class ContentQueryParserTests [Fact] public async Task Should_convert_full_text_query_to_filter_if_single_id_found() { - A.CallTo(() => textIndex.SearchAsync(requestContext.App, A.That.Matches(x => x.Text == "Hello"), requestContext.Scope(), default)) + A.CallTo(() => textIndex.SearchAsync(ApiContext.App, A.That.Matches(x => x.Text == "Hello"), ApiContext.Scope(), CancellationToken)) .Returns(new List { DomainId.Create("1") }); var query = Q.Empty.WithODataQuery("$search=Hello"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Filter: id in ['1']; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -164,12 +157,12 @@ public class ContentQueryParserTests [Fact] public async Task Should_convert_full_text_query_to_filter_if_index_returns_null() { - A.CallTo(() => textIndex.SearchAsync(requestContext.App, A.That.Matches(x => x.Text == "Hello"), requestContext.Scope(), default)) + A.CallTo(() => textIndex.SearchAsync(ApiContext.App, A.That.Matches(x => x.Text == "Hello"), ApiContext.Scope(), CancellationToken)) .Returns(Task.FromResult?>(null)); var query = Q.Empty.WithODataQuery("$search=Hello"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Filter: id == '__notfound__'; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -177,12 +170,12 @@ public class ContentQueryParserTests [Fact] public async Task Should_convert_full_text_query_to_filter_if_index_returns_empty() { - A.CallTo(() => textIndex.SearchAsync(requestContext.App, A.That.Matches(x => x.Text == "Hello"), requestContext.Scope(), default)) + A.CallTo(() => textIndex.SearchAsync(ApiContext.App, A.That.Matches(x => x.Text == "Hello"), ApiContext.Scope(), CancellationToken)) .Returns(new List()); var query = Q.Empty.WithODataQuery("$search=Hello"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Filter: id == '__notfound__'; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -190,12 +183,12 @@ public class ContentQueryParserTests [Fact] public async Task Should_convert_geo_query_to_filter() { - A.CallTo(() => textIndex.SearchAsync(requestContext.App, new GeoQuery(schemaId.Id, "geo.iv", 10, 20, 30, 1000), requestContext.Scope(), default)) + A.CallTo(() => textIndex.SearchAsync(ApiContext.App, new GeoQuery(SchemaId.Id, "geo.iv", 10, 20, 30, 1000), ApiContext.Scope(), CancellationToken)) .Returns(new List { DomainId.Create("1"), DomainId.Create("2") }); var query = Q.Empty.WithODataQuery("$filter=geo.distance(data/geo/iv, geography'POINT(20 10)') lt 30.0"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Filter: id in ['1', '2']; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -203,12 +196,12 @@ public class ContentQueryParserTests [Fact] public async Task Should_convert_geo_query_to_filter_if_single_id_found() { - A.CallTo(() => textIndex.SearchAsync(requestContext.App, new GeoQuery(schemaId.Id, "geo.iv", 10, 20, 30, 1000), requestContext.Scope(), default)) + A.CallTo(() => textIndex.SearchAsync(ApiContext.App, new GeoQuery(SchemaId.Id, "geo.iv", 10, 20, 30, 1000), ApiContext.Scope(), CancellationToken)) .Returns(new List { DomainId.Create("1") }); var query = Q.Empty.WithODataQuery("$filter=geo.distance(data/geo/iv, geography'POINT(20 10)') lt 30.0"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Filter: id in ['1']; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -216,12 +209,12 @@ public class ContentQueryParserTests [Fact] public async Task Should_convert_geo_query_to_filter_if_index_returns_null() { - A.CallTo(() => textIndex.SearchAsync(requestContext.App, new GeoQuery(schemaId.Id, "geo.iv", 10, 20, 30, 1000), requestContext.Scope(), default)) + A.CallTo(() => textIndex.SearchAsync(ApiContext.App, new GeoQuery(SchemaId.Id, "geo.iv", 10, 20, 30, 1000), ApiContext.Scope(), CancellationToken)) .Returns(Task.FromResult?>(null)); var query = Q.Empty.WithODataQuery("$filter=geo.distance(data/geo/iv, geography'POINT(20 10)') lt 30.0"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Filter: id == '__notfound__'; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -229,12 +222,12 @@ public class ContentQueryParserTests [Fact] public async Task Should_convert_geo_query_to_filter_if_index_returns_empty() { - A.CallTo(() => textIndex.SearchAsync(requestContext.App, new GeoQuery(schemaId.Id, "geo.iv", 10, 20, 30, 1000), requestContext.Scope(), default)) + A.CallTo(() => textIndex.SearchAsync(ApiContext.App, new GeoQuery(SchemaId.Id, "geo.iv", 10, 20, 30, 1000), ApiContext.Scope(), CancellationToken)) .Returns(new List()); var query = Q.Empty.WithODataQuery("$filter=geo.distance(data/geo/iv, geography'POINT(20 10)') lt 30.0"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Filter: id == '__notfound__'; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -244,11 +237,11 @@ public class ContentQueryParserTests [InlineData(-1L)] [InlineData(long.MaxValue)] [InlineData(long.MinValue)] - public async Task Should_apply_default_take_size_if_not_defined(long take) + public async Task Should_apply_CancellationToken_take_size_if_not_defined(long take) { var query = Q.Empty.WithQuery(new ClrQuery { Take = take }); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -258,7 +251,7 @@ public class ContentQueryParserTests { var query = Q.Empty.WithIds("1, 2, 3"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Take: 3; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -268,17 +261,17 @@ public class ContentQueryParserTests { var query = Q.Empty.WithIds("1, 2, 3").WithQuery(new ClrQuery { Take = 20 }); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Take: 20; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } [Fact] - public async Task Should_apply_default_take_limit() + public async Task Should_apply_CancellationToken_take_limit() { var query = Q.Empty.WithODataQuery("$top=300&$skip=20"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Skip: 20; Take: 200; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } @@ -288,13 +281,13 @@ public class ContentQueryParserTests { var query = Q.Empty.WithODataQuery("$top=300&$skip=20&$orderby=id desc"); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Skip: 20; Take: 200; Sort: id Descending", q.Query.ToString()); } [Fact] - public async Task Should_convert_json_query_and_enrich_with_defaults() + public async Task Should_convert_json_query_and_enrich_with_CancellationTokens() { var query = Q.Empty.WithJsonQuery( new Query @@ -302,7 +295,7 @@ public class ContentQueryParserTests Filter = new CompareFilter("data.firstName.iv", CompareOperator.Equals, JsonValue.Create("ABC")) }); - var q = await sut.ParseAsync(requestContext, query, schema); + var q = await sut.ParseAsync(ApiContext, query, Schema, CancellationToken); Assert.Equal("Filter: data.firstName.iv == 'ABC'; Take: 30; Sort: lastModified Descending, id Ascending", q.Query.ToString()); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryServiceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryServiceTests.cs index 5aa81e6eb..aba1c70e1 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryServiceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ContentQueryServiceTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Security.Claims; using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; @@ -16,51 +15,40 @@ using Squidex.Infrastructure; using Squidex.Infrastructure.Reflection; using Squidex.Infrastructure.Security; using Squidex.Shared; -using Squidex.Shared.Identity; namespace Squidex.Domain.Apps.Entities.Contents.Queries; -public class ContentQueryServiceTests +public class ContentQueryServiceTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; - private readonly IAppProvider appProvider = A.Fake(); private readonly IContentEnricher contentEnricher = A.Fake(); private readonly IContentRepository contentRepository = A.Fake(); private readonly IContentLoader contentVersionLoader = A.Fake(); - private readonly ISchemaEntity schema; - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly ContentData contentData = new ContentData(); private readonly ContentQueryParser queryParser = A.Fake(); private readonly ContentQueryService sut; public ContentQueryServiceTests() { - ct = cts.Token; - var schemaDef = - new Schema(schemaId.Name) + new Schema(SchemaId.Name) .Publish() .SetScripts(new SchemaScripts { Query = "" }); - schema = Mocks.Schema(appId, schemaId, schemaDef); + A.CallTo(() => Schema.SchemaDef) + .Returns(schemaDef); SetupEnricher(); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Name, A._, ct)) - .Returns(schema); - - A.CallTo(() => appProvider.GetSchemasAsync(appId.Id, ct)) - .Returns(new List { schema }); + A.CallTo(() => AppProvider.GetSchemasAsync(AppId.Id, CancellationToken)) + .Returns(new List { Schema }); - A.CallTo(() => queryParser.ParseAsync(A._, A._, A._, ct)) + A.CallTo(() => queryParser.ParseAsync(A._, A._, A._, CancellationToken)) .ReturnsLazily(c => Task.FromResult(c.GetArgument(1)!)); var options = Options.Create(new ContentOptions()); sut = new ContentQueryService( - appProvider, + AppProvider, contentEnricher, contentRepository, contentVersionLoader, @@ -71,68 +59,61 @@ public class ContentQueryServiceTests [Fact] public async Task Should_get_schema_from_guid_string() { - var input = schemaId.Id.ToString(); - - var requestContext = CreateContext(); + var input = SchemaId.Id.ToString(); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, true, ct)) - .Returns(schema); + var requestContext = SetupContext(); - var actual = await sut.GetSchemaOrThrowAsync(requestContext, input, ct); + var actual = await sut.GetSchemaOrThrowAsync(requestContext, input, CancellationToken); - Assert.Equal(schema, actual); + Assert.Equal(Schema, actual); } [Fact] public async Task Should_get_schema_from_name() { - var input = schemaId.Name; + var input = SchemaId.Name; - var requestContext = CreateContext(); + var requestContext = SetupContext(); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Name, true, ct)) - .Returns(schema); + var actual = await sut.GetSchemaOrThrowAsync(requestContext, input, CancellationToken); - var actual = await sut.GetSchemaOrThrowAsync(requestContext, input, ct); - - Assert.Equal(schema, actual); + Assert.Equal(Schema, actual); } [Fact] public async Task Should_throw_notfound_exception_if_schema_to_get_not_found() { - var requestContext = CreateContext(); + var requestContext = SetupContext(); - A.CallTo(() => appProvider.GetSchemaAsync(A._, A._, true, ct)) - .Returns((ISchemaEntity?)null); + Schema = null!; - await Assert.ThrowsAsync(() => sut.GetSchemaOrThrowAsync(requestContext, schemaId.Name, ct)); + await Assert.ThrowsAsync(() => sut.GetSchemaOrThrowAsync(requestContext, SchemaId.Name, CancellationToken)); } [Fact] public async Task Should_throw_permission_exception_if_content_to_find_is_restricted() { - var requestContext = CreateContext(allowSchema: false); + var requestContext = SetupContext(allowSchema: false); var content = CreateContent(DomainId.NewGuid()); - A.CallTo(() => contentRepository.FindContentAsync(requestContext.App, schema, content.Id, A._, A._)) + A.CallTo(() => contentRepository.FindContentAsync(App, Schema, content.Id, A._, A._)) .Returns(CreateContent(DomainId.NewGuid())); - await Assert.ThrowsAsync(() => sut.FindAsync(requestContext, schemaId.Name, content.Id, ct: ct)); + await Assert.ThrowsAsync(() => sut.FindAsync(requestContext, SchemaId.Name, content.Id, ct: CancellationToken)); } [Fact] public async Task Should_return_null_if_content_by_id_dannot_be_found() { - var requestContext = CreateContext(); + var requestContext = SetupContext(); var content = CreateContent(DomainId.NewGuid()); - A.CallTo(() => contentRepository.FindContentAsync(requestContext.App, schema, content.Id, A._, A._)) + A.CallTo(() => contentRepository.FindContentAsync(App, Schema, content.Id, A._, A._)) .Returns(null); - var actual = await sut.FindAsync(requestContext, schemaId.Name, content.Id, ct: ct); + var actual = await sut.FindAsync(requestContext, SchemaId.Name, content.Id, ct: CancellationToken); Assert.Null(actual); } @@ -140,14 +121,14 @@ public class ContentQueryServiceTests [Fact] public async Task Should_return_content_by_special_id() { - var requestContext = CreateContext(); + var requestContext = SetupContext(); var content = CreateContent(DomainId.NewGuid()); - A.CallTo(() => contentRepository.FindContentAsync(requestContext.App, schema, schema.Id, SearchScope.Published, A._)) + A.CallTo(() => contentRepository.FindContentAsync(App, Schema, SchemaId.Id, SearchScope.Published, A._)) .Returns(content); - var actual = await sut.FindAsync(requestContext, schemaId.Name, DomainId.Create("_schemaId_"), ct: ct); + var actual = await sut.FindAsync(requestContext, SchemaId.Name, DomainId.Create("_schemaId_"), ct: CancellationToken); AssertContent(content, actual); } @@ -159,14 +140,14 @@ public class ContentQueryServiceTests [InlineData(0, 0, SearchScope.Published)] public async Task Should_return_content_by_id(int isFrontend, int unpublished, SearchScope scope) { - var requestContext = CreateContext(isFrontend, isUnpublished: unpublished); + var requestContext = SetupContext(isFrontend, isUnpublished: unpublished); var content = CreateContent(DomainId.NewGuid()); - A.CallTo(() => contentRepository.FindContentAsync(requestContext.App, schema, content.Id, scope, A._)) + A.CallTo(() => contentRepository.FindContentAsync(App, Schema, content.Id, scope, A._)) .Returns(content); - var actual = await sut.FindAsync(requestContext, schemaId.Name, content.Id, ct: ct); + var actual = await sut.FindAsync(requestContext, SchemaId.Name, content.Id, ct: CancellationToken); AssertContent(content, actual); } @@ -174,14 +155,14 @@ public class ContentQueryServiceTests [Fact] public async Task Should_return_content_by_id_and_version() { - var requestContext = CreateContext(); + var requestContext = SetupContext(); var content = CreateContent(DomainId.NewGuid()); - A.CallTo(() => contentVersionLoader.GetAsync(appId.Id, content.Id, 13, A._)) + A.CallTo(() => contentVersionLoader.GetAsync(AppId.Id, content.Id, 13, A._)) .Returns(content); - var actual = await sut.FindAsync(requestContext, schemaId.Name, content.Id, 13, ct); + var actual = await sut.FindAsync(requestContext, SchemaId.Name, content.Id, 13, CancellationToken); AssertContent(content, actual); } @@ -189,9 +170,9 @@ public class ContentQueryServiceTests [Fact] public async Task Should_throw_exception_if_user_has_no_permission_to_query_content() { - var requestContext = CreateContext(allowSchema: false); + var requestContext = SetupContext(allowSchema: false); - await Assert.ThrowsAsync(() => sut.QueryAsync(requestContext, schemaId.Name, Q.Empty, ct)); + await Assert.ThrowsAsync(() => sut.QueryAsync(requestContext, SchemaId.Name, Q.Empty, CancellationToken)); } [Theory] @@ -201,17 +182,17 @@ public class ContentQueryServiceTests [InlineData(0, 0, SearchScope.Published)] public async Task Should_query_contents(int isFrontend, int unpublished, SearchScope scope) { - var requestContext = CreateContext(isFrontend, isUnpublished: unpublished); + var requestContext = SetupContext(isFrontend, isUnpublished: unpublished); var content1 = CreateContent(DomainId.NewGuid()); var content2 = CreateContent(DomainId.NewGuid()); var q = Q.Empty.WithReference(DomainId.NewGuid()); - A.CallTo(() => contentRepository.QueryAsync(requestContext.App, schema, q, scope, A._)) + A.CallTo(() => contentRepository.QueryAsync(App, Schema, q, scope, A._)) .Returns(ResultList.CreateFrom(5, content1, content2)); - var actual = await sut.QueryAsync(requestContext, schemaId.Name, q, ct); + var actual = await sut.QueryAsync(requestContext, SchemaId.Name, q, CancellationToken); Assert.Equal(5, actual.Total); @@ -226,20 +207,19 @@ public class ContentQueryServiceTests [InlineData(0, 0, SearchScope.Published)] public async Task Should_query_contents_by_ids(int isFrontend, int unpublished, SearchScope scope) { - var requestContext = CreateContext(isFrontend, isUnpublished: unpublished); - - var ids = Enumerable.Range(0, 5).Select(x => DomainId.NewGuid()).ToList(); + var requestContext = SetupContext(isFrontend, isUnpublished: unpublished); - var contents = ids.Select(CreateContent).ToList(); + var contentIds = Enumerable.Range(0, 5).Select(x => DomainId.NewGuid()).ToList(); + var contents = contentIds.Select(CreateContent).ToList(); - var q = Q.Empty.WithIds(ids); + var q = Q.Empty.WithIds(contentIds); - A.CallTo(() => contentRepository.QueryAsync(requestContext.App, + A.CallTo(() => contentRepository.QueryAsync(App, A>.That.Matches(x => x.Count == 1), q, scope, A._)) .Returns(ResultList.Create(5, contents)); - var actual = await sut.QueryAsync(requestContext, q, ct); + var actual = await sut.QueryAsync(requestContext, q, CancellationToken); Assert.Equal(5, actual.Total); @@ -252,18 +232,19 @@ public class ContentQueryServiceTests [Fact] public async Task Should_query_contents_with_matching_permissions() { - var requestContext = CreateContext(allowSchema: false); + var requestContext = SetupContext(allowSchema: false); - var ids = Enumerable.Range(0, 5).Select(x => DomainId.NewGuid()).ToList(); + var contentIds = Enumerable.Range(0, 5).Select(x => DomainId.NewGuid()).ToList(); + var contents = contentIds.Select(CreateContent).ToList(); - var q = Q.Empty.WithIds(ids); + var q = Q.Empty.WithIds(contentIds); - A.CallTo(() => contentRepository.QueryAsync(requestContext.App, + A.CallTo(() => contentRepository.QueryAsync(App, A>.That.Matches(x => x.Count == 0), q, SearchScope.All, A._)) - .Returns(ResultList.Create(0, ids.Select(CreateContent))); + .Returns(ResultList.Create(0, contents)); - var actual = await sut.QueryAsync(requestContext, q, ct); + var actual = await sut.QueryAsync(requestContext, q, CancellationToken); Assert.Empty(actual); } @@ -271,11 +252,11 @@ public class ContentQueryServiceTests [Fact] public async Task Should_query_contents_from_user_if_user_has_only_own_permission() { - var requestContext = CreateContext(permissionId: PermissionIds.AppContentsReadOwn); + var requestContext = SetupContext(permissionId: PermissionIds.AppContentsReadOwn); - await sut.QueryAsync(requestContext, schemaId.Name, Q.Empty, ct); + await sut.QueryAsync(requestContext, SchemaId.Name, Q.Empty, CancellationToken); - A.CallTo(() => contentRepository.QueryAsync(requestContext.App, schema, + A.CallTo(() => contentRepository.QueryAsync(App, Schema, A.That.Matches(x => Equals(x.CreatedBy, requestContext.UserPrincipal.Token())), SearchScope.Published, A ._)) .MustHaveHappened(); @@ -284,11 +265,11 @@ public class ContentQueryServiceTests [Fact] public async Task Should_query_all_contents_if_user_has_read_permission() { - var requestContext = CreateContext(permissionId: PermissionIds.AppContentsRead); + var requestContext = SetupContext(permissionId: PermissionIds.AppContentsRead); - await sut.QueryAsync(requestContext, schemaId.Name, Q.Empty, ct); + await sut.QueryAsync(requestContext, SchemaId.Name, Q.Empty, CancellationToken); - A.CallTo(() => contentRepository.QueryAsync(requestContext.App, schema, + A.CallTo(() => contentRepository.QueryAsync(App, Schema, A.That.Matches(x => x.CreatedBy == null), SearchScope.Published, A._)) .MustHaveHappened(); @@ -296,7 +277,7 @@ public class ContentQueryServiceTests private void SetupEnricher() { - A.CallTo(() => contentEnricher.EnrichAsync(A>._, A._, ct)) + A.CallTo(() => contentEnricher.EnrichAsync(A>._, A._, CancellationToken)) .ReturnsLazily(x => { var input = x.GetArgument>(0)!; @@ -305,30 +286,22 @@ public class ContentQueryServiceTests }); } - private Context CreateContext( + private Context SetupContext( int isFrontend = 0, int isUnpublished = 0, bool allowSchema = true, string permissionId = PermissionIds.AppContentsRead) { - var claimsIdentity = new ClaimsIdentity(); - var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); - - claimsIdentity.AddClaim(new Claim(OpenIdClaims.Subject, "user1")); - - if (isFrontend == 1) - { - claimsIdentity.AddClaim(new Claim(OpenIdClaims.ClientId, DefaultClients.Frontend)); - } + var permissions = new List(); if (allowSchema) { - var concretePermission = PermissionIds.ForApp(permissionId, appId.Name, schemaId.Name).Id; + var concretePermission = PermissionIds.ForApp(permissionId, AppId.Name, SchemaId.Name).Id; - claimsIdentity.AddClaim(new Claim(SquidexClaimTypes.Permissions, concretePermission)); + permissions.Add(concretePermission); } - return new Context(claimsPrincipal, Mocks.App(appId)).Clone(b => b.WithUnpublished(isUnpublished == 1)); + return CreateContext(isFrontend == 1, permissions.ToArray()).Clone(b => b.WithUnpublished(isUnpublished == 1)); } private static void AssertContent(IContentEntity source, IEnrichedContentEntity? actual) @@ -345,7 +318,7 @@ public class ContentQueryServiceTests { Id = id, Data = contentData, - SchemaId = schemaId, + SchemaId = SchemaId, Status = Status.Published }; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs index d6e937fde..f9fa9254f 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ConvertDataTests.cs @@ -12,7 +12,6 @@ using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Assets.Repositories; using Squidex.Domain.Apps.Entities.Contents.Queries.Steps; using Squidex.Domain.Apps.Entities.Contents.Repositories; -using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; @@ -20,28 +19,24 @@ using TestUtils = Squidex.Domain.Apps.Core.TestHelpers.TestUtils; namespace Squidex.Domain.Apps.Entities.Contents.Queries; -public class ConvertDataTests +public class ConvertDataTests : GivenContext { - private readonly ISchemaEntity schema; private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly IAssetRepository assetRepository = A.Fake(); private readonly IContentRepository contentRepository = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); - private readonly ProvideSchema schemaProvider; private readonly ConvertData sut; public ConvertDataTests() { var schemaDef = - new Schema("my-schema") + new Schema(SchemaId.Name) .AddReferences(1, "references", Partitioning.Invariant) .AddAssets(2, "assets", Partitioning.Invariant) .AddArray(3, "array", Partitioning.Invariant, a => a .AddAssets(31, "nested")); - schema = Mocks.Schema(appId, schemaId, schemaDef); - schemaProvider = x => Task.FromResult((schema, ResolvedComponents.Empty)); + A.CallTo(() => Schema.SchemaDef) + .Returns(schemaDef); sut = new ConvertData(urlGenerator, TestUtils.DefaultSerializer, assetRepository, contentRepository); } @@ -51,9 +46,7 @@ public class ConvertDataTests { var content = CreateContent(new ContentData()); - var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)); - - await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider, default); + await sut.EnrichAsync(FrontendContext, new[] { content }, SchemaProvider(), CancellationToken); Assert.NotNull(content.Data); } @@ -83,15 +76,13 @@ public class ConvertDataTests new JsonObject() .Add("nested", JsonValue.Array(id2))))); - A.CallTo(() => assetRepository.QueryIdsAsync(appId.Id, A>.That.Is(id1, id2), A._)) + A.CallTo(() => assetRepository.QueryIdsAsync(AppId.Id, A>.That.Is(id1, id2), CancellationToken)) .Returns(new List { id2 }); - A.CallTo(() => contentRepository.QueryIdsAsync(appId.Id, A>.That.Is(id1, id2), SearchScope.All, A._)) + A.CallTo(() => contentRepository.QueryIdsAsync(AppId.Id, A>.That.Is(id1, id2), SearchScope.All, CancellationToken)) .Returns(new List { new ContentIdStatus(id2, id2, Status.Published) }); - var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)); - - await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider, default); + await sut.EnrichAsync(ApiContext, new[] { content }, SchemaProvider(), CancellationToken); Assert.Equal(expected, content.Data); } @@ -121,15 +112,13 @@ public class ConvertDataTests new JsonObject() .Add("nested", JsonValue.Array())))); - A.CallTo(() => assetRepository.QueryIdsAsync(appId.Id, A>.That.Is(id1, id2), A._)) + A.CallTo(() => assetRepository.QueryIdsAsync(AppId.Id, A>.That.Is(id1, id2), CancellationToken)) .Returns(new List()); - A.CallTo(() => contentRepository.QueryIdsAsync(appId.Id, A>.That.Is(id1, id2), SearchScope.All, A._)) + A.CallTo(() => contentRepository.QueryIdsAsync(AppId.Id, A>.That.Is(id1, id2), SearchScope.All, CancellationToken)) .Returns(new List()); - var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)); - - await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider, default); + await sut.EnrichAsync(ApiContext, new[] { content }, SchemaProvider(), CancellationToken); Assert.Equal(expected, content.Data); } @@ -155,9 +144,17 @@ public class ConvertDataTests { return new ContentEntity { + AppId = AppId, + Created = default, + CreatedBy = User, Data = data, - SchemaId = schemaId, + SchemaId = SchemaId, Status = Status.Published }; } + + private ProvideSchema SchemaProvider() + { + return x => Task.FromResult((Schema, ResolvedComponents.Empty)); + } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs index c69b53598..6142a07eb 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs @@ -7,30 +7,19 @@ using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Contents.Queries.Steps; -using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Caching; namespace Squidex.Domain.Apps.Entities.Contents.Queries; -public class EnrichForCachingTests +public class EnrichForCachingTests : GivenContext { - private readonly ISchemaEntity schema; private readonly IRequestCache requestCache = A.Fake(); - private readonly Context requestContext; - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); - private readonly ProvideSchema schemaProvider; private readonly EnrichForCaching sut; public EnrichForCachingTests() { - requestContext = new Context(Mocks.ApiUser(), Mocks.App(appId)); - - schema = Mocks.Schema(appId, schemaId); - schemaProvider = x => Task.FromResult((schema, ResolvedComponents.Empty)); - sut = new EnrichForCaching(requestCache); } @@ -42,7 +31,7 @@ public class EnrichForCachingTests A.CallTo(() => requestCache.AddHeader(A._)) .Invokes(new Action(header => headers.Add(header))); - await sut.EnrichAsync(requestContext, default); + await sut.EnrichAsync(ApiContext, CancellationToken); Assert.Equal(new List { @@ -62,20 +51,25 @@ public class EnrichForCachingTests { var content = CreateContent(); - await sut.EnrichAsync(requestContext, Enumerable.Repeat(content, 1), schemaProvider, default); + await sut.EnrichAsync(ApiContext, Enumerable.Repeat(content, 1), SchemaProvider(), CancellationToken); A.CallTo(() => requestCache.AddDependency(content.UniqueId, content.Version)) .MustHaveHappened(); - A.CallTo(() => requestCache.AddDependency(schema.UniqueId, schema.Version)) + A.CallTo(() => requestCache.AddDependency(Schema.UniqueId, Schema.Version)) .MustHaveHappened(); - A.CallTo(() => requestCache.AddDependency(requestContext.App.UniqueId, requestContext.App.Version)) + A.CallTo(() => requestCache.AddDependency(App.UniqueId, App.Version)) .MustHaveHappened(); } private ContentEntity CreateContent() { - return new ContentEntity { AppId = appId, Id = DomainId.NewGuid(), SchemaId = schemaId, Version = 13 }; + return new ContentEntity { AppId = AppId, Id = DomainId.NewGuid(), SchemaId = SchemaId, Version = 13 }; + } + + private ProvideSchema SchemaProvider() + { + return x => Task.FromResult((Schema, ResolvedComponents.Empty)); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithSchemaTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithSchemaTests.cs index d49d3ba0b..bdea2cdda 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithSchemaTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithSchemaTests.cs @@ -7,36 +7,25 @@ using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Contents.Queries.Steps; -using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Queries; -public class EnrichWithSchemaTests +public class EnrichWithSchemaTests : GivenContext { - private readonly ISchemaEntity schema; - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); - private readonly ProvideSchema schemaProvider; private readonly EnrichWithSchema sut; public EnrichWithSchemaTests() { - schema = Mocks.Schema(appId, schemaId); - schemaProvider = x => Task.FromResult((schema, ResolvedComponents.Empty)); - sut = new EnrichWithSchema(); } [Fact] public async Task Should_enrich_with_reference_fields() { - var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)); - var content = CreateContent(); - await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider, default); + await sut.EnrichAsync(FrontendContext, new[] { content }, SchemaProvider(), CancellationToken); Assert.NotNull(content.ReferenceFields); } @@ -44,29 +33,30 @@ public class EnrichWithSchemaTests [Fact] public async Task Should_not_enrich_with_reference_fields_if_not_frontend() { - var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId)); - - var source = CreateContent(); + var content = CreateContent(); - await sut.EnrichAsync(ctx, Enumerable.Repeat(source, 1), schemaProvider, default); + await sut.EnrichAsync(ApiContext, new[] { content }, SchemaProvider(), CancellationToken); - Assert.Null(source.ReferenceFields); + Assert.Null(content.ReferenceFields); } [Fact] public async Task Should_enrich_with_schema_names() { - var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId)); - var content = CreateContent(); - await sut.EnrichAsync(ctx, Enumerable.Repeat(content, 1), schemaProvider, default); + await sut.EnrichAsync(ApiContext, new[] { content }, SchemaProvider(), CancellationToken); Assert.Equal("my-schema", content.SchemaDisplayName); } private ContentEntity CreateContent() { - return new ContentEntity { SchemaId = schemaId }; + return new ContentEntity { SchemaId = SchemaId }; + } + + private ProvideSchema SchemaProvider() + { + return x => Task.FromResult((Schema, ResolvedComponents.Empty)); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs index 4e7c04f05..16543c96a 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichWithWorkflowsTests.cs @@ -8,42 +8,35 @@ using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Contents.Queries.Steps; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; #pragma warning disable CA2012 // Use ValueTasks correctly namespace Squidex.Domain.Apps.Entities.Contents.Queries; -public class EnrichWithWorkflowsTests +public class EnrichWithWorkflowsTests : GivenContext { private readonly IContentWorkflow workflow = A.Fake(); - private readonly Context requestContext; - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); - private readonly RefToken user = RefToken.User("me"); private readonly EnrichWithWorkflows sut; public EnrichWithWorkflowsTests() { - requestContext = new Context(Mocks.FrontendUser(), Mocks.App(appId)); - sut = new EnrichWithWorkflows(workflow); } [Fact] public async Task Should_enrich_content_with_next_statuses() { - var content = new ContentEntity { SchemaId = schemaId }; + var content = new ContentEntity { SchemaId = SchemaId }; var nexts = new[] { new StatusInfo(Status.Published, StatusColors.Published) }; - A.CallTo(() => workflow.GetNextAsync(content, content.Status, requestContext.UserPrincipal)) + A.CallTo(() => workflow.GetNextAsync(content, content.Status, FrontendContext.UserPrincipal)) .Returns(nexts); - await sut.EnrichAsync(requestContext, new[] { content }, null!, default); + await sut.EnrichAsync(FrontendContext, new[] { content }, null!, CancellationToken); Assert.Equal(nexts, content.NextStatuses); } @@ -51,38 +44,38 @@ public class EnrichWithWorkflowsTests [Fact] public async Task Should_enrich_content_with_next_statuses_if_draft_singleton() { - var content = new ContentEntity { SchemaId = schemaId, IsSingleton = true, Status = Status.Draft }; + var content = new ContentEntity { SchemaId = SchemaId, IsSingleton = true, Status = Status.Draft }; - await sut.EnrichAsync(requestContext, new[] { content }, null!, default); + await sut.EnrichAsync(FrontendContext, new[] { content }, null!, default); Assert.Equal(Status.Published, content.NextStatuses?.Single().Status); - A.CallTo(() => workflow.GetNextAsync(content, A._, requestContext.UserPrincipal)) + A.CallTo(() => workflow.GetNextAsync(content, A._, FrontendContext.UserPrincipal)) .MustNotHaveHappened(); } [Fact] public async Task Should_enrich_content_with_next_statuses_if_published_singleton() { - var content = new ContentEntity { SchemaId = schemaId, IsSingleton = true, Status = Status.Published }; + var content = new ContentEntity { SchemaId = SchemaId, IsSingleton = true, Status = Status.Published }; - await sut.EnrichAsync(requestContext, new[] { content }, null!, default); + await sut.EnrichAsync(FrontendContext, new[] { content }, null!, CancellationToken); Assert.Empty(content.NextStatuses!); - A.CallTo(() => workflow.GetNextAsync(content, A._, requestContext.UserPrincipal)) + A.CallTo(() => workflow.GetNextAsync(content, A._, FrontendContext.UserPrincipal)) .MustNotHaveHappened(); } [Fact] public async Task Should_enrich_content_with_status_color() { - var content = new ContentEntity { SchemaId = schemaId }; + var content = new ContentEntity { SchemaId = SchemaId }; A.CallTo(() => workflow.GetInfoAsync(content, content.Status)) .Returns(new StatusInfo(Status.Published, StatusColors.Published)); - await sut.EnrichAsync(requestContext, new[] { content }, null!, default); + await sut.EnrichAsync(FrontendContext, new[] { content }, null!, CancellationToken); Assert.Equal(StatusColors.Published, content.StatusColor); } @@ -90,12 +83,12 @@ public class EnrichWithWorkflowsTests [Fact] public async Task Should_enrich_content_with_new_status_color() { - var content = new ContentEntity { SchemaId = schemaId, NewStatus = Status.Archived }; + var content = new ContentEntity { SchemaId = SchemaId, NewStatus = Status.Archived }; A.CallTo(() => workflow.GetInfoAsync(content, content.NewStatus.Value)) .Returns(new StatusInfo(Status.Published, StatusColors.Archived)); - await sut.EnrichAsync(requestContext, new[] { content }, null!, default); + await sut.EnrichAsync(FrontendContext, new[] { content }, null!, CancellationToken); Assert.Equal(StatusColors.Archived, content.NewStatusColor); } @@ -103,12 +96,12 @@ public class EnrichWithWorkflowsTests [Fact] public async Task Should_enrich_content_with_scheduled_status_color() { - 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(() => workflow.GetInfoAsync(content, content.ScheduleJob.Status)) .Returns(new StatusInfo(Status.Published, StatusColors.Archived)); - await sut.EnrichAsync(requestContext, new[] { content }, null!, default); + await sut.EnrichAsync(FrontendContext, new[] { content }, null!, CancellationToken); Assert.Equal(StatusColors.Archived, content.ScheduledStatusColor); } @@ -116,14 +109,12 @@ public class EnrichWithWorkflowsTests [Fact] public async Task Should_enrich_content_with_default_color_if_not_found() { - var content = new ContentEntity { SchemaId = schemaId }; + var content = new ContentEntity { SchemaId = SchemaId }; A.CallTo(() => workflow.GetInfoAsync(content, content.Status)) .Returns(ValueTask.FromResult(null!)); - var ctx = requestContext.Clone(b => b.WithResolveFlow(false)); - - await sut.EnrichAsync(ctx, new[] { content }, null!, default); + await sut.EnrichAsync(FrontendContext, new[] { content }, null!, CancellationToken); Assert.Equal(StatusColors.Draft, content.StatusColor); } @@ -131,14 +122,12 @@ public class EnrichWithWorkflowsTests [Fact] public async Task Should_enrich_content_with_can_update() { - var content = new ContentEntity { SchemaId = schemaId }; + var content = new ContentEntity { SchemaId = SchemaId }; - A.CallTo(() => workflow.CanUpdateAsync(content, content.Status, requestContext.UserPrincipal)) + A.CallTo(() => workflow.CanUpdateAsync(content, content.Status, FrontendContext.UserPrincipal)) .Returns(true); - var ctx = requestContext.Clone(b => b.WithResolveFlow(false)); - - await sut.EnrichAsync(ctx, new[] { content }, null!, default); + await sut.EnrichAsync(FrontendContext, new[] { content }, null!, CancellationToken); Assert.True(content.CanUpdate); } @@ -146,15 +135,13 @@ public class EnrichWithWorkflowsTests [Fact] public async Task Should_not_enrich_content_with_can_update_if_disabled_in_context() { - var content = new ContentEntity { SchemaId = schemaId }; - - var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId)).Clone(b => b.WithResolveFlow(false)); + var content = new ContentEntity { SchemaId = SchemaId }; - await sut.EnrichAsync(ctx, new[] { content }, null!, default); + await sut.EnrichAsync(ApiContext.Clone(b => b.WithResolveFlow(false)), new[] { content }, null!, CancellationToken); Assert.False(content.CanUpdate); - A.CallTo(() => workflow.CanUpdateAsync(content, A._, requestContext.UserPrincipal)) + A.CallTo(() => workflow.CanUpdateAsync(content, A._, FrontendContext.UserPrincipal)) .MustNotHaveHappened(); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs index 0f0921ab4..719098723 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveAssetsTests.cs @@ -18,23 +18,18 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Entities.Contents.Queries; -public class ResolveAssetsTests +public class ResolveAssetsTests : GivenContext { private readonly IAssetQueryService assetQuery = A.Fake(); private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly IRequestCache requestCache = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly ProvideSchema schemaProvider; - private readonly Context requestContext; private readonly ResolveAssets sut; public ResolveAssetsTests() { - requestContext = new Context(Mocks.FrontendUser(), Mocks.App(appId, Language.DE)); - var schemaDef = - new Schema(schemaId.Name) + new Schema(SchemaId.Name) .AddAssets(1, "asset1", Partitioning.Invariant, new AssetsFieldProperties { ResolveFirst = true, @@ -49,14 +44,17 @@ public class ResolveAssetsTests }) .SetFieldsInLists("asset1", "asset2"); - A.CallTo(() => urlGenerator.AssetContent(appId, A._)) + A.CallTo(() => Schema.SchemaDef) + .Returns(schemaDef); + + A.CallTo(() => urlGenerator.AssetContent(AppId, A._)) .ReturnsLazily(ctx => $"url/to/{ctx.GetArgument(1)}"); schemaProvider = x => { - if (x == schemaId.Id) + if (x == SchemaId.Id) { - return Task.FromResult((Mocks.Schema(appId, schemaId, schemaDef), ResolvedComponents.Empty)); + return Task.FromResult((Schema, ResolvedComponents.Empty)); } else { @@ -84,10 +82,10 @@ public class ResolveAssetsTests }; A.CallTo(() => assetQuery.QueryAsync( - A.That.Matches(x => x.ShouldSkipAssetEnrichment() && x.ShouldSkipTotal()), null, A.That.HasIds(doc1.Id, doc2.Id), A._)) + A.That.Matches(x => x.ShouldSkipAssetEnrichment() && x.ShouldSkipTotal()), null, A.That.HasIds(doc1.Id, doc2.Id), CancellationToken)) .Returns(ResultList.CreateFrom(4, doc1, doc2)); - await sut.EnrichAsync(requestContext, contents, schemaProvider, default); + await sut.EnrichAsync(FrontendContext, contents, schemaProvider, CancellationToken); A.CallTo(() => requestCache.AddDependency(doc1.UniqueId, doc1.Version)) .MustHaveHappened(); @@ -116,10 +114,10 @@ public class ResolveAssetsTests }; A.CallTo(() => assetQuery.QueryAsync( - A.That.Matches(x => x.ShouldSkipAssetEnrichment() && x.ShouldSkipTotal()), null, A.That.HasIds(doc1.Id, doc2.Id, img1.Id, img2.Id), A._)) + A.That.Matches(x => x.ShouldSkipAssetEnrichment() && x.ShouldSkipTotal()), null, A.That.HasIds(doc1.Id, doc2.Id, img1.Id, img2.Id), CancellationToken)) .Returns(ResultList.CreateFrom(4, img1, img2, doc1, doc2)); - await sut.EnrichAsync(requestContext, contents, schemaProvider, default); + await sut.EnrichAsync(FrontendContext, contents, schemaProvider, CancellationToken); Assert.Equal( new ContentData() @@ -143,16 +141,14 @@ public class ResolveAssetsTests } [Fact] - public async Task Should_not_enrich_references_if_not_api_user() + public async Task Should_not_enrich_references_if_not_frontend_user() { var contents = new[] { CreateContent(new[] { DomainId.NewGuid() }, Array.Empty()) }; - var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId)); - - await sut.EnrichAsync(ctx, contents, schemaProvider, default); + await sut.EnrichAsync(ApiContext, contents, schemaProvider, CancellationToken); Assert.Null(contents[0].ReferenceData); @@ -168,9 +164,7 @@ public class ResolveAssetsTests CreateContent(new[] { DomainId.NewGuid() }, Array.Empty()) }; - var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)).Clone(b => b.WithoutContentEnrichment(true)); - - await sut.EnrichAsync(ctx, contents, schemaProvider, default); + await sut.EnrichAsync(FrontendContext.Clone(b => b.WithoutContentEnrichment(true)), contents, schemaProvider, CancellationToken); Assert.Null(contents[0].ReferenceData); @@ -186,7 +180,7 @@ public class ResolveAssetsTests CreateContent(Array.Empty(), Array.Empty()) }; - await sut.EnrichAsync(requestContext, contents, schemaProvider, default); + await sut.EnrichAsync(FrontendContext, contents, schemaProvider, CancellationToken); Assert.NotNull(contents[0].ReferenceData); @@ -205,7 +199,7 @@ public class ResolveAssetsTests CreateContent(new[] { id1, id2 }, Array.Empty()) }; - await sut.EnrichAsync(requestContext, contents, schemaProvider, default); + await sut.EnrichAsync(FrontendContext, contents, schemaProvider, CancellationToken); Assert.NotNull(contents[0].ReferenceData); @@ -226,7 +220,7 @@ public class ResolveAssetsTests .AddField("asset2", new ContentFieldData() .AddLocalized("en", JsonValue.Array(assets2.Select(x => x.ToString())))), - SchemaId = schemaId + SchemaId = SchemaId }; } @@ -234,7 +228,7 @@ public class ResolveAssetsTests { return new AssetEntity { - AppId = appId, + AppId = AppId, Id = id, Type = type, FileName = fileName, diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveReferencesTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveReferencesTests.cs index ed78dd06b..cfa09cca0 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveReferencesTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ResolveReferencesTests.cs @@ -17,22 +17,17 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Entities.Contents.Queries; -public class ResolveReferencesTests : IClassFixture +public class ResolveReferencesTests : GivenContext, IClassFixture { private readonly IContentQueryService contentQuery = A.Fake(); private readonly IRequestCache requestCache = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly NamedId refSchemaId1 = NamedId.Of(DomainId.NewGuid(), "my-ref1"); private readonly NamedId refSchemaId2 = NamedId.Of(DomainId.NewGuid(), "my-ref2"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly ProvideSchema schemaProvider; - private readonly Context requestContext; private readonly ResolveReferences sut; public ResolveReferencesTests() { - requestContext = new Context(Mocks.FrontendUser(), Mocks.App(appId, Language.DE)); - var refSchemaDef = new Schema("my-ref") .AddString(1, "name", Partitioning.Invariant, @@ -42,7 +37,7 @@ public class ResolveReferencesTests : IClassFixture .SetFieldsInReferences("name", "number"); var schemaDef = - new Schema(schemaId.Name) + new Schema(SchemaId.Name) .AddReferences(1, "ref1", Partitioning.Invariant, new ReferencesFieldProperties { ResolveReference = true, @@ -59,19 +54,22 @@ public class ResolveReferencesTests : IClassFixture }) .SetFieldsInLists("ref1", "ref2"); + A.CallTo(() => Schema.SchemaDef) + .Returns(schemaDef); + schemaProvider = x => { - if (x == schemaId.Id) + if (x == SchemaId.Id) { - return Task.FromResult((Mocks.Schema(appId, schemaId, schemaDef), ResolvedComponents.Empty)); + return Task.FromResult((Schema, ResolvedComponents.Empty)); } else if (x == refSchemaId1.Id) { - return Task.FromResult((Mocks.Schema(appId, refSchemaId1, refSchemaDef), ResolvedComponents.Empty)); + return Task.FromResult((Mocks.Schema(AppId, refSchemaId1, refSchemaDef), ResolvedComponents.Empty)); } else if (x == refSchemaId2.Id) { - return Task.FromResult((Mocks.Schema(appId, refSchemaId2, refSchemaDef), ResolvedComponents.Empty)); + return Task.FromResult((Mocks.Schema(AppId, refSchemaId2, refSchemaDef), ResolvedComponents.Empty)); } else { @@ -100,12 +98,12 @@ public class ResolveReferencesTests : IClassFixture A.That.Matches(x => x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), A.That.HasIds(ref1_1.Id, ref1_2.Id, ref2_1.Id, ref2_2.Id), A._)) .Returns(ResultList.CreateFrom(4, ref1_1, ref1_2, ref2_1, ref2_2)); - await sut.EnrichAsync(requestContext, contents, schemaProvider, default); + await sut.EnrichAsync(FrontendContext, contents, schemaProvider, default); - A.CallTo(() => requestCache.AddDependency(DomainId.Combine(appId, refSchemaId1.Id), 0)) + A.CallTo(() => requestCache.AddDependency(DomainId.Combine(AppId, refSchemaId1.Id), 0)) .MustHaveHappened(); - A.CallTo(() => requestCache.AddDependency(DomainId.Combine(appId, refSchemaId2.Id), 0)) + A.CallTo(() => requestCache.AddDependency(DomainId.Combine(AppId, refSchemaId2.Id), 0)) .MustHaveHappened(); A.CallTo(() => requestCache.AddDependency(ref1_1.UniqueId, ref1_1.Version)) @@ -136,10 +134,10 @@ public class ResolveReferencesTests : IClassFixture }; A.CallTo(() => contentQuery.QueryAsync( - A.That.Matches(x => x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), A.That.HasIds(ref1_1.Id, ref1_2.Id, ref2_1.Id, ref2_2.Id), A._)) + A.That.Matches(x => x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), A.That.HasIds(ref1_1.Id, ref1_2.Id, ref2_1.Id, ref2_2.Id), CancellationToken)) .Returns(ResultList.CreateFrom(4, ref1_1, ref1_2, ref2_1, ref2_2)); - await sut.EnrichAsync(requestContext, contents, schemaProvider, default); + await sut.EnrichAsync(FrontendContext, contents, schemaProvider, CancellationToken); Assert.Equal( new ContentData() @@ -189,10 +187,10 @@ public class ResolveReferencesTests : IClassFixture }; A.CallTo(() => contentQuery.QueryAsync( - A.That.Matches(x => x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), A.That.HasIds(ref1_1.Id, ref1_2.Id, ref2_1.Id, ref2_2.Id), A._)) + A.That.Matches(x => x.ShouldSkipContentEnrichment() && x.ShouldSkipTotal()), A.That.HasIds(ref1_1.Id, ref1_2.Id, ref2_1.Id, ref2_2.Id), CancellationToken)) .Returns(ResultList.CreateFrom(4, ref1_1, ref1_2, ref2_1, ref2_2)); - await sut.EnrichAsync(requestContext, contents, schemaProvider, default); + await sut.EnrichAsync(FrontendContext, contents, schemaProvider, CancellationToken); Assert.Equal( new ContentData() @@ -228,16 +226,14 @@ public class ResolveReferencesTests : IClassFixture } [Fact] - public async Task Should_not_enrich_references_if_not_api_user() + public async Task Should_not_enrich_references_if_not_frontend_user() { var contents = new[] { CreateContent(new[] { DomainId.NewGuid() }, Array.Empty()) }; - var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId)); - - await sut.EnrichAsync(ctx, contents, schemaProvider, default); + await sut.EnrichAsync(ApiContext, contents, schemaProvider, CancellationToken); Assert.Null(contents[0].ReferenceData); @@ -253,9 +249,7 @@ public class ResolveReferencesTests : IClassFixture CreateContent(new[] { DomainId.NewGuid() }, Array.Empty()) }; - var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)).Clone(b => b.WithoutContentEnrichment(true)); - - await sut.EnrichAsync(ctx, contents, schemaProvider, default); + await sut.EnrichAsync(FrontendContext.Clone(b => b.WithoutContentEnrichment(true)), contents, schemaProvider, CancellationToken); Assert.Null(contents[0].ReferenceData); @@ -271,7 +265,7 @@ public class ResolveReferencesTests : IClassFixture CreateContent(Array.Empty(), Array.Empty()) }; - await sut.EnrichAsync(requestContext, contents, schemaProvider, default); + await sut.EnrichAsync(FrontendContext, contents, schemaProvider, CancellationToken); Assert.NotNull(contents[0].ReferenceData); @@ -292,8 +286,8 @@ public class ResolveReferencesTests : IClassFixture .AddField("ref2", new ContentFieldData() .AddInvariant(JsonValue.Array(ref2.Select(x => x.ToString())))), - SchemaId = schemaId, - AppId = appId, + SchemaId = SchemaId, + AppId = AppId, Version = 0 }; } @@ -312,7 +306,7 @@ public class ResolveReferencesTests : IClassFixture new ContentFieldData() .AddInvariant(number)), SchemaId = refSchemaId, - AppId = appId, + AppId = AppId, Version = version }; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs index 5a19257ca..0f74a2c5f 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/ScriptContentTests.cs @@ -17,10 +17,9 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Entities.Contents.Queries; -public class ScriptContentTests +public class ScriptContentTests : GivenContext { private readonly IScriptEngine scriptEngine = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly ScriptContent sut; public ScriptContentTests() @@ -31,14 +30,12 @@ public class ScriptContentTests [Fact] public async Task Should_not_call_script_engine_if_no_script_configured() { - var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId)); - var (provider, schemaId) = CreateSchema( queryPre: "my-pre-query"); var content = new ContentEntity { Data = new ContentData(), SchemaId = schemaId }; - await sut.EnrichAsync(ctx, new[] { content }, provider, default); + await sut.EnrichAsync(ApiContext, new[] { content }, provider, default); A.CallTo(() => scriptEngine.TransformAsync(A._, A._, ScriptOptions(), A._)) .MustNotHaveHappened(); @@ -47,14 +44,12 @@ public class ScriptContentTests [Fact] public async Task Should_not_call_script_engine_for_frontend_user() { - var ctx = new Context(Mocks.FrontendUser(), Mocks.App(appId)); - var (provider, schemaId) = CreateSchema( query: "my-query"); var content = new ContentEntity { Data = new ContentData(), SchemaId = schemaId }; - await sut.EnrichAsync(ctx, new[] { content }, provider, default); + await sut.EnrichAsync(FrontendContext, new[] { content }, provider, default); A.CallTo(() => scriptEngine.TransformAsync(A._, A._, ScriptOptions(), A._)) .MustNotHaveHappened(); @@ -63,8 +58,6 @@ public class ScriptContentTests [Fact] public async Task Should_call_script_engine_with_data() { - var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId)); - var oldData = new ContentData(); var (provider, schemaId) = CreateSchema( @@ -75,15 +68,17 @@ public class ScriptContentTests A.CallTo(() => scriptEngine.TransformAsync(A._, "my-query", ScriptOptions(), A._)) .Returns(new ContentData()); - await sut.EnrichAsync(ctx, new[] { content }, provider, default); + await sut.EnrichAsync(ApiContext, new[] { content }, provider, default); Assert.NotSame(oldData, content.Data); A.CallTo(() => scriptEngine.TransformAsync( A.That.Matches(x => - Equals(x["user"], ctx.UserPrincipal) && + Equals(x["contentId"], content.Id) && Equals(x["data"], oldData) && - Equals(x["contentId"], content.Id)), + Equals(x["AppId"], AppId.Id) && + Equals(x["appName"], AppId.Name) && + Equals(x["user"], ApiContext.UserPrincipal)), "my-query", ScriptOptions(), A._)) .MustHaveHappened(); @@ -92,8 +87,6 @@ public class ScriptContentTests [Fact] public async Task Should_make_test_with_pre_query_script() { - var ctx = new Context(Mocks.ApiUser(), Mocks.App(appId)); - var (provider, id) = CreateSchema( query: @" ctx.data.test = { iv: ctx.custom }; @@ -112,7 +105,7 @@ public class ScriptContentTests var sut2 = new ScriptContent(realScriptEngine); - await sut2.EnrichAsync(ctx, new[] { content }, provider, default); + await sut2.EnrichAsync(ApiContext, new[] { content }, provider, default); Assert.Equal(JsonValue.Create(123), content.Data["test"]!["iv"]); } @@ -121,7 +114,7 @@ public class ScriptContentTests { var id = NamedId.Of(DomainId.NewGuid(), "my-schema"); - return (_ => + return (__ => { var schemaDef = new Schema(id.Name) @@ -131,7 +124,7 @@ public class ScriptContentTests QueryPre = queryPre }); - return Task.FromResult((Mocks.Schema(appId, id, schemaDef), ResolvedComponents.Empty)); + return Task.FromResult((Mocks.Schema(AppId, id, schemaDef), ResolvedComponents.Empty)); }, id); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferencesFluidExtensionTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferencesFluidExtensionTests.cs index 058948fc1..8c99d4e07 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferencesFluidExtensionTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferencesFluidExtensionTests.cs @@ -16,18 +16,16 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Entities.Contents; -public class ReferencesFluidExtensionTests +public class ReferencesFluidExtensionTests : GivenContext { private readonly IContentQueryService contentQuery = A.Fake(); - private readonly IAppProvider appProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly FluidTemplateEngine sut; public ReferencesFluidExtensionTests() { var serviceProvider = new ServiceCollection() - .AddSingleton(appProvider) + .AddSingleton(AppProvider) .AddSingleton(contentQuery) .BuildServiceProvider(); @@ -37,9 +35,6 @@ public class ReferencesFluidExtensionTests new ReferencesFluidExtension(serviceProvider) }; - A.CallTo(() => appProvider.GetAppAsync(appId.Id, false, default)) - .Returns(Mocks.App(appId)); - sut = new FluidTemplateEngine(extensions); } @@ -96,7 +91,7 @@ public class ReferencesFluidExtensionTests .AddField("references", new ContentFieldData() .AddInvariant(JsonValue.Array(referenceId1, referenceId2))), - AppId = appId + AppId = AppId }; A.CallTo(() => contentQuery.QueryAsync(A._, A.That.HasIds(referenceId1), A._)) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferencesJintExtensionTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferencesJintExtensionTests.cs index 8f8a18f10..497ef6cb3 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferencesJintExtensionTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ReferencesJintExtensionTests.cs @@ -18,18 +18,16 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Entities.Contents; -public class ReferencesJintExtensionTests : IClassFixture +public class ReferencesJintExtensionTests : GivenContext, IClassFixture { private readonly IContentQueryService contentQuery = A.Fake(); - private readonly IAppProvider appProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly JintScriptEngine sut; public ReferencesJintExtensionTests() { var serviceProvider = new ServiceCollection() - .AddSingleton(appProvider) + .AddSingleton(AppProvider) .AddSingleton(contentQuery) .BuildServiceProvider(); @@ -38,9 +36,6 @@ public class ReferencesJintExtensionTests : IClassFixture new ReferencesJintExtension(serviceProvider) }; - A.CallTo(() => appProvider.GetAppAsync(appId.Id, false, default)) - .Returns(Mocks.App(appId)); - sut = new JintScriptEngine(new MemoryCache(Options.Create(new MemoryCacheOptions())), Options.Create(new JintScriptOptions { @@ -66,7 +61,7 @@ public class ReferencesJintExtensionTests : IClassFixture complete(`${actual1}`); })"; - var actual = (await sut.ExecuteAsync(vars, script)).ToString(); + var actual = (await sut.ExecuteAsync(vars, script, ct: CancellationToken)).ToString(); Assert.Equal(Cleanup(expected), Cleanup(actual)); } @@ -89,7 +84,7 @@ public class ReferencesJintExtensionTests : IClassFixture complete(`${actual1}\n${actual2}`); })"; - var actual = (await sut.ExecuteAsync(vars, script)).ToString(); + var actual = (await sut.ExecuteAsync(vars, script, ct: CancellationToken)).ToString(); Assert.Equal(Cleanup(expected), Cleanup(actual)); } @@ -108,12 +103,13 @@ public class ReferencesJintExtensionTests : IClassFixture .AddInvariant(JsonValue.Array(referenceIds))); A.CallTo(() => contentQuery.QueryAsync( - A.That.Matches(x => x.App.Id == appId.Id && x.UserPrincipal == user), A.That.HasIds(referenceIds), A._)) + A.That.Matches(x => x.App == App && x.UserPrincipal == user), A.That.HasIds(referenceIds), A._)) .Returns(ResultList.CreateFrom(2, references)); var vars = new ScriptVars { - ["appId"] = appId.Id, + ["appId"] = AppId.Id, + ["appName"] = AppId.Name, ["data"] = data, ["dataOld"] = null, ["user"] = user diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/CachingTextIndexerStateTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/CachingTextIndexerStateTests.cs index b6d41ebea..ffa2a418e 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/CachingTextIndexerStateTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/CachingTextIndexerStateTests.cs @@ -7,22 +7,19 @@ using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Contents.Text.State; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Text; -public class CachingTextIndexerStateTests +public class CachingTextIndexerStateTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly ITextIndexerState inner = A.Fake(); private readonly DomainId contentId = DomainId.NewGuid(); private readonly CachingTextIndexerState sut; public CachingTextIndexerStateTests() { - ct = cts.Token; - sut = new CachingTextIndexerState(inner); } @@ -38,16 +35,16 @@ public class CachingTextIndexerStateTests [contentId] = state }; - A.CallTo(() => inner.GetAsync(A>.That.Is(contentIds), ct)) + A.CallTo(() => inner.GetAsync(A>.That.Is(contentIds), CancellationToken)) .Returns(states); - var found1 = await sut.GetAsync(HashSet.Of(contentId), ct); - var found2 = await sut.GetAsync(HashSet.Of(contentId), ct); + var found1 = await sut.GetAsync(HashSet.Of(contentId), CancellationToken); + var found2 = await sut.GetAsync(HashSet.Of(contentId), CancellationToken); Assert.Same(state, found1[contentId]); Assert.Same(state, found2[contentId]); - A.CallTo(() => inner.GetAsync(A>.That.Is(contentIds), ct)) + A.CallTo(() => inner.GetAsync(A>.That.Is(contentIds), CancellationToken)) .MustHaveHappenedOnceExactly(); } @@ -56,16 +53,16 @@ public class CachingTextIndexerStateTests { var contentIds = HashSet.Of(contentId); - A.CallTo(() => inner.GetAsync(A>.That.Is(contentIds), ct)) + A.CallTo(() => inner.GetAsync(A>.That.Is(contentIds), CancellationToken)) .Returns(new Dictionary()); - var found1 = await sut.GetAsync(HashSet.Of(contentId), ct); - var found2 = await sut.GetAsync(HashSet.Of(contentId), ct); + var found1 = await sut.GetAsync(HashSet.Of(contentId), CancellationToken); + var found2 = await sut.GetAsync(HashSet.Of(contentId), CancellationToken); Assert.Empty(found1); Assert.Empty(found2); - A.CallTo(() => inner.GetAsync(A>.That.Is(contentIds), ct)) + A.CallTo(() => inner.GetAsync(A>.That.Is(contentIds), CancellationToken)) .MustHaveHappenedOnceExactly(); } @@ -76,15 +73,15 @@ public class CachingTextIndexerStateTests var state = new TextContentState { UniqueContentId = contentId }; - await sut.SetAsync(new List { state }, ct); + await sut.SetAsync(new List { state }, CancellationToken); - var found1 = await sut.GetAsync(contentIds, ct); - var found2 = await sut.GetAsync(contentIds, ct); + var found1 = await sut.GetAsync(contentIds, CancellationToken); + var found2 = await sut.GetAsync(contentIds, CancellationToken); Assert.Same(state, found1[contentId]); Assert.Same(state, found2[contentId]); - A.CallTo(() => inner.SetAsync(A>.That.IsSameSequenceAs(state), ct)) + A.CallTo(() => inner.SetAsync(A>.That.IsSameSequenceAs(state), CancellationToken)) .MustHaveHappenedOnceExactly(); A.CallTo(() => inner.GetAsync(A>._, A._)) @@ -101,20 +98,20 @@ public class CachingTextIndexerStateTests await sut.SetAsync(new List { state - }, ct); + }, CancellationToken); await sut.SetAsync(new List { new TextContentState { UniqueContentId = contentId, IsDeleted = true } - }, ct); + }, CancellationToken); - var found1 = await sut.GetAsync(contentIds, ct); - var found2 = await sut.GetAsync(contentIds, ct); + var found1 = await sut.GetAsync(contentIds, CancellationToken); + var found2 = await sut.GetAsync(contentIds, CancellationToken); Assert.Empty(found1); Assert.Empty(found2); - A.CallTo(() => inner.SetAsync(A>.That.Matches(x => x.Count == 1 && x[0].IsDeleted), ct)) + A.CallTo(() => inner.SetAsync(A>.That.Matches(x => x.Count == 1 && x[0].IsDeleted), CancellationToken)) .MustHaveHappenedOnceExactly(); A.CallTo(() => inner.GetAsync(A>._, A._)) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTestsBase.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTestsBase.cs index c351dc092..215bb4187 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTestsBase.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTestsBase.cs @@ -7,7 +7,6 @@ using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.TestHelpers; -using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Contents.Text.State; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events.Contents; @@ -19,14 +18,10 @@ using Squidex.Infrastructure.Json.Objects; namespace Squidex.Domain.Apps.Entities.Contents.Text; -public abstract class TextIndexerTestsBase +public abstract class TextIndexerTestsBase : GivenContext { protected readonly List ids1 = new List { DomainId.NewGuid() }; protected readonly List ids2 = new List { DomainId.NewGuid() }; - - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); - private readonly IAppEntity app; private readonly Lazy sut; protected TextIndexingProcess Sut @@ -42,11 +37,6 @@ public abstract class TextIndexerTestsBase protected TextIndexerTestsBase() { - app = - Mocks.App(appId, - Language.DE, - Language.EN); - sut = new Lazy(CreateSut); } @@ -400,12 +390,12 @@ public abstract class TextIndexerTestsBase private async Task UpdateAsync(DomainId id, ContentEvent contentEvent) { contentEvent.ContentId = id; - contentEvent.AppId = appId; - contentEvent.SchemaId = schemaId; + contentEvent.AppId = AppId; + contentEvent.SchemaId = SchemaId; await Sut.On(Enumerable.Repeat(Envelope.Create(contentEvent), 1)); - await Task.Delay(WaitAfterUpdate); + await Task.Delay(WaitAfterUpdate, default); } private static ContentData TextData(string language, string text) @@ -439,9 +429,9 @@ public abstract class TextIndexerTestsBase protected async Task SearchGeo(List? expected, string field, double latitude, double longitude, SearchScope target = SearchScope.All) { - var query = new GeoQuery(schemaId.Id, field, latitude, longitude, 1000, 1000); + var query = new GeoQuery(SchemaId.Id, field, latitude, longitude, 1000, 1000); - var actual = await Sut.TextIndex.SearchAsync(app, query, target); + var actual = await Sut.TextIndex.SearchAsync(App, query, target, default); if (expected != null) { @@ -457,10 +447,10 @@ public abstract class TextIndexerTestsBase { var query = new TextQuery(text, 1000) { - RequiredSchemaIds = new List { schemaId.Id } + RequiredSchemaIds = new List { SchemaId.Id } }; - var actual = await Sut.TextIndex.SearchAsync(app, query, target); + var actual = await Sut.TextIndex.SearchAsync(App, query, target, default); if (expected != null) { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Invitation/InvitationEventConsumerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Invitation/InvitationEventConsumerTests.cs index a33e25268..0195372c7 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Invitation/InvitationEventConsumerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Invitation/InvitationEventConsumerTests.cs @@ -20,12 +20,9 @@ using Squidex.Shared.Users; namespace Squidex.Domain.Apps.Entities.Invitation; -public class InvitationEventConsumerTests +public class InvitationEventConsumerTests : GivenContext { - private readonly IAppEntity app = Mocks.App(NamedId.Of(DomainId.NewGuid(), "my-app")); - private readonly IAppProvider appProvider = A.Fake(); private readonly ILogger log = A.Fake>(); - private readonly ITeamEntity team = Mocks.Team(DomainId.NewGuid()); private readonly IUser assignee = UserMocks.User("2"); private readonly IUser assigner = UserMocks.User("1"); private readonly IUserNotifications userNotifications = A.Fake(); @@ -45,13 +42,7 @@ public class InvitationEventConsumerTests A.CallTo(() => userResolver.FindByIdAsync(assigneeId, default)) .Returns(assignee); - A.CallTo(() => appProvider.GetAppAsync(app.Id, true, default)) - .Returns(app); - - A.CallTo(() => appProvider.GetTeamAsync(team.Id, default)) - .Returns(team); - - sut = new InvitationEventConsumer(appProvider, userNotifications, userResolver, log); + sut = new InvitationEventConsumer(AppProvider, userNotifications, userResolver, log); } [Fact] @@ -224,7 +215,7 @@ public class InvitationEventConsumerTests await sut.On(@event); - A.CallTo(() => userNotifications.SendInviteAsync(assigner, assignee, app, default)) + A.CallTo(() => userNotifications.SendInviteAsync(assigner, assignee, App, default)) .MustHaveHappened(); } @@ -235,7 +226,7 @@ public class InvitationEventConsumerTests await sut.On(@event); - A.CallTo(() => userNotifications.SendInviteAsync(assigner, assignee, team, default)) + A.CallTo(() => userNotifications.SendInviteAsync(assigner, assignee, Team, default)) .MustHaveHappened(); } @@ -246,7 +237,7 @@ public class InvitationEventConsumerTests await sut.On(@event); - A.CallTo(() => userNotifications.SendInviteAsync(assigner, assignee, app, default)) + A.CallTo(() => userNotifications.SendInviteAsync(assigner, assignee, App, default)) .MustHaveHappened(); } @@ -257,7 +248,7 @@ public class InvitationEventConsumerTests await sut.On(@event); - A.CallTo(() => userNotifications.SendInviteAsync(assigner, assignee, team, default)) + A.CallTo(() => userNotifications.SendInviteAsync(assigner, assignee, Team, default)) .MustHaveHappened(); } @@ -266,7 +257,7 @@ public class InvitationEventConsumerTests { var @event = CreateTeamEvent(true); - A.CallTo(() => appProvider.GetTeamAsync(A._, default)) + A.CallTo(() => AppProvider.GetTeamAsync(A._, default)) .Returns(Task.FromResult(null)); await sut.On(@event); @@ -300,7 +291,7 @@ public class InvitationEventConsumerTests var @event = new AppContributorAssigned { Actor = new RefToken(assignerType, assignerId), - AppId = app.NamedId(), + AppId = AppId, ContributorId = assigneeId, IsCreated = isNewUser, IsAdded = isNewContributor @@ -322,7 +313,7 @@ public class InvitationEventConsumerTests ContributorId = assigneeId, IsCreated = isNewUser, IsAdded = isNewContributor, - TeamId = team.Id + TeamId = TeamId }; var envelope = Envelope.Create(@event); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Invitation/InviteUserCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Invitation/InviteUserCommandMiddlewareTests.cs index 9b6755596..5ce670fbd 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Invitation/InviteUserCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Invitation/InviteUserCommandMiddlewareTests.cs @@ -9,7 +9,6 @@ using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Teams; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Shared.Users; using AssignAppContributor = Squidex.Domain.Apps.Entities.Apps.Commands.AssignContributor; @@ -17,20 +16,14 @@ using AssignTeamContributor = Squidex.Domain.Apps.Entities.Teams.Commands.Assign namespace Squidex.Domain.Apps.Entities.Invitation; -public class InviteUserCommandMiddlewareTests +public class InviteUserCommandMiddlewareTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IUserResolver userResolver = A.Fake(); - private readonly IAppEntity app = Mocks.App(NamedId.Of(DomainId.NewGuid(), "my-app")); - private readonly ITeamEntity team = Mocks.Team(DomainId.NewGuid()); private readonly ICommandBus commandBus = A.Fake(); private readonly InviteUserCommandMiddleware sut; public InviteUserCommandMiddlewareTests() { - ct = cts.Token; - sut = new InviteUserCommandMiddleware(userResolver); } @@ -41,19 +34,19 @@ public class InviteUserCommandMiddlewareTests var context = new CommandContext(command, commandBus) - .Complete(app); + .Complete(App); var user = UserMocks.User("123", command.ContributorId); - A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, ct)) + A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, CancellationToken)) .Returns((user, true)); - await sut.HandleAsync(context, ct); + await sut.HandleAsync(context, CancellationToken); - Assert.Same(context.Result>().Entity, app); + Assert.Same(context.Result>().Entity, App); Assert.Equal(user.Id, command.ContributorId); - A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, ct)) + A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, CancellationToken)) .MustHaveHappened(); } @@ -64,19 +57,19 @@ public class InviteUserCommandMiddlewareTests var context = new CommandContext(command, commandBus) - .Complete(team); + .Complete(Team); var user = UserMocks.User("123", command.ContributorId); - A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, ct)) + A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, CancellationToken)) .Returns((user, true)); - await sut.HandleAsync(context, ct); + await sut.HandleAsync(context, CancellationToken); - Assert.Same(context.Result>().Entity, team); + Assert.Same(context.Result>().Entity, Team); Assert.Equal(user.Id, command.ContributorId); - A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, ct)) + A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, CancellationToken)) .MustHaveHappened(); } @@ -87,19 +80,19 @@ public class InviteUserCommandMiddlewareTests var context = new CommandContext(command, commandBus) - .Complete(app); + .Complete(App); var user = UserMocks.User("123", command.ContributorId); - A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, ct)) + A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, CancellationToken)) .Returns((user, false)); - await sut.HandleAsync(context, ct); + await sut.HandleAsync(context, CancellationToken); - Assert.Same(context.Result(), app); + Assert.Same(context.Result(), App); Assert.Equal(user.Id, command.ContributorId); - A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, ct)) + A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, CancellationToken)) .MustHaveHappened(); } @@ -110,19 +103,19 @@ public class InviteUserCommandMiddlewareTests var context = new CommandContext(command, commandBus) - .Complete(team); + .Complete(Team); var user = UserMocks.User("123", command.ContributorId); - A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, ct)) + A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, CancellationToken)) .Returns((user, false)); - await sut.HandleAsync(context, ct); + await sut.HandleAsync(context, CancellationToken); - Assert.Same(context.Result(), team); + Assert.Same(context.Result(), Team); Assert.Equal(user.Id, command.ContributorId); - A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, ct)) + A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(user.Email, true, CancellationToken)) .MustHaveHappened(); } @@ -133,9 +126,9 @@ public class InviteUserCommandMiddlewareTests var context = new CommandContext(command, commandBus) - .Complete(app); + .Complete(App); - await sut.HandleAsync(context, ct); + await sut.HandleAsync(context, CancellationToken); A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(A._, A._, A._)) .MustNotHaveHappened(); @@ -148,9 +141,9 @@ public class InviteUserCommandMiddlewareTests var context = new CommandContext(command, commandBus) - .Complete(app); + .Complete(App); - await sut.HandleAsync(context, ct); + await sut.HandleAsync(context, CancellationToken); A.CallTo(() => userResolver.CreateUserIfNotExistsAsync(A._, A._, A._)) .MustNotHaveHappened(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Notifications/EmailUserNotificationsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Notifications/EmailUserNotificationsTests.cs index e19c131df..673693afe 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Notifications/EmailUserNotificationsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Notifications/EmailUserNotificationsTests.cs @@ -9,24 +9,19 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.TestHelpers; -using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Domain.Apps.Entities.Teams; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; using Squidex.Infrastructure.Email; using Squidex.Shared.Users; namespace Squidex.Domain.Apps.Entities.Notifications; -public class EmailUserNotificationsTests +public class EmailUserNotificationsTests : GivenContext { private readonly IEmailSender emailSender = A.Fake(); private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly IUser assigner = UserMocks.User("1", "1@email.com", "user1"); private readonly IUser assigned = UserMocks.User("2", "2@email.com", "user2"); private readonly ILogger log = A.Fake>(); - private readonly IAppEntity app = Mocks.App(NamedId.Of(DomainId.NewGuid(), "my-app")); - private readonly ITeamEntity team = Mocks.Team(DomainId.NewGuid()); private readonly EmailUserNotificationOptions texts = new EmailUserNotificationOptions(); private readonly EmailUserNotifications sut; @@ -89,7 +84,7 @@ public class EmailUserNotificationsTests [Fact] public async Task Should_not_send_app_invitation_email_if_texts_for_new_user_are_empty() { - await sut.SendInviteAsync(assigner, assigned, app); + await sut.SendInviteAsync(assigner, assigned, App); A.CallTo(() => emailSender.SendAsync(assigned.Email, A._, A._, A._)) .MustNotHaveHappened(); @@ -100,7 +95,7 @@ public class EmailUserNotificationsTests [Fact] public async Task Should_not_send_text_invitation_email_if_texts_for_new_user_are_empty() { - await sut.SendInviteAsync(assigner, assigned, team); + await sut.SendInviteAsync(assigner, assigned, Team); A.CallTo(() => emailSender.SendAsync(assigned.Email, A._, A._, A._)) .MustNotHaveHappened(); @@ -111,7 +106,7 @@ public class EmailUserNotificationsTests [Fact] public async Task Should_not_send_app_invitation_email_if_texts_for_existing_user_are_empty() { - await sut.SendInviteAsync(assigner, assigned, app); + await sut.SendInviteAsync(assigner, assigned, App); A.CallTo(() => emailSender.SendAsync(assigned.Email, A._, A._, A._)) .MustNotHaveHappened(); @@ -122,7 +117,7 @@ public class EmailUserNotificationsTests [Fact] public async Task Should_not_send_text_invitation_email_if_texts_for_existing_user_are_empty() { - await sut.SendInviteAsync(assigner, assigned, team); + await sut.SendInviteAsync(assigner, assigned, Team); A.CallTo(() => emailSender.SendAsync(assigned.Email, A._, A._, A._)) .MustNotHaveHappened(); @@ -133,7 +128,7 @@ public class EmailUserNotificationsTests [Fact] public async Task Should_not_send_usage_email_if_texts_empty() { - await sut.SendUsageAsync(assigned, app, 100, 120); + await sut.SendUsageAsync(assigned, App, 100, 120); A.CallTo(() => emailSender.SendAsync(assigned.Email, A._, A._, A._)) .MustNotHaveHappened(); @@ -149,7 +144,7 @@ public class EmailUserNotificationsTests texts.ExistingUserSubject = "email-subject"; texts.ExistingUserBody = "email-body"; - await sut.SendInviteAsync(assigner, withoutConsent, app); + await sut.SendInviteAsync(assigner, withoutConsent, App); A.CallTo(() => emailSender.SendAsync(withoutConsent.Email, "email-subject", "email-body", A._)) .MustNotHaveHappened(); @@ -163,7 +158,7 @@ public class EmailUserNotificationsTests texts.ExistingTeamUserSubject = "email-subject"; texts.ExistingTeamUserBody = "email-body"; - await sut.SendInviteAsync(assigner, withoutConsent, team); + await sut.SendInviteAsync(assigner, withoutConsent, Team); A.CallTo(() => emailSender.SendAsync(withoutConsent.Email, "email-subject", "email-body", A._)) .MustNotHaveHappened(); @@ -177,7 +172,7 @@ public class EmailUserNotificationsTests texts.ExistingUserSubject = "email-subject"; texts.ExistingUserBody = "email-body"; - await sut.SendInviteAsync(assigner, withConsent, app); + await sut.SendInviteAsync(assigner, withConsent, App); A.CallTo(() => emailSender.SendAsync(withConsent.Email, "email-subject", "email-body", A._)) .MustHaveHappened(); @@ -191,7 +186,7 @@ public class EmailUserNotificationsTests texts.ExistingTeamUserSubject = "email-subject"; texts.ExistingTeamUserBody = "email-body"; - await sut.SendInviteAsync(assigner, withConsent, team); + await sut.SendInviteAsync(assigner, withConsent, Team); A.CallTo(() => emailSender.SendAsync(withConsent.Email, "email-subject", "email-body", A._)) .MustHaveHappened(); @@ -202,7 +197,7 @@ public class EmailUserNotificationsTests texts.UsageSubject = pattern; texts.UsageBody = pattern; - await sut.SendUsageAsync(assigned, app, 100, 120); + await sut.SendUsageAsync(assigned, App, 100, 120); A.CallTo(() => emailSender.SendAsync(assigned.Email, actual, actual, A._)) .MustHaveHappened(); @@ -213,7 +208,7 @@ public class EmailUserNotificationsTests texts.NewUserSubject = pattern; texts.NewUserBody = pattern; - await sut.SendInviteAsync(assigner, assigned, app); + await sut.SendInviteAsync(assigner, assigned, App); A.CallTo(() => emailSender.SendAsync(assigned.Email, actual, actual, A._)) .MustHaveHappened(); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/BackupRulesTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/BackupRulesTests.cs index d56e2528d..7fbc0c78e 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/BackupRulesTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/BackupRulesTests.cs @@ -7,6 +7,7 @@ using Squidex.Domain.Apps.Entities.Backup; using Squidex.Domain.Apps.Entities.Rules.DomainObject; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events.Rules; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; @@ -14,18 +15,13 @@ using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities.Rules; -public class BackupRulesTests +public class BackupRulesTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly Rebuilder rebuilder = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly BackupRules sut; public BackupRulesTests() { - ct = cts.Token; - sut = new BackupRules(rebuilder); } @@ -42,46 +38,46 @@ public class BackupRulesTests var ruleId2 = DomainId.NewGuid(); var ruleId3 = DomainId.NewGuid(); - var context = new RestoreContext(appId.Id, new UserMapping(RefToken.User("123")), A.Fake(), DomainId.NewGuid()); + var context = new RestoreContext(AppId.Id, new UserMapping(RefToken.User("123")), A.Fake(), DomainId.NewGuid()); await sut.RestoreEventAsync(AppEvent(new RuleCreated { RuleId = ruleId1 - }), context, ct); + }), context, CancellationToken); await sut.RestoreEventAsync(AppEvent(new RuleCreated { RuleId = ruleId2 - }), context, ct); + }), context, CancellationToken); await sut.RestoreEventAsync(AppEvent(new RuleCreated { RuleId = ruleId3 - }), context, ct); + }), context, CancellationToken); await sut.RestoreEventAsync(AppEvent(new RuleDeleted { RuleId = ruleId3 - }), context, ct); + }), context, CancellationToken); var rebuildAssets = new HashSet(); - A.CallTo(() => rebuilder.InsertManyAsync(A>._, A._, ct)) + A.CallTo(() => rebuilder.InsertManyAsync(A>._, A._, CancellationToken)) .Invokes(x => rebuildAssets.AddRange(x.GetArgument>(0)!)); - await sut.RestoreAsync(context, ct); + await sut.RestoreAsync(context, CancellationToken); Assert.Equal(new HashSet { - DomainId.Combine(appId, ruleId1), - DomainId.Combine(appId, ruleId2) + DomainId.Combine(AppId, ruleId1), + DomainId.Combine(AppId, ruleId2) }, rebuildAssets); } private Envelope AppEvent(RuleEvent @event) { - @event.AppId = appId; + @event.AppId = AppId; - return Envelope.Create(@event).SetAggregateId(DomainId.Combine(appId, @event.RuleId)); + return Envelope.Create(@event).SetAggregateId(DomainId.Combine(AppId, @event.RuleId)); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/GuardRuleTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/GuardRuleTests.cs index e96ef72fb..bfa279923 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/GuardRuleTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/GuardRuleTests.cs @@ -11,18 +11,14 @@ using Squidex.Domain.Apps.Core.Rules.Triggers; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Rules.Commands; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; using Squidex.Infrastructure.Collections; using Squidex.Infrastructure.Validation; namespace Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards; -public class GuardRuleTests : IClassFixture +public class GuardRuleTests : GivenContext, IClassFixture { private readonly Uri validUrl = new Uri("https://squidex.io"); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); - private readonly IAppProvider appProvider = A.Fake(); [RuleAction] public sealed record TestAction : RuleAction @@ -30,12 +26,6 @@ public class GuardRuleTests : IClassFixture public Uri Url { get; set; } } - public GuardRuleTests() - { - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false, default)) - .Returns(Mocks.Schema(appId, schemaId)); - } - [Fact] public async Task CanCreate_should_throw_exception_if_trigger_null() { @@ -48,7 +38,7 @@ public class GuardRuleTests : IClassFixture Trigger = null! }); - await ValidationAssert.ThrowsAsync(() => GuardRule.CanCreate(command, appProvider), + await ValidationAssert.ThrowsAsync(() => GuardRule.CanCreate(command, AppProvider), new ValidationError("Trigger is required.", "Trigger")); } @@ -64,7 +54,7 @@ public class GuardRuleTests : IClassFixture Action = null! }); - await ValidationAssert.ThrowsAsync(() => GuardRule.CanCreate(command, appProvider), + await ValidationAssert.ThrowsAsync(() => GuardRule.CanCreate(command, AppProvider), new ValidationError("Action is required.", "Action")); } @@ -83,7 +73,7 @@ public class GuardRuleTests : IClassFixture } }); - await GuardRule.CanCreate(command, appProvider); + await GuardRule.CanCreate(command, AppProvider); } [Fact] @@ -91,7 +81,7 @@ public class GuardRuleTests : IClassFixture { var command = new UpdateRule(); - await GuardRule.CanUpdate(command, Rule(), appProvider); + await GuardRule.CanUpdate(command, Rule(), AppProvider); } [Fact] @@ -99,7 +89,7 @@ public class GuardRuleTests : IClassFixture { var command = new UpdateRule { Name = "MyName" }; - await GuardRule.CanUpdate(command, Rule(), appProvider); + await GuardRule.CanUpdate(command, Rule(), AppProvider); } [Fact] @@ -118,12 +108,12 @@ public class GuardRuleTests : IClassFixture Name = "NewName" }; - await GuardRule.CanUpdate(command, Rule(), appProvider); + await GuardRule.CanUpdate(command, Rule(), AppProvider); } private CreateRule CreateCommand(CreateRule command) { - command.AppId = appId; + command.AppId = AppId; return command; } @@ -132,7 +122,7 @@ public class GuardRuleTests : IClassFixture { var rule = A.Fake(); - A.CallTo(() => rule.AppId).Returns(appId); + A.CallTo(() => rule.AppId).Returns(AppId); return rule; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/Triggers/ContentChangedTriggerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/Triggers/ContentChangedTriggerTests.cs index da1dd79af..2fa5a1540 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/Triggers/ContentChangedTriggerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/Triggers/ContentChangedTriggerTests.cs @@ -15,12 +15,8 @@ using Squidex.Infrastructure.Validation; namespace Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards.Triggers; -public class ContentChangedTriggerTests : IClassFixture +public class ContentChangedTriggerTests : GivenContext, IClassFixture { - private readonly IAppProvider appProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); - [Fact] public async Task Should_add_error_if_schema_id_is_not_defined() { @@ -29,7 +25,7 @@ public class ContentChangedTriggerTests : IClassFixture Schemas = ReadonlyList.Create(new ContentChangedTriggerSchemaV2()) }; - var errors = await RuleTriggerValidator.ValidateAsync(appId.Id, trigger, appProvider); + var errors = await RuleTriggerValidator.ValidateAsync(AppId.Id, trigger, AppProvider); errors.Should().BeEquivalentTo( new List @@ -37,27 +33,27 @@ public class ContentChangedTriggerTests : IClassFixture new ValidationError("Schema ID is required.", "Schemas") }); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A._, false, default)) + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, A._, false, default)) .MustNotHaveHappened(); } [Fact] public async Task Should_add_error_if_schemas_ids_are_not_valid() { - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false, default)) + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, SchemaId.Id, false, default)) .Returns(Task.FromResult(null)); var trigger = new ContentChangedTriggerV2 { - Schemas = ReadonlyList.Create(new ContentChangedTriggerSchemaV2 { SchemaId = schemaId.Id }) + Schemas = ReadonlyList.Create(new ContentChangedTriggerSchemaV2 { SchemaId = SchemaId.Id }) }; - var errors = await RuleTriggerValidator.ValidateAsync(appId.Id, trigger, appProvider); + var errors = await RuleTriggerValidator.ValidateAsync(AppId.Id, trigger, AppProvider); errors.Should().BeEquivalentTo( new List { - new ValidationError($"Schema {schemaId.Id} does not exist.", "Schemas") + new ValidationError($"Schema {SchemaId.Id} does not exist.", "Schemas") }); } @@ -66,7 +62,7 @@ public class ContentChangedTriggerTests : IClassFixture { var trigger = new ContentChangedTriggerV2(); - var errors = await RuleTriggerValidator.ValidateAsync(appId.Id, trigger, appProvider); + var errors = await RuleTriggerValidator.ValidateAsync(AppId.Id, trigger, AppProvider); Assert.Empty(errors); } @@ -79,7 +75,7 @@ public class ContentChangedTriggerTests : IClassFixture Schemas = ReadonlyList.Empty() }; - var errors = await RuleTriggerValidator.ValidateAsync(appId.Id, trigger, appProvider); + var errors = await RuleTriggerValidator.ValidateAsync(AppId.Id, trigger, AppProvider); Assert.Empty(errors); } @@ -87,15 +83,15 @@ public class ContentChangedTriggerTests : IClassFixture [Fact] public async Task Should_not_add_error_if_schemas_ids_are_valid() { - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A._, false, default)) - .Returns(Mocks.Schema(appId, schemaId)); + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, A._, false, default)) + .Returns(Schema); var trigger = new ContentChangedTriggerV2 { - Schemas = ReadonlyList.Create(new ContentChangedTriggerSchemaV2 { SchemaId = schemaId.Id }) + Schemas = ReadonlyList.Create(new ContentChangedTriggerSchemaV2 { SchemaId = SchemaId.Id }) }; - var errors = await RuleTriggerValidator.ValidateAsync(appId.Id, trigger, appProvider); + var errors = await RuleTriggerValidator.ValidateAsync(AppId.Id, trigger, AppProvider); Assert.Empty(errors); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/Triggers/UsageTriggerValidationTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/Triggers/UsageTriggerValidationTests.cs index 71e98e464..29dfdc1ec 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/Triggers/UsageTriggerValidationTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/Guards/Triggers/UsageTriggerValidationTests.cs @@ -7,22 +7,19 @@ using Squidex.Domain.Apps.Core.Rules.Triggers; using Squidex.Domain.Apps.Core.TestHelpers; -using Squidex.Infrastructure; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure.Validation; namespace Squidex.Domain.Apps.Entities.Rules.DomainObject.Guards.Triggers; -public class UsageTriggerValidationTests : IClassFixture +public class UsageTriggerValidationTests : GivenContext, IClassFixture { - private readonly IAppProvider appProvider = A.Fake(); - private readonly DomainId appId = DomainId.NewGuid(); - [Fact] public async Task Should_add_error_if_num_days_less_than_1() { var trigger = new UsageTrigger { NumDays = 0 }; - var errors = await RuleTriggerValidator.ValidateAsync(appId, trigger, appProvider); + var errors = await RuleTriggerValidator.ValidateAsync(AppId.Id, trigger, AppProvider); errors.Should().BeEquivalentTo( new List @@ -36,7 +33,7 @@ public class UsageTriggerValidationTests : IClassFixture { var trigger = new UsageTrigger { NumDays = 32 }; - var errors = await RuleTriggerValidator.ValidateAsync(appId, trigger, appProvider); + var errors = await RuleTriggerValidator.ValidateAsync(AppId.Id, trigger, AppProvider); errors.Should().BeEquivalentTo( new List @@ -50,7 +47,7 @@ public class UsageTriggerValidationTests : IClassFixture { var trigger = new UsageTrigger { NumDays = 20 }; - var errors = await RuleTriggerValidator.ValidateAsync(appId, trigger, appProvider); + var errors = await RuleTriggerValidator.ValidateAsync(AppId.Id, trigger, AppProvider); Assert.Empty(errors); } @@ -60,7 +57,7 @@ public class UsageTriggerValidationTests : IClassFixture { var trigger = new UsageTrigger(); - var errors = await RuleTriggerValidator.ValidateAsync(appId, trigger, appProvider); + var errors = await RuleTriggerValidator.ValidateAsync(AppId.Id, trigger, AppProvider); Assert.Empty(errors); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleCommandMiddlewareTests.cs index 17acb668f..c185c0907 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleCommandMiddlewareTests.cs @@ -16,9 +16,7 @@ public sealed class RuleCommandMiddlewareTests : HandlerTestBase(); private readonly IRuleEnricher ruleEnricher = A.Fake(); - private readonly IContextProvider contextProvider = A.Fake(); private readonly DomainId ruleId = DomainId.NewGuid(); - private readonly Context requestContext; private readonly RuleCommandMiddleware sut; public sealed class MyCommand : SquidexCommand @@ -32,12 +30,7 @@ public sealed class RuleCommandMiddlewareTests : HandlerTestBase contextProvider.Context) - .Returns(requestContext); - - sut = new RuleCommandMiddleware(domainObjectFactory, ruleEnricher, contextProvider); + sut = new RuleCommandMiddleware(domainObjectFactory, ruleEnricher, ApiContextProvider); } [Fact] @@ -45,38 +38,38 @@ public sealed class RuleCommandMiddlewareTests : HandlerTestBase ruleEnricher.EnrichAsync(A._, requestContext, default)) + A.CallTo(() => ruleEnricher.EnrichAsync(A._, ApiContext, A._)) .MustNotHaveHappened(); } [Fact] public async Task Should_not_invoke_enricher_if_already_enriched() { - var actual = new RuleEntity(); + var rule = new RuleEntity(); var context = await HandleAsync(new EnableRule(), - actual); + rule); - Assert.Same(actual, context.Result()); + Assert.Same(rule, context.Result()); - A.CallTo(() => ruleEnricher.EnrichAsync(A._, requestContext, default)) + A.CallTo(() => ruleEnricher.EnrichAsync(A._, ApiContext, A._)) .MustNotHaveHappened(); } [Fact] - public async Task Should_enrich_rule_actual() + public async Task Should_enrich_rule() { - var actual = A.Fake(); + var rule = A.Fake(); var enriched = new RuleEntity(); - A.CallTo(() => ruleEnricher.EnrichAsync(actual, requestContext, default)) + A.CallTo(() => ruleEnricher.EnrichAsync(rule, ApiContext, CancellationToken)) .Returns(enriched); var context = await HandleAsync(new EnableRule(), - actual); + rule); Assert.Same(enriched, context.Result()); } @@ -89,12 +82,12 @@ public sealed class RuleCommandMiddlewareTests : HandlerTestBase(); - A.CallTo(() => domainObject.ExecuteAsync(A._, A._)) + A.CallTo(() => domainObject.ExecuteAsync(A._, CancellationToken)) .Returns(new CommandResult(command.AggregateId, 1, 0, actual)); A.CallTo(() => domainObjectFactory.Create(command.AggregateId)) .Returns(domainObject); - return HandleAsync(sut, command); + return HandleAsync(sut, command, CancellationToken); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleDomainObjectTests.cs index 94d4c6391..111a78dde 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/DomainObject/RuleDomainObjectTests.cs @@ -20,7 +20,6 @@ namespace Squidex.Domain.Apps.Entities.Rules.DomainObject; public class RuleDomainObjectTests : HandlerTestBase { - private readonly IAppProvider appProvider = A.Fake(); private readonly IRuleEnqueuer ruleEnqueuer = A.Fake(); private readonly DomainId ruleId = DomainId.NewGuid(); private readonly RuleDomainObject sut; @@ -42,7 +41,7 @@ public class RuleDomainObjectTests : HandlerTestBase var serviceProvider = new ServiceCollection() - .AddSingleton(appProvider) + .AddSingleton(AppProvider) .AddSingleton(ruleEnqueuer) .BuildServiceProvider(); @@ -69,7 +68,7 @@ public class RuleDomainObjectTests : HandlerTestBase actual.ShouldBeEquivalent(sut.Snapshot); - Assert.Equal(AppId, sut.Snapshot.AppId.Id); + Assert.Equal(AppId, sut.Snapshot.AppId); Assert.Same(command.Trigger, sut.Snapshot.RuleDef.Trigger); Assert.Same(command.Action, sut.Snapshot.RuleDef.Action); @@ -290,7 +289,7 @@ public class RuleDomainObjectTests : HandlerTestBase private async Task PublishAsync(RuleCommand command) { - var actual = await sut.ExecuteAsync(CreateRuleCommand(command), default); + var actual = await sut.ExecuteAsync(CreateRuleCommand(command), CancellationToken); return actual.Payload; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Indexes/RulesIndexTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Indexes/RulesIndexTests.cs index 7c3eed559..4b692d45d 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Indexes/RulesIndexTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Indexes/RulesIndexTests.cs @@ -6,22 +6,17 @@ // ========================================================================== using Squidex.Domain.Apps.Entities.Rules.Repositories; -using Squidex.Infrastructure; +using Squidex.Domain.Apps.Entities.TestHelpers; namespace Squidex.Domain.Apps.Entities.Rules.Indexes; -public class RulesIndexTests +public class RulesIndexTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IRuleRepository ruleRepository = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly RulesIndex sut; public RulesIndexTests() { - ct = cts.Token; - sut = new RulesIndex(ruleRepository); } @@ -30,10 +25,10 @@ public class RulesIndexTests { var rule = SetupRule(0); - A.CallTo(() => ruleRepository.QueryAllAsync(appId.Id, ct)) + A.CallTo(() => ruleRepository.QueryAllAsync(AppId.Id, CancellationToken)) .Returns(new List { rule }); - var actual = await sut.GetRulesAsync(appId.Id, ct); + var actual = await sut.GetRulesAsync(AppId.Id, CancellationToken); Assert.Same(actual[0], rule); } @@ -43,10 +38,10 @@ public class RulesIndexTests { var rule = SetupRule(-1); - A.CallTo(() => ruleRepository.QueryAllAsync(appId.Id, ct)) + A.CallTo(() => ruleRepository.QueryAllAsync(AppId.Id, CancellationToken)) .Returns(new List { rule }); - var actual = await sut.GetRulesAsync(appId.Id, ct); + var actual = await sut.GetRulesAsync(AppId.Id, CancellationToken); Assert.Empty(actual); } @@ -56,16 +51,16 @@ public class RulesIndexTests { var rule = SetupRule(0, true); - A.CallTo(() => ruleRepository.QueryAllAsync(appId.Id, ct)) + A.CallTo(() => ruleRepository.QueryAllAsync(AppId.Id, CancellationToken)) .Returns(new List { rule }); - var actual = await sut.GetRulesAsync(appId.Id, ct); + var actual = await sut.GetRulesAsync(AppId.Id, CancellationToken); Assert.Empty(actual); } private IRuleEntity SetupRule(long version, bool isDeleted = false) { - return new RuleEntity { AppId = appId, Version = version, IsDeleted = isDeleted }; + return new RuleEntity { AppId = AppId, Version = version, IsDeleted = isDeleted }; } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleEnricherTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleEnricherTests.cs index de47638b8..0b891d0a8 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleEnricherTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleEnricherTests.cs @@ -13,22 +13,14 @@ using Squidex.Infrastructure.Caching; namespace Squidex.Domain.Apps.Entities.Rules.Queries; -public class RuleEnricherTests +public class RuleEnricherTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IRuleEventRepository ruleEventRepository = A.Fake(); private readonly IRequestCache requestCache = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly Context requestContext; private readonly RuleEnricher sut; public RuleEnricherTests() { - ct = cts.Token; - - requestContext = Context.Anonymous(Mocks.App(appId)); - sut = new RuleEnricher(ruleEventRepository, requestCache); } @@ -37,7 +29,7 @@ public class RuleEnricherTests { var source = CreateRule(); - var actual = await sut.EnrichAsync(source, requestContext, ct); + var actual = await sut.EnrichAsync(source, ApiContext, CancellationToken); Assert.Equal(0, actual.NumFailed); Assert.Equal(0, actual.NumSucceeded); @@ -64,10 +56,10 @@ public class RuleEnricherTests LastExecuted = SystemClock.Instance.GetCurrentInstant() }; - A.CallTo(() => ruleEventRepository.QueryStatisticsByAppAsync(appId.Id, ct)) + A.CallTo(() => ruleEventRepository.QueryStatisticsByAppAsync(AppId.Id, CancellationToken)) .Returns(new List { stats }); - await sut.EnrichAsync(source, requestContext, ct); + await sut.EnrichAsync(source, ApiContext, CancellationToken); A.CallTo(() => requestCache.AddDependency(source.UniqueId, source.Version)) .MustHaveHappened(); @@ -78,6 +70,6 @@ public class RuleEnricherTests private IRuleEntity CreateRule() { - return new RuleEntity { AppId = appId, Id = DomainId.NewGuid(), Version = 13 }; + return new RuleEntity { AppId = AppId, Id = DomainId.NewGuid(), Version = 13 }; } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleQueryServiceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleQueryServiceTests.cs index 91e2ebddd..834a7707e 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleQueryServiceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/Queries/RuleQueryServiceTests.cs @@ -7,26 +7,17 @@ using Squidex.Domain.Apps.Entities.Rules.Indexes; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Rules.Queries; -public class RuleQueryServiceTests +public class RuleQueryServiceTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly IRulesIndex rulesIndex = A.Fake(); private readonly IRuleEnricher ruleEnricher = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly Context requestContext; private readonly RuleQueryService sut; public RuleQueryServiceTests() { - ct = cts.Token; - - requestContext = Context.Anonymous(Mocks.App(appId)); - sut = new RuleQueryService(rulesIndex, ruleEnricher); } @@ -43,13 +34,13 @@ public class RuleQueryServiceTests new RuleEntity() }; - A.CallTo(() => rulesIndex.GetRulesAsync(appId.Id, ct)) + A.CallTo(() => rulesIndex.GetRulesAsync(AppId.Id, CancellationToken)) .Returns(original); - A.CallTo(() => ruleEnricher.EnrichAsync(original, requestContext, ct)) + A.CallTo(() => ruleEnricher.EnrichAsync(original, ApiContext, CancellationToken)) .Returns(enriched); - var actual = await sut.QueryAsync(requestContext, ct); + var actual = await sut.QueryAsync(ApiContext, CancellationToken); Assert.Same(enriched, actual); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs index a7aa9d216..cb63a9487 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs @@ -14,21 +14,20 @@ using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Core.Rules; using Squidex.Domain.Apps.Core.Rules.Triggers; using Squidex.Domain.Apps.Entities.Rules.Repositories; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events.Contents; using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities.Rules; -public class RuleEnqueuerTests +public class RuleEnqueuerTests : GivenContext { - private readonly IAppProvider appProvider = A.Fake(); private readonly IMemoryCache cache = new MemoryCache(Options.Create(new MemoryCacheOptions())); private readonly ILocalCache localCache = A.Fake(); private readonly IRuleEventRepository ruleEventRepository = A.Fake(); private readonly IRuleService ruleService = A.Fake(); private readonly Instant now = SystemClock.Instance.GetCurrentInstant(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly RuleEnqueuer sut; [RuleAction] @@ -42,7 +41,7 @@ public class RuleEnqueuerTests var options = Options.Create(new RuleOptions()); sut = new RuleEnqueuer(cache, localCache, - appProvider, + AppProvider, ruleEventRepository, ruleService, options, @@ -76,7 +75,7 @@ public class RuleEnqueuerTests [Fact] public async Task Should_not_insert_job_if_null() { - var @event = Envelope.Create(new ContentCreated { AppId = appId }); + var @event = Envelope.Create(new ContentCreated { AppId = AppId }); var rule = CreateRule(); @@ -97,7 +96,7 @@ public class RuleEnqueuerTests [Fact] public async Task Should_not_insert_job_if_job_has_a_skip_reason() { - var @event = Envelope.Create(new ContentCreated { AppId = appId }); + var @event = Envelope.Create(new ContentCreated { AppId = AppId }); var rule = CreateRule(); @@ -118,7 +117,7 @@ public class RuleEnqueuerTests [Fact] public async Task Should_update_repository_if_enqueing() { - var @event = Envelope.Create(new ContentCreated { AppId = appId }); + var @event = Envelope.Create(new ContentCreated { AppId = AppId }); var rule = CreateRule(); @@ -139,7 +138,7 @@ public class RuleEnqueuerTests [Fact] public async Task Should_update_repository_if_enqueing_broken_job() { - var @event = Envelope.Create(new ContentCreated { AppId = appId }); + var @event = Envelope.Create(new ContentCreated { AppId = AppId }); var rule = CreateRule(); @@ -160,7 +159,7 @@ public class RuleEnqueuerTests [Fact] public async Task Should_update_repository_with_jobs_from_service() { - var @event = Envelope.Create(new ContentCreated { AppId = appId }); + var @event = Envelope.Create(new ContentCreated { AppId = AppId }); var job1 = new RuleJob { @@ -178,7 +177,7 @@ public class RuleEnqueuerTests [Fact] public async Task Should_not_eqneue_if_event_restored() { - var @event = Envelope.Create(new ContentCreated { AppId = appId }); + var @event = Envelope.Create(new ContentCreated { AppId = AppId }); var job1 = new RuleJob { Created = now }; @@ -195,7 +194,7 @@ public class RuleEnqueuerTests var rule1 = CreateRule(); var rule2 = CreateRule(); - A.CallTo(() => appProvider.GetRulesAsync(appId.Id, A._)) + A.CallTo(() => AppProvider.GetRulesAsync(AppId.Id, A._)) .Returns(new List { rule1, rule2 }); A.CallTo(() => ruleService.CreateJobsAsync(@event, MatchingContext(rule1), default)) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/BackupSchemasTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/BackupSchemasTests.cs index 848cef377..bb7e3a2d2 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/BackupSchemasTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/BackupSchemasTests.cs @@ -7,6 +7,7 @@ using Squidex.Domain.Apps.Entities.Backup; using Squidex.Domain.Apps.Entities.Schemas.DomainObject; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events.Schemas; using Squidex.Infrastructure; @@ -15,18 +16,13 @@ using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Entities.Schemas; -public class BackupSchemasTests +public class BackupSchemasTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly Rebuilder rebuilder = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly BackupSchemas sut; public BackupSchemasTests() { - ct = cts.Token; - sut = new BackupSchemas(rebuilder); } @@ -43,46 +39,46 @@ public class BackupSchemasTests var schemaId2 = NamedId.Of(DomainId.NewGuid(), "my-schema2"); var schemaId3 = NamedId.Of(DomainId.NewGuid(), "my-schema3"); - var context = new RestoreContext(appId.Id, new UserMapping(RefToken.User("123")), A.Fake(), DomainId.NewGuid()); + var context = new RestoreContext(AppId.Id, new UserMapping(User), A.Fake(), DomainId.NewGuid()); await sut.RestoreEventAsync(AppEvent(new SchemaCreated { SchemaId = schemaId1 - }), context, ct); + }), context, CancellationToken); await sut.RestoreEventAsync(AppEvent(new SchemaCreated { SchemaId = schemaId2 - }), context, ct); + }), context, CancellationToken); await sut.RestoreEventAsync(AppEvent(new SchemaCreated { SchemaId = schemaId3 - }), context, ct); + }), context, CancellationToken); await sut.RestoreEventAsync(AppEvent(new SchemaDeleted { SchemaId = schemaId3 - }), context, ct); + }), context, CancellationToken); var rebuildContents = new HashSet(); - A.CallTo(() => rebuilder.InsertManyAsync(A>._, A._, ct)) + A.CallTo(() => rebuilder.InsertManyAsync(A>._, A._, CancellationToken)) .Invokes(x => rebuildContents.AddRange(x.GetArgument>(0)!)); - await sut.RestoreAsync(context, ct); + await sut.RestoreAsync(context, CancellationToken); Assert.Equal(new HashSet { - DomainId.Combine(appId, schemaId1.Id), - DomainId.Combine(appId, schemaId2.Id) + DomainId.Combine(AppId, schemaId1.Id), + DomainId.Combine(AppId, schemaId2.Id) }, rebuildContents); } private Envelope AppEvent(SchemaEvent @event) { - @event.AppId = appId; + @event.AppId = AppId; - return Envelope.Create(@event).SetAggregateId(DomainId.Combine(appId, @event.SchemaId.Id)); + return Envelope.Create(@event).SetAggregateId(DomainId.Combine(AppId, @event.SchemaId.Id)); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/Guards/GuardSchemaTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/Guards/GuardSchemaTests.cs index f64d1ba4c..4a21e5823 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/Guards/GuardSchemaTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/Guards/GuardSchemaTests.cs @@ -18,10 +18,9 @@ using Squidex.Infrastructure.Validation; namespace Squidex.Domain.Apps.Entities.Schemas.DomainObject.Guards; -public class GuardSchemaTests : IClassFixture +public class GuardSchemaTests : GivenContext, IClassFixture { private readonly Schema schema_0; - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); public GuardSchemaTests() { @@ -663,7 +662,7 @@ public class GuardSchemaTests : IClassFixture private CreateSchema CreateCommand(CreateSchema command) { - command.AppId = appId; + command.AppId = AppId; return command; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/SchemaDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/SchemaDomainObjectTests.cs index 1e8b62678..a27022042 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/SchemaDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/DomainObject/SchemaDomainObjectTests.cs @@ -28,7 +28,7 @@ public class SchemaDomainObjectTests : HandlerTestBase protected override DomainId Id { - get => DomainId.Combine(AppId, SchemaId); + get => DomainId.Combine(AppId.Id, SchemaId.Id); } public SchemaDomainObjectTests() @@ -54,15 +54,15 @@ public class SchemaDomainObjectTests : HandlerTestBase { var properties = new SchemaProperties(); - var command = new CreateSchema { Name = SchemaName, SchemaId = SchemaId, Properties = properties, Type = SchemaType.Singleton }; + var command = new CreateSchema { Name = SchemaId.Name, SchemaId = SchemaId.Id, Properties = properties, Type = SchemaType.Singleton }; var actual = await PublishAsync(command); actual.ShouldBeEquivalent(sut.Snapshot); - Assert.Equal(AppId, sut.Snapshot.AppId.Id); + Assert.Equal(AppId, sut.Snapshot.AppId); - Assert.Equal(SchemaName, sut.Snapshot.SchemaDef.Name); + Assert.Equal(SchemaId.Name, sut.Snapshot.SchemaDef.Name); Assert.Equal(SchemaType.Singleton, sut.Snapshot.SchemaDef.Type); LastEvents @@ -93,7 +93,7 @@ public class SchemaDomainObjectTests : HandlerTestBase } }; - var command = new CreateSchema { Name = SchemaName, SchemaId = SchemaId, Properties = properties, Fields = fields }; + var command = new CreateSchema { Name = SchemaId.Name, SchemaId = SchemaId.Id, Properties = properties, Fields = fields }; var actual = await PublishAsync(command); @@ -101,9 +101,9 @@ public class SchemaDomainObjectTests : HandlerTestBase var @event = (SchemaCreated)LastEvents.Single().Payload; - Assert.Equal(AppId, sut.Snapshot.AppId.Id); - Assert.Equal(SchemaName, sut.Snapshot.SchemaDef.Name); - Assert.Equal(SchemaName, sut.Snapshot.SchemaDef.Name); + Assert.Equal(AppId, sut.Snapshot.AppId); + Assert.Equal(SchemaId.Name, sut.Snapshot.SchemaDef.Name); + Assert.Equal(SchemaType.Default, sut.Snapshot.SchemaDef.Type); Assert.Equal(3, @event.Schema.Fields.Count); } @@ -718,7 +718,7 @@ public class SchemaDomainObjectTests : HandlerTestBase private Task ExecuteCreateAsync() { - return PublishAsync(new CreateSchema { Name = SchemaName, SchemaId = SchemaId }); + return PublishAsync(new CreateSchema { Name = SchemaId.Name, SchemaId = SchemaId.Id }); } private Task ExecuteAddArrayFieldAsync() @@ -766,24 +766,14 @@ public class SchemaDomainObjectTests : HandlerTestBase return new StringFieldProperties { MinLength = 10, MaxLength = 20 }; } - private async Task PublishIdempotentAsync(T command) where T : SquidexCommand, IAggregateCommand + private Task PublishIdempotentAsync(T command) where T : SquidexCommand, IAggregateCommand { - var actual = await PublishAsync(command); - - var previousSnapshot = sut.Snapshot; - var previousVersion = sut.Snapshot.Version; - - await PublishAsync(command); - - Assert.Same(previousSnapshot, sut.Snapshot); - Assert.Equal(previousVersion, sut.Snapshot.Version); - - return actual; + return PublishIdempotentAsync(sut, CreateCommand(command)); } private async Task PublishAsync(T command) where T : SquidexCommand, IAggregateCommand { - var actual = await sut.ExecuteAsync(CreateCommand(command), default); + var actual = await sut.ExecuteAsync(CreateCommand(command), CancellationToken); return actual.Payload; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasIndexTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasIndexTests.cs index 534758192..48cf58a63 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasIndexTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasIndexTests.cs @@ -8,9 +8,9 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using Squidex.Caching; -using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Entities.Schemas.Commands; using Squidex.Domain.Apps.Entities.Schemas.Repositories; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.States; @@ -20,22 +20,16 @@ using Squidex.Messaging; namespace Squidex.Domain.Apps.Entities.Schemas.Indexes; -public class SchemasIndexTests +public class SchemasIndexTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly TestState state; private readonly ISchemaRepository schemaRepository = A.Fake(); private readonly ICommandBus commandBus = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly SchemasIndex sut; public SchemasIndexTests() { - state = new TestState($"{appId.Id}_Schemas"); - - ct = cts.Token; + state = new TestState($"{AppId.Id}_Schemas"); var replicatedCache = new ReplicatedCache(new MemoryCache(Options.Create(new MemoryCacheOptions())), A.Fake(), @@ -47,101 +41,92 @@ public class SchemasIndexTests [Fact] public async Task Should_resolve_schema_by_name() { - var expected = SetupSchema(); - - A.CallTo(() => schemaRepository.FindAsync(appId.Id, schemaId.Name, ct)) - .Returns(expected); + A.CallTo(() => schemaRepository.FindAsync(AppId.Id, SchemaId.Name, CancellationToken)) + .Returns(Schema); - var actual1 = await sut.GetSchemaAsync(appId.Id, schemaId.Name, false, ct); - var actual2 = await sut.GetSchemaAsync(appId.Id, schemaId.Name, false, ct); + var actual1 = await sut.GetSchemaAsync(AppId.Id, SchemaId.Name, false, CancellationToken); + var actual2 = await sut.GetSchemaAsync(AppId.Id, SchemaId.Name, false, CancellationToken); - Assert.Same(expected, actual1); - Assert.Same(expected, actual2); + Assert.Same(Schema, actual1); + Assert.Same(Schema, actual2); - A.CallTo(() => schemaRepository.FindAsync(appId.Id, schemaId.Name, ct)) + A.CallTo(() => schemaRepository.FindAsync(AppId.Id, SchemaId.Name, CancellationToken)) .MustHaveHappenedTwiceExactly(); } [Fact] public async Task Should_resolve_schema_by_name_and_id_if_cached_before() { - var expected = SetupSchema(); - - A.CallTo(() => schemaRepository.FindAsync(appId.Id, schemaId.Name, ct)) - .Returns(expected); + A.CallTo(() => schemaRepository.FindAsync(AppId.Id, SchemaId.Name, CancellationToken)) + .Returns(Schema); - var actual1 = await sut.GetSchemaAsync(appId.Id, schemaId.Name, true, ct); - var actual2 = await sut.GetSchemaAsync(appId.Id, schemaId.Name, true, ct); - var actual3 = await sut.GetSchemaAsync(appId.Id, schemaId.Id, true, ct); + var actual1 = await sut.GetSchemaAsync(AppId.Id, SchemaId.Name, true, CancellationToken); + var actual2 = await sut.GetSchemaAsync(AppId.Id, SchemaId.Name, true, CancellationToken); + var actual3 = await sut.GetSchemaAsync(AppId.Id, SchemaId.Id, true, CancellationToken); - Assert.Same(expected, actual1); - Assert.Same(expected, actual2); - Assert.Same(expected, actual3); + Assert.Same(Schema, actual1); + Assert.Same(Schema, actual2); + Assert.Same(Schema, actual3); - A.CallTo(() => schemaRepository.FindAsync(appId.Id, schemaId.Name, ct)) + A.CallTo(() => schemaRepository.FindAsync(AppId.Id, SchemaId.Name, CancellationToken)) .MustHaveHappenedOnceExactly(); } [Fact] public async Task Should_resolve_schema_by_id() { - var expected = SetupSchema(); + A.CallTo(() => schemaRepository.FindAsync(AppId.Id, SchemaId.Id, CancellationToken)) + .Returns(Schema); - A.CallTo(() => schemaRepository.FindAsync(appId.Id, schemaId.Id, ct)) - .Returns(expected); + var actual1 = await sut.GetSchemaAsync(AppId.Id, SchemaId.Id, false, CancellationToken); + var actual2 = await sut.GetSchemaAsync(AppId.Id, SchemaId.Id, false, CancellationToken); - var actual1 = await sut.GetSchemaAsync(appId.Id, schemaId.Id, false, ct); - var actual2 = await sut.GetSchemaAsync(appId.Id, schemaId.Id, false, ct); + Assert.Same(Schema, actual1); + Assert.Same(Schema, actual2); - Assert.Same(expected, actual1); - Assert.Same(expected, actual2); - - A.CallTo(() => schemaRepository.FindAsync(appId.Id, schemaId.Id, ct)) + A.CallTo(() => schemaRepository.FindAsync(AppId.Id, SchemaId.Id, CancellationToken)) .MustHaveHappenedTwiceExactly(); } [Fact] public async Task Should_resolve_schema_by_id_and_name_if_cached_before() { - var expected = SetupSchema(); - - A.CallTo(() => schemaRepository.FindAsync(appId.Id, schemaId.Id, ct)) - .Returns(expected); + A.CallTo(() => schemaRepository.FindAsync(AppId.Id, SchemaId.Id, CancellationToken)) + .Returns(Schema); - var actual1 = await sut.GetSchemaAsync(appId.Id, schemaId.Id, true, ct); - var actual2 = await sut.GetSchemaAsync(appId.Id, schemaId.Id, true, ct); - var actual3 = await sut.GetSchemaAsync(appId.Id, schemaId.Name, true, ct); + var actual1 = await sut.GetSchemaAsync(AppId.Id, SchemaId.Id, true, CancellationToken); + var actual2 = await sut.GetSchemaAsync(AppId.Id, SchemaId.Id, true, CancellationToken); + var actual3 = await sut.GetSchemaAsync(AppId.Id, SchemaId.Name, true, CancellationToken); - Assert.Same(expected, actual1); - Assert.Same(expected, actual2); - Assert.Same(expected, actual3); + Assert.Same(Schema, actual1); + Assert.Same(Schema, actual2); + Assert.Same(Schema, actual3); - A.CallTo(() => schemaRepository.FindAsync(appId.Id, schemaId.Id, ct)) + A.CallTo(() => schemaRepository.FindAsync(AppId.Id, SchemaId.Id, CancellationToken)) .MustHaveHappenedOnceExactly(); } [Fact] public async Task Should_resolve_schemas() { - var expected = SetupSchema(); - - A.CallTo(() => schemaRepository.QueryAllAsync(appId.Id, ct)) - .Returns(new List { expected }); + A.CallTo(() => schemaRepository.QueryAllAsync(AppId.Id, CancellationToken)) + .Returns(new List { Schema }); - var actual = await sut.GetSchemasAsync(appId.Id, ct); + var actual = await sut.GetSchemasAsync(AppId.Id, CancellationToken); - Assert.Same(actual[0], expected); + Assert.Same(actual[0], Schema); } [Fact] public async Task Should_return_empty_schemas_if_schema_not_created() { - var expected = SetupSchema(EtagVersion.Empty); + A.CallTo(() => Schema.Version) + .Returns(EtagVersion.Empty); - A.CallTo(() => schemaRepository.QueryAllAsync(appId.Id, ct)) - .Returns(new List { expected }); + A.CallTo(() => schemaRepository.QueryAllAsync(AppId.Id, CancellationToken)) + .Returns(new List { Schema }); - var actual = await sut.GetSchemasAsync(appId.Id, ct); + var actual = await sut.GetSchemasAsync(AppId.Id, CancellationToken); Assert.Empty(actual); } @@ -149,12 +134,13 @@ public class SchemasIndexTests [Fact] public async Task Should_return_empty_schemas_if_schema_deleted() { - var expected = SetupSchema(0, true); + A.CallTo(() => Schema.IsDeleted) + .Returns(true); - A.CallTo(() => schemaRepository.QueryAllAsync(appId.Id, ct)) - .Returns(new List { expected }); + A.CallTo(() => schemaRepository.QueryAllAsync(AppId.Id, CancellationToken)) + .Returns(new List { Schema }); - var actual = await sut.GetSchemasAsync(appId.Id, ct); + var actual = await sut.GetSchemasAsync(AppId.Id, CancellationToken); Assert.Empty(actual); } @@ -162,10 +148,10 @@ public class SchemasIndexTests [Fact] public async Task Should_take_and_remove_reservation_if_created() { - A.CallTo(() => schemaRepository.FindAsync(appId.Id, schemaId.Name, ct)) + A.CallTo(() => schemaRepository.FindAsync(AppId.Id, SchemaId.Name, CancellationToken)) .Returns(Task.FromResult(null)); - var command = Create(schemaId.Name); + var command = Create(SchemaId.Name); var context = new CommandContext(command, commandBus) @@ -178,21 +164,21 @@ public class SchemasIndexTests madeReservation = state.Snapshot.Reservations.FirstOrDefault(); return Task.CompletedTask; - }, ct); + }, CancellationToken); Assert.Empty(state.Snapshot.Reservations); - Assert.Equal(schemaId.Id, madeReservation?.Id); - Assert.Equal(schemaId.Name, madeReservation?.Name); + Assert.Equal(SchemaId.Id, madeReservation?.Id); + Assert.Equal(SchemaId.Name, madeReservation?.Name); } [Fact] public async Task Should_clear_reservation_if_schema_creation_failed() { - A.CallTo(() => schemaRepository.FindAsync(appId.Id, schemaId.Name, ct)) + A.CallTo(() => schemaRepository.FindAsync(AppId.Id, SchemaId.Name, CancellationToken)) .Returns(Task.FromResult(null)); - var command = Create(schemaId.Name); + var command = Create(SchemaId.Name); var context = new CommandContext(command, commandBus) @@ -205,44 +191,44 @@ public class SchemasIndexTests madeReservation = state.Snapshot.Reservations.FirstOrDefault(); throw new InvalidOperationException(); - }, ct)); + }, CancellationToken)); Assert.Empty(state.Snapshot.Reservations); - Assert.Equal(schemaId.Id, madeReservation?.Id); - Assert.Equal(schemaId.Name, madeReservation?.Name); + Assert.Equal(SchemaId.Id, madeReservation?.Id); + Assert.Equal(SchemaId.Name, madeReservation?.Name); } [Fact] public async Task Should_not_create_schema_if_name_is_reserved() { - state.Snapshot.Reservations.Add(new NameReservation(RandomHash.Simple(), schemaId.Name, DomainId.NewGuid())); + state.Snapshot.Reservations.Add(new NameReservation(RandomHash.Simple(), SchemaId.Name, DomainId.NewGuid())); - A.CallTo(() => schemaRepository.FindAsync(appId.Id, schemaId.Name, ct)) + A.CallTo(() => schemaRepository.FindAsync(AppId.Id, SchemaId.Name, CancellationToken)) .Returns(Task.FromResult(null)); - var command = Create(schemaId.Name); + var command = Create(SchemaId.Name); var context = new CommandContext(command, commandBus) .Complete(); - await Assert.ThrowsAsync(() => sut.HandleAsync(context, ct)); + await Assert.ThrowsAsync(() => sut.HandleAsync(context, CancellationToken)); } [Fact] public async Task Should_not_create_schema_if_name_is_taken() { - A.CallTo(() => schemaRepository.FindAsync(appId.Id, schemaId.Name, ct)) - .Returns(SetupSchema()); + A.CallTo(() => schemaRepository.FindAsync(AppId.Id, SchemaId.Name, CancellationToken)) + .Returns(Schema); - var command = Create(schemaId.Name); + var command = Create(SchemaId.Name); var context = new CommandContext(command, commandBus) .Complete(); - await Assert.ThrowsAsync(() => sut.HandleAsync(context, ct)); + await Assert.ThrowsAsync(() => sut.HandleAsync(context, CancellationToken)); A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, A._)) .MustNotHaveHappened(); @@ -251,15 +237,13 @@ public class SchemasIndexTests [Fact] public async Task Should_not_make_an_update_for_other_command() { - var schema = SetupSchema(); - - var command = new UpdateSchema { SchemaId = schemaId, AppId = appId }; + var command = new UpdateSchema { SchemaId = SchemaId, AppId = AppId }; var context = new CommandContext(command, commandBus) - .Complete(schema); + .Complete(Schema); - await sut.HandleAsync(context, ct); + await sut.HandleAsync(context, CancellationToken); A.CallTo(() => state.Persistence.WriteSnapshotAsync(A._, A._)) .MustNotHaveHappened(); @@ -267,19 +251,6 @@ public class SchemasIndexTests private CreateSchema Create(string name) { - return new CreateSchema { SchemaId = schemaId.Id, Name = name, AppId = appId }; - } - - private ISchemaEntity SetupSchema(long version = 0, bool isDeleted = false) - { - var schema = A.Fake(); - - A.CallTo(() => schema.SchemaDef).Returns(new Schema(schemaId.Name)); - A.CallTo(() => schema.Id).Returns(schemaId.Id); - A.CallTo(() => schema.AppId).Returns(appId); - A.CallTo(() => schema.Version).Returns(version); - A.CallTo(() => schema.IsDeleted).Returns(isDeleted); - - return schema; + return new CreateSchema { SchemaId = SchemaId.Id, Name = name, AppId = AppId }; } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemasSearchSourceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemasSearchSourceTests.cs index 253b073c8..314ff1887 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemasSearchSourceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/SchemasSearchSourceTests.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Security.Claims; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.TestHelpers; @@ -13,36 +12,30 @@ using Squidex.Domain.Apps.Entities.Search; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Shared; -using Squidex.Shared.Identity; namespace Squidex.Domain.Apps.Entities.Schemas; -public class SchemasSearchSourceTests : IClassFixture -{ - private readonly IUrlGenerator urlGenerator = A.Fake(); - private readonly IAppProvider appProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); +public class SchemasSearchSourceTests : GivenContext, IClassFixture +{ private readonly IUrlGenerator urlGenerator = A.Fake(); private readonly SchemasSearchSource sut; public SchemasSearchSourceTests() { - sut = new SchemasSearchSource(appProvider, urlGenerator); + sut = new SchemasSearchSource(AppProvider, urlGenerator); } [Fact] public async Task Should_not_add_actual_to_contents_if_user_has_no_permission() { - var ctx = ContextWithPermission(); - var schema1 = CreateSchema("schemaA1"); - A.CallTo(() => appProvider.GetSchemasAsync(appId.Id, default)) + A.CallTo(() => AppProvider.GetSchemasAsync(AppId.Id, CancellationToken)) .Returns(new List { schema1 }); - A.CallTo(() => urlGenerator.SchemaUI(appId, schema1.NamedId())) - .Returns("schemaA1-url"); + A.CallTo(() => urlGenerator.SchemaUI(AppId, schema1.NamedId())) + .Returns("schemaA1-url"); - var actual = await sut.SearchAsync("schema", ctx, default); + var actual = await sut.SearchAsync("schema", ApiContext, CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -52,19 +45,17 @@ public class SchemasSearchSourceTests : IClassFixture [Fact] public async Task Should_not_add_actual_to_contents_if_schema_is_component() { - var permission = PermissionIds.ForApp(PermissionIds.AppContentsReadOwn, appId.Name, "schemaA1"); - - var ctx = ContextWithPermission(); + var permission = PermissionIds.ForApp(PermissionIds.AppContentsReadOwn, AppId.Name, "schemaA1"); var schema1 = CreateSchema("schemaA1", SchemaType.Component); - A.CallTo(() => appProvider.GetSchemasAsync(appId.Id, default)) + A.CallTo(() => AppProvider.GetSchemasAsync(AppId.Id, CancellationToken)) .Returns(new List { schema1 }); - A.CallTo(() => urlGenerator.SchemaUI(appId, schema1.NamedId())) + A.CallTo(() => urlGenerator.SchemaUI(AppId, schema1.NamedId())) .Returns("schemaA1-url"); - var actual = await sut.SearchAsync("schema", ctx, default); + var actual = await sut.SearchAsync("schema", CreateContext(false, permission.Id), CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -74,27 +65,25 @@ public class SchemasSearchSourceTests : IClassFixture [Fact] public async Task Should_return_actual_to_schema_and_contents_if_matching_and_permission_given() { - var permission = PermissionIds.ForApp(PermissionIds.AppContentsReadOwn, appId.Name, "schemaA2"); - - var ctx = ContextWithPermission(permission.Id); + var permission = PermissionIds.ForApp(PermissionIds.AppContentsReadOwn, AppId.Name, "schemaA2"); var schema1 = CreateSchema("schemaA1"); var schema2 = CreateSchema("schemaA2"); var schema3 = CreateSchema("schemaB2"); - A.CallTo(() => appProvider.GetSchemasAsync(appId.Id, default)) + A.CallTo(() => AppProvider.GetSchemasAsync(AppId.Id, CancellationToken)) .Returns(new List { schema1, schema2, schema3 }); - A.CallTo(() => urlGenerator.SchemaUI(appId, schema1.NamedId())) + A.CallTo(() => urlGenerator.SchemaUI(AppId, schema1.NamedId())) .Returns("schemaA1-url"); - A.CallTo(() => urlGenerator.SchemaUI(appId, schema2.NamedId())) + A.CallTo(() => urlGenerator.SchemaUI(AppId, schema2.NamedId())) .Returns("schemaA2-url"); - A.CallTo(() => urlGenerator.ContentsUI(appId, schema2.NamedId())) + A.CallTo(() => urlGenerator.ContentsUI(AppId, schema2.NamedId())) .Returns("schemaA2-contents-url"); - var actual = await sut.SearchAsync("schemaA", ctx, default); + var actual = await sut.SearchAsync("schemaA", CreateContext(false, permission.Id), CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -106,22 +95,20 @@ public class SchemasSearchSourceTests : IClassFixture [Fact] public async Task Should_return_actual_to_schema_and_contents_if_schema_is_singleton() { - var permission = PermissionIds.ForApp(PermissionIds.AppContentsReadOwn, appId.Name, "schemaA1"); - - var ctx = ContextWithPermission(permission.Id); + var permission = PermissionIds.ForApp(PermissionIds.AppContentsReadOwn, AppId.Name, "schemaA1"); var schema1 = CreateSchema("schemaA1", SchemaType.Singleton); - A.CallTo(() => appProvider.GetSchemasAsync(appId.Id, default)) + A.CallTo(() => AppProvider.GetSchemasAsync(AppId.Id, CancellationToken)) .Returns(new List { schema1 }); - A.CallTo(() => urlGenerator.SchemaUI(appId, schema1.NamedId())) + A.CallTo(() => urlGenerator.SchemaUI(AppId, schema1.NamedId())) .Returns("schemaA1-url"); - A.CallTo(() => urlGenerator.ContentUI(appId, schema1.NamedId(), schema1.Id)) + A.CallTo(() => urlGenerator.ContentUI(AppId, schema1.NamedId(), schema1.Id)) .Returns("schemaA1-content-url"); - var actual = await sut.SearchAsync("schemaA", ctx, default); + var actual = await sut.SearchAsync("schemaA", CreateContext(false, permission.Id), CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -131,19 +118,6 @@ public class SchemasSearchSourceTests : IClassFixture private ISchemaEntity CreateSchema(string name, SchemaType type = SchemaType.Default) { - return Mocks.Schema(appId, NamedId.Of(DomainId.NewGuid(), name), new Schema(name, type: type)); - } - - private Context ContextWithPermission(string? permission = null) - { - var claimsIdentity = new ClaimsIdentity(); - var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); - - if (permission != null) - { - claimsIdentity.AddClaim(new Claim(SquidexClaimTypes.Permissions, permission)); - } - - return new Context(claimsPrincipal, Mocks.App(appId)); + return Mocks.Schema(AppId, NamedId.Of(DomainId.NewGuid(), name), new Schema(name, type: type)); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Search/SearchManagerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Search/SearchManagerTests.cs index e5a35309d..a871c7fe5 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Search/SearchManagerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Search/SearchManagerTests.cs @@ -7,16 +7,14 @@ using Microsoft.Extensions.Logging; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Search; -public class SearchManagerTests +public class SearchManagerTests : GivenContext { private readonly ISearchSource source1 = A.Fake(); private readonly ISearchSource source2 = A.Fake(); private readonly ILogger log = A.Fake>(); - private readonly Context requestContext = Context.Anonymous(Mocks.App(NamedId.Of(DomainId.NewGuid(), "my-app"))); private readonly SearchManager sut; public SearchManagerTests() @@ -27,7 +25,7 @@ public class SearchManagerTests [Fact] public async Task Should_not_call_sources_and_return_empty_if_query_is_empty() { - var actual = await sut.SearchAsync(string.Empty, requestContext); + var actual = await sut.SearchAsync(string.Empty, ApiContext, CancellationToken); Assert.Empty(actual); @@ -41,7 +39,7 @@ public class SearchManagerTests [Fact] public async Task Should_not_call_sources_and_return_empty_if_is_too_short() { - var actual = await sut.SearchAsync("11", requestContext); + var actual = await sut.SearchAsync("11", ApiContext, CancellationToken); Assert.Empty(actual); @@ -60,13 +58,13 @@ public class SearchManagerTests var query = "a query"; - A.CallTo(() => source1.SearchAsync(query, requestContext, A._)) + A.CallTo(() => source1.SearchAsync(query, ApiContext, CancellationToken)) .Returns(actual1); - A.CallTo(() => source2.SearchAsync(query, requestContext, A._)) + A.CallTo(() => source2.SearchAsync(query, ApiContext, CancellationToken)) .Returns(actual2); - var actual = await sut.SearchAsync(query, requestContext); + var actual = await sut.SearchAsync(query, ApiContext, CancellationToken); actual.Should().BeEquivalentTo( new SearchResults() @@ -81,13 +79,13 @@ public class SearchManagerTests var query = "a query"; - A.CallTo(() => source1.SearchAsync(query, requestContext, A._)) + A.CallTo(() => source1.SearchAsync(query, ApiContext, CancellationToken)) .Throws(new InvalidOperationException()); - A.CallTo(() => source2.SearchAsync(query, requestContext, A._)) + A.CallTo(() => source2.SearchAsync(query, ApiContext, CancellationToken)) .Returns(actual2); - var actual = await sut.SearchAsync(query, requestContext); + var actual = await sut.SearchAsync(query, ApiContext, CancellationToken); actual.Should().BeEquivalentTo(actual2); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Tags/TagServiceTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Tags/TagServiceTests.cs index ef9af8760..947b2b0ea 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Tags/TagServiceTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Tags/TagServiceTests.cs @@ -6,26 +6,22 @@ // ========================================================================== using Squidex.Domain.Apps.Core.Tags; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.TestHelpers; namespace Squidex.Domain.Apps.Entities.Tags; -public class TagServiceTests +public class TagServiceTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly TestState state; - private readonly DomainId appId = DomainId.NewGuid(); private readonly string group = DomainId.NewGuid().ToString(); private readonly string stateId; private readonly TagService sut; public TagServiceTests() { - ct = cts.Token; - - stateId = $"{appId}_{group}"; + stateId = $"{AppId.Id}_{group}"; state = new TestState(stateId); sut = new TagService(state.PersistenceFactory); @@ -34,34 +30,34 @@ public class TagServiceTests [Fact] public async Task Should_delete_and_reset_state_if_cleaning() { - await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag1", "tag2"), ct); - await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag2", "tag3"), ct); + await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag1", "tag2"), CancellationToken); + await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag2", "tag3"), CancellationToken); - await sut.ClearAsync(appId, group, ct); + await sut.ClearAsync(AppId.Id, group, CancellationToken); - var allTags = await sut.GetTagsAsync(appId, group, ct); + var allTags = await sut.GetTagsAsync(AppId.Id, group, CancellationToken); Assert.Empty(allTags); - A.CallTo(() => state.Persistence.DeleteAsync(ct)) + A.CallTo(() => state.Persistence.DeleteAsync(CancellationToken)) .MustHaveHappened(); } [Fact] public async Task Should_unset_count_on_full_clear() { - var ids = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag1", "tag2"), ct); + var ids = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag1", "tag2"), CancellationToken); - await sut.UpdateAsync(appId, group, new Dictionary + await sut.UpdateAsync(AppId.Id, group, new Dictionary { [ids["tag1"]] = 1, [ids["tag2"]] = 1 - }, ct); + }, CancellationToken); // Clear is called by the event consumer to fill the counts again, therefore we do not delete other things. - await sut.ClearAsync(ct); + await sut.ClearAsync(CancellationToken); - var allTags = await sut.GetTagsAsync(appId, group, ct); + var allTags = await sut.GetTagsAsync(AppId.Id, group, CancellationToken); Assert.Equal(new Dictionary { @@ -69,25 +65,25 @@ public class TagServiceTests ["tag2"] = 0 }, allTags); - A.CallTo(() => state.Persistence.DeleteAsync(ct)) + A.CallTo(() => state.Persistence.DeleteAsync(CancellationToken)) .MustNotHaveHappened(); } [Fact] public async Task Should_rename_tag() { - var ids_0 = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag_0"), ct); + var ids_0 = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag_0"), CancellationToken); - await sut.RenameTagAsync(appId, group, "tag_0", "tag_1", ct); + await sut.RenameTagAsync(AppId.Id, group, "tag_0", "tag_1", CancellationToken); // Both names should map to the same tag. - var ids_1 = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag_0"), ct); - var ids_2 = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag_1"), ct); + var ids_1 = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag_0"), CancellationToken); + var ids_2 = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag_1"), CancellationToken); Assert.Equal(ids_0.Values, ids_1.Values); Assert.Equal(ids_0.Values, ids_2.Values); - var allTags = await sut.GetTagsAsync(appId, group, ct); + var allTags = await sut.GetTagsAsync(AppId.Id, group, CancellationToken); Assert.Equal(new Dictionary { @@ -98,22 +94,22 @@ public class TagServiceTests [Fact] public async Task Should_rename_tag_twice() { - var ids_0 = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag_0"), ct); + var ids_0 = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag_0"), CancellationToken); // Forward the old name to the new name. - await sut.RenameTagAsync(appId, group, "tag_0", "tag_1", ct); - await sut.RenameTagAsync(appId, group, "tag_1", "tag_2", ct); + await sut.RenameTagAsync(AppId.Id, group, "tag_0", "tag_1", CancellationToken); + await sut.RenameTagAsync(AppId.Id, group, "tag_1", "tag_2", CancellationToken); // All names should map to the same tag. - var ids_1 = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag_0"), ct); - var ids_2 = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag_1"), ct); - var ids_3 = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag_2"), ct); + var ids_1 = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag_0"), CancellationToken); + var ids_2 = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag_1"), CancellationToken); + var ids_3 = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag_2"), CancellationToken); Assert.Equal(ids_0.Values, ids_1.Values); Assert.Equal(ids_0.Values, ids_2.Values); Assert.Equal(ids_0.Values, ids_3.Values); - var allTags = await sut.GetTagsAsync(appId, group, ct); + var allTags = await sut.GetTagsAsync(AppId.Id, group, CancellationToken); Assert.Equal(new Dictionary { @@ -124,20 +120,20 @@ public class TagServiceTests [Fact] public async Task Should_rename_tag_back() { - var ids_0 = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag_0"), ct); + var ids_0 = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag_0"), CancellationToken); // Forward the old name to the new name. - await sut.RenameTagAsync(appId, group, "tag_0", "tag_1", ct); - await sut.RenameTagAsync(appId, group, "tag_1", "tag_0", ct); + await sut.RenameTagAsync(AppId.Id, group, "tag_0", "tag_1", CancellationToken); + await sut.RenameTagAsync(AppId.Id, group, "tag_1", "tag_0", CancellationToken); // All names should map to the same tag. - var ids_1 = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag_0"), ct); - var ids_2 = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag_1"), ct); + var ids_1 = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag_0"), CancellationToken); + var ids_2 = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag_1"), CancellationToken); Assert.Equal(ids_0.Values, ids_1.Values); Assert.Equal(ids_0.Values, ids_2.Values); - var allTags = await sut.GetTagsAsync(appId, group, ct); + var allTags = await sut.GetTagsAsync(AppId.Id, group, CancellationToken); Assert.Equal(new Dictionary { @@ -148,17 +144,17 @@ public class TagServiceTests [Fact] public async Task Should_merge_tags_on_rename() { - var ids = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag1", "tag2"), ct); + var ids = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag1", "tag2"), CancellationToken); - await sut.UpdateAsync(appId, group, new Dictionary + await sut.UpdateAsync(AppId.Id, group, new Dictionary { [ids["tag1"]] = 1, [ids["tag2"]] = 2 - }, ct); + }, CancellationToken); - await sut.RenameTagAsync(appId, group, "tag2", "tag1", ct); + await sut.RenameTagAsync(AppId.Id, group, "tag2", "tag1", CancellationToken); - var allTags = await sut.GetTagsAsync(appId, group, ct); + var allTags = await sut.GetTagsAsync(AppId.Id, group, CancellationToken); Assert.Equal(new Dictionary { @@ -179,9 +175,9 @@ public class TagServiceTests Alias = null! }; - await sut.RebuildTagsAsync(appId, group, tags, ct); + await sut.RebuildTagsAsync(AppId.Id, group, tags, CancellationToken); - var allTags = await sut.GetTagsAsync(appId, group, ct); + var allTags = await sut.GetTagsAsync(AppId.Id, group, CancellationToken); Assert.Equal(new Dictionary { @@ -204,9 +200,9 @@ public class TagServiceTests Alias = null! }; - await sut.RebuildTagsAsync(appId, group, tags, ct); + await sut.RebuildTagsAsync(AppId.Id, group, tags, CancellationToken); - var allTags = await sut.GetTagsAsync(appId, group, ct); + var allTags = await sut.GetTagsAsync(AppId.Id, group, CancellationToken); Assert.Equal(new Dictionary { @@ -231,9 +227,9 @@ public class TagServiceTests Alias = null! }; - await sut.RebuildTagsAsync(appId, group, tags, ct); + await sut.RebuildTagsAsync(AppId.Id, group, tags, CancellationToken); - var allTags = await sut.GetTagsAsync(appId, group, ct); + var allTags = await sut.GetTagsAsync(AppId.Id, group, CancellationToken); Assert.Equal(new Dictionary { @@ -242,7 +238,7 @@ public class TagServiceTests ["tag3"] = 6 }, allTags); - var export = await sut.GetExportableTagsAsync(appId, group, ct); + var export = await sut.GetExportableTagsAsync(AppId.Id, group, CancellationToken); Assert.Equal(tags.Tags, export.Tags); Assert.Empty(export.Alias); @@ -260,9 +256,9 @@ public class TagServiceTests Tags = null! }; - await sut.RebuildTagsAsync(appId, group, tags, ct); + await sut.RebuildTagsAsync(AppId.Id, group, tags, CancellationToken); - var export = await sut.GetExportableTagsAsync(appId, group, ct); + var export = await sut.GetExportableTagsAsync(AppId.Id, group, CancellationToken); Assert.Equal(tags.Alias, export.Alias); Assert.Empty(export.Tags); @@ -271,10 +267,10 @@ public class TagServiceTests [Fact] public async Task Should_add_tag_but_not_count_tags() { - await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag1", "tag2"), ct); - await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag2", "tag3"), ct); + await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag1", "tag2"), CancellationToken); + await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag2", "tag3"), CancellationToken); - var allTags = await sut.GetTagsAsync(appId, group, ct); + var allTags = await sut.GetTagsAsync(AppId.Id, group, CancellationToken); Assert.Equal(new Dictionary { @@ -287,21 +283,21 @@ public class TagServiceTests [Fact] public async Task Should_add_and_increment_tags() { - var ids = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag1", "tag2", "tag3"), ct); + var ids = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag1", "tag2", "tag3"), CancellationToken); - await sut.UpdateAsync(appId, group, new Dictionary + await sut.UpdateAsync(AppId.Id, group, new Dictionary { [ids["tag1"]] = 1, [ids["tag2"]] = 1 - }, ct); + }, CancellationToken); - await sut.UpdateAsync(appId, group, new Dictionary + await sut.UpdateAsync(AppId.Id, group, new Dictionary { [ids["tag2"]] = 1, [ids["tag3"]] = 1 - }, ct); + }, CancellationToken); - var allTags = await sut.GetTagsAsync(appId, group, ct); + var allTags = await sut.GetTagsAsync(AppId.Id, group, CancellationToken); Assert.Equal(new Dictionary { @@ -314,21 +310,21 @@ public class TagServiceTests [Fact] public async Task Should_add_and_decrement_tags() { - var ids = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag1", "tag2", "tag3"), ct); + var ids = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag1", "tag2", "tag3"), CancellationToken); - await sut.UpdateAsync(appId, group, new Dictionary + await sut.UpdateAsync(AppId.Id, group, new Dictionary { [ids["tag1"]] = 1, [ids["tag2"]] = 1 - }, ct); + }, CancellationToken); - await sut.UpdateAsync(appId, group, new Dictionary + await sut.UpdateAsync(AppId.Id, group, new Dictionary { [ids["tag2"]] = -2, [ids["tag3"]] = -2 - }, ct); + }, CancellationToken); - var allTags = await sut.GetTagsAsync(appId, group, ct); + var allTags = await sut.GetTagsAsync(AppId.Id, group, CancellationToken); Assert.Equal(new Dictionary { @@ -342,13 +338,13 @@ public class TagServiceTests public async Task Should_not_update_non_existing_tags() { // We have no names for these IDs so we cannot update it. - await sut.UpdateAsync(appId, group, new Dictionary + await sut.UpdateAsync(AppId.Id, group, new Dictionary { ["id1"] = 1, ["id2"] = 1 - }, ct); + }, CancellationToken); - var allTags = await sut.GetTagsAsync(appId, group, ct); + var allTags = await sut.GetTagsAsync(AppId.Id, group, CancellationToken); Assert.Empty(allTags); } @@ -357,10 +353,10 @@ public class TagServiceTests public async Task Should_resolve_tag_names() { // Get IDs from names. - var tagIds = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag1", "tag2"), ct); + var tagIds = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag1", "tag2"), CancellationToken); // Get names from IDs (reverse operation). - var tagNames = await sut.GetTagNamesAsync(appId, group, tagIds.Values.ToHashSet(), ct); + var tagNames = await sut.GetTagNamesAsync(AppId.Id, group, tagIds.Values.ToHashSet(), CancellationToken); Assert.Equal(tagIds.Keys.ToArray(), tagNames.Values.ToArray()); } @@ -368,9 +364,9 @@ public class TagServiceTests [Fact] public async Task Should_get_exportable_tags() { - var ids = await sut.GetTagIdsAsync(appId, group, HashSet.Of("tag1", "tag2"), ct); + var ids = await sut.GetTagIdsAsync(AppId.Id, group, HashSet.Of("tag1", "tag2"), CancellationToken); - var allTags = await sut.GetExportableTagsAsync(appId, group, ct); + var allTags = await sut.GetExportableTagsAsync(AppId.Id, group, CancellationToken); allTags.Tags.Should().BeEquivalentTo(new Dictionary { diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/DomainObject/Guards/GuardTeamContributorsTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/DomainObject/Guards/GuardTeamContributorsTests.cs index ae8514b7d..013fcbce8 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/DomainObject/Guards/GuardTeamContributorsTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/DomainObject/Guards/GuardTeamContributorsTests.cs @@ -14,20 +14,21 @@ using Squidex.Infrastructure; using Squidex.Infrastructure.Validation; using Squidex.Shared.Users; -#pragma warning disable SA1310 // Field names must not contain underscore - namespace Squidex.Domain.Apps.Entities.Teams.DomainObject.Guards; -public class GuardTeamContributorsTests : IClassFixture +public class GuardTeamContributorsTests : GivenContext, IClassFixture { private readonly IUser user1 = UserMocks.User("1"); private readonly IUser user2 = UserMocks.User("2"); private readonly IUser user3 = UserMocks.User("3"); private readonly IUserResolver users = A.Fake(); - private readonly Contributors contributors_0 = Contributors.Empty; + private Contributors contributors = Contributors.Empty; public GuardTeamContributorsTests() { + A.CallTo(() => Team.Contributors) + .ReturnsLazily(() => contributors); + A.CallTo(() => user1.Id) .Returns("1"); @@ -55,7 +56,7 @@ public class GuardTeamContributorsTests : IClassFixture { var command = new AssignContributor(); - await ValidationAssert.ThrowsAsync(() => GuardTeamContributors.CanAssign(command, Team(contributors_0), users), + await ValidationAssert.ThrowsAsync(() => GuardTeamContributors.CanAssign(command, Team, users), new ValidationError("Contributor ID or email is required.", "ContributorId")); } @@ -64,7 +65,7 @@ public class GuardTeamContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "1", Role = "Invalid" }; - await ValidationAssert.ThrowsAsync(() => GuardTeamContributors.CanAssign(command, Team(contributors_0), users), + await ValidationAssert.ThrowsAsync(() => GuardTeamContributors.CanAssign(command, Team, users), new ValidationError("Role is not a valid value.", "Role")); } @@ -73,9 +74,9 @@ public class GuardTeamContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "1", Role = Role.Owner }; - var contributors_1 = contributors_0.Assign("1", Role.Owner); + contributors = contributors.Assign("1", Role.Owner); - await GuardTeamContributors.CanAssign(command, Team(contributors_1), users); + await GuardTeamContributors.CanAssign(command, Team, users); } [Fact] @@ -83,9 +84,9 @@ public class GuardTeamContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "1", Role = Role.Owner, IgnoreActor = true }; - var contributors_1 = contributors_0.Assign("1", Role.Owner); + contributors = contributors.Assign("1", Role.Owner); - await GuardTeamContributors.CanAssign(command, Team(contributors_1), users); + await GuardTeamContributors.CanAssign(command, Team, users); } [Fact] @@ -93,7 +94,7 @@ public class GuardTeamContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "notfound", Role = Role.Owner }; - await Assert.ThrowsAsync(() => GuardTeamContributors.CanAssign(command, Team(contributors_0), users)); + await Assert.ThrowsAsync(() => GuardTeamContributors.CanAssign(command, Team, users)); } [Fact] @@ -101,7 +102,7 @@ public class GuardTeamContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "3", Role = Role.Editor, Actor = RefToken.User("3") }; - await Assert.ThrowsAsync(() => GuardTeamContributors.CanAssign(command, Team(contributors_0), users)); + await Assert.ThrowsAsync(() => GuardTeamContributors.CanAssign(command, Team, users)); } [Fact] @@ -109,7 +110,7 @@ public class GuardTeamContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "1" }; - await GuardTeamContributors.CanAssign(command, Team(contributors_0), users); + await GuardTeamContributors.CanAssign(command, Team, users); } [Fact] @@ -117,9 +118,9 @@ public class GuardTeamContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "1" }; - var contributors_1 = contributors_0.Assign("1", Role.Owner); + contributors = contributors.Assign("1", Role.Owner); - await GuardTeamContributors.CanAssign(command, Team(contributors_1), users); + await GuardTeamContributors.CanAssign(command, Team, users); } [Fact] @@ -127,10 +128,9 @@ public class GuardTeamContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "1" }; - var contributors_1 = contributors_0.Assign("1", Role.Owner); - var contributors_2 = contributors_1.Assign("2", Role.Owner); + contributors = contributors.Assign("1", Role.Owner).Assign("2", Role.Owner); - await GuardTeamContributors.CanAssign(command, Team(contributors_2), users); + await GuardTeamContributors.CanAssign(command, Team, users); } [Fact] @@ -138,10 +138,9 @@ public class GuardTeamContributorsTests : IClassFixture { var command = new AssignContributor { ContributorId = "3", IgnorePlans = true }; - var contributors_1 = contributors_0.Assign("1", Role.Editor); - var contributors_2 = contributors_1.Assign("2", Role.Editor); + contributors = contributors.Assign("1", Role.Editor).Assign("2", Role.Editor); - await GuardTeamContributors.CanAssign(command, Team(contributors_2), users); + await GuardTeamContributors.CanAssign(command, Team, users); } [Fact] @@ -149,7 +148,7 @@ public class GuardTeamContributorsTests : IClassFixture { var command = new RemoveContributor(); - ValidationAssert.Throws(() => GuardTeamContributors.CanRemove(command, Team(contributors_0)), + ValidationAssert.Throws(() => GuardTeamContributors.CanRemove(command, Team), new ValidationError("Contributor ID or email is required.", "ContributorId")); } @@ -158,7 +157,7 @@ public class GuardTeamContributorsTests : IClassFixture { var command = new RemoveContributor { ContributorId = "1" }; - Assert.Throws(() => GuardTeamContributors.CanRemove(command, Team(contributors_0))); + Assert.Throws(() => GuardTeamContributors.CanRemove(command, Team)); } [Fact] @@ -166,10 +165,9 @@ public class GuardTeamContributorsTests : IClassFixture { var command = new RemoveContributor { ContributorId = "1" }; - var contributors_1 = contributors_0.Assign("1", Role.Owner); - var contributors_2 = contributors_1.Assign("2", Role.Editor); + contributors = contributors.Assign("1", Role.Owner).Assign("2", Role.Editor); - ValidationAssert.Throws(() => GuardTeamContributors.CanRemove(command, Team(contributors_2)), + ValidationAssert.Throws(() => GuardTeamContributors.CanRemove(command, Team), new ValidationError("Cannot remove the only owner.")); } @@ -178,18 +176,8 @@ public class GuardTeamContributorsTests : IClassFixture { var command = new RemoveContributor { ContributorId = "1" }; - var contributors_1 = contributors_0.Assign("1", Role.Owner); - var contributors_2 = contributors_1.Assign("2", Role.Owner); - - GuardTeamContributors.CanRemove(command, Team(contributors_2)); - } - - private static ITeamEntity Team(Contributors contributors) - { - var team = A.Fake(); - - A.CallTo(() => team.Contributors).Returns(contributors); + contributors = contributors.Assign("1", Role.Owner).Assign("2", Role.Owner); - return team; + GuardTeamContributors.CanRemove(command, Team); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/DomainObject/Guards/GuardTeamTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/DomainObject/Guards/GuardTeamTests.cs index e32c78d3c..7f1be24e3 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/DomainObject/Guards/GuardTeamTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/DomainObject/Guards/GuardTeamTests.cs @@ -10,13 +10,12 @@ using Squidex.Domain.Apps.Entities.Billing; using Squidex.Domain.Apps.Entities.Teams.Commands; using Squidex.Domain.Apps.Entities.Teams.DomainObject.Guards; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; using Squidex.Infrastructure.Validation; using Squidex.Shared.Users; namespace Squidex.Domain.Teams.Apps.Teams.DomainObject.Guards; -public class GuardTeamTests : IClassFixture +public class GuardTeamTests : GivenContext, IClassFixture { private readonly IUserResolver users = A.Fake(); private readonly IBillingPlans billingPlans = A.Fake(); @@ -58,7 +57,7 @@ public class GuardTeamTests : IClassFixture [Fact] public void CanChangePlan_should_throw_exception_if_plan_id_is_null() { - var command = new ChangePlan { Actor = RefToken.User("me") }; + var command = new ChangePlan { Actor = User }; ValidationAssert.Throws(() => GuardTeam.CanChangePlan(command, billingPlans), new ValidationError("Plan ID is required.", "PlanId")); @@ -67,7 +66,7 @@ public class GuardTeamTests : IClassFixture [Fact] public void CanChangePlan_should_throw_exception_if_plan_not_found() { - var command = new ChangePlan { PlanId = "notfound", Actor = RefToken.User("me") }; + var command = new ChangePlan { PlanId = "notfound", Actor = User }; ValidationAssert.Throws(() => GuardTeam.CanChangePlan(command, billingPlans), new ValidationError("A plan with this id does not exist.", "PlanId")); @@ -76,7 +75,7 @@ public class GuardTeamTests : IClassFixture [Fact] public void CanChangePlan_should_not_throw_exception_if_plan_is_found() { - var command = new ChangePlan { PlanId = "basic", Actor = RefToken.User("me") }; + var command = new ChangePlan { PlanId = "basic", Actor = User }; GuardTeam.CanChangePlan(command, billingPlans); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/DomainObject/TeamDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/DomainObject/TeamDomainObjectTests.cs index 989873758..f69160f56 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/DomainObject/TeamDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/DomainObject/TeamDomainObjectTests.cs @@ -28,12 +28,11 @@ public class TeamDomainObjectTests : HandlerTestBase private readonly Plan planFree = new Plan { Id = "free" }; private readonly string contributorId = DomainId.NewGuid().ToString(); private readonly string name = "My Team"; - private readonly DomainId teamId = DomainId.NewGuid(); private readonly TeamDomainObject sut; protected override DomainId Id { - get => teamId; + get => TeamId; } public TeamDomainObjectTests() @@ -52,7 +51,7 @@ public class TeamDomainObjectTests : HandlerTestBase A.CallTo(() => billingPlans.GetPlan(planPaid.Id)) .Returns(planPaid); - A.CallTo(() => billingManager.MustRedirectToPortalAsync(Actor.Identifier, A._, A._, default)) + A.CallTo(() => billingManager.MustRedirectToPortalAsync(User.Identifier, A._, A._, CancellationToken)) .Returns(Task.FromResult(null)); var serviceProvider = @@ -72,7 +71,7 @@ public class TeamDomainObjectTests : HandlerTestBase [Fact] public async Task Create_should_create_events_and_set_intitial_state() { - var command = new CreateTeam { Name = name }; + var command = new CreateTeam { Name = name, TeamId = TeamId }; var actual = await PublishAsync(command); @@ -82,15 +81,15 @@ public class TeamDomainObjectTests : HandlerTestBase LastEvents .ShouldHaveSameEvents( - CreateTeamEvent(new TeamCreated { Name = name }), - CreateTeamEvent(new TeamContributorAssigned { ContributorId = Actor.Identifier, Role = Role.Owner }) + CreateEvent(new TeamCreated { Name = name }), + CreateEvent(new TeamContributorAssigned { ContributorId = User.Identifier, Role = Role.Owner }) ); } [Fact] public async Task Create_should_not_assign_client_as_contributor() { - var command = new CreateTeam { Name = name, Actor = ActorClient }; + var command = new CreateTeam { Name = name, Actor = Client, TeamId = TeamId }; var actual = await PublishAsync(command); @@ -100,7 +99,7 @@ public class TeamDomainObjectTests : HandlerTestBase LastEvents .ShouldHaveSameEvents( - CreateTeamEvent(new TeamCreated { Name = name }, true) // Must be with client actor. + CreateEvent(new TeamCreated { Name = name }, true) // Must be with client User. ); } @@ -119,7 +118,7 @@ public class TeamDomainObjectTests : HandlerTestBase LastEvents .ShouldHaveSameEvents( - CreateTeamEvent(new TeamUpdated { Name = command.Name }) + CreateEvent(new TeamUpdated { Name = command.Name }) ); } @@ -128,7 +127,7 @@ public class TeamDomainObjectTests : HandlerTestBase { var command = new ChangePlan { PlanId = planPaid.Id }; - A.CallTo(() => billingManager.MustRedirectToPortalAsync(Actor.Identifier, A._, planPaid.Id, default)) + A.CallTo(() => billingManager.MustRedirectToPortalAsync(User.Identifier, A._, planPaid.Id, CancellationToken)) .Returns(Task.FromResult(null)); await ExecuteCreateAsync(); @@ -141,13 +140,13 @@ public class TeamDomainObjectTests : HandlerTestBase LastEvents .ShouldHaveSameEvents( - CreateTeamEvent(new TeamPlanChanged { PlanId = planPaid.Id }) + CreateEvent(new TeamPlanChanged { PlanId = planPaid.Id }) ); - A.CallTo(() => billingManager.MustRedirectToPortalAsync(Actor.Identifier, A._, planPaid.Id, default)) + A.CallTo(() => billingManager.MustRedirectToPortalAsync(User.Identifier, A._, planPaid.Id, CancellationToken)) .MustHaveHappened(); - A.CallTo(() => billingManager.SubscribeAsync(Actor.Identifier, A._, planPaid.Id, default)) + A.CallTo(() => billingManager.SubscribeAsync(User.Identifier, A._, planPaid.Id, default)) .MustHaveHappened(); } @@ -166,7 +165,7 @@ public class TeamDomainObjectTests : HandlerTestBase LastEvents .ShouldHaveSameEvents( - CreateTeamEvent(new TeamPlanChanged { PlanId = planPaid.Id }) + CreateEvent(new TeamPlanChanged { PlanId = planPaid.Id }) ); A.CallTo(() => billingManager.MustRedirectToPortalAsync(A._, A._, A._, A._)) @@ -192,10 +191,10 @@ public class TeamDomainObjectTests : HandlerTestBase LastEvents .ShouldHaveSameEvents( - CreateTeamEvent(new TeamPlanReset()) + CreateEvent(new TeamPlanReset()) ); - A.CallTo(() => billingManager.MustRedirectToPortalAsync(A._, A._, A._, A._)) + A.CallTo(() => billingManager.MustRedirectToPortalAsync(A._, A._, A._, CancellationToken)) .MustHaveHappenedOnceExactly(); A.CallTo(() => billingManager.UnsubscribeAsync(A._, A._, A._)) @@ -218,10 +217,10 @@ public class TeamDomainObjectTests : HandlerTestBase LastEvents .ShouldHaveSameEvents( - CreateTeamEvent(new TeamPlanReset()) + CreateEvent(new TeamPlanReset()) ); - A.CallTo(() => billingManager.MustRedirectToPortalAsync(Actor.Identifier, A._, planPaid.Id, default)) + A.CallTo(() => billingManager.MustRedirectToPortalAsync(User.Identifier, A._, planPaid.Id, CancellationToken)) .MustHaveHappenedOnceExactly(); A.CallTo(() => billingManager.UnsubscribeAsync(A._, A._, A._)) @@ -233,7 +232,7 @@ public class TeamDomainObjectTests : HandlerTestBase { var command = new ChangePlan { PlanId = planPaid.Id }; - A.CallTo(() => billingManager.MustRedirectToPortalAsync(Actor.Identifier, A._, planPaid.Id, default)) + A.CallTo(() => billingManager.MustRedirectToPortalAsync(User.Identifier, A._, planPaid.Id, CancellationToken)) .Returns(new Uri("http://squidex.io")); await ExecuteCreateAsync(); @@ -258,10 +257,10 @@ public class TeamDomainObjectTests : HandlerTestBase Assert.Equal(planPaid.Id, sut.Snapshot.Plan?.PlanId); - A.CallTo(() => billingManager.MustRedirectToPortalAsync(Actor.Identifier, A._, planPaid.Id, A._)) + A.CallTo(() => billingManager.MustRedirectToPortalAsync(User.Identifier, A._, planPaid.Id, A._)) .MustNotHaveHappened(); - A.CallTo(() => billingManager.SubscribeAsync(Actor.Identifier, A._, planPaid.Id, A._)) + A.CallTo(() => billingManager.SubscribeAsync(User.Identifier, A._, planPaid.Id, A._)) .MustNotHaveHappened(); } @@ -280,7 +279,7 @@ public class TeamDomainObjectTests : HandlerTestBase LastEvents .ShouldHaveSameEvents( - CreateTeamEvent(new TeamContributorAssigned { ContributorId = contributorId, Role = command.Role, IsAdded = true }) + CreateEvent(new TeamContributorAssigned { ContributorId = contributorId, Role = command.Role, IsAdded = true }) ); } @@ -300,13 +299,13 @@ public class TeamDomainObjectTests : HandlerTestBase LastEvents .ShouldHaveSameEvents( - CreateTeamEvent(new TeamContributorRemoved { ContributorId = contributorId }) + CreateEvent(new TeamContributorRemoved { ContributorId = contributorId }) ); } private Task ExecuteCreateAsync() { - return PublishAsync(new CreateTeam { Name = name }); + return PublishAsync(new CreateTeam { Name = name, TeamId = TeamId }); } private Task ExecuteAssignContributorAsync() @@ -319,28 +318,14 @@ public class TeamDomainObjectTests : HandlerTestBase return PublishAsync(new ChangePlan { PlanId = planPaid.Id }); } - private T CreateTeamEvent(T @event, bool fromClient = false) where T : TeamEvent - { - @event.TeamId = teamId; - - return CreateEvent(@event, fromClient); - } - - private T CreateTeamCommand(T command) where T : TeamCommand - { - command.TeamId = teamId; - - return CreateCommand(command); - } - private Task PublishIdempotentAsync(TeamCommand command) { - return PublishIdempotentAsync(sut, CreateTeamCommand(command)); + return PublishIdempotentAsync(sut, CreateCommand(command)); } private async Task PublishAsync(TeamCommand command) { - var actual = await sut.ExecuteAsync(CreateTeamCommand(command), default); + var actual = await sut.ExecuteAsync(CreateCommand(command), CancellationToken); return actual.Payload; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/Indexes/TeamsIndexTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/Indexes/TeamsIndexTests.cs index 9a4c12cef..dcbdfb04a 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/Indexes/TeamsIndexTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Teams/Indexes/TeamsIndexTests.cs @@ -11,17 +11,13 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Teams.Indexes; -public class TeamsIndexTests +public class TeamsIndexTests : GivenContext { - private readonly CancellationTokenSource cts = new CancellationTokenSource(); - private readonly CancellationToken ct; private readonly ITeamRepository teamRepository = A.Fake(); private readonly TeamsIndex sut; public TeamsIndexTests() { - ct = cts.Token; - sut = new TeamsIndex(teamRepository); } @@ -30,10 +26,10 @@ public class TeamsIndexTests { var team = SetupTeam(0); - A.CallTo(() => teamRepository.QueryAllAsync("user1", ct)) + A.CallTo(() => teamRepository.QueryAllAsync("user1", CancellationToken)) .Returns(new List { team }); - var actual = await sut.GetTeamsAsync("user1", ct); + var actual = await sut.GetTeamsAsync("user1", CancellationToken); Assert.Same(actual[0], team); } @@ -43,10 +39,10 @@ public class TeamsIndexTests { var team = SetupTeam(-1); - A.CallTo(() => teamRepository.QueryAllAsync("user1", ct)) + A.CallTo(() => teamRepository.QueryAllAsync("user1", CancellationToken)) .Returns(new List { team }); - var actual = await sut.GetTeamsAsync("user1", ct); + var actual = await sut.GetTeamsAsync("user1", CancellationToken); Assert.Empty(actual); } @@ -56,10 +52,10 @@ public class TeamsIndexTests { var team = SetupTeam(0); - A.CallTo(() => teamRepository.FindAsync(team.Id, ct)) + A.CallTo(() => teamRepository.FindAsync(team.Id, CancellationToken)) .Returns(team); - var actual = await sut.GetTeamAsync(team.Id, ct); + var actual = await sut.GetTeamAsync(team.Id, CancellationToken); Assert.Same(actual, team); } @@ -69,10 +65,10 @@ public class TeamsIndexTests { var team = SetupTeam(0); - A.CallTo(() => teamRepository.FindAsync(team.Id, ct)) + A.CallTo(() => teamRepository.FindAsync(team.Id, CancellationToken)) .Returns(Task.FromResult(null)); - var actual = await sut.GetTeamAsync(team.Id, ct); + var actual = await sut.GetTeamAsync(team.Id, CancellationToken); Assert.Null(actual); } @@ -81,7 +77,8 @@ public class TeamsIndexTests { var team = Mocks.Team(DomainId.NewGuid()); - A.CallTo(() => team.Version).Returns(version); + A.CallTo(() => team.Version) + .Returns(version); return team; } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/GivenContext.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/GivenContext.cs new file mode 100644 index 000000000..4715fe381 --- /dev/null +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/GivenContext.cs @@ -0,0 +1,131 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Security.Claims; +using Squidex.Domain.Apps.Entities.Apps; +using Squidex.Domain.Apps.Entities.Schemas; +using Squidex.Domain.Apps.Entities.Teams; +using Squidex.Infrastructure; +using Squidex.Infrastructure.Security; +using Squidex.Shared; +using Squidex.Shared.Identity; + +namespace Squidex.Domain.Apps.Entities.TestHelpers; + +public abstract class GivenContext +{ + private readonly CancellationTokenSource cts = new CancellationTokenSource(); + private IAppProvider? appProvider; + private IContextProvider? contextProviderApi; + private IContextProvider? contextProviderFrontend; + private Context? contextApi; + private Context? contextFrontend; + + public DomainId TeamId { get; } = DomainId.NewGuid(); + + public NamedId AppId { get; } = NamedId.Of(DomainId.NewGuid(), "my-app"); + + public NamedId SchemaId { get; } = NamedId.Of(DomainId.NewGuid(), "my-schema"); + + public ITeamEntity Team { get; set; } + + public IAppEntity App { get; set; } + + public ISchemaEntity Schema { get; set; } + + public RefToken User { get; } = RefToken.User("me"); + + public RefToken Client { get; } = RefToken.Client("client"); + + public Context ApiContext + { + get => contextApi ??= new Context(Mocks.ApiUser(), App); + } + + public Context FrontendContext + { + get => contextFrontend ??= new Context(Mocks.FrontendUser(), App); + } + + public IContextProvider ApiContextProvider + { + get => contextProviderApi ??= CreateContextProvider(ApiContext); + } + + public IContextProvider FrontendContextProvider + { + get => contextProviderFrontend ??= CreateContextProvider(FrontendContext); + } + + public IAppProvider AppProvider + { + get => appProvider ??= CreateAppProvider(); + } + + public CancellationToken CancellationToken => cts.Token; + + protected GivenContext() + { + App = Mocks.App(AppId, Language.EN, Language.DE); + + Team = Mocks.Team(TeamId, "my-team", User.Identifier); + + Schema = Mocks.Schema(AppId, SchemaId); + } + + public Context CreateContext(bool isFrontend, params string[] permissions) + { + var claimsIdentity = new ClaimsIdentity(); + var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); + + claimsIdentity.AddClaim(new Claim(OpenIdClaims.Subject, User.Identifier)); + + if (isFrontend) + { + claimsIdentity.AddClaim(new Claim(OpenIdClaims.ClientId, DefaultClients.Frontend)); + } + + foreach (var permission in permissions) + { + claimsIdentity.AddClaim(new Claim(SquidexClaimTypes.Permissions, permission)); + } + + return new Context(claimsPrincipal, App); + } + + private static IContextProvider CreateContextProvider(Context context) + { + var result = A.Fake(); + + A.CallTo(() => result.Context) + .Returns(context); + + return result; + } + + private IAppProvider CreateAppProvider() + { + var result = A.Fake(); + + A.CallTo(() => result.GetAppAsync(AppId.Id, A._, A._)) + .ReturnsLazily(() => App); + + A.CallTo(() => result.GetTeamAsync(TeamId, A._)) + .ReturnsLazily(() => Team); + + A.CallTo(() => result.GetSchemaAsync(AppId.Id, SchemaId.Id, A._, A._)) + .ReturnsLazily(() => Schema); + + A.CallTo(() => result.GetSchemaAsync(AppId.Id, SchemaId.Name, A._, A._)) + .ReturnsLazily(() => Schema); + + A.CallTo(() => result.GetAppWithSchemaAsync(AppId.Id, SchemaId.Id, A._, A._)) + .ReturnsLazily(() => (App, Schema)); + + return result; + } +} diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs index 40f338094..f68d3dc17 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/HandlerTestBase.cs @@ -5,8 +5,8 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using System.Security.Claims; using Squidex.Domain.Apps.Events; +using Squidex.Domain.Apps.Events.Teams; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.EventSourcing; @@ -14,35 +14,11 @@ using Squidex.Infrastructure.States; namespace Squidex.Domain.Apps.Entities.TestHelpers; -public abstract class HandlerTestBase +public abstract class HandlerTestBase : GivenContext { private readonly IPersistenceFactory persistenceFactory = A.Fake>(); private readonly IPersistence persistence = A.Fake>(); - protected RefToken Actor { get; } = RefToken.User("me"); - - protected RefToken ActorClient { get; } = RefToken.Client("client"); - - protected DomainId AppId { get; } = DomainId.NewGuid(); - - protected DomainId SchemaId { get; } = DomainId.NewGuid(); - - protected string AppName { get; } = "my-app"; - - protected string SchemaName { get; } = "my-schema"; - - protected ClaimsPrincipal User { get; } = Mocks.FrontendUser(); - - protected NamedId AppNamedId - { - get => NamedId.Of(AppId, AppName); - } - - protected NamedId SchemaNamedId - { - get => NamedId.Of(SchemaId, SchemaName); - } - protected abstract DomainId Id { get; } public IPersistenceFactory PersistenceFactory @@ -61,10 +37,10 @@ public abstract class HandlerTestBase A.CallTo(() => persistenceFactory.WithEventSourcing(A._, Id, A._)) .Returns(persistence); - A.CallTo(() => persistence.WriteEventsAsync(A>>._, default)) + A.CallTo(() => persistence.WriteEventsAsync(A>>._, CancellationToken)) .Invokes((IReadOnlyList> events, CancellationToken _) => LastEvents = events); - A.CallTo(() => persistence.DeleteAsync(default)) + A.CallTo(() => persistence.DeleteAsync(CancellationToken)) .Invokes(() => LastEvents = Enumerable.Empty>()); #pragma warning restore MA0056 // Do not call overridable members in constructor } @@ -84,15 +60,14 @@ public abstract class HandlerTestBase return context; } - protected async Task PublishIdempotentAsync(DomainObject domainObject, IAggregateCommand command, - CancellationToken ct = default) where T : class, IDomainState, new() + protected async Task PublishIdempotentAsync(DomainObject domainObject, IAggregateCommand command) where T : class, IDomainState, new() { - var actual = await domainObject.ExecuteAsync(command, default); + var actual = await domainObject.ExecuteAsync(command, CancellationToken); var previousSnapshot = domainObject.Snapshot; var previousVersion = domainObject.Snapshot.Version; - await domainObject.ExecuteAsync(command, ct); + await domainObject.ExecuteAsync(command, CancellationToken); Assert.Same(previousSnapshot, domainObject.Snapshot); Assert.Equal(previousVersion, domainObject.Snapshot.Version); @@ -103,21 +78,26 @@ public abstract class HandlerTestBase protected TCommand CreateCommand(TCommand command) where TCommand : SquidexCommand { command.ExpectedVersion = EtagVersion.Any; - command.Actor ??= Actor; + command.Actor ??= User; if (command.User == null && command.Actor.IsUser) { - command.User = User; + command.User = ApiContext.UserPrincipal; } if (command is IAppCommand { AppId: null } appCommand) { - appCommand.AppId = AppNamedId; + appCommand.AppId = AppId; } if (command is ISchemaCommand { SchemaId: null } schemaCommand) { - schemaCommand.SchemaId = SchemaNamedId; + schemaCommand.SchemaId = SchemaId; + } + + if (command is ITeamCommand teamCommand && teamCommand.TeamId == default) + { + teamCommand.TeamId = TeamId; } return command; @@ -125,16 +105,21 @@ public abstract class HandlerTestBase protected TEvent CreateEvent(TEvent @event, bool fromClient = false) where TEvent : SquidexEvent { - @event.Actor = fromClient ? ActorClient : Actor; + @event.Actor = fromClient ? Client : User; if (@event is AppEvent appEvent) { - appEvent.AppId = AppNamedId; + appEvent.AppId = AppId; } if (@event is SchemaEvent schemaEvent) { - schemaEvent.SchemaId = SchemaNamedId; + schemaEvent.SchemaId = SchemaId; + } + + if (@event is TeamEvent teamEvent && teamEvent.TeamId == default) + { + teamEvent.TeamId = TeamId; } return @event; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs index 85f17e27f..51850694e 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/TestHelpers/Mocks.cs @@ -44,7 +44,7 @@ public static class Mocks { var schema = A.Fake(); - schemaDef ??= new Schema(schemaId.Name); + schemaDef ??= new Schema(schemaId.Name).Publish(); A.CallTo(() => schema.Id).Returns(schemaId.Id); A.CallTo(() => schema.AppId).Returns(appId); diff --git a/backend/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs b/backend/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs index 7e745f877..9902620a0 100644 --- a/backend/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs +++ b/backend/tests/Squidex.Web.Tests/ApiPermissionAttributeTests.cs @@ -13,7 +13,6 @@ using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Routing; using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; using Squidex.Shared; using Squidex.Shared.Identity; using Squidex.Web.Pipeline; @@ -22,14 +21,12 @@ using Squidex.Web.Pipeline; namespace Squidex.Web; -public class ApiPermissionAttributeTests +public class ApiPermissionAttributeTests : GivenContext { private readonly HttpContext httpContext = new DefaultHttpContext(); private readonly ActionExecutingContext actionExecutingContext; private readonly ActionExecutionDelegate next; private readonly ClaimsIdentity user = new ClaimsIdentity(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private bool isNextCalled; public ApiPermissionAttributeTests() @@ -62,7 +59,7 @@ public class ApiPermissionAttributeTests [Fact] public async Task Should_make_permission_check_with_app_feature() { - actionExecutingContext.HttpContext.Features.Set(new AppFeature(Mocks.App(appId))); + actionExecutingContext.HttpContext.Features.Set(new AppFeature(App)); user.AddClaim(new Claim(SquidexClaimTypes.Permissions, "squidex.apps.my-app")); @@ -79,8 +76,8 @@ public class ApiPermissionAttributeTests [Fact] public async Task Should_make_permission_check_with_schema_feature() { - actionExecutingContext.HttpContext.Features.Set(new AppFeature(Mocks.App(appId))); - actionExecutingContext.HttpContext.Features.Set(new SchemaFeature(Mocks.Schema(appId, schemaId))); + actionExecutingContext.HttpContext.Features.Set(new AppFeature(App)); + actionExecutingContext.HttpContext.Features.Set(new SchemaFeature(Schema)); user.AddClaim(new Claim(SquidexClaimTypes.Permissions, "squidex.apps.my-app.schemas.my-schema")); @@ -97,7 +94,7 @@ public class ApiPermissionAttributeTests [Fact] public async Task Should_return_forbidden_if_user_has_wrong_permission() { - actionExecutingContext.HttpContext.Features.Set(new AppFeature(Mocks.App(appId))); + actionExecutingContext.HttpContext.Features.Set(new AppFeature(App)); user.AddClaim(new Claim(SquidexClaimTypes.Permissions, "squidex.apps.other-app")); diff --git a/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs b/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs index a389097b8..27165cb6f 100644 --- a/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithAppIdCommandMiddlewareTests.cs @@ -13,27 +13,19 @@ using Squidex.Infrastructure.Commands; namespace Squidex.Web.CommandMiddlewares; -public class EnrichWithAppIdCommandMiddlewareTests +public class EnrichWithAppIdCommandMiddlewareTests : GivenContext { - private readonly IContextProvider contextProvider = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly Context requestContext; private readonly EnrichWithAppIdCommandMiddleware sut; public EnrichWithAppIdCommandMiddlewareTests() { - requestContext = Context.Anonymous(Mocks.App(appId)); - - A.CallTo(() => contextProvider.Context) - .Returns(requestContext); - - sut = new EnrichWithAppIdCommandMiddleware(contextProvider); + sut = new EnrichWithAppIdCommandMiddleware(ApiContextProvider); } [Fact] public async Task Should_throw_exception_if_app_not_found() { - A.CallTo(() => contextProvider.Context) + A.CallTo(() => ApiContextProvider.Context) .Returns(Context.Anonymous(null!)); await Assert.ThrowsAsync(() => HandleAsync(new CreateContent())); @@ -44,7 +36,7 @@ public class EnrichWithAppIdCommandMiddlewareTests { var context = await HandleAsync(new CreateContent()); - Assert.Equal(appId, ((IAppCommand)context.Command).AppId); + Assert.Equal(AppId, ((IAppCommand)context.Command).AppId); } [Fact] diff --git a/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithContentIdCommandMiddlewareTests.cs b/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithContentIdCommandMiddlewareTests.cs index 3926ac1b6..ae16bd455 100644 --- a/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithContentIdCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithContentIdCommandMiddlewareTests.cs @@ -6,15 +6,14 @@ // ========================================================================== using Squidex.Domain.Apps.Entities.Contents.Commands; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; namespace Squidex.Web.CommandMiddlewares; -public class EnrichWithContentIdCommandMiddlewareTests +public class EnrichWithContentIdCommandMiddlewareTests : GivenContext { - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly EnrichWithContentIdCommandMiddleware sut; public EnrichWithContentIdCommandMiddlewareTests() @@ -32,7 +31,7 @@ public class EnrichWithContentIdCommandMiddlewareTests await HandleAsync(command); - Assert.Equal(schemaId.Id, command.ContentId); + Assert.Equal(SchemaId.Id, command.ContentId); } [Fact] @@ -40,12 +39,12 @@ public class EnrichWithContentIdCommandMiddlewareTests { var command = new CreateContent { - ContentId = DomainId.Create("_schemaId_") + ContentId = DomainId.Create("_SchemaId_") }; await HandleAsync(command); - Assert.NotEqual(schemaId.Id, command.ContentId); + Assert.NotEqual(SchemaId.Id, command.ContentId); } [Fact] @@ -58,13 +57,13 @@ public class EnrichWithContentIdCommandMiddlewareTests await HandleAsync(command); - Assert.NotEqual(schemaId.Id, command.ContentId); + Assert.NotEqual(SchemaId.Id, command.ContentId); } private async Task HandleAsync(ContentCommand command) { - command.AppId = appId; - command.SchemaId = schemaId; + command.AppId = AppId; + command.SchemaId = SchemaId; var commandContext = new CommandContext(command, A.Fake()); diff --git a/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs b/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs index b53a53c9b..bd0a57af4 100644 --- a/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithSchemaIdCommandMiddlewareTests.cs @@ -15,18 +15,16 @@ using Squidex.Web.Pipeline; namespace Squidex.Web.CommandMiddlewares; -public class EnrichWithSchemaIdCommandMiddlewareTests +public class EnrichWithSchemaIdCommandMiddlewareTests : GivenContext { private readonly IHttpContextAccessor httpContextAccessor = A.Fake(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); private readonly HttpContext httpContext = new DefaultHttpContext(); private readonly EnrichWithSchemaIdCommandMiddleware sut; public EnrichWithSchemaIdCommandMiddlewareTests() { - httpContext.Features.Set(new AppFeature(Mocks.App(appId))); - httpContext.Features.Set(new SchemaFeature(Mocks.Schema(appId, schemaId))); + httpContext.Features.Set(new AppFeature(App)); + httpContext.Features.Set(new SchemaFeature(Schema)); A.CallTo(() => httpContextAccessor.HttpContext) .Returns(httpContext); @@ -47,7 +45,7 @@ public class EnrichWithSchemaIdCommandMiddlewareTests { var context = await HandleAsync(new CreateContent()); - Assert.Equal(schemaId, ((ISchemaCommand)context.Command).SchemaId); + Assert.Equal(SchemaId, ((ISchemaCommand)context.Command).SchemaId); } [Fact] @@ -62,7 +60,7 @@ public class EnrichWithSchemaIdCommandMiddlewareTests private async Task HandleAsync(IAppCommand command) { - command.AppId = appId; + command.AppId = AppId; var commandContext = new CommandContext(command, A.Fake()); diff --git a/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithTeamIdCommandMiddlewareTests.cs b/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithTeamIdCommandMiddlewareTests.cs index b18da4042..98c880e2b 100644 --- a/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithTeamIdCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Web.Tests/CommandMiddlewares/EnrichWithTeamIdCommandMiddlewareTests.cs @@ -15,16 +15,15 @@ using Squidex.Web.Pipeline; namespace Squidex.Web.CommandMiddlewares; -public class EnrichWithTeamIdCommandMiddlewareTests +public class EnrichWithTeamIdCommandMiddlewareTests : GivenContext { private readonly IHttpContextAccessor httpContextAccessor = A.Fake(); - private readonly DomainId teamId = DomainId.NewGuid(); private readonly HttpContext httpContext = new DefaultHttpContext(); private readonly EnrichWithTeamIdCommandMiddleware sut; public EnrichWithTeamIdCommandMiddlewareTests() { - httpContext.Features.Set(new TeamFeature(Mocks.Team(teamId))); + httpContext.Features.Set(new TeamFeature(Team)); A.CallTo(() => httpContextAccessor.HttpContext) .Returns(httpContext); @@ -45,7 +44,7 @@ public class EnrichWithTeamIdCommandMiddlewareTests { var context = await HandleAsync(new UpdateTeam()); - Assert.Equal(teamId, ((ITeamCommand)context.Command).TeamId); + Assert.Equal(TeamId, ((ITeamCommand)context.Command).TeamId); } [Fact] diff --git a/backend/tests/Squidex.Web.Tests/Pipeline/ApiCostsFilterTests.cs b/backend/tests/Squidex.Web.Tests/Pipeline/ApiCostsFilterTests.cs index 0e9329146..1ce60ba2f 100644 --- a/backend/tests/Squidex.Web.Tests/Pipeline/ApiCostsFilterTests.cs +++ b/backend/tests/Squidex.Web.Tests/Pipeline/ApiCostsFilterTests.cs @@ -11,14 +11,13 @@ using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Routing; using Squidex.Domain.Apps.Entities; -using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Billing; +using Squidex.Domain.Apps.Entities.TestHelpers; namespace Squidex.Web.Pipeline; -public class ApiCostsFilterTests +public class ApiCostsFilterTests : GivenContext { - private readonly IAppEntity appEntity = A.Fake(); private readonly IUsageGate usageGate = A.Fake(); private readonly ActionExecutingContext actionContext; private readonly ActionExecutionDelegate next; @@ -51,7 +50,7 @@ public class ApiCostsFilterTests SetupApp(); - A.CallTo(() => usageGate.IsBlockedAsync(appEntity, A._, DateTime.Today, default)) + A.CallTo(() => usageGate.IsBlockedAsync(App, A._, DateTime.Today, default)) .Returns(true); await sut.OnActionExecutionAsync(actionContext, next); @@ -67,7 +66,7 @@ public class ApiCostsFilterTests SetupApp(); - A.CallTo(() => usageGate.IsBlockedAsync(appEntity, A._, DateTime.Today, default)) + A.CallTo(() => usageGate.IsBlockedAsync(App, A._, DateTime.Today, default)) .Returns(false); await sut.OnActionExecutionAsync(actionContext, next); @@ -86,7 +85,7 @@ public class ApiCostsFilterTests Assert.True(isNextCalled); - A.CallTo(() => usageGate.IsBlockedAsync(appEntity, A._, DateTime.Today, default)) + A.CallTo(() => usageGate.IsBlockedAsync(App, A._, DateTime.Today, default)) .MustNotHaveHappened(); } @@ -99,12 +98,12 @@ public class ApiCostsFilterTests Assert.True(isNextCalled); - A.CallTo(() => usageGate.IsBlockedAsync(appEntity, A._, DateTime.Today, default)) + A.CallTo(() => usageGate.IsBlockedAsync(App, A._, DateTime.Today, default)) .MustNotHaveHappened(); } private void SetupApp() { - httpContext.Features.Set(Context.Anonymous(appEntity)); + httpContext.Features.Set(Context.Anonymous(App)); } } diff --git a/backend/tests/Squidex.Web.Tests/Pipeline/AppResolverTests.cs b/backend/tests/Squidex.Web.Tests/Pipeline/AppResolverTests.cs index 66b86555d..d3424b357 100644 --- a/backend/tests/Squidex.Web.Tests/Pipeline/AppResolverTests.cs +++ b/backend/tests/Squidex.Web.Tests/Pipeline/AppResolverTests.cs @@ -14,8 +14,8 @@ using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Routing; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Apps; -using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Apps; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure.Security; using Squidex.Shared; using Squidex.Shared.Identity; @@ -24,14 +24,12 @@ using Squidex.Shared.Identity; namespace Squidex.Web.Pipeline; -public class AppResolverTests +public class AppResolverTests : GivenContext { - private readonly IAppProvider appProvider = A.Fake(); private readonly HttpContext httpContext = new DefaultHttpContext(); private readonly ActionContext actionContext; private readonly ActionExecutingContext actionExecutingContext; private readonly ActionExecutionDelegate next; - private readonly string appName = "my-app"; private readonly AppResolver sut; private bool isNextCalled; @@ -44,7 +42,7 @@ public class AppResolverTests actionExecutingContext = new ActionExecutingContext(actionContext, new List(), new Dictionary(), this); actionExecutingContext.HttpContext = httpContext; - actionExecutingContext.RouteData.Values["app"] = appName; + actionExecutingContext.RouteData.Values["app"] = AppId.Name; next = () => { @@ -53,7 +51,7 @@ public class AppResolverTests return Task.FromResult(null!); }; - sut = new AppResolver(appProvider); + sut = new AppResolver(AppProvider); } [Theory] @@ -71,7 +69,7 @@ public class AppResolverTests Assert.IsType(actionExecutingContext.Result); Assert.False(isNextCalled); - A.CallTo(() => appProvider.GetAppAsync(A._, false, httpContext.RequestAborted)) + A.CallTo(() => AppProvider.GetAppAsync(A._, false, httpContext.RequestAborted)) .MustNotHaveHappened(); } @@ -80,7 +78,7 @@ public class AppResolverTests { SetupUser(); - A.CallTo(() => appProvider.GetAppAsync(appName, false, httpContext.RequestAborted)) + A.CallTo(() => AppProvider.GetAppAsync(AppId.Name, false, httpContext.RequestAborted)) .Returns(Task.FromResult(null)); await sut.OnActionExecutionAsync(actionExecutingContext, next); @@ -94,10 +92,8 @@ public class AppResolverTests { SetupUser(null); - var app = CreateApp(appName); - - A.CallTo(() => appProvider.GetAppAsync(appName, false, httpContext.RequestAborted)) - .Returns(app); + A.CallTo(() => AppProvider.GetAppAsync(AppId.Name, false, httpContext.RequestAborted)) + .Returns(App); await sut.OnActionExecutionAsync(actionExecutingContext, next); @@ -110,22 +106,20 @@ public class AppResolverTests { var user = SetupUser(); - var app = CreateApp(appName); - - user.AddClaim(new Claim(OpenIdClaims.Subject, "user1")); - user.AddClaim(new Claim(SquidexClaimTypes.Permissions, $"squidex.apps.{appName}")); + user.AddClaim(new Claim(OpenIdClaims.Subject, User.Identifier)); + user.AddClaim(new Claim(SquidexClaimTypes.Permissions, $"squidex.apps.{AppId.Name}")); - A.CallTo(() => appProvider.GetAppAsync(appName, true, httpContext.RequestAborted)) - .Returns(app); + A.CallTo(() => AppProvider.GetAppAsync(AppId.Name, true, httpContext.RequestAborted)) + .Returns(App); await sut.OnActionExecutionAsync(actionExecutingContext, next); var permissions = user.Claims.Where(x => x.Type == SquidexClaimTypes.Permissions).ToList(); - Assert.Same(app, httpContext.Context().App); + Assert.Same(App, httpContext.Context().App); Assert.True(user.Claims.Any()); Assert.True(permissions.Count < 3); - Assert.True(permissions.All(x => x.Value.StartsWith($"squidex.apps.{appName}", StringComparison.OrdinalIgnoreCase))); + Assert.True(permissions.All(x => x.Value.StartsWith($"squidex.apps.{AppId.Name}", StringComparison.OrdinalIgnoreCase))); Assert.True(isNextCalled); } @@ -134,21 +128,22 @@ public class AppResolverTests { var user = SetupUser(); - var app = CreateApp(appName, user: "user1"); + user.AddClaim(new Claim(OpenIdClaims.Subject, User.Identifier)); - user.AddClaim(new Claim(OpenIdClaims.Subject, "user1")); + A.CallTo(() => App.Contributors) + .Returns(Contributors.Empty.Assign(User.Identifier, Role.Reader)); - A.CallTo(() => appProvider.GetAppAsync(appName, true, httpContext.RequestAborted)) - .Returns(app); + A.CallTo(() => AppProvider.GetAppAsync(AppId.Name, true, httpContext.RequestAborted)) + .Returns(App); await sut.OnActionExecutionAsync(actionExecutingContext, next); var permissions = user.Claims.Where(x => x.Type == SquidexClaimTypes.Permissions).ToList(); - Assert.Same(app, httpContext.Context().App); + Assert.Same(App, httpContext.Context().App); Assert.True(user.Claims.Count() > 2); Assert.True(permissions.Count < 3); - Assert.True(permissions.All(x => x.Value.StartsWith($"squidex.apps.{appName}", StringComparison.OrdinalIgnoreCase))); + Assert.True(permissions.All(x => x.Value.StartsWith($"squidex.apps.{AppId.Name}", StringComparison.OrdinalIgnoreCase))); Assert.True(isNextCalled); } @@ -157,22 +152,23 @@ public class AppResolverTests { var user = SetupUser(); - var app = CreateApp(appName, user: "user1"); - - user.AddClaim(new Claim(OpenIdClaims.Subject, "user1")); + user.AddClaim(new Claim(OpenIdClaims.Subject, User.Identifier)); user.AddClaim(new Claim(OpenIdClaims.ClientId, DefaultClients.Frontend)); - A.CallTo(() => appProvider.GetAppAsync(appName, false, httpContext.RequestAborted)) - .Returns(app); + A.CallTo(() => App.Contributors) + .Returns(Contributors.Empty.Assign(User.Identifier, Role.Reader)); + + A.CallTo(() => AppProvider.GetAppAsync(AppId.Name, false, httpContext.RequestAborted)) + .Returns(App); await sut.OnActionExecutionAsync(actionExecutingContext, next); var permissions = user.Claims.Where(x => x.Type == SquidexClaimTypes.Permissions).ToList(); - Assert.Same(app, httpContext.Context().App); + Assert.Same(App, httpContext.Context().App); Assert.True(user.Claims.Count() > 2); Assert.True(permissions.Count > 10); - Assert.True(permissions.All(x => x.Value.StartsWith($"squidex.apps.{appName}", StringComparison.OrdinalIgnoreCase))); + Assert.True(permissions.All(x => x.Value.StartsWith($"squidex.apps.{AppId.Name}", StringComparison.OrdinalIgnoreCase))); Assert.True(isNextCalled); } @@ -181,16 +177,17 @@ public class AppResolverTests { var user = SetupUser(); - user.AddClaim(new Claim(OpenIdClaims.ClientId, $"{appName}:client1")); + user.AddClaim(new Claim(OpenIdClaims.ClientId, $"{AppId.Name}:{Client.Identifier}")); - var app = CreateApp(appName, client: "client1"); + A.CallTo(() => App.Clients) + .Returns(AppClients.Empty.Add(Client.Identifier, Role.Reader)); - A.CallTo(() => appProvider.GetAppAsync(appName, true, httpContext.RequestAborted)) - .Returns(app); + A.CallTo(() => AppProvider.GetAppAsync(AppId.Name, true, httpContext.RequestAborted)) + .Returns(App); await sut.OnActionExecutionAsync(actionExecutingContext, next); - Assert.Same(app, httpContext.Context().App); + Assert.Same(App, httpContext.Context().App); Assert.True(user.Claims.Count() > 2); Assert.True(isNextCalled); } @@ -200,17 +197,18 @@ public class AppResolverTests { var user = SetupUser(); - var app = CreateApp(appName, client: "client1", allowAnonymous: true); + A.CallTo(() => App.Clients) + .Returns(AppClients.Empty.Add(Client.Identifier, Role.Reader).Update(Client.Identifier, allowAnonymous: true)); - A.CallTo(() => appProvider.GetAppAsync(appName, true, httpContext.RequestAborted)) - .Returns(app); + A.CallTo(() => AppProvider.GetAppAsync(AppId.Name, true, httpContext.RequestAborted)) + .Returns(App); await sut.OnActionExecutionAsync(actionExecutingContext, next); - Assert.Same(app, httpContext.Context().App); + Assert.Same(App, httpContext.Context().App); Assert.True(user.Claims.Count() > 2); Assert.True(isNextCalled); - Assert.Contains(user.Claims, x => x.Type == OpenIdClaims.ClientId && x.Value == "client1"); + Assert.Contains(user.Claims, x => x.Type == OpenIdClaims.ClientId && x.Value == Client.Identifier); } [Fact] @@ -218,19 +216,17 @@ public class AppResolverTests { var user = SetupUser(); - user.AddClaim(new Claim(OpenIdClaims.ClientId, $"{appName}:client1")); + user.AddClaim(new Claim(OpenIdClaims.ClientId, $"{AppId.Name}:{Client.Identifier}")); user.AddClaim(new Claim(SquidexClaimTypes.Permissions, "squidex.apps.other-app")); - var app = CreateApp(appName); - actionContext.ActionDescriptor.EndpointMetadata.Add(new AllowAnonymousAttribute()); - A.CallTo(() => appProvider.GetAppAsync(appName, true, httpContext.RequestAborted)) - .Returns(app); + A.CallTo(() => AppProvider.GetAppAsync(AppId.Name, true, httpContext.RequestAborted)) + .Returns(App); await sut.OnActionExecutionAsync(actionExecutingContext, next); - Assert.Same(app, httpContext.Context().App); + Assert.Same(App, httpContext.Context().App); Assert.Equal(2, user.Claims.Count()); Assert.True(isNextCalled); } @@ -240,13 +236,11 @@ public class AppResolverTests { var user = SetupUser(); - user.AddClaim(new Claim(OpenIdClaims.ClientId, $"{appName}:client1")); + user.AddClaim(new Claim(OpenIdClaims.ClientId, $"{AppId.Name}:{Client.Identifier}")); user.AddClaim(new Claim(SquidexClaimTypes.Permissions, "squidex.apps.other-app")); - var app = CreateApp(appName); - - A.CallTo(() => appProvider.GetAppAsync(appName, false, httpContext.RequestAborted)) - .Returns(app); + A.CallTo(() => AppProvider.GetAppAsync(AppId.Name, false, httpContext.RequestAborted)) + .Returns(App); await sut.OnActionExecutionAsync(actionExecutingContext, next); @@ -259,12 +253,13 @@ public class AppResolverTests { var user = SetupUser(); - user.AddClaim(new Claim(OpenIdClaims.ClientId, "other:client1")); + user.AddClaim(new Claim(OpenIdClaims.ClientId, $"other:{Client.Identifier}")); - var app = CreateApp(appName, client: "client1"); + A.CallTo(() => App.Clients) + .Returns(AppClients.Empty.Add(Client.Identifier, Role.Reader)); - A.CallTo(() => appProvider.GetAppAsync(appName, false, httpContext.RequestAborted)) - .Returns(app); + A.CallTo(() => AppProvider.GetAppAsync(AppId.Name, false, httpContext.RequestAborted)) + .Returns(App); await sut.OnActionExecutionAsync(actionExecutingContext, next); @@ -281,7 +276,7 @@ public class AppResolverTests Assert.True(isNextCalled); - A.CallTo(() => appProvider.GetAppAsync(A._, false, httpContext.RequestAborted)) + A.CallTo(() => AppProvider.GetAppAsync(A._, false, httpContext.RequestAborted)) .MustNotHaveHappened(); } @@ -294,30 +289,4 @@ public class AppResolverTests return userIdentity; } - - private static IAppEntity CreateApp(string name, string? user = null, string? client = null, bool? allowAnonymous = null) - { - var app = A.Fake(); - - var contributors = Contributors.Empty; - - if (user != null) - { - contributors = contributors.Assign(user, Role.Reader); - } - - var clients = AppClients.Empty; - - if (client != null) - { - clients = clients.Add(client, "secret").Update(client, allowAnonymous: allowAnonymous); - } - - A.CallTo(() => app.Contributors).Returns(contributors); - A.CallTo(() => app.Clients).Returns(clients); - A.CallTo(() => app.Name).Returns(name); - A.CallTo(() => app.Roles).Returns(Roles.Empty); - - return app; - } } diff --git a/backend/tests/Squidex.Web.Tests/Pipeline/SchemaResolverTests.cs b/backend/tests/Squidex.Web.Tests/Pipeline/SchemaResolverTests.cs index 2ae88e695..2ff5153e7 100644 --- a/backend/tests/Squidex.Web.Tests/Pipeline/SchemaResolverTests.cs +++ b/backend/tests/Squidex.Web.Tests/Pipeline/SchemaResolverTests.cs @@ -11,8 +11,6 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Routing; -using Squidex.Domain.Apps.Core.Schemas; -using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; @@ -23,16 +21,13 @@ using Squidex.Shared; namespace Squidex.Web.Pipeline; -public class SchemaResolverTests +public class SchemaResolverTests : GivenContext { - private readonly IAppProvider appProvider = A.Fake(); private readonly HttpContext httpContext = new DefaultHttpContext(); private readonly ActionContext actionContext; private readonly ActionExecutingContext actionExecutingContext; private readonly ActionExecutionDelegate next; private readonly ClaimsIdentity user = new ClaimsIdentity(); - private readonly NamedId schemaId = NamedId.Of(DomainId.NewGuid(), "my-schema"); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly SchemaResolver sut; private bool isNextCalled; @@ -46,7 +41,7 @@ public class SchemaResolverTests actionExecutingContext = new ActionExecutingContext(actionContext, new List(), new Dictionary(), this); actionExecutingContext.HttpContext = httpContext; actionExecutingContext.HttpContext.User = new ClaimsPrincipal(user); - actionExecutingContext.HttpContext.Features.Set(new AppFeature(Mocks.App(appId))); + actionExecutingContext.HttpContext.Features.Set(new AppFeature(App)); next = () => { @@ -55,7 +50,7 @@ public class SchemaResolverTests return Task.FromResult(null!); }; - sut = new SchemaResolver(appProvider); + sut = new SchemaResolver(AppProvider); } [Theory] @@ -70,7 +65,7 @@ public class SchemaResolverTests AssertNotFound(); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A._, true, httpContext.RequestAborted)) + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, A._, true, httpContext.RequestAborted)) .MustNotHaveHappened(); } @@ -78,12 +73,13 @@ public class SchemaResolverTests public async Task Should_return_404_if_schema_not_published_when_attribute_applied() { actionContext.ActionDescriptor.EndpointMetadata.Add(new SchemaMustBePublishedAttribute()); - actionContext.RouteData.Values["schema"] = schemaId.Id.ToString(); + actionContext.RouteData.Values["schema"] = SchemaId.Id.ToString(); - var schema = CreateSchema(false); + A.CallTo(() => Schema.SchemaDef) + .Returns(Schema.SchemaDef.Unpublish()); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A._, true, httpContext.RequestAborted)) - .Returns(schema); + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, A._, true, httpContext.RequestAborted)) + .Returns(Schema); await sut.OnActionExecutionAsync(actionExecutingContext, next); @@ -93,24 +89,25 @@ public class SchemaResolverTests [Fact] public async Task Should_resolve_schema_if_schema_not_published() { - actionContext.RouteData.Values["schema"] = schemaId.Id.ToString(); + actionContext.RouteData.Values["schema"] = SchemaId.Id.ToString(); - var schema = CreateSchema(false); + A.CallTo(() => Schema.SchemaDef) + .Returns(Schema.SchemaDef.Unpublish()); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A._, true, httpContext.RequestAborted)) - .Returns(schema); + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, A._, true, httpContext.RequestAborted)) + .Returns(Schema); await sut.OnActionExecutionAsync(actionExecutingContext, next); - AssertSchema(schema); + AssertSchema(Schema); } [Fact] public async Task Should_return_404_if_schema_not_found() { - actionContext.RouteData.Values["schema"] = schemaId.Id.ToString(); + actionContext.RouteData.Values["schema"] = SchemaId.Id.ToString(); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A._, true, httpContext.RequestAborted)) + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, A._, true, httpContext.RequestAborted)) .Returns(Task.FromResult(null)); await sut.OnActionExecutionAsync(actionExecutingContext, next); @@ -121,16 +118,14 @@ public class SchemaResolverTests [Fact] public async Task Should_resolve_schema_from_id() { - actionContext.RouteData.Values["schema"] = schemaId.Id.ToString(); + actionContext.RouteData.Values["schema"] = SchemaId.Id.ToString(); - var schema = CreateSchema(true); - - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, true, httpContext.RequestAborted)) - .Returns(schema); + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, SchemaId.Id, true, httpContext.RequestAborted)) + .Returns(Schema); await sut.OnActionExecutionAsync(actionExecutingContext, next); - AssertSchema(schema); + AssertSchema(Schema); } [Fact] @@ -138,31 +133,27 @@ public class SchemaResolverTests { user.AddClaim(new Claim(OpenIdClaims.ClientId, DefaultClients.Frontend)); - actionContext.RouteData.Values["schema"] = schemaId.Id.ToString(); - - var schema = CreateSchema(true); + actionContext.RouteData.Values["schema"] = SchemaId.Id.ToString(); - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false, httpContext.RequestAborted)) - .Returns(schema); + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, SchemaId.Id, false, httpContext.RequestAborted)) + .Returns(Schema); await sut.OnActionExecutionAsync(actionExecutingContext, next); - AssertSchema(schema); + AssertSchema(Schema); } [Fact] public async Task Should_resolve_schema_from_name() { - actionContext.RouteData.Values["schema"] = schemaId.Name; - - var schema = CreateSchema(true); + actionContext.RouteData.Values["schema"] = SchemaId.Name; - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Name, true, httpContext.RequestAborted)) - .Returns(schema); + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, SchemaId.Name, true, httpContext.RequestAborted)) + .Returns(Schema); await sut.OnActionExecutionAsync(actionExecutingContext, next); - AssertSchema(schema); + AssertSchema(Schema); } [Fact] @@ -170,29 +161,27 @@ public class SchemaResolverTests { user.AddClaim(new Claim(OpenIdClaims.ClientId, DefaultClients.Frontend)); - actionContext.RouteData.Values["schema"] = schemaId.Name; + actionContext.RouteData.Values["schema"] = SchemaId.Name; - var schema = CreateSchema(true); - - A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Name, false, httpContext.RequestAborted)) - .Returns(schema); + A.CallTo(() => AppProvider.GetSchemaAsync(AppId.Id, SchemaId.Name, false, httpContext.RequestAborted)) + .Returns(Schema); await sut.OnActionExecutionAsync(actionExecutingContext, next); - AssertSchema(schema); + AssertSchema(Schema); } [Fact] public async Task Should_do_nothing_if_app_feature_not_set() { actionExecutingContext.HttpContext.Features.Set(null!); - actionExecutingContext.RouteData.Values["schema"] = schemaId.Name; + actionExecutingContext.RouteData.Values["schema"] = SchemaId.Name; await sut.OnActionExecutionAsync(actionExecutingContext, next); Assert.True(isNextCalled); - A.CallTo(() => appProvider.GetAppAsync(A._, false, httpContext.RequestAborted)) + A.CallTo(() => AppProvider.GetAppAsync(A._, false, httpContext.RequestAborted)) .MustNotHaveHappened(); } @@ -203,7 +192,7 @@ public class SchemaResolverTests Assert.True(isNextCalled); - A.CallTo(() => appProvider.GetAppAsync(A._, false, httpContext.RequestAborted)) + A.CallTo(() => AppProvider.GetAppAsync(A._, false, httpContext.RequestAborted)) .MustNotHaveHappened(); } @@ -215,24 +204,7 @@ public class SchemaResolverTests private void AssertSchema(ISchemaEntity schema) { - Assert.Equal(schema, actionContext.HttpContext.Features.Get()!.Schema); + Assert.Equal(Schema, actionContext.HttpContext.Features.Get()!.Schema); Assert.True(isNextCalled); } - - private ISchemaEntity CreateSchema(bool published) - { - var schema = new Schema(schemaId.Name); - - if (published) - { - schema = schema.Publish(); - } - - var schemaEntity = A.Fake(); - - A.CallTo(() => schemaEntity.Id).Returns(schemaId.Id); - A.CallTo(() => schemaEntity.SchemaDef).Returns(schema); - - return schemaEntity; - } } diff --git a/backend/tests/Squidex.Web.Tests/Pipeline/TeamResolverTests.cs b/backend/tests/Squidex.Web.Tests/Pipeline/TeamResolverTests.cs index 139aa7f15..872b5fd3f 100644 --- a/backend/tests/Squidex.Web.Tests/Pipeline/TeamResolverTests.cs +++ b/backend/tests/Squidex.Web.Tests/Pipeline/TeamResolverTests.cs @@ -14,8 +14,8 @@ using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Routing; using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core.Apps; -using Squidex.Domain.Apps.Entities; using Squidex.Domain.Apps.Entities.Teams; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Security; using Squidex.Shared.Identity; @@ -24,14 +24,12 @@ using Squidex.Shared.Identity; namespace Squidex.Web.Pipeline; -public class TeamResolverTests +public class TeamResolverTests : GivenContext { - private readonly IAppProvider appProvider = A.Fake(); private readonly HttpContext httpContext = new DefaultHttpContext(); private readonly ActionContext actionContext; private readonly ActionExecutingContext actionExecutingContext; private readonly ActionExecutionDelegate next; - private readonly DomainId teamId = DomainId.NewGuid(); private readonly TeamResolver sut; private bool isNextCalled; @@ -44,7 +42,7 @@ public class TeamResolverTests actionExecutingContext = new ActionExecutingContext(actionContext, new List(), new Dictionary(), this); actionExecutingContext.HttpContext = httpContext; - actionExecutingContext.RouteData.Values["team"] = teamId.ToString(); + actionExecutingContext.RouteData.Values["team"] = TeamId.ToString(); next = () => { @@ -53,7 +51,7 @@ public class TeamResolverTests return Task.FromResult(null!); }; - sut = new TeamResolver(appProvider); + sut = new TeamResolver(AppProvider); } [Theory] @@ -71,7 +69,7 @@ public class TeamResolverTests Assert.IsType(actionExecutingContext.Result); Assert.False(isNextCalled); - A.CallTo(() => appProvider.GetTeamAsync(A._, httpContext.RequestAborted)) + A.CallTo(() => AppProvider.GetTeamAsync(A._, httpContext.RequestAborted)) .MustNotHaveHappened(); } @@ -80,7 +78,7 @@ public class TeamResolverTests { SetupUser(); - A.CallTo(() => appProvider.GetTeamAsync(teamId, httpContext.RequestAborted)) + A.CallTo(() => AppProvider.GetTeamAsync(TeamId, httpContext.RequestAborted)) .Returns(Task.FromResult(null)); await sut.OnActionExecutionAsync(actionExecutingContext, next); @@ -94,10 +92,8 @@ public class TeamResolverTests { SetupUser(null); - var team = CreateTeam(teamId); - - A.CallTo(() => appProvider.GetTeamAsync(teamId, httpContext.RequestAborted)) - .Returns(team); + A.CallTo(() => AppProvider.GetTeamAsync(TeamId, httpContext.RequestAborted)) + .Returns(Team); await sut.OnActionExecutionAsync(actionExecutingContext, next); @@ -110,22 +106,20 @@ public class TeamResolverTests { var user = SetupUser(); - var team = CreateTeam(teamId); - - user.AddClaim(new Claim(OpenIdClaims.Subject, "user1")); - user.AddClaim(new Claim(SquidexClaimTypes.Permissions, $"squidex.teams.{teamId}")); + user.AddClaim(new Claim(OpenIdClaims.Subject, User.Identifier)); + user.AddClaim(new Claim(SquidexClaimTypes.Permissions, $"squidex.teams.{TeamId}")); - A.CallTo(() => appProvider.GetTeamAsync(teamId, httpContext.RequestAborted)) - .Returns(team); + A.CallTo(() => AppProvider.GetTeamAsync(TeamId, httpContext.RequestAborted)) + .Returns(Team); await sut.OnActionExecutionAsync(actionExecutingContext, next); var permissions = user.Claims.Where(x => x.Type == SquidexClaimTypes.Permissions).ToList(); - Assert.Same(team, httpContext.Features.Get()!.Team); + Assert.Same(Team, httpContext.Features.Get()!.Team); Assert.True(user.Claims.Any()); Assert.True(permissions.Count < 3); - Assert.True(permissions.All(x => x.Value.StartsWith($"squidex.teams.{teamId}", StringComparison.OrdinalIgnoreCase))); + Assert.True(permissions.All(x => x.Value.StartsWith($"squidex.teams.{TeamId}", StringComparison.OrdinalIgnoreCase))); Assert.True(isNextCalled); } @@ -134,21 +128,22 @@ public class TeamResolverTests { var user = SetupUser(); - var team = CreateTeam(teamId, user: "user1"); + user.AddClaim(new Claim(OpenIdClaims.Subject, User.Identifier)); - user.AddClaim(new Claim(OpenIdClaims.Subject, "user1")); + A.CallTo(() => Team.Contributors) + .Returns(Contributors.Empty.Assign(User.Identifier, Role.Owner)); - A.CallTo(() => appProvider.GetTeamAsync(teamId, httpContext.RequestAborted)) - .Returns(team); + A.CallTo(() => AppProvider.GetTeamAsync(TeamId, httpContext.RequestAborted)) + .Returns(Team); await sut.OnActionExecutionAsync(actionExecutingContext, next); var permissions = user.Claims.Where(x => x.Type == SquidexClaimTypes.Permissions).ToList(); - Assert.Same(team, httpContext.Features.Get()!.Team); + Assert.Same(Team, httpContext.Features.Get()!.Team); Assert.True(user.Claims.Count() > 2); Assert.True(permissions.Count < 3); - Assert.True(permissions.All(x => x.Value.StartsWith($"squidex.teams.{teamId}", StringComparison.OrdinalIgnoreCase))); + Assert.True(permissions.All(x => x.Value.StartsWith($"squidex.teams.{TeamId}", StringComparison.OrdinalIgnoreCase))); Assert.True(isNextCalled); } @@ -157,19 +152,17 @@ public class TeamResolverTests { var user = SetupUser(); - user.AddClaim(new Claim(OpenIdClaims.ClientId, $"{teamId}:client1")); + user.AddClaim(new Claim(OpenIdClaims.ClientId, $"{TeamId}:client1")); user.AddClaim(new Claim(SquidexClaimTypes.Permissions, "squidex.teams.other-team")); - var team = CreateTeam(teamId); - actionContext.ActionDescriptor.EndpointMetadata.Add(new AllowAnonymousAttribute()); - A.CallTo(() => appProvider.GetTeamAsync(teamId, httpContext.RequestAborted)) - .Returns(team); + A.CallTo(() => AppProvider.GetTeamAsync(TeamId, httpContext.RequestAborted)) + .Returns(Team); await sut.OnActionExecutionAsync(actionExecutingContext, next); - Assert.Same(team, httpContext.Features.Get()!.Team); + Assert.Same(Team, httpContext.Features.Get()!.Team); Assert.Equal(2, user.Claims.Count()); Assert.True(isNextCalled); } @@ -179,13 +172,11 @@ public class TeamResolverTests { var user = SetupUser(); - user.AddClaim(new Claim(OpenIdClaims.ClientId, $"{teamId}:client1")); + user.AddClaim(new Claim(OpenIdClaims.ClientId, $"{TeamId}:client1")); user.AddClaim(new Claim(SquidexClaimTypes.Permissions, "squidex.teams.other-team")); - var team = CreateTeam(teamId); - - A.CallTo(() => appProvider.GetTeamAsync(teamId, httpContext.RequestAborted)) - .Returns(team); + A.CallTo(() => AppProvider.GetTeamAsync(TeamId, httpContext.RequestAborted)) + .Returns(Team); await sut.OnActionExecutionAsync(actionExecutingContext, next); @@ -202,7 +193,7 @@ public class TeamResolverTests Assert.True(isNextCalled); - A.CallTo(() => appProvider.GetTeamAsync(A._, httpContext.RequestAborted)) + A.CallTo(() => AppProvider.GetTeamAsync(A._, httpContext.RequestAborted)) .MustNotHaveHappened(); } @@ -215,21 +206,4 @@ public class TeamResolverTests return userIdentity; } - - private static ITeamEntity CreateTeam(DomainId id, string? user = null) - { - var team = A.Fake(); - - var contributors = Contributors.Empty; - - if (user != null) - { - contributors = contributors.Assign(user, Role.Owner); - } - - A.CallTo(() => team.Id).Returns(id); - A.CallTo(() => team.Contributors).Returns(contributors); - - return team; - } } diff --git a/backend/tests/Squidex.Web.Tests/Pipeline/UsageMiddlewareTests.cs b/backend/tests/Squidex.Web.Tests/Pipeline/UsageMiddlewareTests.cs index bdc5e3f2f..78b087eba 100644 --- a/backend/tests/Squidex.Web.Tests/Pipeline/UsageMiddlewareTests.cs +++ b/backend/tests/Squidex.Web.Tests/Pipeline/UsageMiddlewareTests.cs @@ -11,18 +11,16 @@ using NodaTime; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Billing; using Squidex.Domain.Apps.Entities.TestHelpers; -using Squidex.Infrastructure; namespace Squidex.Web.Pipeline; -public class UsageMiddlewareTests +public class UsageMiddlewareTests : GivenContext { private readonly IAppLogStore usageLog = A.Fake(); private readonly IUsageGate usageGate = A.Fake(); private readonly IClock clock = A.Fake(); private readonly Instant instant = SystemClock.Instance.GetCurrentInstant(); private readonly HttpContext httpContext = new DefaultHttpContext(); - private readonly NamedId appId = NamedId.Of(DomainId.NewGuid(), "my-app"); private readonly RequestDelegate next; private readonly UsageMiddleware sut; private bool isNextCalled; @@ -61,9 +59,7 @@ public class UsageMiddlewareTests [Fact] public async Task Should_not_track_if_call_blocked() { - var app = Mocks.App(appId); - - httpContext.Features.Set(new AppFeature(app)); + httpContext.Features.Set(new AppFeature(App)); httpContext.Features.Set(new ApiCostsAttribute(13)); httpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests; @@ -74,16 +70,14 @@ public class UsageMiddlewareTests var date = instant.ToDateTimeUtc().Date; - A.CallTo(() => usageGate.TrackRequestAsync(app, A._, date, A._, A._, A._, default)) + A.CallTo(() => usageGate.TrackRequestAsync(App, A._, date, A._, A._, A._, default)) .MustNotHaveHappened(); } [Fact] public async Task Should_track_if_calls_left() { - var app = Mocks.App(appId); - - httpContext.Features.Set(new AppFeature(app)); + httpContext.Features.Set(new AppFeature(App)); httpContext.Features.Set(new ApiCostsAttribute(13)); await sut.InvokeAsync(httpContext, next); @@ -92,16 +86,14 @@ public class UsageMiddlewareTests var date = instant.ToDateTimeUtc().Date; - A.CallTo(() => usageGate.TrackRequestAsync(app, A._, date, 13, A._, A._, default)) + A.CallTo(() => usageGate.TrackRequestAsync(App, A._, date, 13, A._, A._, default)) .MustHaveHappened(); } [Fact] public async Task Should_track_request_bytes() { - var app = Mocks.App(appId); - - httpContext.Features.Set(new AppFeature(app)); + httpContext.Features.Set(new AppFeature(App)); httpContext.Features.Set(new ApiCostsAttribute(13)); httpContext.Request.ContentLength = 1024; @@ -111,16 +103,14 @@ public class UsageMiddlewareTests var date = instant.ToDateTimeUtc().Date; - A.CallTo(() => usageGate.TrackRequestAsync(app, A._, date, 13, A._, 1024, default)) + A.CallTo(() => usageGate.TrackRequestAsync(App, A._, date, 13, A._, 1024, default)) .MustHaveHappened(); } [Fact] public async Task Should_track_response_bytes_with_writer() { - var app = Mocks.App(appId); - - httpContext.Features.Set(new AppFeature(app)); + httpContext.Features.Set(new AppFeature(App)); httpContext.Features.Set(new ApiCostsAttribute(13)); await sut.InvokeAsync(httpContext, async x => @@ -134,16 +124,14 @@ public class UsageMiddlewareTests var date = instant.ToDateTimeUtc().Date; - A.CallTo(() => usageGate.TrackRequestAsync(app, A._, date, 13, A._, 11, default)) + A.CallTo(() => usageGate.TrackRequestAsync(App, A._, date, 13, A._, 11, default)) .MustHaveHappened(); } [Fact] public async Task Should_track_response_bytes_with_stream() { - var app = Mocks.App(appId); - - httpContext.Features.Set(new AppFeature(app)); + httpContext.Features.Set(new AppFeature(App)); httpContext.Features.Set(new ApiCostsAttribute(13)); await sut.InvokeAsync(httpContext, async x => @@ -157,16 +145,14 @@ public class UsageMiddlewareTests var date = instant.ToDateTimeUtc().Date; - A.CallTo(() => usageGate.TrackRequestAsync(app, A._, date, 13, A._, 11, default)) + A.CallTo(() => usageGate.TrackRequestAsync(App, A._, date, 13, A._, 11, default)) .MustHaveHappened(); } [Fact] public async Task Should_track_response_bytes_with_file() { - var app = Mocks.App(appId); - - httpContext.Features.Set(new AppFeature(app)); + httpContext.Features.Set(new AppFeature(App)); httpContext.Features.Set(new ApiCostsAttribute(13)); var tempFileName = Path.GetTempFileName(); @@ -190,16 +176,14 @@ public class UsageMiddlewareTests var date = instant.ToDateTimeUtc().Date; - A.CallTo(() => usageGate.TrackRequestAsync(app, A._, date, 13, A._, 11, default)) + A.CallTo(() => usageGate.TrackRequestAsync(App, A._, date, 13, A._, 11, default)) .MustHaveHappened(); } [Fact] public async Task Should_not_track_if_costs_are_zero() { - var app = Mocks.App(appId); - - httpContext.Features.Set(new AppFeature(app)); + httpContext.Features.Set(new AppFeature(App)); httpContext.Features.Set(new ApiCostsAttribute(0)); await sut.InvokeAsync(httpContext, next); @@ -208,16 +192,14 @@ public class UsageMiddlewareTests var date = instant.ToDateTimeUtc().Date; - A.CallTo(() => usageGate.TrackRequestAsync(app, A._, date, A._, A._, A._, default)) + A.CallTo(() => usageGate.TrackRequestAsync(App, A._, date, A._, A._, A._, default)) .MustNotHaveHappened(); } [Fact] public async Task Should_log_request_even_if_costs_are_zero() { - var app = Mocks.App(appId); - - httpContext.Features.Set(new AppFeature(app)); + httpContext.Features.Set(new AppFeature(App)); httpContext.Features.Set(new ApiCostsAttribute(0)); httpContext.Request.Method = "GET"; @@ -225,7 +207,7 @@ public class UsageMiddlewareTests await sut.InvokeAsync(httpContext, next); - A.CallTo(() => usageLog.LogAsync(appId.Id, + A.CallTo(() => usageLog.LogAsync(AppId.Id, A.That.Matches(x => x.Timestamp == instant && x.RequestMethod == "GET" && diff --git a/frontend/src/app/features/schemas/declarations.ts b/frontend/src/app/features/schemas/declarations.ts index 680ccc3d0..f9a6638c4 100644 --- a/frontend/src/app/features/schemas/declarations.ts +++ b/frontend/src/app/features/schemas/declarations.ts @@ -44,7 +44,6 @@ export * from './pages/schema/preview/schema-preview-urls-form.component'; export * from './pages/schema/rules/schema-field-rules-form.component'; export * from './pages/schema/schema-page.component'; export * from './pages/schema/scripts/schema-scripts-form.component'; -export * from './pages/schema/scripts/schema-scripts.pipes'; export * from './pages/schema/ui/field-list.component'; export * from './pages/schema/ui/schema-ui-form.component'; export * from './pages/schemas/schema-form.component'; diff --git a/frontend/src/app/features/schemas/module.ts b/frontend/src/app/features/schemas/module.ts index 3011f4c73..ae1b30e23 100644 --- a/frontend/src/app/features/schemas/module.ts +++ b/frontend/src/app/features/schemas/module.ts @@ -8,7 +8,7 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { HelpComponent, HistoryComponent, LoadSchemasGuard, SchemaMustExistGuard, SqxFrameworkModule, SqxSharedModule } from '@app/shared'; -import { ArrayValidationComponent, AssetsUIComponent, AssetsValidationComponent, BooleanUIComponent, BooleanValidationComponent, ComponentsUIComponent, ComponentsValidationComponent, ComponentUIComponent, ComponentValidationComponent, DateTimeUIComponent, DateTimeValidationComponent, FieldComponent, FieldFormCommonComponent, FieldFormComponent, FieldFormUIComponent, FieldFormValidationComponent, FieldGroupComponent, FieldListComponent, FieldWizardComponent, GeolocationUIComponent, GeolocationValidationComponent, JsonMoreComponent, JsonUIComponent, JsonValidationComponent, NumberUIComponent, NumberValidationComponent, ReferencesUIComponent, ReferencesValidationComponent, SchemaEditFormComponent, SchemaExportFormComponent, SchemaFieldRulesFormComponent, SchemaFieldsComponent, SchemaFormComponent, SchemaPageComponent, SchemaPreviewUrlsFormComponent, SchemaScriptNamePipe, SchemaScriptsFormComponent, SchemasPageComponent, SchemaUIFormComponent, SortableFieldListComponent, StringUIComponent, StringValidationComponent, TagsUIComponent, TagsValidationComponent } from './declarations'; +import { ArrayValidationComponent, AssetsUIComponent, AssetsValidationComponent, BooleanUIComponent, BooleanValidationComponent, ComponentsUIComponent, ComponentsValidationComponent, ComponentUIComponent, ComponentValidationComponent, DateTimeUIComponent, DateTimeValidationComponent, FieldComponent, FieldFormCommonComponent, FieldFormComponent, FieldFormUIComponent, FieldFormValidationComponent, FieldGroupComponent, FieldListComponent, FieldWizardComponent, GeolocationUIComponent, GeolocationValidationComponent, JsonMoreComponent, JsonUIComponent, JsonValidationComponent, NumberUIComponent, NumberValidationComponent, ReferencesUIComponent, ReferencesValidationComponent, SchemaEditFormComponent, SchemaExportFormComponent, SchemaFieldRulesFormComponent, SchemaFieldsComponent, SchemaFormComponent, SchemaPageComponent, SchemaPreviewUrlsFormComponent, SchemaScriptsFormComponent, SchemasPageComponent, SchemaUIFormComponent, SortableFieldListComponent, StringUIComponent, StringValidationComponent, TagsUIComponent, TagsValidationComponent } from './declarations'; const routes: Routes = [ { @@ -87,7 +87,6 @@ const routes: Routes = [ SchemaPageComponent, SchemaPreviewUrlsFormComponent, SchemaScriptsFormComponent, - SchemaScriptNamePipe, SchemasPageComponent, SchemaUIFormComponent, SortableFieldListComponent, diff --git a/frontend/src/app/features/schemas/pages/schema/scripts/schema-scripts-form.component.html b/frontend/src/app/features/schemas/pages/schema/scripts/schema-scripts-form.component.html index 08aabcd67..42657685a 100644 --- a/frontend/src/app/features/schemas/pages/schema/scripts/schema-scripts-form.component.html +++ b/frontend/src/app/features/schemas/pages/schema/scripts/schema-scripts-form.component.html @@ -3,7 +3,7 @@ diff --git a/frontend/src/app/features/schemas/pages/schema/scripts/schema-scripts.pipes.ts b/frontend/src/app/features/schemas/pages/schema/scripts/schema-scripts.pipes.ts deleted file mode 100644 index 523dfd157..000000000 --- a/frontend/src/app/features/schemas/pages/schema/scripts/schema-scripts.pipes.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Squidex Headless CMS - * - * @license - * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. - */ - -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'sqxSchemaScriptName', - pure: true, -}) -export class SchemaScriptNamePipe implements PipeTransform { - public transform(value: string) { - if (value === 'queryPre') { - return 'Prepare Query'; - } else { - return value.substring(0, 1).toUpperCase() + value.substring(1); - } - } -} \ No newline at end of file diff --git a/frontend/src/app/features/settings/pages/asset-scripts/asset-scripts-page.component.html b/frontend/src/app/features/settings/pages/asset-scripts/asset-scripts-page.component.html index f153dd7c5..ff85ffa47 100644 --- a/frontend/src/app/features/settings/pages/asset-scripts/asset-scripts-page.component.html +++ b/frontend/src/app/features/settings/pages/asset-scripts/asset-scripts-page.component.html @@ -15,7 +15,7 @@ diff --git a/frontend/src/app/features/settings/pages/asset-scripts/asset-scripts-page.component.ts b/frontend/src/app/features/settings/pages/asset-scripts/asset-scripts-page.component.ts index 942a44f26..9f48bd6f2 100644 --- a/frontend/src/app/features/settings/pages/asset-scripts/asset-scripts-page.component.ts +++ b/frontend/src/app/features/settings/pages/asset-scripts/asset-scripts-page.component.ts @@ -15,7 +15,7 @@ import { AppsState, AssetCompletions, AssetScriptsState, AssetsService, EditAsse templateUrl: './asset-scripts-page.component.html', }) export class AssetScriptsPageComponent extends ResourceOwner implements OnInit { - public assetScript = 'annotate'; + public assetScript = 'query'; public assetCompletions: Observable = EMPTY; public editForm = new EditAssetScriptsForm(); diff --git a/frontend/src/app/features/schemas/pages/schema/scripts/schema-scripts.pipes.spec.ts b/frontend/src/app/shared/components/pipes.spec.ts similarity index 74% rename from frontend/src/app/features/schemas/pages/schema/scripts/schema-scripts.pipes.spec.ts rename to frontend/src/app/shared/components/pipes.spec.ts index a85ae273a..58c965609 100644 --- a/frontend/src/app/features/schemas/pages/schema/scripts/schema-scripts.pipes.spec.ts +++ b/frontend/src/app/shared/components/pipes.spec.ts @@ -5,10 +5,10 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { SchemaScriptNamePipe } from './schema-scripts.pipes'; +import { ScriptNamePipe } from './pipes'; -describe('SchemaScriptsPipe', () => { - const pipe = new SchemaScriptNamePipe(); +describe('ScriptNamePipe', () => { + const pipe = new ScriptNamePipe(); it('should return titlecase for schema name', () => { const actual = pipe.transform('create'); diff --git a/frontend/src/app/shared/components/pipes.ts b/frontend/src/app/shared/components/pipes.ts index e69652007..20ff12839 100644 --- a/frontend/src/app/shared/components/pipes.ts +++ b/frontend/src/app/shared/components/pipes.ts @@ -10,6 +10,20 @@ import { Observable, of, Subscription } from 'rxjs'; import { map } from 'rxjs/operators'; import { ApiUrlConfig, UserDto, UsersProviderService } from '@app/shared/internal'; +@Pipe({ + name: 'sqxScriptName', + pure: true, +}) +export class ScriptNamePipe implements PipeTransform { + public transform(value: string) { + if (value === 'queryPre') { + return 'Prepare Query'; + } else { + return value.substring(0, 1).toUpperCase() + value.substring(1); + } + } +} + class UserAsyncPipe { private lastUserId?: string; private lastValue: string | undefined = undefined; diff --git a/frontend/src/app/shared/module.ts b/frontend/src/app/shared/module.ts index 0ec5f3534..30c10119b 100644 --- a/frontend/src/app/shared/module.ts +++ b/frontend/src/app/shared/module.ts @@ -13,7 +13,7 @@ import { MentionModule } from 'angular-mentions'; import { NgChartsModule } from 'ng2-charts'; import { NgxDocViewerModule } from 'ngx-doc-viewer'; import { SqxFrameworkModule } from '@app/framework'; -import { ApiCallsCardComponent, ApiCallsSummaryCardComponent, ApiPerformanceCardComponent, ApiTrafficCardComponent, ApiTrafficSummaryCardComponent, AppFormComponent, AppLanguagesService, AppMustExistGuard, AppsService, AppsState, AssetComponent, AssetDialogComponent, AssetFolderComponent, AssetFolderDialogComponent, AssetFolderDropdownComponent, AssetFolderDropdownItemComponent, AssetHistoryComponent, AssetPathComponent, AssetPreviewUrlPipe, AssetScriptsState, AssetsListComponent, AssetSelectorComponent, AssetsService, AssetsState, AssetTextEditorComponent, AssetUploaderComponent, AssetUploaderState, AssetUploadsCountCardComponent, AssetUploadsSizeCardComponent, AssetUploadsSizeSummaryCardComponent, AssetUrlPipe, AuthInterceptor, AuthService, AutoSaveService, BackupsService, BackupsState, ClientsService, ClientsState, CommentComponent, CommentsComponent, CommentsService, ContentListCellDirective, ContentListCellResizeDirective, ContentListFieldComponent, ContentListHeaderComponent, ContentListWidthDirective, ContentMustExistGuard, ContentsColumnsPipe, ContentSelectorComponent, ContentSelectorItemComponent, ContentsService, ContentsState, ContentStatusComponent, ContentValueComponent, ContentValueEditorComponent, ContributorsService, ContributorsState, FileIconPipe, FilterComparisonComponent, FilterLogicalComponent, FilterNodeComponent, FilterOperatorPipe, GeolocationEditorComponent, HelpComponent, HelpMarkdownPipe, HelpService, HistoryComponent, HistoryListComponent, HistoryMessagePipe, HistoryService, IFrameCardComponent, ImageCropperComponent, ImageFocusPointComponent, LanguagesService, LanguagesState, LoadAppsGuard, LoadLanguagesGuard, LoadSchemasGuard, LoadTeamsGuard, MarkdownEditorComponent, MustBeAuthenticatedGuard, MustBeNotAuthenticatedGuard, NewsService, NotifoComponent, PlansService, PlansState, PreviewableType, QueryComponent, QueryListComponent, QueryPathComponent, RandomCatCardComponent, RandomDogCardComponent, ReferenceInputComponent, RichEditorComponent, RolesService, RolesState, RuleEventsState, RuleMustExistGuard, RuleSimulatorState, RulesService, RulesState, SavedQueriesComponent, SchemaCategoryComponent, SchemaMustExistGuard, SchemaMustExistPublishedGuard, SchemaMustNotBeSingletonGuard, SchemasService, SchemasState, SchemaTagSource, SearchFormComponent, SearchService, SortingComponent, StockPhotoService, SupportCardComponent, TableHeaderComponent, TeamFormComponent, TeamMustExistGuard, TeamsService, TeamsState, TemplatesService, TemplatesState, TranslationsService, TranslationStatusComponent, UIService, UIState, UnsetAppGuard, UnsetTeamGuard, UsagesService, UserDtoPicture, UserIdPicturePipe, UserNamePipe, UserNameRefPipe, UserPicturePipe, UserPictureRefPipe, UsersProviderService, UsersService, WatchingUsersComponent, WorkflowsService, WorkflowsState } from './declarations'; +import { ApiCallsCardComponent, ApiCallsSummaryCardComponent, ApiPerformanceCardComponent, ApiTrafficCardComponent, ApiTrafficSummaryCardComponent, AppFormComponent, AppLanguagesService, AppMustExistGuard, AppsService, AppsState, AssetComponent, AssetDialogComponent, AssetFolderComponent, AssetFolderDialogComponent, AssetFolderDropdownComponent, AssetFolderDropdownItemComponent, AssetHistoryComponent, AssetPathComponent, AssetPreviewUrlPipe, AssetScriptsState, AssetsListComponent, AssetSelectorComponent, AssetsService, AssetsState, AssetTextEditorComponent, AssetUploaderComponent, AssetUploaderState, AssetUploadsCountCardComponent, AssetUploadsSizeCardComponent, AssetUploadsSizeSummaryCardComponent, AssetUrlPipe, AuthInterceptor, AuthService, AutoSaveService, BackupsService, BackupsState, ClientsService, ClientsState, CommentComponent, CommentsComponent, CommentsService, ContentListCellDirective, ContentListCellResizeDirective, ContentListFieldComponent, ContentListHeaderComponent, ContentListWidthDirective, ContentMustExistGuard, ContentsColumnsPipe, ContentSelectorComponent, ContentSelectorItemComponent, ContentsService, ContentsState, ContentStatusComponent, ContentValueComponent, ContentValueEditorComponent, ContributorsService, ContributorsState, FileIconPipe, FilterComparisonComponent, FilterLogicalComponent, FilterNodeComponent, FilterOperatorPipe, GeolocationEditorComponent, HelpComponent, HelpMarkdownPipe, HelpService, HistoryComponent, HistoryListComponent, HistoryMessagePipe, HistoryService, IFrameCardComponent, ImageCropperComponent, ImageFocusPointComponent, LanguagesService, LanguagesState, LoadAppsGuard, LoadLanguagesGuard, LoadSchemasGuard, LoadTeamsGuard, MarkdownEditorComponent, MustBeAuthenticatedGuard, MustBeNotAuthenticatedGuard, NewsService, NotifoComponent, PlansService, PlansState, PreviewableType, QueryComponent, QueryListComponent, QueryPathComponent, RandomCatCardComponent, RandomDogCardComponent, ReferenceInputComponent, RichEditorComponent, RolesService, RolesState, RuleEventsState, RuleMustExistGuard, RuleSimulatorState, RulesService, RulesState, SavedQueriesComponent, SchemaCategoryComponent, SchemaMustExistGuard, SchemaMustExistPublishedGuard, SchemaMustNotBeSingletonGuard, SchemasService, SchemasState, SchemaTagSource, SearchFormComponent, SearchService, SortingComponent, StockPhotoService, SupportCardComponent, TableHeaderComponent, TeamFormComponent, TeamMustExistGuard, TeamsService, TeamsState, TemplatesService, TemplatesState, TranslationsService, TranslationStatusComponent, UIService, UIState, UnsetAppGuard, UnsetTeamGuard, UsagesService, UserDtoPicture, UserIdPicturePipe, UserNamePipe, UserNameRefPipe, UserPicturePipe, UserPictureRefPipe, UsersProviderService, UsersService, WatchingUsersComponent, WorkflowsService, WorkflowsState, ScriptNamePipe } from './declarations'; @NgModule({ imports: [ @@ -87,6 +87,7 @@ import { ApiCallsCardComponent, ApiCallsSummaryCardComponent, ApiPerformanceCard RichEditorComponent, SavedQueriesComponent, SchemaCategoryComponent, + ScriptNamePipe, SearchFormComponent, SortingComponent, SupportCardComponent, @@ -155,6 +156,7 @@ import { ApiCallsCardComponent, ApiCallsSummaryCardComponent, ApiPerformanceCard RouterModule, SavedQueriesComponent, SchemaCategoryComponent, + ScriptNamePipe, SearchFormComponent, SupportCardComponent, TableHeaderComponent, diff --git a/frontend/src/app/shared/services/assets.service.ts b/frontend/src/app/shared/services/assets.service.ts index 78f1983a2..f4b35be8e 100644 --- a/frontend/src/app/shared/services/assets.service.ts +++ b/frontend/src/app/shared/services/assets.service.ts @@ -87,7 +87,7 @@ export class AssetDto { public fullUrl(apiUrl: ApiUrlConfig, authService?: AuthService) { let url = apiUrl.buildUrl(this.contentUrl); - if (this.isProtected && authService && authService.user) { + if (authService && authService.user) { url = StringHelper.appendToUrl(url, 'access_token', authService.user.accessToken); } diff --git a/frontend/src/app/shared/state/assets.forms.ts b/frontend/src/app/shared/state/assets.forms.ts index 0ee403a09..74bbbf1cc 100644 --- a/frontend/src/app/shared/state/assets.forms.ts +++ b/frontend/src/app/shared/state/assets.forms.ts @@ -175,6 +175,12 @@ class MetadataTemplate { export class EditAssetScriptsForm extends Form { constructor() { super(new ExtendedFormGroup({ + query: new UntypedFormControl('', + Validators.nullValidator, + ), + queryPre: new UntypedFormControl('', + Validators.nullValidator, + ), annotate: new UntypedFormControl('', Validators.nullValidator, ), diff --git a/tools/TestSuite/TestSuite.ApiTests/AssetTests.cs b/tools/TestSuite/TestSuite.ApiTests/AssetTests.cs index 94e6ff23d..079410f12 100644 --- a/tools/TestSuite/TestSuite.ApiTests/AssetTests.cs +++ b/tools/TestSuite/TestSuite.ApiTests/AssetTests.cs @@ -393,8 +393,6 @@ public class AssetTests : IClassFixture [Fact] public async Task Should_protect_asset() { - var fileName = $"{Guid.NewGuid()}.png"; - // STEP 1: Create asset var asset_1 = await _.Assets.UploadFileAsync(_.AppName, "Assets/logo-squared.png", "image/png"); @@ -461,6 +459,70 @@ public class AssetTests : IClassFixture await Verify(asset_2); } + [Fact] + public async Task Should_protect_asset_with_script() + { + var appName = Guid.NewGuid().ToString(); + + // STEP 0: Create app. + var appRequest = new CreateAppDto + { + Name = appName + }; + + await _.Apps.PostAppAsync(appRequest); + + + // STEP 1: Create folder. + var folderRequest = new CreateAssetFolderDto + { + FolderName = "folder" + }; + + var folder = await _.Assets.PostAssetFolderAsync(appName, folderRequest); + + + // STEP 2: Create asset + var asset_1 = await _.Assets.UploadFileAsync(appName, "Assets/logo-squared.png", "image/png", parentId: folder.Id); + + + // STEP 3: Download asset + await using (var stream = new FileStream("Assets/logo-squared.png", FileMode.Open)) + { + var downloaded = await _.DownloadAsync(asset_1); + + // Should dowload with correct size. + Assert.Equal(stream.Length, downloaded.Length); + } + + + // STEP 4: Protect asset using a script + var scriptsRequest = new UpdateAssetScriptsDto + { + Query = $@" + if (ctx.assetId === '{asset_1.Id}') {{ + disallow(); + }}" + }; + + await _.Apps.PutAssetScriptsAsync(appName, scriptsRequest); + + + // STEP 5: Download asset. + await using (var stream = new FileStream("Assets/logo-squared.png", FileMode.Open)) + { + var ex = await Assert.ThrowsAnyAsync(() => + { + return _.DownloadAsync(asset_1); + }); + + // Should return 403 from the script. + Assert.Equal(HttpStatusCode.Forbidden, ex.StatusCode); + } + + await Verify(asset_1); + } + [Fact] public async Task Should_query_asset_by_metadata() { diff --git a/tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj b/tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj index 87bb9fb34..fa207a354 100644 --- a/tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj +++ b/tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj @@ -17,17 +17,17 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - + - + all runtime; build; native; contentfiles; analyzers diff --git a/tools/TestSuite/TestSuite.ApiTests/Verify/AssetTests.Should_protect_asset_with_script.verified.txt b/tools/TestSuite/TestSuite.ApiTests/Verify/AssetTests.Should_protect_asset_with_script.verified.txt new file mode 100644 index 000000000..eae8532dc --- /dev/null +++ b/tools/TestSuite/TestSuite.ApiTests/Verify/AssetTests.Should_protect_asset_with_script.verified.txt @@ -0,0 +1,46 @@ +{ + id: Guid_1, + parentId: Guid_2, + fileName: logo-squared.png, + fileHash: pAp0RDvipkoNCCTgey1HTJekRKKEWT6Ft5JdRLuAfAc=, + isProtected: false, + slug: logo-squared.png, + mimeType: image/png, + fileType: png, + metadataText: 600x600px, 19 kB, + metadata: { + description: PNG File, + pixelHeight: 600, + pixelWidth: 600 + }, + tags: [ + type/png, + image, + image/medium + ], + fileSize: 19430, + type: Image, + _links: { + content: { + method: GET + }, + content/slug: { + method: GET + }, + delete: { + method: DELETE + }, + move: { + method: PUT + }, + self: { + method: GET + }, + update: { + method: PUT + }, + upload: { + method: PUT + } + } +} \ No newline at end of file diff --git a/tools/TestSuite/TestSuite.LoadTests/TestSuite.LoadTests.csproj b/tools/TestSuite/TestSuite.LoadTests/TestSuite.LoadTests.csproj index d61c51a99..bdc1ec5e7 100644 --- a/tools/TestSuite/TestSuite.LoadTests/TestSuite.LoadTests.csproj +++ b/tools/TestSuite/TestSuite.LoadTests/TestSuite.LoadTests.csproj @@ -6,13 +6,13 @@ enable - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + all runtime; build; native; contentfiles; analyzers diff --git a/tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj b/tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj index 0b5e960e2..5b5597052 100644 --- a/tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj +++ b/tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj @@ -6,21 +6,21 @@ enable - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - - + + - +