Browse Source

Grain improved.

pull/342/head
Sebastian Stehle 8 years ago
parent
commit
404acb31ad
  1. 2
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/IRuleTriggerHandler.cs
  2. 4
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs
  3. 7
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleTriggerHandler.cs
  4. 1
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/Triggers/AssetChangedTriggerHandler.cs
  5. 2
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/Triggers/ContentChangedTriggerHandler.cs
  6. 4
      src/Squidex.Domain.Apps.Core.Operations/HandleRules/Triggers/UsageTriggerHandler.cs
  7. 2
      src/Squidex.Domain.Apps.Entities/Apps/InviteUserCommandMiddleware.cs
  8. 2
      src/Squidex.Domain.Apps.Entities/Rules/EventEnricher.cs
  9. 2
      src/Squidex.Domain.Apps.Entities/Rules/RuleEnqueuer.cs
  10. 10
      src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/IUsageTrackerGrain.cs
  11. 54
      src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/UsageTrackerGrain.cs
  12. 69
      src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/UsageTriggerHandler.cs
  13. 7
      src/Squidex.Domain.Apps.Events/AppUsageExceeded.cs
  14. 5
      src/Squidex.Infrastructure/Commands/CommandContext.cs
  15. 5
      src/Squidex/Areas/Api/Controllers/Apps/AppContributorsController.cs
  16. 2
      src/Squidex/Areas/Api/Controllers/Plans/AppPlansController.cs
  17. 2
      src/Squidex/Pipeline/CommandMiddlewares/ETagCommandMiddleware.cs
  18. 69
      tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleServiceTests.cs
  19. 4
      tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/Triggers/AssetChangedTriggerTests.cs
  20. 11
      tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/Triggers/ContentChangedTriggerTests.cs
  21. 20
      tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/Triggers/UsageTriggerHandlerTests.cs
  22. 18
      tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs
  23. 19
      tests/Squidex.Infrastructure.Tests/Commands/CommandContextTests.cs

2
src/Squidex.Domain.Apps.Core.Operations/HandleRules/IRuleTriggerHandler.cs

@ -18,6 +18,6 @@ namespace Squidex.Domain.Apps.Core.HandleRules
bool Trigger(EnrichedEvent @event, RuleTrigger trigger); bool Trigger(EnrichedEvent @event, RuleTrigger trigger);
bool Trigger(IEvent @event, RuleTrigger trigger); bool Trigger(IEvent @event, RuleTrigger trigger, Guid ruleId);
} }
} }

4
src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleService.cs

@ -56,7 +56,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules
this.clock = clock; this.clock = clock;
} }
public virtual async Task<RuleJob> CreateJobAsync(Rule rule, Envelope<IEvent> @event) public virtual async Task<RuleJob> CreateJobAsync(Rule rule, Guid ruleId, Envelope<IEvent> @event)
{ {
Guard.NotNull(rule, nameof(rule)); Guard.NotNull(rule, nameof(rule));
Guard.NotNull(@event, nameof(@event)); Guard.NotNull(@event, nameof(@event));
@ -83,7 +83,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules
return null; return null;
} }
if (!triggerHandler.Trigger(@event.Payload, rule.Trigger)) if (!triggerHandler.Trigger(@event.Payload, rule.Trigger, ruleId))
{ {
return null; return null;
} }

7
src/Squidex.Domain.Apps.Core.Operations/HandleRules/RuleTriggerHandler.cs

@ -6,7 +6,6 @@
// ========================================================================== // ==========================================================================
using System; using System;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.HandleRules.EnrichedEvents; using Squidex.Domain.Apps.Core.HandleRules.EnrichedEvents;
using Squidex.Domain.Apps.Core.Rules; using Squidex.Domain.Apps.Core.Rules;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
@ -28,14 +27,14 @@ namespace Squidex.Domain.Apps.Core.HandleRules
return @event is TEnrichedEvent e && Trigger(e, (TTrigger)trigger); return @event is TEnrichedEvent e && Trigger(e, (TTrigger)trigger);
} }
bool IRuleTriggerHandler.Trigger(IEvent @event, RuleTrigger trigger) bool IRuleTriggerHandler.Trigger(IEvent @event, RuleTrigger trigger, Guid ruleId)
{ {
return @event is TEvent e && Trigger(e, (TTrigger)trigger); return @event is TEvent e && Trigger(e, (TTrigger)trigger, ruleId);
} }
protected abstract bool Trigger(TEnrichedEvent @event, TTrigger trigger); protected abstract bool Trigger(TEnrichedEvent @event, TTrigger trigger);
protected virtual bool Trigger(TEvent @event, TTrigger trigger) protected virtual bool Trigger(TEvent @event, TTrigger trigger, Guid ruleId)
{ {
return true; return true;
} }

1
src/Squidex.Domain.Apps.Core.Operations/HandleRules/Triggers/AssetChangedTriggerHandler.cs

@ -5,7 +5,6 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.HandleRules.EnrichedEvents; using Squidex.Domain.Apps.Core.HandleRules.EnrichedEvents;
using Squidex.Domain.Apps.Core.Rules.Triggers; using Squidex.Domain.Apps.Core.Rules.Triggers;
using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Core.Scripting;

2
src/Squidex.Domain.Apps.Core.Operations/HandleRules/Triggers/ContentChangedTriggerHandler.cs

@ -25,7 +25,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules.Triggers
this.scriptEngine = scriptEngine; this.scriptEngine = scriptEngine;
} }
protected override bool Trigger(ContentEvent @event, ContentChangedTriggerV2 trigger) protected override bool Trigger(ContentEvent @event, ContentChangedTriggerV2 trigger, Guid ruleId)
{ {
if (trigger.HandleAll) if (trigger.HandleAll)
{ {

4
src/Squidex.Domain.Apps.Core.Operations/HandleRules/Triggers/UsageTriggerHandler.cs

@ -5,11 +5,9 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.HandleRules.EnrichedEvents; using Squidex.Domain.Apps.Core.HandleRules.EnrichedEvents;
using Squidex.Domain.Apps.Core.Rules.Triggers; using Squidex.Domain.Apps.Core.Rules.Triggers;
using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events;
using Squidex.Infrastructure.EventSourcing;
namespace Squidex.Domain.Apps.Core.HandleRules.Triggers namespace Squidex.Domain.Apps.Core.HandleRules.Triggers
{ {
@ -17,7 +15,7 @@ namespace Squidex.Domain.Apps.Core.HandleRules.Triggers
{ {
protected override bool Trigger(EnrichedUsageExceededEvent @event, UsageTrigger trigger) protected override bool Trigger(EnrichedUsageExceededEvent @event, UsageTrigger trigger)
{ {
return true; return @event.Limit == trigger.Limit;
} }
} }
} }

2
src/Squidex.Domain.Apps.Entities/Apps/InviteUserCommandMiddleware.cs

@ -35,7 +35,7 @@ namespace Squidex.Domain.Apps.Entities.Apps
await next(); await next();
if (isInvited && context.Result<object>() is EntityCreatedResult<string> id) if (isInvited && context.PlainResult is EntityCreatedResult<string> id)
{ {
context.Complete(new InvitedResult { Id = id }); context.Complete(new InvitedResult { Id = id });
} }

2
src/Squidex.Domain.Apps.Entities/Rules/EventEnricher.cs

@ -72,7 +72,7 @@ namespace Squidex.Domain.Apps.Entities.Rules
case AppUsageExceeded usageExceeded: case AppUsageExceeded usageExceeded:
{ {
var result = new EnrichedUsageExceededEvent { Current = usageExceeded.Current, Limit = usageExceeded.Limit }; var result = new EnrichedUsageExceededEvent { Current = usageExceeded.CallsCurrent, Limit = usageExceeded.CallsLimit };
await EnrichDefaultAsync(result, @event); await EnrichDefaultAsync(result, @event);

2
src/Squidex.Domain.Apps.Entities/Rules/RuleEnqueuer.cs

@ -65,7 +65,7 @@ namespace Squidex.Domain.Apps.Entities.Rules
foreach (var ruleEntity in rules) foreach (var ruleEntity in rules)
{ {
var job = await ruleService.CreateJobAsync(ruleEntity.RuleDef, @event); var job = await ruleService.CreateJobAsync(ruleEntity.RuleDef, ruleEntity.Id, @event);
if (job != null) if (job != null)
{ {

10
src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/IUsageTrackerGrain.cs

@ -14,12 +14,14 @@ namespace Squidex.Domain.Apps.Entities.Rules.UsageTracking
{ {
public interface IUsageTrackerGrain : IGrainWithStringKey public interface IUsageTrackerGrain : IGrainWithStringKey
{ {
Task AddTargetAsync(NamedId<Guid> appId, int limits); Task AddTargetAsync(Guid ruleId, NamedId<Guid> appId, int limits);
Task ActivateTargetAsync(NamedId<Guid> appId); Task ActivateTargetAsync(Guid ruleId);
Task DeactivateTargetAsync(NamedId<Guid> appId); Task DeactivateTargetAsync(Guid ruleId);
Task RemoveTargetAsync(NamedId<Guid> appId); Task RemoveTargetAsync(Guid ruleId);
Task UpdateTargetAsync(Guid ruleId, int limits);
} }
} }

54
src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/UsageTrackerGrain.cs

@ -24,17 +24,19 @@ namespace Squidex.Domain.Apps.Entities.Rules.UsageTracking
public sealed class Target public sealed class Target
{ {
public int Limit { get; set; } public int Limits { get; set; }
public bool Enabled { get; set; } public bool Disabled { get; set; }
public DateTime Triggered { get; set; } public DateTime Triggered { get; set; }
public NamedId<Guid> AppId { get; set; }
} }
[CollectionName("UsageTracker")] [CollectionName("UsageTracker")]
public sealed class GrainState public sealed class GrainState
{ {
public Dictionary<NamedId<Guid>, Target> Targets { get; set; } = new Dictionary<NamedId<Guid>, Target>(); public Dictionary<Guid, Target> Targets { get; set; } = new Dictionary<Guid, Target>();
} }
public UsageTrackerGrain(IStore<string> store, IUsageTracker usageTracker) public UsageTrackerGrain(IStore<string> store, IUsageTracker usageTracker)
@ -60,19 +62,25 @@ namespace Squidex.Domain.Apps.Entities.Rules.UsageTracking
foreach (var kvp in State.Targets) foreach (var kvp in State.Targets)
{ {
var appId = kvp.Key; var appId = kvp.Value.AppId;
if (!IsSameMonth(today, kvp.Value.Triggered)) if (!IsSameMonth(today, kvp.Value.Triggered))
{ {
var usage = await usageTracker.GetMonthlyCallsAsync(appId.Id.ToString(), today); var usage = await usageTracker.GetMonthlyCallsAsync(appId.Id.ToString(), today);
var limit = kvp.Value.Limit; var limit = kvp.Value.Limits;
if (usage > limit) if (usage > limit)
{ {
kvp.Value.Triggered = today; kvp.Value.Triggered = today;
var @event = new AppUsageExceeded { AppId = appId, Current = usage, Limit = limit }; var @event = new AppUsageExceeded
{
AppId = appId,
CallsCurrent = usage,
CallsLimit = limit,
RuleId = kvp.Key
};
await Persistence.WriteEventAsync(@event); await Persistence.WriteEventAsync(@event);
} }
@ -87,37 +95,51 @@ namespace Squidex.Domain.Apps.Entities.Rules.UsageTracking
return lhs.Year == rhs.Year && lhs.Month == rhs.Month; return lhs.Year == rhs.Year && lhs.Month == rhs.Month;
} }
public Task ActivateTargetAsync(NamedId<Guid> appId) public Task AddTargetAsync(Guid ruleId, NamedId<Guid> appId, int limits)
{
UpdateTarget(ruleId, t => { t.Limits = limits; t.AppId = appId; });
return WriteStateAsync();
}
public Task UpdateTargetAsync(Guid ruleId, int limits)
{
UpdateTarget(ruleId, t => t.Limits = limits);
return WriteStateAsync();
}
public Task ActivateTargetAsync(Guid ruleId)
{ {
UpdateTarget(appId, t => t.Enabled = true); UpdateTarget(ruleId, t => t.Disabled = false);
return WriteStateAsync(); return WriteStateAsync();
} }
public Task DeactivateTargetAsync(NamedId<Guid> appId) public Task DeactivateTargetAsync(Guid ruleId)
{ {
UpdateTarget(appId, t => t.Enabled = false); UpdateTarget(ruleId, t => t.Disabled = true);
return WriteStateAsync(); return WriteStateAsync();
} }
public Task AddTargetAsync(NamedId<Guid> appId, int limits) public Task AddTargetAsync(Guid ruleId, int limits)
{ {
UpdateTarget(appId, t => t.Limit = limits); UpdateTarget(ruleId, t => t.Limits = limits);
return WriteStateAsync(); return WriteStateAsync();
} }
public Task RemoveTargetAsync(NamedId<Guid> appId) public Task RemoveTargetAsync(Guid ruleId)
{ {
State.Targets.Remove(appId); State.Targets.Remove(ruleId);
return WriteStateAsync(); return WriteStateAsync();
} }
private void UpdateTarget(NamedId<Guid> appId, Action<Target> updater) private void UpdateTarget(Guid ruleId, Action<Target> updater)
{ {
updater(State.Targets.GetOrAddNew(appId));; updater(State.Targets.GetOrAddNew(ruleId));
} }
} }
} }

69
src/Squidex.Domain.Apps.Entities/Rules/UsageTracking/UsageTriggerHandler.cs

@ -1,69 +0,0 @@
//// ==========================================================================
//// Squidex Headless CMS
//// ==========================================================================
//// Copyright (c) Squidex UG (haftungsbeschraenkt)
//// All rights reserved. Licensed under the MIT license.
//// ==========================================================================
//using System.Threading.Tasks;
//using Orleans;
//using Squidex.Domain.Apps.Core.HandleRules;
//using Squidex.Domain.Apps.Core.HandleRules.EnrichedEvents;
//using Squidex.Domain.Apps.Core.Rules.Triggers;
//using Squidex.Domain.Apps.Events;
//using Squidex.Domain.Apps.Events.Rules;
//using Squidex.Infrastructure;
//using Squidex.Infrastructure.Orleans;
//using Squidex.Infrastructure.Tasks;
//namespace Squidex.Domain.Apps.Entities.Rules.UsageTracking
//{
// public sealed class UsageTriggerHandler : RuleTriggerHandler<UsageTrigger, AppEvent, EnrichedUsageExceededEvent>
// {
// private readonly IUsageTrackerGrain usageTrackerGrain;
// public UsageTriggerHandler(IGrainFactory grainFactory)
// {
// Guard.NotNull(grainFactory, nameof(grainFactory));
// usageTrackerGrain = grainFactory.GetGrain<IUsageTrackerGrain>(SingleGrain.Id);
// }
// protected override async Task<bool> Trigger(AppEvent @event, UsageTrigger trigger)
// {
// switch (@event)
// {
// case RuleDeleted _:
// await usageTrackerGrain.RemoveTargetAsync(@event.AppId);
// break;
// case RuleEnabled _:
// await usageTrackerGrain.ActivateTargetAsync(@event.AppId);
// break;
// case RuleDisabled _:
// await usageTrackerGrain.DeactivateTargetAsync(@event.AppId);
// break;
// case RuleCreated ruleCreated:
// if (ruleCreated.Trigger is UsageTrigger createdTrigger)
// {
// await usageTrackerGrain.AddTargetAsync(ruleCreated.AppId, createdTrigger.Limit);
// }
// break;
// case RuleUpdated ruleUpdated:
// if (ruleUpdated.Trigger is UsageTrigger updatedTrigger)
// {
// await usageTrackerGrain.AddTargetAsync(ruleUpdated.AppId, updatedTrigger.Limit);
// }
// break;
// }
// return @event is AppUsageExceeded;
// }
// protected override Task<bool> Trigger(EnrichedUsageExceededEvent @event, UsageTrigger trigger)
// {
// return TaskHelper.True;
// }
// }
//}

7
src/Squidex.Domain.Apps.Events/AppUsageExceeded.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
namespace Squidex.Domain.Apps.Events namespace Squidex.Domain.Apps.Events
@ -12,8 +13,10 @@ namespace Squidex.Domain.Apps.Events
[EventType(nameof(AppUsageExceeded))] [EventType(nameof(AppUsageExceeded))]
public sealed class AppUsageExceeded : AppEvent public sealed class AppUsageExceeded : AppEvent
{ {
public long Current { get; set; } public long CallsCurrent { get; set; }
public long Limit { get; set; } public long CallsLimit { get; set; }
public Guid RuleId { get; set; }
} }
} }

5
src/Squidex.Infrastructure/Commands/CommandContext.cs

@ -19,6 +19,11 @@ namespace Squidex.Infrastructure.Commands
public ICommandBus CommandBus { get; } public ICommandBus CommandBus { get; }
public object PlainResult
{
get { return result?.Item1; }
}
public bool IsCompleted public bool IsCompleted
{ {
get { return result != null; } get { return result != null; }

5
src/Squidex/Areas/Api/Controllers/Apps/AppContributorsController.cs

@ -75,14 +75,13 @@ namespace Squidex.Areas.Api.Controllers.Apps
var command = request.ToCommand(); var command = request.ToCommand();
var context = await CommandBus.PublishAsync(command); var context = await CommandBus.PublishAsync(command);
var result = context.Result<object>();
var response = (ContributorAssignedDto)null; var response = (ContributorAssignedDto)null;
if (result is EntityCreatedResult<string> idOrValue) if (context.PlainResult is EntityCreatedResult<string> idOrValue)
{ {
response = ContributorAssignedDto.FromId(idOrValue.IdOrValue, false); response = ContributorAssignedDto.FromId(idOrValue.IdOrValue, false);
} }
else if (result is InvitedResult invited) else if (context.PlainResult is InvitedResult invited)
{ {
response = ContributorAssignedDto.FromId(invited.Id.IdOrValue, true); response = ContributorAssignedDto.FromId(invited.Id.IdOrValue, true);
} }

2
src/Squidex/Areas/Api/Controllers/Plans/AppPlansController.cs

@ -80,7 +80,7 @@ namespace Squidex.Areas.Api.Controllers.Plans
string redirectUri = null; string redirectUri = null;
if (context.Result<object>() is RedirectToCheckoutResult result) if (context.PlainResult is RedirectToCheckoutResult result)
{ {
redirectUri = result.Url.ToString(); redirectUri = result.Url.ToString();
} }

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

@ -54,7 +54,7 @@ namespace Squidex.Pipeline.CommandMiddlewares
await next(); await next();
if (context.Result<object>() is EntitySavedResult result) if (context.PlainResult is EntitySavedResult result)
{ {
httpContextAccessor.HttpContext.Response.Headers[HeaderNames.ETag] = result.Version.ToString(); httpContextAccessor.HttpContext.Response.Headers[HeaderNames.ETag] = result.Version.ToString();
} }

69
tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/RuleServiceTests.cs

@ -33,6 +33,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
private readonly string actionDump = "MyDump"; private readonly string actionDump = "MyDump";
private readonly string actionName = "ValidAction"; private readonly string actionName = "ValidAction";
private readonly string actionDescription = "MyDescription"; private readonly string actionDescription = "MyDescription";
private readonly Guid ruleId = Guid.NewGuid();
private readonly NamedId<Guid> appId = NamedId.Of(Guid.NewGuid(), "my-app"); private readonly NamedId<Guid> appId = NamedId.Of(Guid.NewGuid(), "my-app");
private readonly NamedId<Guid> schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); private readonly NamedId<Guid> schemaId = NamedId.Of(Guid.NewGuid(), "my-schema");
private readonly TypeNameRegistry typeNameRegistry = new TypeNameRegistry(); private readonly TypeNameRegistry typeNameRegistry = new TypeNameRegistry();
@ -87,10 +88,10 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
[Fact] [Fact]
public async Task Should_not_create_if_rule_disabled() public async Task Should_not_create_if_rule_disabled()
{ {
var ruleConfig = ValidRule().Disable(); var rule = ValidRule().Disable();
var ruleEnvelope = Envelope.Create(new ContentCreated()); var ruleEvent = Envelope.Create(new ContentCreated());
var job = await sut.CreateJobAsync(ruleConfig, ruleEnvelope); var job = await sut.CreateJobAsync(rule, ruleId, ruleEvent);
Assert.Null(job); Assert.Null(job);
@ -101,10 +102,10 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
[Fact] [Fact]
public async Task Should_not_create_job_for_invalid_event() public async Task Should_not_create_job_for_invalid_event()
{ {
var ruleConfig = ValidRule(); var rule = ValidRule();
var ruleEnvelope = Envelope.Create(new InvalidEvent()); var ruleEvent = Envelope.Create(new InvalidEvent());
var job = await sut.CreateJobAsync(ruleConfig, ruleEnvelope); var job = await sut.CreateJobAsync(rule, ruleId, ruleEvent);
Assert.Null(job); Assert.Null(job);
@ -115,10 +116,10 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
[Fact] [Fact]
public async Task Should_not_create_job_if_no_trigger_handler_registered() public async Task Should_not_create_job_if_no_trigger_handler_registered()
{ {
var ruleConfig = new Rule(new InvalidTrigger(), new ValidAction()); var rule = new Rule(new InvalidTrigger(), new ValidAction());
var ruleEnvelope = Envelope.Create(new ContentCreated()); var ruleEvent = Envelope.Create(new ContentCreated());
var job = await sut.CreateJobAsync(ruleConfig, ruleEnvelope); var job = await sut.CreateJobAsync(rule, ruleId, ruleEvent);
Assert.Null(job); Assert.Null(job);
@ -129,10 +130,10 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
[Fact] [Fact]
public async Task Should_not_create_job_if_no_action_handler_registered() public async Task Should_not_create_job_if_no_action_handler_registered()
{ {
var ruleConfig = new Rule(new ContentChangedTriggerV2(), new InvalidAction()); var rule = new Rule(new ContentChangedTriggerV2(), new InvalidAction());
var ruleEnvelope = Envelope.Create(new ContentCreated()); var ruleEvent = Envelope.Create(new ContentCreated());
var job = await sut.CreateJobAsync(ruleConfig, ruleEnvelope); var job = await sut.CreateJobAsync(rule, ruleId, ruleEvent);
Assert.Null(job); Assert.Null(job);
@ -143,13 +144,13 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
[Fact] [Fact]
public async Task Should_not_create_job_if_not_triggered_with_precheck() public async Task Should_not_create_job_if_not_triggered_with_precheck()
{ {
var ruleConfig = ValidRule(); var rule = ValidRule();
var ruleEnvelope = Envelope.Create(new ContentCreated()); var ruleEvent = Envelope.Create(new ContentCreated());
A.CallTo(() => ruleTriggerHandler.Trigger(A<IEvent>.Ignored, ruleConfig.Trigger)) A.CallTo(() => ruleTriggerHandler.Trigger(A<IEvent>.Ignored, rule.Trigger, ruleId))
.Returns(false); .Returns(false);
var job = await sut.CreateJobAsync(ruleConfig, ruleEnvelope); var job = await sut.CreateJobAsync(rule, ruleId, ruleEvent);
Assert.Null(job); Assert.Null(job);
@ -160,16 +161,16 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
[Fact] [Fact]
public async Task Should_not_create_job_if_not_triggered() public async Task Should_not_create_job_if_not_triggered()
{ {
var ruleConfig = ValidRule(); var rule = ValidRule();
var ruleEnvelope = Envelope.Create(new ContentCreated()); var ruleEvent = Envelope.Create(new ContentCreated());
A.CallTo(() => ruleTriggerHandler.Trigger(A<IEvent>.Ignored, ruleConfig.Trigger)) A.CallTo(() => ruleTriggerHandler.Trigger(A<IEvent>.Ignored, rule.Trigger, ruleId))
.Returns(true); .Returns(true);
A.CallTo(() => ruleTriggerHandler.Trigger(A<EnrichedEvent>.Ignored, ruleConfig.Trigger)) A.CallTo(() => ruleTriggerHandler.Trigger(A<EnrichedEvent>.Ignored, rule.Trigger))
.Returns(false); .Returns(false);
var job = await sut.CreateJobAsync(ruleConfig, ruleEnvelope); var job = await sut.CreateJobAsync(rule, ruleId, ruleEvent);
Assert.Null(job); Assert.Null(job);
} }
@ -177,22 +178,22 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
[Fact] [Fact]
public async Task Should_not_create_job_if_too_old() public async Task Should_not_create_job_if_too_old()
{ {
var @event = new ContentCreated { SchemaId = schemaId, AppId = appId }; var ruleEvent = new ContentCreated { SchemaId = schemaId, AppId = appId };
var now = SystemClock.Instance.GetCurrentInstant(); var now = SystemClock.Instance.GetCurrentInstant();
var ruleConfig = ValidRule(); var rule = ValidRule();
var ruleEnvelope = Envelope.Create(@event); var ruleEnvelope = Envelope.Create(ruleEvent);
ruleEnvelope.SetTimestamp(now.Minus(Duration.FromDays(3))); ruleEnvelope.SetTimestamp(now.Minus(Duration.FromDays(3)));
A.CallTo(() => clock.GetCurrentInstant()) A.CallTo(() => clock.GetCurrentInstant())
.Returns(now); .Returns(now);
A.CallTo(() => ruleActionHandler.CreateJobAsync(A<EnrichedEvent>.Ignored, ruleConfig.Action)) A.CallTo(() => ruleActionHandler.CreateJobAsync(A<EnrichedEvent>.Ignored, rule.Action))
.Returns((actionDescription, actionData)); .Returns((actionDescription, actionData));
var job = await sut.CreateJobAsync(ruleConfig, ruleEnvelope); var job = await sut.CreateJobAsync(rule, ruleId, ruleEnvelope);
Assert.Null(job); Assert.Null(job);
@ -203,28 +204,28 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
[Fact] [Fact]
public async Task Should_create_job_if_triggered() public async Task Should_create_job_if_triggered()
{ {
var @event = new ContentCreated { SchemaId = schemaId, AppId = appId }; var ruleEvent = new ContentCreated { SchemaId = schemaId, AppId = appId };
var now = Instant.FromUnixTimeSeconds(SystemClock.Instance.GetCurrentInstant().ToUnixTimeSeconds()); var now = Instant.FromUnixTimeSeconds(SystemClock.Instance.GetCurrentInstant().ToUnixTimeSeconds());
var ruleConfig = ValidRule(); var rule = ValidRule();
var ruleEnvelope = Envelope.Create(@event); var ruleEnvelope = Envelope.Create(ruleEvent);
ruleEnvelope.SetTimestamp(now); ruleEnvelope.SetTimestamp(now);
A.CallTo(() => clock.GetCurrentInstant()) A.CallTo(() => clock.GetCurrentInstant())
.Returns(now); .Returns(now);
A.CallTo(() => ruleTriggerHandler.Trigger(A<EnrichedEvent>.Ignored, ruleConfig.Trigger)) A.CallTo(() => ruleTriggerHandler.Trigger(A<EnrichedEvent>.Ignored, rule.Trigger))
.Returns(true); .Returns(true);
A.CallTo(() => ruleTriggerHandler.Trigger(A<IEvent>.Ignored, ruleConfig.Trigger)) A.CallTo(() => ruleTriggerHandler.Trigger(A<IEvent>.Ignored, rule.Trigger, ruleId))
.Returns(true); .Returns(true);
A.CallTo(() => ruleActionHandler.CreateJobAsync(A<EnrichedEvent>.Ignored, ruleConfig.Action)) A.CallTo(() => ruleActionHandler.CreateJobAsync(A<EnrichedEvent>.Ignored, rule.Action))
.Returns((actionDescription, new ValidData { Value = 10 })); .Returns((actionDescription, new ValidData { Value = 10 }));
var job = await sut.CreateJobAsync(ruleConfig, ruleEnvelope); var job = await sut.CreateJobAsync(rule, ruleId, ruleEnvelope);
Assert.Equal(actionData, job.ActionData); Assert.Equal(actionData, job.ActionData);
Assert.Equal(actionName, job.ActionName); Assert.Equal(actionName, job.ActionName);
@ -233,7 +234,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules
Assert.Equal(now, job.Created); Assert.Equal(now, job.Created);
Assert.Equal(now.Plus(Duration.FromDays(2)), job.Expires); Assert.Equal(now.Plus(Duration.FromDays(2)), job.Expires);
Assert.Equal(@event.AppId.Id, job.AppId); Assert.Equal(ruleEvent.AppId.Id, job.AppId);
Assert.NotEqual(Guid.Empty, job.JobId); Assert.NotEqual(Guid.Empty, job.JobId);
} }

4
tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/Triggers/AssetChangedTriggerTests.cs

@ -39,7 +39,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules.Triggers
{ {
TestForCondition(string.Empty, trigger => TestForCondition(string.Empty, trigger =>
{ {
var result = sut.Trigger(new ContentCreated(), trigger); var result = sut.Trigger(new ContentCreated(), trigger, Guid.NewGuid());
Assert.False(result); Assert.False(result);
}); });
@ -50,7 +50,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules.Triggers
{ {
TestForCondition(string.Empty, trigger => TestForCondition(string.Empty, trigger =>
{ {
var result = sut.Trigger(new AssetCreated(), trigger); var result = sut.Trigger(new AssetCreated(), trigger, Guid.NewGuid());
Assert.True(result); Assert.True(result);
}); });

11
tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/Triggers/ContentChangedTriggerTests.cs

@ -28,6 +28,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules.Triggers
{ {
private readonly IScriptEngine scriptEngine = A.Fake<IScriptEngine>(); private readonly IScriptEngine scriptEngine = A.Fake<IScriptEngine>();
private readonly IRuleTriggerHandler sut; private readonly IRuleTriggerHandler sut;
private readonly Guid ruleId = Guid.NewGuid();
private static readonly NamedId<Guid> SchemaMatch = NamedId.Of(Guid.NewGuid(), "my-schema1"); private static readonly NamedId<Guid> SchemaMatch = NamedId.Of(Guid.NewGuid(), "my-schema1");
private static readonly NamedId<Guid> SchemaNonMatch = NamedId.Of(Guid.NewGuid(), "my-schema2"); private static readonly NamedId<Guid> SchemaNonMatch = NamedId.Of(Guid.NewGuid(), "my-schema2");
@ -47,7 +48,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules.Triggers
{ {
TestForTrigger(handleAll: true, schemaId: null, condition: null, action: trigger => TestForTrigger(handleAll: true, schemaId: null, condition: null, action: trigger =>
{ {
var result = sut.Trigger(new AssetCreated(), trigger); var result = sut.Trigger(new AssetCreated(), trigger, ruleId);
Assert.False(result); Assert.False(result);
}); });
@ -58,7 +59,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules.Triggers
{ {
TestForTrigger(handleAll: false, schemaId: null, condition: null, action: trigger => TestForTrigger(handleAll: false, schemaId: null, condition: null, action: trigger =>
{ {
var result = sut.Trigger(new ContentCreated { SchemaId = SchemaMatch }, trigger); var result = sut.Trigger(new ContentCreated { SchemaId = SchemaMatch }, trigger, ruleId);
Assert.False(result); Assert.False(result);
}); });
@ -69,7 +70,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules.Triggers
{ {
TestForTrigger(handleAll: true, schemaId: SchemaMatch, condition: null, action: trigger => TestForTrigger(handleAll: true, schemaId: SchemaMatch, condition: null, action: trigger =>
{ {
var result = sut.Trigger(new ContentCreated { SchemaId = SchemaMatch }, trigger); var result = sut.Trigger(new ContentCreated { SchemaId = SchemaMatch }, trigger, ruleId);
Assert.True(result); Assert.True(result);
}); });
@ -80,7 +81,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules.Triggers
{ {
TestForTrigger(handleAll: false, schemaId: SchemaMatch, condition: string.Empty, action: trigger => TestForTrigger(handleAll: false, schemaId: SchemaMatch, condition: string.Empty, action: trigger =>
{ {
var result = sut.Trigger(new ContentCreated { SchemaId = SchemaMatch }, trigger); var result = sut.Trigger(new ContentCreated { SchemaId = SchemaMatch }, trigger, ruleId);
Assert.True(result); Assert.True(result);
}); });
@ -91,7 +92,7 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules.Triggers
{ {
TestForTrigger(handleAll: false, schemaId: SchemaNonMatch, condition: null, action: trigger => TestForTrigger(handleAll: false, schemaId: SchemaNonMatch, condition: null, action: trigger =>
{ {
var result = sut.Trigger(new ContentCreated { SchemaId = SchemaMatch }, trigger); var result = sut.Trigger(new ContentCreated { SchemaId = SchemaMatch }, trigger, ruleId);
Assert.False(result); Assert.False(result);
}); });

20
tests/Squidex.Domain.Apps.Core.Tests/Operations/HandleRules/Triggers/UsageTriggerHandlerTests.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System;
using Squidex.Domain.Apps.Core.HandleRules; using Squidex.Domain.Apps.Core.HandleRules;
using Squidex.Domain.Apps.Core.HandleRules.EnrichedEvents; using Squidex.Domain.Apps.Core.HandleRules.EnrichedEvents;
using Squidex.Domain.Apps.Core.HandleRules.Triggers; using Squidex.Domain.Apps.Core.HandleRules.Triggers;
@ -17,38 +18,39 @@ namespace Squidex.Domain.Apps.Core.Operations.HandleRules.Triggers
{ {
public class UsageTriggerHandlerTests public class UsageTriggerHandlerTests
{ {
private readonly Guid ruleId = Guid.NewGuid();
private readonly IRuleTriggerHandler sut = new UsageTriggerHandler(); private readonly IRuleTriggerHandler sut = new UsageTriggerHandler();
[Fact] [Fact]
public void Should_not_trigger_precheck_when_event_type_not_correct() public void Should_not_trigger_precheck_when_event_type_not_correct()
{ {
var result = sut.Trigger(new ContentCreated(), new UsageTrigger()); var result = sut.Trigger(new ContentCreated(), new UsageTrigger(), ruleId);
Assert.False(result); Assert.False(result);
} }
[Fact] [Fact]
public void Should_trigger_precheck_when_event_type_correct() public void Should_not_trigger_precheck_when_rule_id_not_matchs()
{ {
var result = sut.Trigger(new AppUsageExceeded(), new UsageTrigger()); var result = sut.Trigger(new AppUsageExceeded { RuleId = Guid.NewGuid() }, new UsageTrigger(), ruleId);
Assert.True(result); Assert.True(result);
} }
[Fact] [Fact]
public void Should_not_trigger_check_when_event_type_not_correct() public void Should_trigger_precheck_when_event_type_correct_and_rule_id_matchs()
{ {
var result = sut.Trigger(new EnrichedContentEvent(), new UsageTrigger()); var result = sut.Trigger(new AppUsageExceeded { RuleId = ruleId }, new UsageTrigger(), ruleId);
Assert.False(result); Assert.True(result);
} }
[Fact] [Fact]
public void Should_trigger_check_when_type_correct() public void Should_not_trigger_check_when_event_type_not_correct()
{ {
var result = sut.Trigger(new AppUsageExceeded(), new UsageTrigger()); var result = sut.Trigger(new EnrichedContentEvent(), new UsageTrigger());
Assert.True(result); Assert.False(result);
} }
} }
} }

18
tests/Squidex.Domain.Apps.Entities.Tests/Rules/RuleEnqueuerTests.cs

@ -28,9 +28,9 @@ namespace Squidex.Domain.Apps.Entities.Rules
private readonly IAppProvider appProvider = A.Fake<IAppProvider>(); private readonly IAppProvider appProvider = A.Fake<IAppProvider>();
private readonly IMemoryCache cache = new MemoryCache(Options.Create(new MemoryCacheOptions())); private readonly IMemoryCache cache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
private readonly IRuleEventRepository ruleEventRepository = A.Fake<IRuleEventRepository>(); private readonly IRuleEventRepository ruleEventRepository = A.Fake<IRuleEventRepository>();
private readonly RuleService ruleService = A.Fake<RuleService>();
private readonly Instant now = SystemClock.Instance.GetCurrentInstant(); private readonly Instant now = SystemClock.Instance.GetCurrentInstant();
private readonly NamedId<Guid> appId = NamedId.Of(Guid.NewGuid(), "my-app"); private readonly NamedId<Guid> appId = NamedId.Of(Guid.NewGuid(), "my-app");
private readonly RuleService ruleService = A.Fake<RuleService>();
private readonly RuleEnqueuer sut; private readonly RuleEnqueuer sut;
public sealed class TestAction : RuleAction public sealed class TestAction : RuleAction
@ -72,38 +72,28 @@ namespace Squidex.Domain.Apps.Entities.Rules
var rule1 = new Rule(new ContentChangedTriggerV2(), new TestAction { Url = new Uri("https://squidex.io") }); var rule1 = new Rule(new ContentChangedTriggerV2(), new TestAction { Url = new Uri("https://squidex.io") });
var rule2 = new Rule(new ContentChangedTriggerV2(), new TestAction { Url = new Uri("https://squidex.io") }); var rule2 = new Rule(new ContentChangedTriggerV2(), new TestAction { Url = new Uri("https://squidex.io") });
var rule3 = new Rule(new ContentChangedTriggerV2(), new TestAction { Url = new Uri("https://squidex.io") });
var job1 = new RuleJob { Created = now }; var job1 = new RuleJob { Created = now };
var job2 = new RuleJob { Created = now };
var ruleEntity1 = A.Fake<IRuleEntity>(); var ruleEntity1 = A.Fake<IRuleEntity>();
var ruleEntity2 = A.Fake<IRuleEntity>(); var ruleEntity2 = A.Fake<IRuleEntity>();
var ruleEntity3 = A.Fake<IRuleEntity>();
A.CallTo(() => ruleEntity1.RuleDef).Returns(rule1); A.CallTo(() => ruleEntity1.RuleDef).Returns(rule1);
A.CallTo(() => ruleEntity2.RuleDef).Returns(rule2); A.CallTo(() => ruleEntity2.RuleDef).Returns(rule2);
A.CallTo(() => ruleEntity3.RuleDef).Returns(rule3);
A.CallTo(() => appProvider.GetRulesAsync(appId.Id)) A.CallTo(() => appProvider.GetRulesAsync(appId.Id))
.Returns(new List<IRuleEntity> { ruleEntity1, ruleEntity2, ruleEntity3 }); .Returns(new List<IRuleEntity> { ruleEntity1, ruleEntity2 });
A.CallTo(() => ruleService.CreateJobAsync(rule1, @event)) A.CallTo(() => ruleService.CreateJobAsync(rule1, ruleEntity1.Id, @event))
.Returns(job1); .Returns(job1);
A.CallTo(() => ruleService.CreateJobAsync(rule2, @event)) A.CallTo(() => ruleService.CreateJobAsync(rule2, ruleEntity2.Id, @event))
.Returns(job2);
A.CallTo(() => ruleService.CreateJobAsync(rule3, @event))
.Returns(Task.FromResult<RuleJob>(null)); .Returns(Task.FromResult<RuleJob>(null));
await sut.On(@event); await sut.On(@event);
A.CallTo(() => ruleEventRepository.EnqueueAsync(job1, now)) A.CallTo(() => ruleEventRepository.EnqueueAsync(job1, now))
.MustHaveHappened(); .MustHaveHappened();
A.CallTo(() => ruleEventRepository.EnqueueAsync(job2, now))
.MustHaveHappened();
} }
} }
} }

19
tests/Squidex.Infrastructure.Tests/Commands/CommandContextTests.cs

@ -26,8 +26,13 @@ namespace Squidex.Infrastructure.Commands
public void Should_instantiate_and_provide_command() public void Should_instantiate_and_provide_command()
{ {
Assert.Equal(command, sut.Command); Assert.Equal(command, sut.Command);
Assert.False(sut.IsCompleted);
Assert.Null(sut.PlainResult);
Assert.Null(sut.Result<string>());
Assert.NotEqual(Guid.Empty, sut.ContextId); Assert.NotEqual(Guid.Empty, sut.ContextId);
Assert.False(sut.IsCompleted);
} }
[Fact] [Fact]
@ -39,9 +44,19 @@ namespace Squidex.Infrastructure.Commands
} }
[Fact] [Fact]
public void Should_provide_result_valid_when_succeeded_with_value() public void Should_provide_result_when_succeeded_with_value()
{
sut.Complete("RESULT");
Assert.Equal("RESULT", sut.Result<string>());
}
[Fact]
public void Should_provide_plain_result_when_succeeded_with_value()
{ {
sut.Complete("RESULT"); sut.Complete("RESULT");
Assert.Equal("RESULT", sut.PlainResult);
} }
} }
} }

Loading…
Cancel
Save