Browse Source

Fixes to app plan management

pull/906/head
Sebastian 4 years ago
parent
commit
3a6bce5178
  1. 105
      backend/src/Squidex.Domain.Apps.Entities/Apps/DomainObject/AppDomainObject.cs
  2. 8
      backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/IAppPlanBillingManager.cs
  3. 13
      backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/IChangePlanResult.cs
  4. 20
      backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/NoopAppPlanBillingManager.cs
  5. 13
      backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/PlanChangeAsyncResult.cs
  6. 4
      backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/PlanChangedResult.cs
  7. 23
      backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/RedirectToCheckoutResult.cs
  8. 4
      backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetDomainObject.cs
  9. 16
      backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/Guards/TagsExtensions.cs
  10. 4
      backend/src/Squidex/Areas/Api/Controllers/Plans/AppPlansController.cs
  11. 63
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs
  12. 22
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Plans/NoopAppPlanBillingManagerTests.cs
  13. 15
      backend/tests/Squidex.Infrastructure.Tests/EventSourcing/Consume/EventConsumerManagerTests.cs
  14. 23
      backend/tests/Squidex.Infrastructure.Tests/EventSourcing/Consume/EventConsumerProcessorTests.cs
  15. 20
      backend/tests/Squidex.Infrastructure.Tests/TestHelpers/TestState.cs

105
backend/src/Squidex.Domain.Apps.Entities/Apps/DomainObject/AppDomainObject.cs

@ -118,7 +118,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
case AssignContributor assignContributor:
return UpdateReturnAsync(assignContributor, async (c, ct) =>
{
await GuardAppContributors.CanAssign(c, Snapshot, UserResolver(), GetPlan());
await GuardAppContributors.CanAssign(c, Snapshot, Users(), GetPlan());
AssignContributor(c, !Snapshot.Contributors.ContainsKey(assignContributor.ContributorId));
@ -255,46 +255,71 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
return Snapshot;
}, ct);
case ChangePlan changePlan:
return UpdateReturnAsync(changePlan, async (c, ct) =>
{
GuardApp.CanChangePlan(c, Snapshot, AppPlansProvider());
if (c.FromCallback)
{
ChangePlan(c);
return null;
}
else
{
var result = await AppPlanBillingManager().ChangePlanAsync(c.Actor.Identifier, Snapshot.NamedId(), c.PlanId, c.Referer, default);
switch (result)
{
case PlanChangedResult:
ChangePlan(c);
break;
}
return result;
}
}, ct);
case DeleteApp delete:
return UpdateAsync(delete, async (c, ct) =>
{
await AppPlanBillingManager().ChangePlanAsync(c.Actor.Identifier, Snapshot.NamedId(), null, null, ct);
await Billing().SubscribeAsync(c.Actor.Identifier, Snapshot.NamedId(), null, null, ct);
DeleteApp(c);
}, ct);
case ChangePlan changePlan:
return ChangePlanAsync(changePlan, ct);
default:
ThrowHelper.NotSupportedException();
return default!;
}
}
private async Task<CommandResult> ChangePlanAsync(ChangePlan changePlan,
CancellationToken ct)
{
var userId = changePlan.Actor.Identifier;
var result = await UpdateReturnAsync(changePlan, async (c, ct) =>
{
GuardApp.CanChangePlan(c, Snapshot, Plans());
if (string.Equals(GetFreePlan()?.Id, c.PlanId, StringComparison.Ordinal))
{
ResetPlan(c);
return new PlanChangedResult(c.PlanId, true, null);
}
if (!c.FromCallback)
{
var redirectUri = await Billing().MustRedirectToPortalAsync(userId, Snapshot.NamedId(), c.PlanId, c.Referer, default);
if (redirectUri != null)
{
return new PlanChangedResult(c.PlanId, false, redirectUri);
}
}
ChangePlan(c);
return new PlanChangedResult(c.PlanId);
});
if (changePlan.FromCallback)
{
return result;
}
if (result.Payload is PlanChangedResult { Unsubscribed: true, RedirectUri: null })
{
await Billing().UnsubscribeAsync(userId, Snapshot.NamedId(), changePlan.Referer, default);
}
else if (result.Payload is PlanChangedResult { RedirectUri: null })
{
await Billing().SubscribeAsync(userId, Snapshot.NamedId(), changePlan.PlanId, changePlan.Referer);
}
return result;
}
private void Create(CreateApp command)
{
var appId = NamedId.Of(command.AppId, command.Name);
@ -321,14 +346,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
private void ChangePlan(ChangePlan command)
{
if (string.Equals(GetFreePlan()?.Id, command.PlanId, StringComparison.Ordinal))
{
Raise(command, new AppPlanReset());
}
else
{
Raise(command, new AppPlanChanged());
}
Raise(command, new AppPlanChanged());
}
private void ResetPlan(ChangePlan command)
{
Raise(command, new AppPlanReset());
}
private void Update(UpdateApp command)
@ -455,29 +478,29 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
return new AppSettingsUpdated { Settings = serviceProvider.GetRequiredService<InitialSettings>().Settings };
}
private IAppPlansProvider AppPlansProvider()
private IAppPlansProvider Plans()
{
return serviceProvider.GetRequiredService<IAppPlansProvider>();
}
private IAppPlanBillingManager AppPlanBillingManager()
private IAppPlanBillingManager Billing()
{
return serviceProvider.GetRequiredService<IAppPlanBillingManager>();
}
private IUserResolver UserResolver()
private IUserResolver Users()
{
return serviceProvider.GetRequiredService<IUserResolver>();
}
private IAppLimitsPlan GetFreePlan()
{
return AppPlansProvider().GetFreePlan();
return Plans().GetFreePlan();
}
private IAppLimitsPlan GetPlan()
{
return AppPlansProvider().GetPlanForApp(Snapshot).Plan;
return Plans().GetPlanForApp(Snapshot).Plan;
}
}
}

8
backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/IAppPlanBillingManager.cs

@ -13,7 +13,13 @@ namespace Squidex.Domain.Apps.Entities.Apps.Plans
{
bool HasPortal { get; }
Task<IChangePlanResult> ChangePlanAsync(string userId, NamedId<DomainId> appId, string? planId, string? referer,
Task<Uri?> MustRedirectToPortalAsync(string userId, NamedId<DomainId> appId, string? planId, string? referer,
CancellationToken ct = default);
Task SubscribeAsync(string userId, NamedId<DomainId> appId, string? planId, string? referer,
CancellationToken ct = default);
Task UnsubscribeAsync(string userId, NamedId<DomainId> appId, string? referer,
CancellationToken ct = default);
Task<string> GetPortalLinkAsync(string userId,

13
backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/IChangePlanResult.cs

@ -1,13 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Domain.Apps.Entities.Apps.Plans
{
public interface IChangePlanResult
{
}
}

20
backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/NoopAppPlanBillingManager.cs

@ -16,16 +16,28 @@ namespace Squidex.Domain.Apps.Entities.Apps.Plans
get => false;
}
public Task<IChangePlanResult> ChangePlanAsync(string userId, NamedId<DomainId> appId, string? planId, string? referer,
public Task<string> GetPortalLinkAsync(string userId,
CancellationToken ct = default)
{
return Task.FromResult<IChangePlanResult>(new PlanChangedResult());
return Task.FromResult(string.Empty);
}
public Task<string> GetPortalLinkAsync(string userId,
public Task<Uri?> MustRedirectToPortalAsync(string userId, NamedId<DomainId> appId, string? planId, string? referer,
CancellationToken ct = default)
{
return Task.FromResult(string.Empty);
return Task.FromResult<Uri?>(null);
}
public Task SubscribeAsync(string userId, NamedId<DomainId> appId, string? planId, string? referer,
CancellationToken ct = default)
{
return Task.CompletedTask;
}
public Task UnsubscribeAsync(string userId, NamedId<DomainId> appId, string? referer,
CancellationToken ct = default)
{
return Task.CompletedTask;
}
}
}

13
backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/PlanChangeAsyncResult.cs

@ -1,13 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Domain.Apps.Entities.Apps.Plans
{
public sealed class PlanChangeAsyncResult : IChangePlanResult
{
}
}

4
backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/PlanChangedResult.cs

@ -5,9 +5,11 @@
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
#pragma warning disable SA1313 // Parameter names should begin with lower-case letter
namespace Squidex.Domain.Apps.Entities.Apps.Plans
{
public sealed class PlanChangedResult : IChangePlanResult
public sealed record PlanChangedResult(string PlanId, bool Unsubscribed = false, Uri? RedirectUri = null)
{
}
}

23
backend/src/Squidex.Domain.Apps.Entities/Apps/Plans/RedirectToCheckoutResult.cs

@ -1,23 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Entities.Apps.Plans
{
public sealed class RedirectToCheckoutResult : IChangePlanResult
{
public Uri Url { get; }
public RedirectToCheckoutResult(Uri url)
{
Guard.NotNull(url);
Url = url;
}
}
}

4
backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/AssetDomainObject.cs

@ -166,7 +166,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
if (create.Tags != null)
{
create.Tags = await operation.NormalizeTagsAsync(create.Tags);
create.Tags = await operation.GetTagIdsAsync(create.Tags);
}
Create(create);
@ -181,7 +181,7 @@ namespace Squidex.Domain.Apps.Entities.Assets.DomainObject
if (annotate.Tags != null)
{
annotate.Tags = await operation.NormalizeTagsAsync(annotate.Tags);
annotate.Tags = await operation.GetTagIdsAsync(annotate.Tags);
}
Annotate(annotate);

16
backend/src/Squidex.Domain.Apps.Entities/Assets/DomainObject/Guards/TagsExtensions.cs

@ -6,18 +6,26 @@
// ==========================================================================
using Squidex.Domain.Apps.Core.Tags;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Entities.Assets.DomainObject.Guards
{
public static class TagsExtensions
{
public static async Task<HashSet<string>> NormalizeTagsAsync(this AssetOperation operation, HashSet<string> names)
public static async Task<HashSet<string>> GetTagIdsAsync(this AssetOperation operation, HashSet<string>? names)
{
var tagService = operation.Resolve<ITagService>();
var result = new HashSet<string>(names?.Count ?? 0);
var normalized = await tagService.GetTagIdsAsync(operation.App.Id, TagGroups.Assets, names);
if (names != null)
{
var tagService = operation.Resolve<ITagService>();
return new HashSet<string>(normalized.Values);
var normalized = await tagService.GetTagIdsAsync(operation.App.Id, TagGroups.Assets, names);
result.AddRange(normalized.Values);
}
return result;
}
}
}

4
backend/src/Squidex/Areas/Api/Controllers/Plans/AppPlansController.cs

@ -81,9 +81,9 @@ namespace Squidex.Areas.Api.Controllers.Plans
string? redirectUri = null;
if (context.PlainResult is RedirectToCheckoutResult result)
if (context.PlainResult is PlanChangedResult result)
{
redirectUri = result.Url.ToString();
redirectUri = result.RedirectUri?.ToString();
}
return Ok(new PlanChangedDto { RedirectUri = redirectUri });

63
backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/DomainObject/AppDomainObjectTests.cs

@ -59,6 +59,9 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
A.CallTo(() => appPlansProvider.GetPlan(planIdPaid))
.Returns(new ConfigAppLimitsPlan { Id = planIdPaid, MaxContributors = 30 });
A.CallTo(() => appPlansBillingManager.MustRedirectToPortalAsync(Actor.Identifier, AppNamedId, A<string>._, A<string>._, default))
.Returns(Task.FromResult<Uri?>(null));
// Create a non-empty setting, otherwise the event is not raised as it does not change the domain object.
initialSettings = new InitialSettings
{
@ -217,14 +220,14 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
{
var command = new ChangePlan { PlanId = planIdPaid };
A.CallTo(() => appPlansBillingManager.ChangePlanAsync(Actor.Identifier, AppNamedId, planIdPaid, command.Referer, default))
.Returns(new PlanChangedResult());
A.CallTo(() => appPlansBillingManager.MustRedirectToPortalAsync(Actor.Identifier, AppNamedId, planIdPaid, command.Referer, default))
.Returns(Task.FromResult<Uri?>(null));
await ExecuteCreateAsync();
var result = await PublishIdempotentAsync(command);
Assert.True(result is PlanChangedResult);
result.ShouldBeEquivalent(new PlanChangedResult(planIdPaid));
Assert.Equal(planIdPaid, sut.Snapshot.Plan!.PlanId);
@ -232,6 +235,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
.ShouldHaveSameEvents(
CreateEvent(new AppPlanChanged { PlanId = planIdPaid })
);
A.CallTo(() => appPlansBillingManager.MustRedirectToPortalAsync(Actor.Identifier, AppNamedId, planIdPaid, command.Referer, default))
.MustHaveHappened();
A.CallTo(() => appPlansBillingManager.SubscribeAsync(Actor.Identifier, AppNamedId, planIdPaid, command.Referer, default))
.MustHaveHappened();
}
[Fact]
@ -243,7 +252,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
var result = await PublishIdempotentAsync(command);
result.ShouldBeEquivalent(None.Value);
result.ShouldBeEquivalent(new PlanChangedResult(planIdPaid));
Assert.Equal(planIdPaid, sut.Snapshot.Plan!.PlanId);
@ -252,7 +261,10 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
CreateEvent(new AppPlanChanged { PlanId = planIdPaid })
);
A.CallTo(() => appPlansBillingManager.ChangePlanAsync(A<string>._, A<NamedId<DomainId>>._, A<string?>._, A<string?>._, A<CancellationToken>._))
A.CallTo(() => appPlansBillingManager.MustRedirectToPortalAsync(A<string>._, A<NamedId<DomainId>>._, A<string?>._, A<string?>._, default))
.MustNotHaveHappened();
A.CallTo(() => appPlansBillingManager.SubscribeAsync(A<string>._, A<NamedId<DomainId>>._, A<string?>._, A<string?>._, A<CancellationToken>._))
.MustNotHaveHappened();
}
@ -261,15 +273,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
{
var command = new ChangePlan { PlanId = planIdFree, FromCallback = true };
A.CallTo(() => appPlansBillingManager.ChangePlanAsync(Actor.Identifier, AppNamedId, planIdPaid, command.Referer, default))
.Returns(new PlanChangedResult());
await ExecuteCreateAsync();
await ExecuteChangePlanAsync();
var result = await PublishIdempotentAsync(command);
result.ShouldBeEquivalent(None.Value);
result.ShouldBeEquivalent(new PlanChangedResult(planIdFree, true));
Assert.Null(sut.Snapshot.Plan);
@ -278,7 +287,10 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
CreateEvent(new AppPlanReset())
);
A.CallTo(() => appPlansBillingManager.ChangePlanAsync(A<string>._, A<NamedId<DomainId>>._, planIdFree, A<string?>._, A<CancellationToken>._))
A.CallTo(() => appPlansBillingManager.MustRedirectToPortalAsync(A<string>._, A<NamedId<DomainId>>._, A<string?>._, A<string?>._, default))
.MustHaveHappenedOnceExactly();
A.CallTo(() => appPlansBillingManager.UnsubscribeAsync(A<string>._, A<NamedId<DomainId>>._, A<string?>._, A<CancellationToken>._))
.MustNotHaveHappened();
}
@ -287,18 +299,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
{
var command = new ChangePlan { PlanId = planIdFree };
A.CallTo(() => appPlansBillingManager.ChangePlanAsync(Actor.Identifier, AppNamedId, planIdPaid, command.Referer, default))
.Returns(new PlanChangedResult());
A.CallTo(() => appPlansBillingManager.ChangePlanAsync(Actor.Identifier, AppNamedId, planIdFree, command.Referer, default))
.Returns(new PlanChangedResult());
await ExecuteCreateAsync();
await ExecuteChangePlanAsync();
var result = await PublishIdempotentAsync(command);
Assert.True(result is PlanChangedResult);
result.ShouldBeEquivalent(new PlanChangedResult(planIdFree, true));
Assert.Null(sut.Snapshot.Plan);
@ -306,6 +312,12 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
.ShouldHaveSameEvents(
CreateEvent(new AppPlanReset())
);
A.CallTo(() => appPlansBillingManager.MustRedirectToPortalAsync(Actor.Identifier, AppNamedId, planIdPaid, command.Referer, default))
.MustHaveHappenedOnceExactly();
A.CallTo(() => appPlansBillingManager.UnsubscribeAsync(A<string>._, A<NamedId<DomainId>>._, A<string?>._, A<CancellationToken>._))
.MustHaveHappened();
}
[Fact]
@ -313,14 +325,14 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
{
var command = new ChangePlan { PlanId = planIdPaid };
A.CallTo(() => appPlansBillingManager.ChangePlanAsync(Actor.Identifier, AppNamedId, planIdPaid, command.Referer, default))
.Returns(new RedirectToCheckoutResult(new Uri("http://squidex.io")));
A.CallTo(() => appPlansBillingManager.MustRedirectToPortalAsync(Actor.Identifier, AppNamedId, planIdPaid, command.Referer, default))
.Returns(new Uri("http://squidex.io"));
await ExecuteCreateAsync();
var result = await PublishIdempotentAsync(command);
result.ShouldBeEquivalent(new RedirectToCheckoutResult(new Uri("http://squidex.io")));
result.ShouldBeEquivalent(new PlanChangedResult(planIdPaid, false, new Uri("http://squidex.io")));
Assert.Null(sut.Snapshot.Plan);
}
@ -334,9 +346,14 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
var result = await PublishIdempotentAsync(command);
result.ShouldBeEquivalent(None.Value);
result.ShouldBeEquivalent(new PlanChangedResult(planIdPaid));
Assert.Equal(planIdPaid, sut.Snapshot.Plan?.PlanId);
A.CallTo(() => appPlansBillingManager.MustRedirectToPortalAsync(Actor.Identifier, AppNamedId, planIdPaid, command.Referer, default))
.MustNotHaveHappened();
A.CallTo(() => appPlansBillingManager.ChangePlanAsync(Actor.Identifier, AppNamedId, planIdPaid, A<string?>._, default))
A.CallTo(() => appPlansBillingManager.SubscribeAsync(Actor.Identifier, AppNamedId, planIdPaid, A<string?>._, default))
.MustNotHaveHappened();
}
@ -651,7 +668,7 @@ namespace Squidex.Domain.Apps.Entities.Apps.DomainObject
CreateEvent(new AppDeleted())
);
A.CallTo(() => appPlansBillingManager.ChangePlanAsync(command.Actor.Identifier, AppNamedId, null, A<string?>._, default))
A.CallTo(() => appPlansBillingManager.SubscribeAsync(command.Actor.Identifier, AppNamedId, null, A<string?>._, default))
.MustHaveHappened();
}

22
backend/tests/Squidex.Domain.Apps.Entities.Tests/Apps/Plans/NoopAppPlanBillingManagerTests.cs

@ -20,15 +20,31 @@ namespace Squidex.Domain.Apps.Entities.Apps.Plans
}
[Fact]
public async Task Should_do_nothing_if_changing_plan()
public async Task Should_do_nothing_if_subscribing()
{
await sut.ChangePlanAsync(null!, null!, null, null);
await sut.SubscribeAsync(null!, null!, null, null);
}
[Fact]
public async Task Should_do_nothing_if_unsubscribing()
{
await sut.SubscribeAsync(null!, null!, null, null);
}
[Fact]
public async Task Should_not_return_portal_link()
{
Assert.Equal(string.Empty, await sut.GetPortalLinkAsync(null!));
var result = await sut.GetPortalLinkAsync(null!);
Assert.Empty(result);
}
[Fact]
public async Task Should_do_nothing_if_checking_for_redirect()
{
var result = await sut.MustRedirectToPortalAsync(null!, null!, null, null);
Assert.Null(result);
}
}
}

15
backend/tests/Squidex.Infrastructure.Tests/EventSourcing/Consume/EventConsumerManagerTests.cs

@ -83,12 +83,13 @@ namespace Squidex.Infrastructure.EventSourcing.Consume
[Fact]
public async Task Should_publish_event_on_start()
{
var testState = new TestState<EventConsumerState>(DomainId.Create(consumerName1), persistenceFactory)
var testState = new TestState<EventConsumerState>(consumerName1, persistenceFactory)
{
Snapshot = new EventConsumerState
{
Position = "42"
}
},
Version = 0
};
var response = await sut.StartAsync(consumerName1, default);
@ -102,12 +103,13 @@ namespace Squidex.Infrastructure.EventSourcing.Consume
[Fact]
public async Task Should_publish_event_on_stop()
{
var testState = new TestState<EventConsumerState>(DomainId.Create(consumerName1), persistenceFactory)
var testState = new TestState<EventConsumerState>(consumerName1, persistenceFactory)
{
Snapshot = new EventConsumerState
{
Position = "42"
}
},
Version = 0
};
var response = await sut.StopAsync(consumerName1, default);
@ -121,12 +123,13 @@ namespace Squidex.Infrastructure.EventSourcing.Consume
[Fact]
public async Task Should_publish_event_on_reset()
{
var testState = new TestState<EventConsumerState>(DomainId.Create(consumerName1), persistenceFactory)
var testState = new TestState<EventConsumerState>(consumerName1, persistenceFactory)
{
Snapshot = new EventConsumerState
{
Position = "42"
}
},
Version = 0
};
var response = await sut.ResetAsync(consumerName1, default);

23
backend/tests/Squidex.Infrastructure.Tests/EventSourcing/Consume/EventConsumerProcessorTests.cs

@ -71,6 +71,9 @@ namespace Squidex.Infrastructure.EventSourcing.Consume
A.CallTo(() => eventConsumer.Name)
.Returns(consumerName);
A.CallTo(() => eventConsumer.CanClear)
.Returns(true);
A.CallTo(() => eventConsumer.Handles(A<StoredEvent>._))
.Returns(true);
@ -205,6 +208,26 @@ namespace Squidex.Infrastructure.EventSourcing.Consume
.MustHaveHappenedOnceExactly();
}
[Fact]
public async Task Should_not_reset_consumer_if_not_allowed()
{
A.CallTo(() => eventConsumer.CanClear)
.Returns(false);
await sut.InitializeAsync(default);
await sut.ActivateAsync();
await sut.StopAsync();
await sut.ResetAsync();
await sut.CompleteAsync();
AssertGrainState(isStopped: true, position: initialPosition);
A.CallTo(() => eventConsumer.ClearAsync())
.MustNotHaveHappened();
}
[Fact]
public async Task Should_invoke_and_update_position_if_event_received()
{

20
backend/tests/Squidex.Infrastructure.Tests/TestHelpers/TestState.cs

@ -33,16 +33,6 @@ namespace Squidex.Infrastructure.TestHelpers
{
}
public void AddEvent(Envelope<IEvent> @event)
{
events.Add(@event);
}
public void AddEvent(IEvent @event)
{
events.Add(Envelope.Create(@event));
}
public TestState(DomainId id, IPersistenceFactory<T>? persistenceFactory = null)
{
Id = id;
@ -115,5 +105,15 @@ namespace Squidex.Infrastructure.TestHelpers
Snapshot = new T();
});
}
public void AddEvent(Envelope<IEvent> @event)
{
events.Add(@event);
}
public void AddEvent(IEvent @event)
{
events.Add(Envelope.Create(@event));
}
}
}

Loading…
Cancel
Save