mirror of https://github.com/Squidex/squidex.git
43 changed files with 3049 additions and 296 deletions
@ -0,0 +1,29 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AppPlan.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.Apps |
||||
|
{ |
||||
|
public sealed class AppPlan |
||||
|
{ |
||||
|
public RefToken Owner { get; } |
||||
|
|
||||
|
public string PlanId { get; } |
||||
|
|
||||
|
public AppPlan(RefToken owner, string planId) |
||||
|
{ |
||||
|
Guard.NotNull(owner, nameof(owner)); |
||||
|
Guard.NotNullOrEmpty(planId, nameof(planId)); |
||||
|
|
||||
|
Owner = owner; |
||||
|
|
||||
|
PlanId = planId; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
// ==========================================================================
|
||||
|
// GuardApp.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Squidex.Domain.Apps.Core.Apps; |
||||
|
using Squidex.Domain.Apps.Read.Apps.Services; |
||||
|
using Squidex.Domain.Apps.Write.Apps.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Apps.Guards |
||||
|
{ |
||||
|
public static class GuardApp |
||||
|
{ |
||||
|
public static Task CanCreate(CreateApp command, IAppProvider apps) |
||||
|
{ |
||||
|
Guard.NotNull(command, nameof(command)); |
||||
|
|
||||
|
return Validate.It(() => "Cannot create app.", async error => |
||||
|
{ |
||||
|
if (await apps.FindAppByNameAsync(command.Name) != null) |
||||
|
{ |
||||
|
error(new ValidationError($"An app with name '{command.Name}' already exists", nameof(command.Name))); |
||||
|
} |
||||
|
|
||||
|
if (!command.Name.IsSlug()) |
||||
|
{ |
||||
|
error(new ValidationError("Name must be a valid slug.", nameof(command.Name))); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public static void CanChangePlan(ChangePlan command, AppPlan plan, IAppPlansProvider appPlans) |
||||
|
{ |
||||
|
Guard.NotNull(command, nameof(command)); |
||||
|
|
||||
|
Validate.It(() => "Cannot change plan.", error => |
||||
|
{ |
||||
|
if (string.IsNullOrWhiteSpace(command.PlanId)) |
||||
|
{ |
||||
|
error(new ValidationError("PlanId is not defined.", nameof(command.PlanId))); |
||||
|
} |
||||
|
else if (appPlans.GetPlan(command.PlanId) == null) |
||||
|
{ |
||||
|
error(new ValidationError("Plan id not available.", nameof(command.PlanId))); |
||||
|
} |
||||
|
|
||||
|
if (!string.IsNullOrWhiteSpace(command.PlanId) && plan != null && !plan.Owner.Equals(command.Actor)) |
||||
|
{ |
||||
|
error(new ValidationError("Plan can only be changed from current user.")); |
||||
|
} |
||||
|
|
||||
|
if (string.Equals(command.PlanId, plan?.PlanId, StringComparison.OrdinalIgnoreCase)) |
||||
|
{ |
||||
|
error(new ValidationError("App has already this plan.")); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,82 @@ |
|||||
|
// ==========================================================================
|
||||
|
// GuardApp.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Squidex.Domain.Apps.Core.Apps; |
||||
|
using Squidex.Domain.Apps.Read.Apps.Services; |
||||
|
using Squidex.Domain.Apps.Write.Apps.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Shared.Users; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Apps.Guards |
||||
|
{ |
||||
|
public static class GuardAppContributors |
||||
|
{ |
||||
|
public static Task CanAssign(AppContributors contributors, AssignContributor command, IUserResolver users, IAppLimitsPlan plan) |
||||
|
{ |
||||
|
Guard.NotNull(command, nameof(command)); |
||||
|
|
||||
|
return Validate.It(() => "Cannot assign contributor.", async error => |
||||
|
{ |
||||
|
if (!command.Permission.IsEnumValue()) |
||||
|
{ |
||||
|
error(new ValidationError("Permission is not valid.", nameof(command.Permission))); |
||||
|
} |
||||
|
|
||||
|
if (string.IsNullOrWhiteSpace(command.ContributorId)) |
||||
|
{ |
||||
|
error(new ValidationError("Contributor id not assigned.", nameof(command.ContributorId))); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (await users.FindByIdAsync(command.ContributorId) == null) |
||||
|
{ |
||||
|
error(new ValidationError("Cannot find contributor id.", nameof(command.ContributorId))); |
||||
|
} |
||||
|
else if (contributors.Contributors.TryGetValue(command.ContributorId, out var existing)) |
||||
|
{ |
||||
|
if (existing == command.Permission) |
||||
|
{ |
||||
|
error(new ValidationError("Contributor has already this permission.", nameof(command.Permission))); |
||||
|
} |
||||
|
} |
||||
|
else if (plan.MaxContributors == contributors.Contributors.Count) |
||||
|
{ |
||||
|
error(new ValidationError("You have reached the maximum number of contributors for your plan.")); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public static void CanRemove(AppContributors contributors, RemoveContributor command) |
||||
|
{ |
||||
|
Guard.NotNull(command, nameof(command)); |
||||
|
|
||||
|
Validate.It(() => "Cannot remove contributor.", error => |
||||
|
{ |
||||
|
if (string.IsNullOrWhiteSpace(command.ContributorId)) |
||||
|
{ |
||||
|
error(new ValidationError("Contributor id not assigned.", nameof(command.ContributorId))); |
||||
|
} |
||||
|
|
||||
|
var ownerIds = contributors.Contributors.Where(x => x.Value == AppContributorPermission.Owner).Select(x => x.Key).ToList(); |
||||
|
|
||||
|
if (ownerIds.Count == 1 && ownerIds.Contains(command.ContributorId)) |
||||
|
{ |
||||
|
error(new ValidationError("Cannot remove the only owner.", nameof(command.ContributorId))); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
if (!contributors.Contributors.ContainsKey(command.ContributorId)) |
||||
|
{ |
||||
|
throw new DomainObjectNotFoundException(command.ContributorId, "Contributors", typeof(AppDomainObject)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,90 @@ |
|||||
|
// ==========================================================================
|
||||
|
// GuardApp.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Domain.Apps.Core; |
||||
|
using Squidex.Domain.Apps.Write.Apps.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Apps.Guards |
||||
|
{ |
||||
|
public static class GuardAppLanguages |
||||
|
{ |
||||
|
public static void CanAdd(LanguagesConfig languages, AddLanguage command) |
||||
|
{ |
||||
|
Guard.NotNull(command, nameof(command)); |
||||
|
|
||||
|
Validate.It(() => "Cannot add language.", error => |
||||
|
{ |
||||
|
if (command.Language == null) |
||||
|
{ |
||||
|
error(new ValidationError("Language cannot be null.", nameof(command.Language))); |
||||
|
} |
||||
|
else if (languages.Contains(command.Language)) |
||||
|
{ |
||||
|
error(new ValidationError("Language already added.", nameof(command.Language))); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public static void CanRemove(LanguagesConfig languages, RemoveLanguage command) |
||||
|
{ |
||||
|
Guard.NotNull(command, nameof(command)); |
||||
|
|
||||
|
var languageConfig = GetLanguageConfigOrThrow(languages, command.Language); |
||||
|
|
||||
|
Validate.It(() => "Cannot remove language.", error => |
||||
|
{ |
||||
|
if (languages.Master == languageConfig) |
||||
|
{ |
||||
|
error(new ValidationError("Language config is master.", nameof(command.Language))); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public static void CanUpdate(LanguagesConfig languages, UpdateLanguage command) |
||||
|
{ |
||||
|
Guard.NotNull(command, nameof(command)); |
||||
|
|
||||
|
var languageConfig = GetLanguageConfigOrThrow(languages, command.Language); |
||||
|
|
||||
|
Validate.It(() => "Cannot update language.", error => |
||||
|
{ |
||||
|
if ((languages.Master == languageConfig || command.IsMaster) && command.IsOptional) |
||||
|
{ |
||||
|
error(new ValidationError("Cannot make master language optional.", nameof(command.IsMaster))); |
||||
|
} |
||||
|
|
||||
|
if (command.Fallback != null) |
||||
|
{ |
||||
|
foreach (var fallback in command.Fallback) |
||||
|
{ |
||||
|
if (!languages.Contains(fallback)) |
||||
|
{ |
||||
|
error(new ValidationError($"Config does not contain fallback language {fallback}.", nameof(command.Fallback))); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private static LanguageConfig GetLanguageConfigOrThrow(LanguagesConfig languages, Language language) |
||||
|
{ |
||||
|
if (language == null) |
||||
|
{ |
||||
|
throw new DomainObjectNotFoundException(language, "Languages", typeof(AppDomainObject)); |
||||
|
} |
||||
|
|
||||
|
if (!languages.TryGetConfig(language, out var languageConfig)) |
||||
|
{ |
||||
|
throw new DomainObjectNotFoundException(language, "Languages", typeof(AppDomainObject)); |
||||
|
} |
||||
|
|
||||
|
return languageConfig; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,49 @@ |
|||||
|
// ==========================================================================
|
||||
|
// GuardAsset.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Domain.Apps.Write.Assets.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Assets.Guards |
||||
|
{ |
||||
|
public static class GuardAsset |
||||
|
{ |
||||
|
public static void CanRename(RenameAsset command, string oldName) |
||||
|
{ |
||||
|
Guard.NotNull(command, nameof(command)); |
||||
|
|
||||
|
Validate.It(() => "Cannot rename asset.", error => |
||||
|
{ |
||||
|
if (string.IsNullOrWhiteSpace(command.FileName)) |
||||
|
{ |
||||
|
error(new ValidationError("Name must be defined.", nameof(command.FileName))); |
||||
|
} |
||||
|
|
||||
|
if (string.Equals(command.FileName, oldName)) |
||||
|
{ |
||||
|
error(new ValidationError("Name is equal to old name.", nameof(command.FileName))); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public static void CanCreate(CreateAsset command) |
||||
|
{ |
||||
|
Guard.NotNull(command, nameof(command)); |
||||
|
} |
||||
|
|
||||
|
public static void CanUpdate(UpdateAsset command) |
||||
|
{ |
||||
|
Guard.NotNull(command, nameof(command)); |
||||
|
} |
||||
|
|
||||
|
public static void CanDelete(DeleteAsset command) |
||||
|
{ |
||||
|
Guard.NotNull(command, nameof(command)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,243 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AppCommandMiddlewareTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using FakeItEasy; |
||||
|
using Squidex.Domain.Apps.Read.Apps; |
||||
|
using Squidex.Domain.Apps.Read.Apps.Services; |
||||
|
using Squidex.Domain.Apps.Read.Apps.Services.Implementations; |
||||
|
using Squidex.Domain.Apps.Write.Apps.Commands; |
||||
|
using Squidex.Domain.Apps.Write.TestHelpers; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Commands; |
||||
|
using Squidex.Shared.Users; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Apps |
||||
|
{ |
||||
|
public class AppCommandMiddlewareTests : HandlerTestBase<AppDomainObject> |
||||
|
{ |
||||
|
private readonly IAppProvider appProvider = A.Fake<IAppProvider>(); |
||||
|
private readonly IAppPlansProvider appPlansProvider = A.Fake<IAppPlansProvider>(); |
||||
|
private readonly IAppPlanBillingManager appPlansBillingManager = A.Fake<IAppPlanBillingManager>(); |
||||
|
private readonly IUserResolver userResolver = A.Fake<IUserResolver>(); |
||||
|
private readonly AppCommandMiddleware sut; |
||||
|
private readonly AppDomainObject app; |
||||
|
private readonly Language language = Language.DE; |
||||
|
private readonly string contributorId = Guid.NewGuid().ToString(); |
||||
|
private readonly string clientName = "client"; |
||||
|
|
||||
|
public AppCommandMiddlewareTests() |
||||
|
{ |
||||
|
app = new AppDomainObject(AppId, -1); |
||||
|
|
||||
|
A.CallTo(() => appProvider.FindAppByNameAsync(AppName)) |
||||
|
.Returns((IAppEntity)null); |
||||
|
|
||||
|
A.CallTo(() => userResolver.FindByIdAsync(contributorId)) |
||||
|
.Returns(A.Fake<IUser>()); |
||||
|
|
||||
|
sut = new AppCommandMiddleware(Handler, appProvider, appPlansProvider, appPlansBillingManager, userResolver); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Create_should_create_domain_object() |
||||
|
{ |
||||
|
var context = CreateContextForCommand(new CreateApp { Name = AppName, AppId = AppId }); |
||||
|
|
||||
|
await TestCreate(app, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
Assert.Equal(AppId, context.Result<EntityCreatedResult<Guid>>().IdOrValue); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task AssignContributor_should_assign_if_user_found() |
||||
|
{ |
||||
|
A.CallTo(() => appPlansProvider.GetPlan(null)) |
||||
|
.Returns(new ConfigAppLimitsPlan { MaxContributors = -1 }); |
||||
|
|
||||
|
CreateApp(); |
||||
|
|
||||
|
var context = CreateContextForCommand(new AssignContributor { ContributorId = contributorId }); |
||||
|
|
||||
|
await TestUpdate(app, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task RemoveContributor_should_update_domain_object() |
||||
|
{ |
||||
|
CreateApp() |
||||
|
.AssignContributor(CreateCommand(new AssignContributor { ContributorId = contributorId })); |
||||
|
|
||||
|
var context = CreateContextForCommand(new RemoveContributor { ContributorId = contributorId }); |
||||
|
|
||||
|
await TestUpdate(app, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task AttachClient_should_update_domain_object() |
||||
|
{ |
||||
|
CreateApp(); |
||||
|
|
||||
|
var context = CreateContextForCommand(new AttachClient { Id = clientName }); |
||||
|
|
||||
|
await TestUpdate(app, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task RenameClient_should_update_domain_object() |
||||
|
{ |
||||
|
CreateApp() |
||||
|
.AttachClient(CreateCommand(new AttachClient { Id = clientName })); |
||||
|
|
||||
|
var context = CreateContextForCommand(new UpdateClient { Id = clientName, Name = "New Name" }); |
||||
|
|
||||
|
await TestUpdate(app, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task RevokeClient_should_update_domain_object() |
||||
|
{ |
||||
|
CreateApp() |
||||
|
.AttachClient(CreateCommand(new AttachClient { Id = clientName })); |
||||
|
|
||||
|
var context = CreateContextForCommand(new RevokeClient { Id = clientName }); |
||||
|
|
||||
|
await TestUpdate(app, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task ChangePlan_should_update_domain_object() |
||||
|
{ |
||||
|
A.CallTo(() => appPlansProvider.IsConfiguredPlan("my-plan")) |
||||
|
.Returns(true); |
||||
|
|
||||
|
CreateApp(); |
||||
|
|
||||
|
var context = CreateContextForCommand(new ChangePlan { PlanId = "my-plan" }); |
||||
|
|
||||
|
await TestUpdate(app, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, app.Id, app.Name, "my-plan")).MustHaveHappened(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task ChangePlan_should_not_make_update_for_redirect_result() |
||||
|
{ |
||||
|
A.CallTo(() => appPlansProvider.IsConfiguredPlan("my-plan")) |
||||
|
.Returns(true); |
||||
|
|
||||
|
A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, app.Id, app.Name, "my-plan")) |
||||
|
.Returns(CreateRedirectResult()); |
||||
|
|
||||
|
CreateApp(); |
||||
|
|
||||
|
var context = CreateContextForCommand(new ChangePlan { PlanId = "my-plan" }); |
||||
|
|
||||
|
await TestUpdate(app, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
Assert.Null(app.Plan); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task ChangePlan_should_not_call_billing_manager_for_callback() |
||||
|
{ |
||||
|
A.CallTo(() => appPlansProvider.IsConfiguredPlan("my-plan")) |
||||
|
.Returns(true); |
||||
|
|
||||
|
CreateApp(); |
||||
|
|
||||
|
var context = CreateContextForCommand(new ChangePlan { PlanId = "my-plan", FromCallback = true }); |
||||
|
|
||||
|
await TestUpdate(app, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, app.Id, app.Name, "my-plan")).MustNotHaveHappened(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task AddLanguage_should_update_domain_object() |
||||
|
{ |
||||
|
CreateApp(); |
||||
|
|
||||
|
var context = CreateContextForCommand(new AddLanguage { Language = language }); |
||||
|
|
||||
|
await TestUpdate(app, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task RemoveLanguage_should_update_domain_object() |
||||
|
{ |
||||
|
CreateApp() |
||||
|
.AddLanguage(CreateCommand(new AddLanguage { Language = language })); |
||||
|
|
||||
|
var context = CreateContextForCommand(new RemoveLanguage { Language = language }); |
||||
|
|
||||
|
await TestUpdate(app, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task UpdateLanguage_should_update_domain_object() |
||||
|
{ |
||||
|
CreateApp() |
||||
|
.AddLanguage(CreateCommand(new AddLanguage { Language = language })); |
||||
|
|
||||
|
var context = CreateContextForCommand(new UpdateLanguage { Language = language }); |
||||
|
|
||||
|
await TestUpdate(app, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private AppDomainObject CreateApp() |
||||
|
{ |
||||
|
app.Create(CreateCommand(new CreateApp { Name = AppName })); |
||||
|
|
||||
|
return app; |
||||
|
} |
||||
|
|
||||
|
private static Task<IChangePlanResult> CreateRedirectResult() |
||||
|
{ |
||||
|
return Task.FromResult<IChangePlanResult>(new RedirectToCheckoutResult(new Uri("http://squidex.io"))); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,288 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AppDomainObjectTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Squidex.Domain.Apps.Core.Apps; |
||||
|
using Squidex.Domain.Apps.Events.Apps; |
||||
|
using Squidex.Domain.Apps.Write.Apps.Commands; |
||||
|
using Squidex.Domain.Apps.Write.TestHelpers; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Apps |
||||
|
{ |
||||
|
public class AppDomainObjectTests : HandlerTestBase<AppDomainObject> |
||||
|
{ |
||||
|
private readonly AppDomainObject sut; |
||||
|
private readonly string contributorId = Guid.NewGuid().ToString(); |
||||
|
private readonly string clientId = "client"; |
||||
|
private readonly string clientNewName = "My Client"; |
||||
|
private readonly string planId = "premium"; |
||||
|
|
||||
|
public AppDomainObjectTests() |
||||
|
{ |
||||
|
sut = new AppDomainObject(AppId, 0); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_throw_exception_if_created() |
||||
|
{ |
||||
|
CreateApp(); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Create(CreateCommand(new CreateApp { Name = AppName })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_specify_name_and_owner() |
||||
|
{ |
||||
|
sut.Create(CreateCommand(new CreateApp { Name = AppName, Actor = User, AppId = AppId })); |
||||
|
|
||||
|
Assert.Equal(AppName, sut.Name); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateEvent(new AppCreated { Name = AppName }), |
||||
|
CreateEvent(new AppContributorAssigned { ContributorId = User.Identifier, Permission = AppContributorPermission.Owner }), |
||||
|
CreateEvent(new AppLanguageAdded { Language = Language.EN }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void ChangePlan_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.ChangePlan(CreateCommand(new ChangePlan { PlanId = planId })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void ChangePlan_should_create_events() |
||||
|
{ |
||||
|
CreateApp(); |
||||
|
|
||||
|
sut.ChangePlan(CreateCommand(new ChangePlan { PlanId = planId })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateEvent(new AppPlanChanged { PlanId = planId }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void AssignContributor_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.AssignContributor(CreateCommand(new AssignContributor { ContributorId = contributorId })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void AssignContributor_should_create_events() |
||||
|
{ |
||||
|
CreateApp(); |
||||
|
|
||||
|
sut.AssignContributor(CreateCommand(new AssignContributor { ContributorId = contributorId, Permission = AppContributorPermission.Editor })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateEvent(new AppContributorAssigned { ContributorId = contributorId, Permission = AppContributorPermission.Editor }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void RemoveContributor_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.RemoveContributor(CreateCommand(new RemoveContributor { ContributorId = contributorId })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void RemoveContributor_should_create_events_and_remove_contributor() |
||||
|
{ |
||||
|
CreateApp(); |
||||
|
|
||||
|
sut.AssignContributor(CreateCommand(new AssignContributor { ContributorId = contributorId, Permission = AppContributorPermission.Editor })); |
||||
|
sut.RemoveContributor(CreateCommand(new RemoveContributor { ContributorId = contributorId })); |
||||
|
|
||||
|
sut.GetUncomittedEvents().Skip(1) |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateEvent(new AppContributorRemoved { ContributorId = contributorId }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void AttachClient_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.AttachClient(CreateCommand(new AttachClient { Id = clientId })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void AttachClient_should_create_events() |
||||
|
{ |
||||
|
var command = new AttachClient { Id = clientId }; |
||||
|
|
||||
|
CreateApp(); |
||||
|
|
||||
|
sut.AttachClient(CreateCommand(command)); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateEvent(new AppClientAttached { Id = clientId, Secret = command.Secret }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void RevokeClient_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.RevokeClient(CreateCommand(new RevokeClient { Id = "not-found" })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void RevokeClient_should_create_events() |
||||
|
{ |
||||
|
CreateApp(); |
||||
|
CreateClient(); |
||||
|
|
||||
|
sut.RevokeClient(CreateCommand(new RevokeClient { Id = clientId })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateEvent(new AppClientRevoked { Id = clientId }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void UpdateClient_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.UpdateClient(CreateCommand(new UpdateClient { Id = "not-found", Name = clientNewName })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void UpdateClient_should_create_events() |
||||
|
{ |
||||
|
CreateApp(); |
||||
|
CreateClient(); |
||||
|
|
||||
|
sut.UpdateClient(CreateCommand(new UpdateClient { Id = clientId, Name = clientNewName, Permission = AppClientPermission.Developer })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateEvent(new AppClientRenamed { Id = clientId, Name = clientNewName }), |
||||
|
CreateEvent(new AppClientUpdated { Id = clientId, Permission = AppClientPermission.Developer }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void AddLanguage_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.AddLanguage(CreateCommand(new AddLanguage { Language = Language.DE })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void AddLanguage_should_create_events() |
||||
|
{ |
||||
|
CreateApp(); |
||||
|
|
||||
|
sut.AddLanguage(CreateCommand(new AddLanguage { Language = Language.DE })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateEvent(new AppLanguageAdded { Language = Language.DE }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void RemoveLanguage_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.RemoveLanguage(CreateCommand(new RemoveLanguage { Language = Language.EN })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void RemoveLanguage_should_create_events() |
||||
|
{ |
||||
|
CreateApp(); |
||||
|
CreateLanguage(Language.DE); |
||||
|
|
||||
|
sut.RemoveLanguage(CreateCommand(new RemoveLanguage { Language = Language.DE })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateEvent(new AppLanguageRemoved { Language = Language.DE }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void UpdateLanguage_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.UpdateLanguage(CreateCommand(new UpdateLanguage { Language = Language.EN })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void UpdateLanguage_should_create_events() |
||||
|
{ |
||||
|
CreateApp(); |
||||
|
CreateLanguage(Language.DE); |
||||
|
|
||||
|
sut.UpdateLanguage(CreateCommand(new UpdateLanguage { Language = Language.DE, Fallback = new List<Language> { Language.EN } })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateEvent(new AppLanguageUpdated { Language = Language.DE, Fallback = new List<Language> { Language.EN } }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private void CreateApp() |
||||
|
{ |
||||
|
sut.Create(CreateCommand(new CreateApp { Name = AppName })); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
|
||||
|
private void CreateClient() |
||||
|
{ |
||||
|
sut.AttachClient(CreateCommand(new AttachClient { Id = clientId })); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
|
||||
|
private void CreateLanguage(Language language) |
||||
|
{ |
||||
|
sut.AddLanguage(CreateCommand(new AddLanguage { Language = language })); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,51 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AppEventTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Squidex.Domain.Apps.Core.Apps; |
||||
|
using Squidex.Domain.Apps.Events; |
||||
|
using Squidex.Domain.Apps.Events.Apps; |
||||
|
using Squidex.Domain.Apps.Events.Apps.Old; |
||||
|
using Squidex.Domain.Apps.Write.TestHelpers; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Xunit; |
||||
|
|
||||
|
#pragma warning disable CS0612 // Type or member is obsolete
|
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Apps |
||||
|
{ |
||||
|
public class AppEventTests |
||||
|
{ |
||||
|
private readonly RefToken actor = new RefToken("User", Guid.NewGuid().ToString()); |
||||
|
private readonly NamedId<Guid> appId = new NamedId<Guid>(Guid.NewGuid(), "my-app"); |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_migrate_client_changed_as_reader_to_client_updated() |
||||
|
{ |
||||
|
var source = CreateEvent(new AppClientChanged { IsReader = true }); |
||||
|
|
||||
|
source.Migrate().ShouldBeSameEvent(CreateEvent(new AppClientUpdated { Permission = AppClientPermission.Reader })); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_migrate_client_changed_as_writer_to_client_updated() |
||||
|
{ |
||||
|
var source = CreateEvent(new AppClientChanged { IsReader = false }); |
||||
|
|
||||
|
source.Migrate().ShouldBeSameEvent(CreateEvent(new AppClientUpdated { Permission = AppClientPermission.Editor })); |
||||
|
} |
||||
|
|
||||
|
private T CreateEvent<T>(T contentEvent) where T : AppEvent |
||||
|
{ |
||||
|
contentEvent.Actor = actor; |
||||
|
contentEvent.AppId = appId; |
||||
|
|
||||
|
return contentEvent; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,179 @@ |
|||||
|
// ==========================================================================
|
||||
|
// GuardAppContributorsTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Threading.Tasks; |
||||
|
using FakeItEasy; |
||||
|
using Squidex.Domain.Apps.Core.Apps; |
||||
|
using Squidex.Domain.Apps.Read.Apps.Services; |
||||
|
using Squidex.Domain.Apps.Write.Apps.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Shared.Users; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Apps.Guards |
||||
|
{ |
||||
|
public class GuardAppContributorsTests |
||||
|
{ |
||||
|
private readonly IUserResolver users = A.Fake<IUserResolver>(); |
||||
|
private readonly IAppLimitsPlan appPlan = A.Fake<IAppLimitsPlan>(); |
||||
|
|
||||
|
public GuardAppContributorsTests() |
||||
|
{ |
||||
|
A.CallTo(() => users.FindByIdAsync(A<string>.Ignored)) |
||||
|
.Returns(A.Fake<IUser>()); |
||||
|
|
||||
|
A.CallTo(() => appPlan.MaxContributors) |
||||
|
.Returns(10); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public Task CanAssign_should_throw_exception_if_contributor_id_is_null() |
||||
|
{ |
||||
|
var command = new AssignContributor(); |
||||
|
|
||||
|
var contributors = new AppContributors(); |
||||
|
|
||||
|
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors, command, users, appPlan)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public Task CanAssign_should_throw_exception_if_permission_not_valid() |
||||
|
{ |
||||
|
var command = new AssignContributor { ContributorId = "1", Permission = (AppContributorPermission)10 }; |
||||
|
|
||||
|
var contributors = new AppContributors(); |
||||
|
|
||||
|
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors, command, users, appPlan)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public Task CanAssign_should_throw_exception_if_user_already_exists_with_same_permission() |
||||
|
{ |
||||
|
var command = new AssignContributor { ContributorId = "1" }; |
||||
|
|
||||
|
var contributors = new AppContributors(); |
||||
|
|
||||
|
contributors.Assign("1", AppContributorPermission.Owner); |
||||
|
|
||||
|
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors, command, users, appPlan)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public Task CanAssign_should_throw_exception_if_user_not_found() |
||||
|
{ |
||||
|
A.CallTo(() => users.FindByIdAsync(A<string>.Ignored)) |
||||
|
.Returns(Task.FromResult<IUser>(null)); |
||||
|
|
||||
|
var command = new AssignContributor { ContributorId = "1", Permission = (AppContributorPermission)10 }; |
||||
|
|
||||
|
var contributors = new AppContributors(); |
||||
|
|
||||
|
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors, command, users, appPlan)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public Task CanAssign_should_throw_exception_if_contributor_max_reached() |
||||
|
{ |
||||
|
A.CallTo(() => appPlan.MaxContributors) |
||||
|
.Returns(2); |
||||
|
|
||||
|
var command = new AssignContributor { ContributorId = "3" }; |
||||
|
|
||||
|
var contributors = new AppContributors(); |
||||
|
|
||||
|
contributors.Assign("1", AppContributorPermission.Owner); |
||||
|
contributors.Assign("2", AppContributorPermission.Editor); |
||||
|
|
||||
|
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors, command, users, appPlan)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public Task CanAssign_should_not_throw_exception_if_user_found() |
||||
|
{ |
||||
|
var command = new AssignContributor { ContributorId = "1" }; |
||||
|
|
||||
|
var contributors = new AppContributors(); |
||||
|
|
||||
|
return GuardAppContributors.CanAssign(contributors, command, users, appPlan); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public Task CanAssign_should_not_throw_exception_if_contributor_has_another_permission() |
||||
|
{ |
||||
|
var command = new AssignContributor { ContributorId = "1" }; |
||||
|
|
||||
|
var contributors = new AppContributors(); |
||||
|
|
||||
|
contributors.Assign("1", AppContributorPermission.Editor); |
||||
|
|
||||
|
return GuardAppContributors.CanAssign(contributors, command, users, appPlan); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public Task CanAssign_should_not_throw_exception_if_contributor_max_reached_but_permission_changed() |
||||
|
{ |
||||
|
A.CallTo(() => appPlan.MaxContributors) |
||||
|
.Returns(2); |
||||
|
|
||||
|
var command = new AssignContributor { ContributorId = "1" }; |
||||
|
|
||||
|
var contributors = new AppContributors(); |
||||
|
|
||||
|
contributors.Assign("1", AppContributorPermission.Editor); |
||||
|
contributors.Assign("2", AppContributorPermission.Editor); |
||||
|
|
||||
|
return GuardAppContributors.CanAssign(contributors, command, users, appPlan); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanRemove_should_throw_exception_if_contributor_id_is_null() |
||||
|
{ |
||||
|
var command = new RemoveContributor(); |
||||
|
|
||||
|
var contributors = new AppContributors(); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => GuardAppContributors.CanRemove(contributors, command)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanRemove_should_throw_exception_if_contributor_not_found() |
||||
|
{ |
||||
|
var command = new RemoveContributor { ContributorId = "1" }; |
||||
|
|
||||
|
var contributors = new AppContributors(); |
||||
|
|
||||
|
Assert.Throws<DomainObjectNotFoundException>(() => GuardAppContributors.CanRemove(contributors, command)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanRemove_should_throw_exception_if_contributor_is_only_owner() |
||||
|
{ |
||||
|
var command = new RemoveContributor { ContributorId = "1" }; |
||||
|
|
||||
|
var contributors = new AppContributors(); |
||||
|
|
||||
|
contributors.Assign("1", AppContributorPermission.Owner); |
||||
|
contributors.Assign("2", AppContributorPermission.Editor); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => GuardAppContributors.CanRemove(contributors, command)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanRemove_should_not_throw_exception_if_contributor_not_only_owner() |
||||
|
{ |
||||
|
var command = new RemoveContributor { ContributorId = "1" }; |
||||
|
|
||||
|
var contributors = new AppContributors(); |
||||
|
|
||||
|
contributors.Assign("1", AppContributorPermission.Owner); |
||||
|
contributors.Assign("2", AppContributorPermission.Owner); |
||||
|
|
||||
|
GuardAppContributors.CanRemove(contributors, command); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,129 @@ |
|||||
|
// ==========================================================================
|
||||
|
// GuardAppLanguagesTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using Squidex.Domain.Apps.Core; |
||||
|
using Squidex.Domain.Apps.Write.Apps.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Apps.Guards |
||||
|
{ |
||||
|
public class GuardAppLanguagesTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void CanAddLanguage_should_throw_exception_if_language_is_null() |
||||
|
{ |
||||
|
var command = new AddLanguage(); |
||||
|
|
||||
|
var languages = LanguagesConfig.Build(Language.DE); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanAdd(languages, command)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanAddLanguage_should_throw_exception_if_language_already_added() |
||||
|
{ |
||||
|
var command = new AddLanguage { Language = Language.DE }; |
||||
|
|
||||
|
var languages = LanguagesConfig.Build(Language.DE); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanAdd(languages, command)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanAddLanguage_should_not_throw_exception_if_language_valid() |
||||
|
{ |
||||
|
var command = new AddLanguage { Language = Language.EN }; |
||||
|
|
||||
|
var languages = LanguagesConfig.Build(Language.DE); |
||||
|
|
||||
|
GuardAppLanguages.CanAdd(languages, command); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanRemoveLanguage_should_throw_exception_if_language_is_null() |
||||
|
{ |
||||
|
var command = new RemoveLanguage(); |
||||
|
|
||||
|
var languages = LanguagesConfig.Build(Language.DE); |
||||
|
|
||||
|
Assert.Throws<DomainObjectNotFoundException>(() => GuardAppLanguages.CanRemove(languages, command)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanRemoveLanguage_should_throw_exception_if_language_not_found() |
||||
|
{ |
||||
|
var command = new RemoveLanguage { Language = Language.EN }; |
||||
|
|
||||
|
var languages = LanguagesConfig.Build(Language.DE); |
||||
|
|
||||
|
Assert.Throws<DomainObjectNotFoundException>(() => GuardAppLanguages.CanRemove(languages, command)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanRemoveLanguage_should_throw_exception_if_language_is_master() |
||||
|
{ |
||||
|
var command = new RemoveLanguage { Language = Language.DE }; |
||||
|
|
||||
|
var languages = LanguagesConfig.Build(Language.DE); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanRemove(languages, command)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanRemoveLanguage_should_not_throw_exception_if_language_is_valid() |
||||
|
{ |
||||
|
var command = new RemoveLanguage { Language = Language.EN }; |
||||
|
|
||||
|
var languages = LanguagesConfig.Build(Language.DE, Language.EN); |
||||
|
|
||||
|
GuardAppLanguages.CanRemove(languages, command); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanUpdateLanguage_should_throw_exception_if_language_is_optional_and_master() |
||||
|
{ |
||||
|
var command = new UpdateLanguage { Language = Language.DE, IsOptional = true }; |
||||
|
|
||||
|
var languages = LanguagesConfig.Build(Language.DE, Language.EN); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanUpdate(languages, command)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanUpdateLanguage_should_throw_exception_if_language_has_invalid_fallback() |
||||
|
{ |
||||
|
var command = new UpdateLanguage { Language = Language.DE, Fallback = new List<Language> { Language.IT } }; |
||||
|
|
||||
|
var languages = LanguagesConfig.Build(Language.DE, Language.EN); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanUpdate(languages, command)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanUpdateLanguage_should_throw_exception_if_not_found() |
||||
|
{ |
||||
|
var command = new UpdateLanguage { Language = Language.IT }; |
||||
|
|
||||
|
var languages = LanguagesConfig.Build(Language.DE, Language.EN); |
||||
|
|
||||
|
Assert.Throws<DomainObjectNotFoundException>(() => GuardAppLanguages.CanUpdate(languages, command)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanUpdateLanguage_should_not_throw_exception_if_language_is_valid() |
||||
|
{ |
||||
|
var command = new UpdateLanguage { Language = Language.DE, Fallback = new List<Language> { Language.EN } }; |
||||
|
|
||||
|
var languages = LanguagesConfig.Build(Language.DE, Language.EN); |
||||
|
|
||||
|
GuardAppLanguages.CanUpdate(languages, command); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,119 @@ |
|||||
|
// ==========================================================================
|
||||
|
// GuardAppTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Threading.Tasks; |
||||
|
using FakeItEasy; |
||||
|
using Squidex.Domain.Apps.Core.Apps; |
||||
|
using Squidex.Domain.Apps.Read.Apps; |
||||
|
using Squidex.Domain.Apps.Read.Apps.Services; |
||||
|
using Squidex.Domain.Apps.Write.Apps.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Shared.Users; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Apps.Guards |
||||
|
{ |
||||
|
public class GuardAppTests |
||||
|
{ |
||||
|
private readonly IAppProvider apps = A.Fake<IAppProvider>(); |
||||
|
private readonly IUserResolver users = A.Fake<IUserResolver>(); |
||||
|
private readonly IAppPlansProvider appPlans = A.Fake<IAppPlansProvider>(); |
||||
|
|
||||
|
public GuardAppTests() |
||||
|
{ |
||||
|
A.CallTo(() => apps.FindAppByNameAsync("new-app")) |
||||
|
.Returns(Task.FromResult<IAppEntity>(null)); |
||||
|
|
||||
|
A.CallTo(() => users.FindByIdAsync(A<string>.Ignored)) |
||||
|
.Returns(A.Fake<IUser>()); |
||||
|
|
||||
|
A.CallTo(() => appPlans.GetPlan("free")) |
||||
|
.Returns(A.Fake<IAppLimitsPlan>()); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public Task CanCreate_should_throw_exception_if_name_already_in_use() |
||||
|
{ |
||||
|
A.CallTo(() => apps.FindAppByNameAsync("new-app")) |
||||
|
.Returns(A.Fake<IAppEntity>()); |
||||
|
|
||||
|
var command = new CreateApp { Name = "new-app" }; |
||||
|
|
||||
|
return Assert.ThrowsAsync<ValidationException>(() => GuardApp.CanCreate(command, apps)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public Task CanCreate_should_throw_exception_if_name_not_valid() |
||||
|
{ |
||||
|
var command = new CreateApp { Name = "INVALID NAME" }; |
||||
|
|
||||
|
return Assert.ThrowsAsync<ValidationException>(() => GuardApp.CanCreate(command, apps)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public Task CanCreate_should_not_throw_exception_if_app_name_is_free() |
||||
|
{ |
||||
|
var command = new CreateApp { Name = "new-app" }; |
||||
|
|
||||
|
return GuardApp.CanCreate(command, apps); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanChangePlan_should_throw_exception_if_plan_id_null() |
||||
|
{ |
||||
|
var command = new ChangePlan { Actor = new RefToken("user", "me") }; |
||||
|
|
||||
|
AppPlan plan = null; |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => GuardApp.CanChangePlan(command, plan, appPlans)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanChangePlan_should_throw_exception_if_plan_not_found() |
||||
|
{ |
||||
|
A.CallTo(() => appPlans.GetPlan("free")) |
||||
|
.Returns(null); |
||||
|
|
||||
|
var command = new ChangePlan { PlanId = "free", Actor = new RefToken("user", "me") }; |
||||
|
|
||||
|
AppPlan plan = null; |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => GuardApp.CanChangePlan(command, plan, appPlans)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanChangePlan_should_throw_exception_if_plan_was_configured_from_another_user() |
||||
|
{ |
||||
|
var command = new ChangePlan { PlanId = "free", Actor = new RefToken("user", "me") }; |
||||
|
|
||||
|
var plan = new AppPlan(new RefToken("user", "other"), "premium"); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => GuardApp.CanChangePlan(command, plan, appPlans)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanChangePlan_should_throw_exception_if_plan_is_the_same() |
||||
|
{ |
||||
|
var command = new ChangePlan { PlanId = "free", Actor = new RefToken("user", "me") }; |
||||
|
|
||||
|
var plan = new AppPlan(new RefToken("user", "me"), "free"); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => GuardApp.CanChangePlan(command, plan, appPlans)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanChangePlan_should_not_throw_exception_if_same_user_but_other_plan() |
||||
|
{ |
||||
|
var command = new ChangePlan { PlanId = "free", Actor = new RefToken("user", "me") }; |
||||
|
|
||||
|
var plan = new AppPlan(new RefToken("user", "me"), "premium"); |
||||
|
|
||||
|
GuardApp.CanChangePlan(command, plan, appPlans); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,139 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AssetCommandMiddlewareTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.IO; |
||||
|
using System.Threading.Tasks; |
||||
|
using FakeItEasy; |
||||
|
using Squidex.Domain.Apps.Write.Assets.Commands; |
||||
|
using Squidex.Domain.Apps.Write.TestHelpers; |
||||
|
using Squidex.Infrastructure.Assets; |
||||
|
using Squidex.Infrastructure.CQRS.Commands; |
||||
|
using Squidex.Infrastructure.Tasks; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Assets |
||||
|
{ |
||||
|
public class AssetCommandMiddlewareTests : HandlerTestBase<AssetDomainObject> |
||||
|
{ |
||||
|
private readonly IAssetThumbnailGenerator assetThumbnailGenerator = A.Fake<IAssetThumbnailGenerator>(); |
||||
|
private readonly IAssetStore assetStore = A.Fake<IAssetStore>(); |
||||
|
private readonly AssetCommandMiddleware sut; |
||||
|
private readonly AssetDomainObject asset; |
||||
|
private readonly Guid assetId = Guid.NewGuid(); |
||||
|
private readonly Stream stream = new MemoryStream(); |
||||
|
private readonly ImageInfo image = new ImageInfo(2048, 2048); |
||||
|
private readonly AssetFile file; |
||||
|
|
||||
|
public AssetCommandMiddlewareTests() |
||||
|
{ |
||||
|
file = new AssetFile("my-image.png", "image/png", 1024, () => stream); |
||||
|
|
||||
|
asset = new AssetDomainObject(assetId, -1); |
||||
|
|
||||
|
sut = new AssetCommandMiddleware(Handler, assetStore, assetThumbnailGenerator); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Create_should_create_domain_object() |
||||
|
{ |
||||
|
var context = CreateContextForCommand(new CreateAsset { AssetId = assetId, File = file }); |
||||
|
|
||||
|
SetupStore(0, context.ContextId); |
||||
|
SetupImageInfo(); |
||||
|
|
||||
|
await TestCreate(asset, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
Assert.Equal(assetId, context.Result<EntityCreatedResult<Guid>>().IdOrValue); |
||||
|
|
||||
|
VerifyStore(0, context.ContextId); |
||||
|
VerifyImageInfo(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Update_should_update_domain_object() |
||||
|
{ |
||||
|
var context = CreateContextForCommand(new UpdateAsset { AssetId = assetId, File = file }); |
||||
|
|
||||
|
SetupStore(1, context.ContextId); |
||||
|
SetupImageInfo(); |
||||
|
|
||||
|
CreateAsset(); |
||||
|
|
||||
|
await TestUpdate(asset, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
VerifyStore(1, context.ContextId); |
||||
|
VerifyImageInfo(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Rename_should_update_domain_object() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
|
||||
|
var context = CreateContextForCommand(new RenameAsset { AssetId = assetId, FileName = "my-new-image.png" }); |
||||
|
|
||||
|
await TestUpdate(asset, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Delete_should_update_domain_object() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
|
||||
|
var command = CreateContextForCommand(new DeleteAsset { AssetId = assetId }); |
||||
|
|
||||
|
await TestUpdate(asset, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(command); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private void CreateAsset() |
||||
|
{ |
||||
|
asset.Create(new CreateAsset { File = file }); |
||||
|
} |
||||
|
|
||||
|
private void SetupImageInfo() |
||||
|
{ |
||||
|
A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(stream)) |
||||
|
.Returns(image); |
||||
|
} |
||||
|
|
||||
|
private void SetupStore(long version, Guid commitId) |
||||
|
{ |
||||
|
A.CallTo(() => assetStore.UploadTemporaryAsync(commitId.ToString(), stream)) |
||||
|
.Returns(TaskHelper.Done); |
||||
|
A.CallTo(() => assetStore.CopyTemporaryAsync(commitId.ToString(), assetId.ToString(), version, null)) |
||||
|
.Returns(TaskHelper.Done); |
||||
|
A.CallTo(() => assetStore.DeleteTemporaryAsync(commitId.ToString())) |
||||
|
.Returns(TaskHelper.Done); |
||||
|
} |
||||
|
|
||||
|
private void VerifyImageInfo() |
||||
|
{ |
||||
|
A.CallTo(() => assetThumbnailGenerator.GetImageInfoAsync(stream)).MustHaveHappened(); |
||||
|
} |
||||
|
|
||||
|
private void VerifyStore(long version, Guid commitId) |
||||
|
{ |
||||
|
A.CallTo(() => assetStore.UploadTemporaryAsync(commitId.ToString(), stream)).MustHaveHappened(); |
||||
|
A.CallTo(() => assetStore.CopyTemporaryAsync(commitId.ToString(), assetId.ToString(), version, null)).MustHaveHappened(); |
||||
|
A.CallTo(() => assetStore.DeleteTemporaryAsync(commitId.ToString())).MustHaveHappened(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,213 @@ |
|||||
|
// ==========================================================================
|
||||
|
// AssetDomainObjectTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.IO; |
||||
|
using Squidex.Domain.Apps.Events.Assets; |
||||
|
using Squidex.Domain.Apps.Write.Assets.Commands; |
||||
|
using Squidex.Domain.Apps.Write.TestHelpers; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Assets; |
||||
|
using Squidex.Infrastructure.CQRS; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Assets |
||||
|
{ |
||||
|
public class AssetDomainObjectTests : HandlerTestBase<AssetDomainObject> |
||||
|
{ |
||||
|
private readonly AssetDomainObject sut; |
||||
|
private readonly ImageInfo image = new ImageInfo(2048, 2048); |
||||
|
private readonly AssetFile file = new AssetFile("my-image.png", "image/png", 1024, () => new MemoryStream()); |
||||
|
|
||||
|
public Guid AssetId { get; } = Guid.NewGuid(); |
||||
|
|
||||
|
public AssetDomainObjectTests() |
||||
|
{ |
||||
|
sut = new AssetDomainObject(AssetId, 0); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_throw_exception_if_created() |
||||
|
{ |
||||
|
sut.Create(new CreateAsset { File = file }); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Create(CreateAssetCommand(new CreateAsset { File = file })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_create_events() |
||||
|
{ |
||||
|
sut.Create(CreateAssetCommand(new CreateAsset { File = file, ImageInfo = image })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateAssetEvent(new AssetCreated |
||||
|
{ |
||||
|
IsImage = true, |
||||
|
FileName = file.FileName, |
||||
|
FileSize = file.FileSize, |
||||
|
FileVersion = 0, |
||||
|
MimeType = file.MimeType, |
||||
|
PixelWidth = image.PixelWidth, |
||||
|
PixelHeight = image.PixelHeight |
||||
|
}) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Update(CreateAssetCommand(new UpdateAsset { File = file })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_throw_exception_if_asset_is_deleted() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
DeleteAsset(); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Update(CreateAssetCommand(new UpdateAsset())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_create_events() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
|
||||
|
sut.Update(CreateAssetCommand(new UpdateAsset { File = file, ImageInfo = image })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateAssetEvent(new AssetUpdated |
||||
|
{ |
||||
|
IsImage = true, |
||||
|
FileSize = file.FileSize, |
||||
|
FileVersion = 1, |
||||
|
MimeType = file.MimeType, |
||||
|
PixelWidth = image.PixelWidth, |
||||
|
PixelHeight = image.PixelHeight |
||||
|
}) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Rename_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Rename(CreateAssetCommand(new RenameAsset { FileName = "new-file.png" })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Rename_should_throw_exception_if_asset_is_deleted() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
DeleteAsset(); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Update(CreateAssetCommand(new UpdateAsset())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Rename_should_create_events() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
|
||||
|
sut.Rename(CreateAssetCommand(new RenameAsset { FileName = "my-new-image.png" })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateAssetEvent(new AssetRenamed { FileName = "my-new-image.png" }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Delete(CreateAssetCommand(new DeleteAsset())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_throw_exception_if_already_deleted() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
DeleteAsset(); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Delete(CreateAssetCommand(new DeleteAsset())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_create_events_with_total_file_size() |
||||
|
{ |
||||
|
CreateAsset(); |
||||
|
UpdateAsset(); |
||||
|
|
||||
|
sut.Delete(CreateAssetCommand(new DeleteAsset())); |
||||
|
|
||||
|
Assert.True(sut.IsDeleted); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateAssetEvent(new AssetDeleted { DeletedSize = 2048 }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private void CreateAsset() |
||||
|
{ |
||||
|
sut.Create(CreateAssetCommand(new CreateAsset { File = file })); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
|
||||
|
private void UpdateAsset() |
||||
|
{ |
||||
|
sut.Update(CreateAssetCommand(new UpdateAsset { File = file })); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
|
||||
|
private void DeleteAsset() |
||||
|
{ |
||||
|
sut.Delete(CreateAssetCommand(new DeleteAsset())); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
|
||||
|
protected T CreateAssetEvent<T>(T @event) where T : AssetEvent |
||||
|
{ |
||||
|
@event.AssetId = AssetId; |
||||
|
|
||||
|
return CreateEvent(@event); |
||||
|
} |
||||
|
|
||||
|
protected T CreateAssetCommand<T>(T command) where T : AssetAggregateCommand |
||||
|
{ |
||||
|
command.AssetId = AssetId; |
||||
|
|
||||
|
return CreateCommand(command); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,65 @@ |
|||||
|
// ==========================================================================
|
||||
|
// GuardAssetTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Domain.Apps.Write.Assets.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Assets.Guards |
||||
|
{ |
||||
|
public class GuardAssetTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void CanRename_should_throw_exception_if_name_not_defined() |
||||
|
{ |
||||
|
var command = new RenameAsset(); |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => GuardAsset.CanRename(command, "asset-name")); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanRename_should_throw_exception_if_name_are_the_same() |
||||
|
{ |
||||
|
var command = new RenameAsset { FileName = "asset-name" }; |
||||
|
|
||||
|
Assert.Throws<ValidationException>(() => GuardAsset.CanRename(command, "asset-name")); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanRename_not_should_throw_exception_if_name_are_different() |
||||
|
{ |
||||
|
var command = new RenameAsset { FileName = "new-name" }; |
||||
|
|
||||
|
GuardAsset.CanRename(command, "asset-name"); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanCreate_should_not_throw_exception() |
||||
|
{ |
||||
|
var command = new CreateAsset(); |
||||
|
|
||||
|
GuardAsset.CanCreate(command); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanUpdate_should_not_throw_exception() |
||||
|
{ |
||||
|
var command = new UpdateAsset(); |
||||
|
|
||||
|
GuardAsset.CanUpdate(command); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanDelete_should_not_throw_exception() |
||||
|
{ |
||||
|
var command = new DeleteAsset(); |
||||
|
|
||||
|
GuardAsset.CanDelete(command); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,249 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ContentCommandMiddlewareTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Security.Claims; |
||||
|
using System.Threading.Tasks; |
||||
|
using FakeItEasy; |
||||
|
using Squidex.Domain.Apps.Core; |
||||
|
using Squidex.Domain.Apps.Core.Contents; |
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
using Squidex.Domain.Apps.Core.Scripting; |
||||
|
using Squidex.Domain.Apps.Read.Apps; |
||||
|
using Squidex.Domain.Apps.Read.Apps.Services; |
||||
|
using Squidex.Domain.Apps.Read.Assets.Repositories; |
||||
|
using Squidex.Domain.Apps.Read.Contents.Repositories; |
||||
|
using Squidex.Domain.Apps.Read.Schemas; |
||||
|
using Squidex.Domain.Apps.Read.Schemas.Services; |
||||
|
using Squidex.Domain.Apps.Write.Contents.Commands; |
||||
|
using Squidex.Domain.Apps.Write.TestHelpers; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Commands; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Contents |
||||
|
{ |
||||
|
public class ContentCommandMiddlewareTests : HandlerTestBase<ContentDomainObject> |
||||
|
{ |
||||
|
private readonly ContentCommandMiddleware sut; |
||||
|
private readonly ContentDomainObject content; |
||||
|
private readonly ISchemaProvider schemas = A.Fake<ISchemaProvider>(); |
||||
|
private readonly ISchemaEntity schema = A.Fake<ISchemaEntity>(); |
||||
|
private readonly IScriptEngine scriptEngine = A.Fake<IScriptEngine>(); |
||||
|
private readonly IAppProvider appProvider = A.Fake<IAppProvider>(); |
||||
|
private readonly IAppEntity app = A.Fake<IAppEntity>(); |
||||
|
private readonly ClaimsPrincipal user = new ClaimsPrincipal(); |
||||
|
private readonly LanguagesConfig languagesConfig = LanguagesConfig.Build(Language.DE); |
||||
|
private readonly Guid contentId = Guid.NewGuid(); |
||||
|
|
||||
|
private readonly NamedContentData invalidData = |
||||
|
new NamedContentData() |
||||
|
.AddField("my-field1", new ContentFieldData() |
||||
|
.AddValue(null)) |
||||
|
.AddField("my-field2", new ContentFieldData() |
||||
|
.AddValue(1)); |
||||
|
private readonly NamedContentData data = |
||||
|
new NamedContentData() |
||||
|
.AddField("my-field1", new ContentFieldData() |
||||
|
.AddValue(1)) |
||||
|
.AddField("my-field2", new ContentFieldData() |
||||
|
.AddValue(1)); |
||||
|
private readonly NamedContentData patch = |
||||
|
new NamedContentData() |
||||
|
.AddField("my-field1", new ContentFieldData() |
||||
|
.AddValue(1)); |
||||
|
|
||||
|
public ContentCommandMiddlewareTests() |
||||
|
{ |
||||
|
var schemaDef = new Schema("my-schema"); |
||||
|
|
||||
|
schemaDef.AddField(new NumberField(1, "my-field1", Partitioning.Invariant, |
||||
|
new NumberFieldProperties { IsRequired = true })); |
||||
|
schemaDef.AddField(new NumberField(2, "my-field2", Partitioning.Invariant, |
||||
|
new NumberFieldProperties { IsRequired = false })); |
||||
|
|
||||
|
content = new ContentDomainObject(contentId, -1); |
||||
|
|
||||
|
sut = new ContentCommandMiddleware(Handler, appProvider, A.Dummy<IAssetRepository>(), schemas, scriptEngine, A.Dummy<IContentRepository>()); |
||||
|
|
||||
|
A.CallTo(() => app.LanguagesConfig).Returns(languagesConfig); |
||||
|
A.CallTo(() => app.PartitionResolver).Returns(languagesConfig.ToResolver()); |
||||
|
|
||||
|
A.CallTo(() => appProvider.FindAppByIdAsync(AppId)).Returns(app); |
||||
|
|
||||
|
A.CallTo(() => schema.SchemaDef).Returns(schemaDef); |
||||
|
A.CallTo(() => schema.ScriptCreate).Returns("<create-script>"); |
||||
|
A.CallTo(() => schema.ScriptChange).Returns("<change-script>"); |
||||
|
A.CallTo(() => schema.ScriptUpdate).Returns("<update-script>"); |
||||
|
A.CallTo(() => schema.ScriptDelete).Returns("<delete-script>"); |
||||
|
|
||||
|
A.CallTo(() => schemas.FindSchemaByIdAsync(SchemaId, false)).Returns(schema); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Create_should_throw_exception_if_data_is_not_valid() |
||||
|
{ |
||||
|
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored)) |
||||
|
.Returns(invalidData); |
||||
|
|
||||
|
var context = CreateContextForCommand(new CreateContent { ContentId = contentId, Data = invalidData, User = user }); |
||||
|
|
||||
|
await TestCreate(content, async _ => |
||||
|
{ |
||||
|
await Assert.ThrowsAsync<ValidationException>(() => sut.HandleAsync(context)); |
||||
|
}, false); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Create_should_create_content() |
||||
|
{ |
||||
|
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored)) |
||||
|
.Returns(data); |
||||
|
|
||||
|
var context = CreateContextForCommand(new CreateContent { ContentId = contentId, Data = data, User = user }); |
||||
|
|
||||
|
await TestCreate(content, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
Assert.Equal(data, context.Result<EntityCreatedResult<NamedContentData>>().IdOrValue); |
||||
|
|
||||
|
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, "<create-script>")).MustHaveHappened(); |
||||
|
A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<change-script>")).MustNotHaveHappened(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Create_should_also_invoke_publish_script_when_publishing() |
||||
|
{ |
||||
|
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored)) |
||||
|
.Returns(data); |
||||
|
|
||||
|
var context = CreateContextForCommand(new CreateContent { ContentId = contentId, Data = data, User = user, Publish = true }); |
||||
|
|
||||
|
await TestCreate(content, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
Assert.Equal(data, context.Result<EntityCreatedResult<NamedContentData>>().IdOrValue); |
||||
|
|
||||
|
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, "<create-script>")).MustHaveHappened(); |
||||
|
A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<change-script>")).MustHaveHappened(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Update_should_throw_exception_if_data_is_not_valid() |
||||
|
{ |
||||
|
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored)) |
||||
|
.Returns(invalidData); |
||||
|
|
||||
|
CreateContent(); |
||||
|
|
||||
|
var context = CreateContextForCommand(new UpdateContent { ContentId = contentId, Data = invalidData, User = user }); |
||||
|
|
||||
|
await TestUpdate(content, async _ => |
||||
|
{ |
||||
|
await Assert.ThrowsAsync<ValidationException>(() => sut.HandleAsync(context)); |
||||
|
}, false); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Update_should_update_domain_object() |
||||
|
{ |
||||
|
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored)) |
||||
|
.Returns(data); |
||||
|
|
||||
|
CreateContent(); |
||||
|
|
||||
|
var context = CreateContextForCommand(new UpdateContent { ContentId = contentId, Data = data, User = user }); |
||||
|
|
||||
|
await TestUpdate(content, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
Assert.Equal(data, context.Result<ContentDataChangedResult>().Data); |
||||
|
|
||||
|
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, "<update-script>")).MustHaveHappened(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Patch_should_throw_exception_if_data_is_not_valid() |
||||
|
{ |
||||
|
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored)) |
||||
|
.Returns(invalidData); |
||||
|
|
||||
|
CreateContent(); |
||||
|
|
||||
|
var context = CreateContextForCommand(new PatchContent { ContentId = contentId, Data = invalidData, User = user }); |
||||
|
|
||||
|
await TestUpdate(content, async _ => |
||||
|
{ |
||||
|
await Assert.ThrowsAsync<ValidationException>(() => sut.HandleAsync(context)); |
||||
|
}, false); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Patch_should_update_domain_object() |
||||
|
{ |
||||
|
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored)) |
||||
|
.Returns(data); |
||||
|
|
||||
|
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, A<string>.Ignored)).Returns(patch); |
||||
|
|
||||
|
CreateContent(); |
||||
|
|
||||
|
var context = CreateContextForCommand(new PatchContent { ContentId = contentId, Data = patch, User = user }); |
||||
|
|
||||
|
await TestUpdate(content, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
Assert.NotNull(context.Result<ContentDataChangedResult>().Data); |
||||
|
|
||||
|
A.CallTo(() => scriptEngine.ExecuteAndTransform(A<ScriptContext>.Ignored, "<update-script>")).MustHaveHappened(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task ChangeStatus_should_publish_domain_object() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
|
||||
|
var context = CreateContextForCommand(new ChangeContentStatus { ContentId = contentId, User = user, Status = Status.Published }); |
||||
|
|
||||
|
await TestUpdate(content, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<change-script>")).MustHaveHappened(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Delete_should_update_domain_object() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
|
||||
|
var command = CreateContextForCommand(new DeleteContent { ContentId = contentId, User = user }); |
||||
|
|
||||
|
await TestUpdate(content, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(command); |
||||
|
}); |
||||
|
|
||||
|
A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<delete-script>")).MustHaveHappened(); |
||||
|
} |
||||
|
|
||||
|
private void CreateContent() |
||||
|
{ |
||||
|
content.Create(new CreateContent { Data = data }); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,280 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ContentDomainObjectTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using FluentAssertions; |
||||
|
using Squidex.Domain.Apps.Core.Contents; |
||||
|
using Squidex.Domain.Apps.Events.Contents; |
||||
|
using Squidex.Domain.Apps.Write.Contents.Commands; |
||||
|
using Squidex.Domain.Apps.Write.TestHelpers; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Contents |
||||
|
{ |
||||
|
public class ContentDomainObjectTests : HandlerTestBase<ContentDomainObject> |
||||
|
{ |
||||
|
private readonly ContentDomainObject sut; |
||||
|
private readonly NamedContentData data = |
||||
|
new NamedContentData() |
||||
|
.AddField("field1", |
||||
|
new ContentFieldData() |
||||
|
.AddValue("iv", 1)); |
||||
|
private readonly NamedContentData otherData = |
||||
|
new NamedContentData() |
||||
|
.AddField("field2", |
||||
|
new ContentFieldData() |
||||
|
.AddValue("iv", 2)); |
||||
|
|
||||
|
public Guid ContentId { get; } = Guid.NewGuid(); |
||||
|
|
||||
|
public ContentDomainObjectTests() |
||||
|
{ |
||||
|
sut = new ContentDomainObject(ContentId, 0); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_throw_exception_if_created() |
||||
|
{ |
||||
|
sut.Create(new CreateContent { Data = data }); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Create(CreateContentCommand(new CreateContent { Data = data })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_create_events() |
||||
|
{ |
||||
|
sut.Create(CreateContentCommand(new CreateContent { Data = data })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateContentEvent(new ContentCreated { Data = data }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_also_publish_if_set_to_true() |
||||
|
{ |
||||
|
sut.Create(CreateContentCommand(new CreateContent { Data = data, Publish = true })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateContentEvent(new ContentCreated { Data = data }), |
||||
|
CreateContentEvent(new ContentStatusChanged { Status = Status.Published }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Update(CreateContentCommand(new UpdateContent { Data = data })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_throw_exception_if_content_is_deleted() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
DeleteContent(); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Update(CreateContentCommand(new UpdateContent())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_create_events() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
|
||||
|
sut.Update(CreateContentCommand(new UpdateContent { Data = otherData })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateContentEvent(new ContentUpdated { Data = otherData }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_not_create_event_for_same_data() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
UpdateContent(); |
||||
|
|
||||
|
sut.Update(CreateContentCommand(new UpdateContent { Data = data })); |
||||
|
|
||||
|
sut.GetUncomittedEvents().Should().BeEmpty(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Patch_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Patch(CreateContentCommand(new PatchContent { Data = data })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Patch_should_throw_exception_if_content_is_deleted() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
DeleteContent(); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Patch(CreateContentCommand(new PatchContent())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Patch_should_create_events() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
|
||||
|
sut.Patch(CreateContentCommand(new PatchContent { Data = otherData })); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateContentEvent(new ContentUpdated { Data = otherData }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Patch_should_not_create_event_for_same_data() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
UpdateContent(); |
||||
|
|
||||
|
sut.Patch(CreateContentCommand(new PatchContent { Data = data })); |
||||
|
|
||||
|
sut.GetUncomittedEvents().Should().BeEmpty(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void ChangeStatus_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.ChangeStatus(CreateContentCommand(new ChangeContentStatus())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void ChangeStatus_should_throw_exception_if_content_is_deleted() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
DeleteContent(); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.ChangeStatus(CreateContentCommand(new ChangeContentStatus())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void ChangeStatus_should_refresh_properties_and_create_events() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
|
||||
|
sut.ChangeStatus(CreateContentCommand(new ChangeContentStatus { Status = Status.Published })); |
||||
|
|
||||
|
Assert.Equal(Status.Published, sut.Status); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateContentEvent(new ContentStatusChanged { Status = Status.Published }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Delete(CreateContentCommand(new DeleteContent())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_throw_exception_if_already_deleted() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
DeleteContent(); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Delete(CreateContentCommand(new DeleteContent())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_update_properties_and_create_events() |
||||
|
{ |
||||
|
CreateContent(); |
||||
|
|
||||
|
sut.Delete(CreateContentCommand(new DeleteContent())); |
||||
|
|
||||
|
Assert.True(sut.IsDeleted); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateContentEvent(new ContentDeleted()) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private void CreateContent() |
||||
|
{ |
||||
|
sut.Create(CreateContentCommand(new CreateContent { Data = data })); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
|
||||
|
private void UpdateContent() |
||||
|
{ |
||||
|
sut.Update(CreateContentCommand(new UpdateContent { Data = data })); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
|
||||
|
private void ChangeStatus(Status status) |
||||
|
{ |
||||
|
sut.ChangeStatus(CreateContentCommand(new ChangeContentStatus { Status = status })); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
|
||||
|
private void DeleteContent() |
||||
|
{ |
||||
|
sut.Delete(CreateContentCommand(new DeleteContent())); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
|
||||
|
protected T CreateContentEvent<T>(T @event) where T : ContentEvent |
||||
|
{ |
||||
|
@event.ContentId = ContentId; |
||||
|
|
||||
|
return CreateEvent(@event); |
||||
|
} |
||||
|
|
||||
|
protected T CreateContentCommand<T>(T command) where T : ContentCommand |
||||
|
{ |
||||
|
command.ContentId = ContentId; |
||||
|
|
||||
|
return CreateCommand(command); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
// ==========================================================================
|
||||
|
// SchemaEventTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Squidex.Domain.Apps.Core.Contents; |
||||
|
using Squidex.Domain.Apps.Events.Contents; |
||||
|
using Squidex.Domain.Apps.Events.Contents.Old; |
||||
|
using Squidex.Domain.Apps.Write.TestHelpers; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Xunit; |
||||
|
|
||||
|
#pragma warning disable CS0612 // Type or member is obsolete
|
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Contents |
||||
|
{ |
||||
|
public class ContentEventTests |
||||
|
{ |
||||
|
private readonly RefToken actor = new RefToken("User", Guid.NewGuid().ToString()); |
||||
|
private readonly NamedId<Guid> appId = new NamedId<Guid>(Guid.NewGuid(), "my-app"); |
||||
|
private readonly NamedId<Guid> schemaId = new NamedId<Guid>(Guid.NewGuid(), "my-schema"); |
||||
|
private readonly Guid contentId = Guid.NewGuid(); |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_migrate_content_published_to_content_status_changed() |
||||
|
{ |
||||
|
var source = CreateEvent(new ContentPublished()); |
||||
|
|
||||
|
source.Migrate().ShouldBeSameEvent(CreateEvent(new ContentStatusChanged { Status = Status.Published })); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_migrate_content_unpublished_to_content_status_changed() |
||||
|
{ |
||||
|
var source = CreateEvent(new ContentUnpublished()); |
||||
|
|
||||
|
source.Migrate().ShouldBeSameEvent(CreateEvent(new ContentStatusChanged { Status = Status.Draft })); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_migrate_content_restored_to_content_status_changed() |
||||
|
{ |
||||
|
var source = CreateEvent(new ContentRestored()); |
||||
|
|
||||
|
source.Migrate().ShouldBeSameEvent(CreateEvent(new ContentStatusChanged { Status = Status.Draft })); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_migrate_content_archived_to_content_status_changed() |
||||
|
{ |
||||
|
var source = CreateEvent(new ContentArchived()); |
||||
|
|
||||
|
source.Migrate().ShouldBeSameEvent(CreateEvent(new ContentStatusChanged { Status = Status.Archived })); |
||||
|
} |
||||
|
|
||||
|
private T CreateEvent<T>(T contentEvent) where T : ContentEvent |
||||
|
{ |
||||
|
contentEvent.Actor = actor; |
||||
|
contentEvent.AppId = appId; |
||||
|
contentEvent.SchemaId = schemaId; |
||||
|
contentEvent.ContentId = contentId; |
||||
|
|
||||
|
return contentEvent; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,139 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ContentVersionLoaderTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using FakeItEasy; |
||||
|
using Squidex.Domain.Apps.Core.Contents; |
||||
|
using Squidex.Domain.Apps.Events.Contents; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Events; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Contents |
||||
|
{ |
||||
|
public class ContentVersionLoaderTests |
||||
|
{ |
||||
|
private readonly IEventStore eventStore = A.Fake<IEventStore>(); |
||||
|
private readonly IStreamNameResolver nameResolver = A.Fake<IStreamNameResolver>(); |
||||
|
private readonly EventDataFormatter formatter = A.Fake<EventDataFormatter>(); |
||||
|
private readonly Guid id = Guid.NewGuid(); |
||||
|
private readonly Guid appId = Guid.NewGuid(); |
||||
|
private readonly string streamName = Guid.NewGuid().ToString(); |
||||
|
private readonly ContentVersionLoader sut; |
||||
|
|
||||
|
public ContentVersionLoaderTests() |
||||
|
{ |
||||
|
A.CallTo(() => nameResolver.GetStreamName(typeof(ContentDomainObject), id)) |
||||
|
.Returns(streamName); |
||||
|
|
||||
|
sut = new ContentVersionLoader(eventStore, nameResolver, formatter); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_throw_exception_when_event_store_returns_no_events() |
||||
|
{ |
||||
|
A.CallTo(() => eventStore.GetEventsAsync(streamName)) |
||||
|
.Returns(new List<StoredEvent>()); |
||||
|
|
||||
|
await Assert.ThrowsAsync<DomainObjectNotFoundException>(() => sut.LoadAsync(appId, id, -1)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_throw_exception_when_version_not_found() |
||||
|
{ |
||||
|
A.CallTo(() => eventStore.GetEventsAsync(streamName)) |
||||
|
.Returns(new List<StoredEvent>()); |
||||
|
|
||||
|
await Assert.ThrowsAsync<DomainObjectNotFoundException>(() => sut.LoadAsync(appId, id, 3)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_throw_exception_when_content_is_from_another_event() |
||||
|
{ |
||||
|
var eventData1 = new EventData(); |
||||
|
|
||||
|
var event1 = new ContentCreated { Data = new NamedContentData(), AppId = new NamedId<Guid>(Guid.NewGuid(), "my-app") }; |
||||
|
|
||||
|
var events = new List<StoredEvent> |
||||
|
{ |
||||
|
new StoredEvent("0", 0, eventData1) |
||||
|
}; |
||||
|
|
||||
|
A.CallTo(() => eventStore.GetEventsAsync(streamName)) |
||||
|
.Returns(events); |
||||
|
|
||||
|
A.CallTo(() => formatter.Parse(eventData1, true)) |
||||
|
.Returns(new Envelope<IEvent>(event1)); |
||||
|
|
||||
|
await Assert.ThrowsAsync<DomainObjectNotFoundException>(() => sut.LoadAsync(appId, id, 0)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_load_content_from_created_event() |
||||
|
{ |
||||
|
var eventData1 = new EventData(); |
||||
|
var eventData2 = new EventData(); |
||||
|
|
||||
|
var event1 = new ContentCreated { Data = new NamedContentData(), AppId = new NamedId<Guid>(appId, "my-app") }; |
||||
|
var event2 = new ContentStatusChanged(); |
||||
|
|
||||
|
var events = new List<StoredEvent> |
||||
|
{ |
||||
|
new StoredEvent("0", 0, eventData1), |
||||
|
new StoredEvent("1", 1, eventData2) |
||||
|
}; |
||||
|
|
||||
|
A.CallTo(() => eventStore.GetEventsAsync(streamName)) |
||||
|
.Returns(events); |
||||
|
|
||||
|
A.CallTo(() => formatter.Parse(eventData1, true)) |
||||
|
.Returns(new Envelope<IEvent>(event1)); |
||||
|
A.CallTo(() => formatter.Parse(eventData2, true)) |
||||
|
.Returns(new Envelope<IEvent>(event2)); |
||||
|
|
||||
|
var data = await sut.LoadAsync(appId, id, 3); |
||||
|
|
||||
|
Assert.Same(event1.Data, data); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_load_content_from_correct_version() |
||||
|
{ |
||||
|
var eventData1 = new EventData(); |
||||
|
var eventData2 = new EventData(); |
||||
|
var eventData3 = new EventData(); |
||||
|
|
||||
|
var event1 = new ContentCreated { Data = new NamedContentData(), AppId = new NamedId<Guid>(appId, "my-app") }; |
||||
|
var event2 = new ContentUpdated { Data = new NamedContentData() }; |
||||
|
var event3 = new ContentUpdated { Data = new NamedContentData() }; |
||||
|
|
||||
|
var events = new List<StoredEvent> |
||||
|
{ |
||||
|
new StoredEvent("0", 0, eventData1), |
||||
|
new StoredEvent("1", 1, eventData2), |
||||
|
new StoredEvent("2", 2, eventData3) |
||||
|
}; |
||||
|
|
||||
|
A.CallTo(() => eventStore.GetEventsAsync(streamName)) |
||||
|
.Returns(events); |
||||
|
|
||||
|
A.CallTo(() => formatter.Parse(eventData1, true)) |
||||
|
.Returns(new Envelope<IEvent>(event1)); |
||||
|
A.CallTo(() => formatter.Parse(eventData2, true)) |
||||
|
.Returns(new Envelope<IEvent>(event2)); |
||||
|
A.CallTo(() => formatter.Parse(eventData3, true)) |
||||
|
.Returns(new Envelope<IEvent>(event3)); |
||||
|
|
||||
|
var data = await sut.LoadAsync(appId, id, 1); |
||||
|
|
||||
|
Assert.Equal(event2.Data, data); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
// ==========================================================================
|
||||
|
// JsonFieldPropertiesTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Linq; |
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Schemas.Guards.FieldProperties |
||||
|
{ |
||||
|
public class JsonFieldPropertiesTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void Should_add_error_if_editor_is_not_valid() |
||||
|
{ |
||||
|
var sut = new JsonFieldProperties(); |
||||
|
|
||||
|
var errors = FieldPropertiesValidator.Validate(sut).ToList(); |
||||
|
|
||||
|
Assert.Empty(errors); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,138 @@ |
|||||
|
// ==========================================================================
|
||||
|
// GuardWebhookTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using FakeItEasy; |
||||
|
using Squidex.Domain.Apps.Core.Webhooks; |
||||
|
using Squidex.Domain.Apps.Read.Schemas; |
||||
|
using Squidex.Domain.Apps.Read.Schemas.Services; |
||||
|
using Squidex.Domain.Apps.Write.Webhooks.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Webhooks.Guards |
||||
|
{ |
||||
|
public class GuardWebhookTests |
||||
|
{ |
||||
|
private readonly ISchemaProvider schemas = A.Fake<ISchemaProvider>(); |
||||
|
|
||||
|
public GuardWebhookTests() |
||||
|
{ |
||||
|
A.CallTo(() => schemas.FindSchemaByIdAsync(A<Guid>.Ignored, false)) |
||||
|
.Returns(A.Fake<ISchemaEntity>()); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task CanCreate_should_throw_exception_if_url_defined() |
||||
|
{ |
||||
|
var command = new CreateWebhook(); |
||||
|
|
||||
|
await Assert.ThrowsAsync<ValidationException>(() => GuardWebhook.CanCreate(command, schemas)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task CanCreate_should_throw_exception_if_url_not_valid() |
||||
|
{ |
||||
|
var command = new CreateWebhook { Url = new Uri("/invalid", UriKind.Relative) }; |
||||
|
|
||||
|
await Assert.ThrowsAsync<ValidationException>(() => GuardWebhook.CanCreate(command, schemas)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task CanCreate_should_throw_exception_if_schema_id_not_found() |
||||
|
{ |
||||
|
A.CallTo(() => schemas.FindSchemaByIdAsync(A<Guid>.Ignored, false)) |
||||
|
.Returns(Task.FromResult<ISchemaEntity>(null)); |
||||
|
|
||||
|
var command = new CreateWebhook |
||||
|
{ |
||||
|
Schemas = new List<WebhookSchema> |
||||
|
{ |
||||
|
new WebhookSchema() |
||||
|
}, |
||||
|
Url = new Uri("/invalid", UriKind.Relative) |
||||
|
}; |
||||
|
|
||||
|
await Assert.ThrowsAsync<ValidationException>(() => GuardWebhook.CanCreate(command, schemas)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task CanCreate_should_not_throw_exception_if_schema_id_found() |
||||
|
{ |
||||
|
var command = new CreateWebhook |
||||
|
{ |
||||
|
Schemas = new List<WebhookSchema> |
||||
|
{ |
||||
|
new WebhookSchema() |
||||
|
}, |
||||
|
Url = new Uri("/invalid", UriKind.Relative) |
||||
|
}; |
||||
|
|
||||
|
await Assert.ThrowsAsync<ValidationException>(() => GuardWebhook.CanCreate(command, schemas)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task CanUpdate_should_throw_exception_if_url_not_defined() |
||||
|
{ |
||||
|
var command = new UpdateWebhook(); |
||||
|
|
||||
|
await Assert.ThrowsAsync<ValidationException>(() => GuardWebhook.CanUpdate(command, schemas)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task CanUpdate_should_throw_exception_if_url_not_valid() |
||||
|
{ |
||||
|
var command = new UpdateWebhook { Url = new Uri("/invalid", UriKind.Relative) }; |
||||
|
|
||||
|
await Assert.ThrowsAsync<ValidationException>(() => GuardWebhook.CanUpdate(command, schemas)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task CanUpdate_should_throw_exception_if_schema_id_not_found() |
||||
|
{ |
||||
|
A.CallTo(() => schemas.FindSchemaByIdAsync(A<Guid>.Ignored, false)) |
||||
|
.Returns(Task.FromResult<ISchemaEntity>(null)); |
||||
|
|
||||
|
var command = new UpdateWebhook |
||||
|
{ |
||||
|
Schemas = new List<WebhookSchema> |
||||
|
{ |
||||
|
new WebhookSchema() |
||||
|
}, |
||||
|
Url = new Uri("/invalid", UriKind.Relative) |
||||
|
}; |
||||
|
|
||||
|
await Assert.ThrowsAsync<ValidationException>(() => GuardWebhook.CanUpdate(command, schemas)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task CanUpdate_should_not_throw_exception_if_schema_id_found() |
||||
|
{ |
||||
|
var command = new UpdateWebhook |
||||
|
{ |
||||
|
Schemas = new List<WebhookSchema> |
||||
|
{ |
||||
|
new WebhookSchema() |
||||
|
}, |
||||
|
Url = new Uri("/invalid", UriKind.Relative) |
||||
|
}; |
||||
|
|
||||
|
await Assert.ThrowsAsync<ValidationException>(() => GuardWebhook.CanUpdate(command, schemas)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void CanDelete_should_not_throw_exception() |
||||
|
{ |
||||
|
var command = new DeleteWebhook(); |
||||
|
|
||||
|
GuardWebhook.CanDelete(command); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,115 @@ |
|||||
|
// ==========================================================================
|
||||
|
// WebhookCommandMiddlewareTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using FakeItEasy; |
||||
|
using Squidex.Domain.Apps.Core.Webhooks; |
||||
|
using Squidex.Domain.Apps.Read.Schemas; |
||||
|
using Squidex.Domain.Apps.Read.Schemas.Services; |
||||
|
using Squidex.Domain.Apps.Write.TestHelpers; |
||||
|
using Squidex.Domain.Apps.Write.Webhooks.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Commands; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Webhooks |
||||
|
{ |
||||
|
public class WebhookCommandMiddlewareTests : HandlerTestBase<WebhookDomainObject> |
||||
|
{ |
||||
|
private readonly ISchemaProvider schemas = A.Fake<ISchemaProvider>(); |
||||
|
private readonly WebhookCommandMiddleware sut; |
||||
|
private readonly WebhookDomainObject webhook; |
||||
|
private readonly Uri url = new Uri("http://squidex.io"); |
||||
|
private readonly Guid schemaId = Guid.NewGuid(); |
||||
|
private readonly Guid webhookId = Guid.NewGuid(); |
||||
|
private readonly List<WebhookSchema> webhookSchemas; |
||||
|
|
||||
|
public WebhookCommandMiddlewareTests() |
||||
|
{ |
||||
|
A.CallTo(() => schemas.FindSchemaByIdAsync(schemaId, false)) |
||||
|
.Returns(A.Fake<ISchemaEntity>()); |
||||
|
|
||||
|
webhook = new WebhookDomainObject(webhookId, -1); |
||||
|
|
||||
|
webhookSchemas = new List<WebhookSchema> |
||||
|
{ |
||||
|
new WebhookSchema { SchemaId = schemaId } |
||||
|
}; |
||||
|
|
||||
|
sut = new WebhookCommandMiddleware(Handler, schemas); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Create_should_create_domain_object() |
||||
|
{ |
||||
|
var context = CreateContextForCommand(new CreateWebhook { Schemas = webhookSchemas, Url = url, WebhookId = webhookId }); |
||||
|
|
||||
|
await TestCreate(webhook, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
A.CallTo(() => schemas.FindSchemaByIdAsync(schemaId, false)).MustHaveHappened(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Update_should_update_domain_object() |
||||
|
{ |
||||
|
var context = CreateContextForCommand(new UpdateWebhook { Schemas = webhookSchemas, Url = url, WebhookId = webhookId }); |
||||
|
|
||||
|
A.CallTo(() => schemas.FindSchemaByIdAsync(schemaId, false)).Returns(A.Fake<ISchemaEntity>()); |
||||
|
|
||||
|
CreateWebhook(); |
||||
|
|
||||
|
await TestUpdate(webhook, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
|
||||
|
A.CallTo(() => schemas.FindSchemaByIdAsync(schemaId, false)).MustHaveHappened(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Update_should_throw_exception_when_schema_is_not_found() |
||||
|
{ |
||||
|
var context = CreateContextForCommand(new UpdateWebhook { Schemas = webhookSchemas, Url = url, WebhookId = webhookId }); |
||||
|
|
||||
|
A.CallTo(() => schemas.FindSchemaByIdAsync(schemaId, false)).Returns((ISchemaEntity)null); |
||||
|
|
||||
|
CreateWebhook(); |
||||
|
|
||||
|
await Assert.ThrowsAsync<ValidationException>(async () => |
||||
|
{ |
||||
|
await TestCreate(webhook, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(context); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Delete_should_update_domain_object() |
||||
|
{ |
||||
|
CreateWebhook(); |
||||
|
|
||||
|
var command = CreateContextForCommand(new DeleteWebhook { WebhookId = webhookId }); |
||||
|
|
||||
|
await TestUpdate(webhook, async _ => |
||||
|
{ |
||||
|
await sut.HandleAsync(command); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private void CreateWebhook() |
||||
|
{ |
||||
|
webhook.Create(new CreateWebhook { Url = url }); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,159 @@ |
|||||
|
// ==========================================================================
|
||||
|
// WebhookDomainObjectTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Squidex.Domain.Apps.Events.Webhooks; |
||||
|
using Squidex.Domain.Apps.Write.TestHelpers; |
||||
|
using Squidex.Domain.Apps.Write.Webhooks.Commands; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Write.Webhooks |
||||
|
{ |
||||
|
public class WebhookDomainObjectTests : HandlerTestBase<WebhookDomainObject> |
||||
|
{ |
||||
|
private readonly Uri url = new Uri("http://squidex.io"); |
||||
|
private readonly WebhookDomainObject sut; |
||||
|
|
||||
|
public Guid WebhookId { get; } = Guid.NewGuid(); |
||||
|
|
||||
|
public WebhookDomainObjectTests() |
||||
|
{ |
||||
|
sut = new WebhookDomainObject(WebhookId, 0); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_throw_exception_if_created() |
||||
|
{ |
||||
|
sut.Create(new CreateWebhook { Url = url }); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Create(CreateWebhookCommand(new CreateWebhook { Url = url })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Create_should_create_events() |
||||
|
{ |
||||
|
var command = new CreateWebhook { Url = url }; |
||||
|
|
||||
|
sut.Create(CreateWebhookCommand(command)); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateWebhookEvent(new WebhookCreated |
||||
|
{ |
||||
|
Url = url, |
||||
|
Schemas = command.Schemas, |
||||
|
SharedSecret = command.SharedSecret, |
||||
|
WebhookId = command.WebhookId |
||||
|
}) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Update(CreateWebhookCommand(new UpdateWebhook { Url = url })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_throw_exception_if_webhook_is_deleted() |
||||
|
{ |
||||
|
CreateWebhook(); |
||||
|
DeleteWebhook(); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Update(CreateWebhookCommand(new UpdateWebhook { Url = url })); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Update_should_create_events() |
||||
|
{ |
||||
|
CreateWebhook(); |
||||
|
|
||||
|
var command = new UpdateWebhook { Url = url }; |
||||
|
|
||||
|
sut.Update(CreateWebhookCommand(command)); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateWebhookEvent(new WebhookUpdated { Url = url, Schemas = command.Schemas }) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_throw_exception_if_not_created() |
||||
|
{ |
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Delete(CreateWebhookCommand(new DeleteWebhook())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_throw_exception_if_already_deleted() |
||||
|
{ |
||||
|
CreateWebhook(); |
||||
|
DeleteWebhook(); |
||||
|
|
||||
|
Assert.Throws<DomainException>(() => |
||||
|
{ |
||||
|
sut.Delete(CreateWebhookCommand(new DeleteWebhook())); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Delete_should_update_properties_create_events() |
||||
|
{ |
||||
|
CreateWebhook(); |
||||
|
|
||||
|
sut.Delete(CreateWebhookCommand(new DeleteWebhook())); |
||||
|
|
||||
|
sut.GetUncomittedEvents() |
||||
|
.ShouldHaveSameEvents( |
||||
|
CreateWebhookEvent(new WebhookDeleted()) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
private void CreateWebhook() |
||||
|
{ |
||||
|
sut.Create(CreateWebhookCommand(new CreateWebhook { Url = url })); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
|
||||
|
private void DeleteWebhook() |
||||
|
{ |
||||
|
sut.Delete(CreateWebhookCommand(new DeleteWebhook())); |
||||
|
|
||||
|
((IAggregate)sut).ClearUncommittedEvents(); |
||||
|
} |
||||
|
|
||||
|
protected T CreateWebhookEvent<T>(T @event) where T : WebhookEvent |
||||
|
{ |
||||
|
@event.WebhookId = WebhookId; |
||||
|
|
||||
|
return CreateEvent(@event); |
||||
|
} |
||||
|
|
||||
|
protected T CreateWebhookCommand<T>(T command) where T : WebhookAggregateCommand |
||||
|
{ |
||||
|
command.WebhookId = WebhookId; |
||||
|
|
||||
|
return CreateCommand(command); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue