mirror of https://github.com/Squidex/squidex.git
7 changed files with 379 additions and 3 deletions
@ -0,0 +1,229 @@ |
|||||
|
// ==========================================================================
|
||||
|
// RuleServiceTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using FakeItEasy; |
||||
|
using NodaTime; |
||||
|
using Squidex.Domain.Apps.Core.HandleRules; |
||||
|
using Squidex.Domain.Apps.Core.Rules; |
||||
|
using Squidex.Domain.Apps.Core.Rules.Actions; |
||||
|
using Squidex.Domain.Apps.Core.Rules.Triggers; |
||||
|
using Squidex.Domain.Apps.Events; |
||||
|
using Squidex.Domain.Apps.Events.Contents; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Events; |
||||
|
using Xunit; |
||||
|
|
||||
|
#pragma warning disable xUnit2009 // Do not use boolean check to check for string equality
|
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.Operations.HandleRules |
||||
|
{ |
||||
|
public class RuleServiceTests |
||||
|
{ |
||||
|
private readonly IRuleTriggerHandler ruleTriggerHandler = A.Fake<IRuleTriggerHandler>(); |
||||
|
private readonly IRuleActionHandler ruleActionHandler = A.Fake<IRuleActionHandler>(); |
||||
|
private readonly IClock clock = A.Fake<IClock>(); |
||||
|
private readonly TypeNameRegistry typeNameRegistry = new TypeNameRegistry(); |
||||
|
private readonly RuleService sut; |
||||
|
|
||||
|
public sealed class InvalidEvent : IEvent |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public sealed class InvalidAction : RuleAction |
||||
|
{ |
||||
|
public override T Accept<T>(IRuleActionVisitor<T> visitor) |
||||
|
{ |
||||
|
return default(T); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public sealed class InvalidTrigger : RuleTrigger |
||||
|
{ |
||||
|
public override T Accept<T>(IRuleTriggerVisitor<T> visitor) |
||||
|
{ |
||||
|
return default(T); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public RuleServiceTests() |
||||
|
{ |
||||
|
typeNameRegistry.Map(typeof(ContentCreated)); |
||||
|
typeNameRegistry.Map(typeof(WebhookAction)); |
||||
|
|
||||
|
A.CallTo(() => ruleActionHandler.ActionType) |
||||
|
.Returns(typeof(WebhookAction)); |
||||
|
|
||||
|
A.CallTo(() => ruleTriggerHandler.TriggerType) |
||||
|
.Returns(typeof(ContentChangedTrigger)); |
||||
|
|
||||
|
sut = new RuleService(new[] { ruleTriggerHandler }, new[] { ruleActionHandler }, clock, typeNameRegistry); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_not_create_job_for_invalid_event() |
||||
|
{ |
||||
|
var ruleConfig = new Rule(new ContentChangedTrigger(), new WebhookAction()); |
||||
|
var ruleEnvelope = Envelope.Create(new InvalidEvent()); |
||||
|
|
||||
|
var job = sut.CreateJob(ruleConfig, ruleEnvelope); |
||||
|
|
||||
|
Assert.Null(job); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_not_create_trigger_if_no_trigger_handler_registered() |
||||
|
{ |
||||
|
var ruleConfig = new Rule(new InvalidTrigger(), new WebhookAction()); |
||||
|
var ruleEnvelope = Envelope.Create(new ContentCreated()); |
||||
|
|
||||
|
var job = sut.CreateJob(ruleConfig, ruleEnvelope); |
||||
|
|
||||
|
Assert.Null(job); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_not_create_trigger_if_no_action_handler_registered() |
||||
|
{ |
||||
|
var ruleConfig = new Rule(new ContentChangedTrigger(), new InvalidAction()); |
||||
|
var ruleEnvelope = Envelope.Create(new ContentCreated()); |
||||
|
|
||||
|
var job = sut.CreateJob(ruleConfig, ruleEnvelope); |
||||
|
|
||||
|
Assert.Null(job); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_not_create_if_not_triggered() |
||||
|
{ |
||||
|
var ruleConfig = new Rule(new ContentChangedTrigger(), new InvalidAction()); |
||||
|
var ruleEnvelope = Envelope.Create(new ContentCreated()); |
||||
|
|
||||
|
A.CallTo(() => ruleTriggerHandler.Triggers(A<Envelope<AppEvent>>.Ignored, ruleConfig.Trigger)) |
||||
|
.Returns(false); |
||||
|
|
||||
|
var job = sut.CreateJob(ruleConfig, ruleEnvelope); |
||||
|
|
||||
|
Assert.Null(job); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_job_if_triggeres() |
||||
|
{ |
||||
|
var e = new ContentCreated { SchemaId = new NamedId<Guid>(Guid.NewGuid(), "my-schema"), AppId = new NamedId<Guid>(Guid.NewGuid(), "my-event") }; |
||||
|
|
||||
|
var now = SystemClock.Instance.GetCurrentInstant(); |
||||
|
|
||||
|
var ruleConfig = new Rule(new ContentChangedTrigger(), new WebhookAction()); |
||||
|
var ruleEnvelope = Envelope.Create(e); |
||||
|
|
||||
|
var actionName = "WebhookAction"; |
||||
|
var actionData = new RuleJobData(); |
||||
|
var actionDescription = "MyDescription"; |
||||
|
|
||||
|
var eventName = "MySchemaCreatedEvent"; |
||||
|
|
||||
|
A.CallTo(() => clock.GetCurrentInstant()) |
||||
|
.Returns(now); |
||||
|
|
||||
|
A.CallTo(() => ruleTriggerHandler.Triggers(A<Envelope<AppEvent>>.Ignored, ruleConfig.Trigger)) |
||||
|
.Returns(true); |
||||
|
|
||||
|
A.CallTo(() => ruleActionHandler.CreateJob(A<Envelope<AppEvent>>.Ignored, eventName, ruleConfig.Action)) |
||||
|
.Returns((actionDescription, actionData)); |
||||
|
|
||||
|
var job = sut.CreateJob(ruleConfig, ruleEnvelope); |
||||
|
|
||||
|
Assert.Equal(eventName, job.EventName); |
||||
|
|
||||
|
Assert.Equal(actionData, job.ActionData); |
||||
|
Assert.Equal(actionName, job.ActionName); |
||||
|
Assert.Equal(actionDescription, job.Description); |
||||
|
|
||||
|
Assert.Equal(now, job.Created); |
||||
|
Assert.Equal(now.Plus(Duration.FromDays(2)), job.Expires); |
||||
|
|
||||
|
Assert.Equal(e.AppId.Id, job.AppId); |
||||
|
|
||||
|
Assert.NotEqual(Guid.Empty, job.RuleId); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_return_succeeded_job_with_full_dump_when_handler_returns_no_exception() |
||||
|
{ |
||||
|
var ruleJob = new RuleJobData(); |
||||
|
var ruleEx = new InvalidOperationException(); |
||||
|
|
||||
|
var actionDump = "MyDump"; |
||||
|
|
||||
|
A.CallTo(() => ruleActionHandler.ExecuteJobAsync(ruleJob)) |
||||
|
.Returns((actionDump, null)); |
||||
|
|
||||
|
var result = await sut.InvokeAsync("WebhookAction", ruleJob); |
||||
|
|
||||
|
Assert.Equal(RuleResult.Success, result.Result); |
||||
|
|
||||
|
Assert.True(result.Elapsed >= TimeSpan.Zero); |
||||
|
Assert.StartsWith(actionDump, result.Dump, StringComparison.OrdinalIgnoreCase); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_return_failed_job_with_full_dump_when_handler_returns_exception() |
||||
|
{ |
||||
|
var ruleJob = new RuleJobData(); |
||||
|
var ruleEx = new InvalidOperationException(); |
||||
|
|
||||
|
var actionDump = "MyDump"; |
||||
|
|
||||
|
A.CallTo(() => ruleActionHandler.ExecuteJobAsync(ruleJob)) |
||||
|
.Returns((actionDump, new InvalidOperationException())); |
||||
|
|
||||
|
var result = await sut.InvokeAsync("WebhookAction", ruleJob); |
||||
|
|
||||
|
Assert.Equal(RuleResult.Failed, result.Result); |
||||
|
|
||||
|
Assert.True(result.Elapsed >= TimeSpan.Zero); |
||||
|
Assert.True(result.Dump.StartsWith(actionDump, StringComparison.OrdinalIgnoreCase)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_return_timedout_job_with_full_dump_when_exception_from_handler_indicates_timeout() |
||||
|
{ |
||||
|
var ruleJob = new RuleJobData(); |
||||
|
var ruleEx = new InvalidOperationException(); |
||||
|
|
||||
|
var actionDump = "MyDump"; |
||||
|
|
||||
|
A.CallTo(() => ruleActionHandler.ExecuteJobAsync(ruleJob)) |
||||
|
.Returns((actionDump, new TimeoutException())); |
||||
|
|
||||
|
var result = await sut.InvokeAsync("WebhookAction", ruleJob); |
||||
|
|
||||
|
Assert.Equal(RuleResult.Timeout, result.Result); |
||||
|
|
||||
|
Assert.True(result.Elapsed >= TimeSpan.Zero); |
||||
|
Assert.True(result.Dump.StartsWith(actionDump, StringComparison.OrdinalIgnoreCase)); |
||||
|
Assert.True(result.Dump.IndexOf("Action timed out.", StringComparison.OrdinalIgnoreCase) >= 0); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_create_exception_details_when_job_to_execute_failed() |
||||
|
{ |
||||
|
var ruleJob = new RuleJobData(); |
||||
|
var ruleEx = new InvalidOperationException(); |
||||
|
|
||||
|
A.CallTo(() => ruleActionHandler.ExecuteJobAsync(ruleJob)) |
||||
|
.Throws(ruleEx); |
||||
|
|
||||
|
var result = await sut.InvokeAsync("WebhookAction", ruleJob); |
||||
|
|
||||
|
Assert.Equal((ruleEx.ToString(), RuleResult.Failed, TimeSpan.Zero), result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,88 @@ |
|||||
|
// ==========================================================================
|
||||
|
// ContentChangedTriggerTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Squidex.Domain.Apps.Core.Contents; |
||||
|
using Squidex.Domain.Apps.Core.HandleRules; |
||||
|
using Squidex.Domain.Apps.Core.HandleRules.Triggers; |
||||
|
using Squidex.Domain.Apps.Core.Rules.Triggers; |
||||
|
using Squidex.Domain.Apps.Events; |
||||
|
using Squidex.Domain.Apps.Events.Contents; |
||||
|
using Squidex.Domain.Apps.Events.Rules; |
||||
|
using Squidex.Domain.Apps.Events.Schemas; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.CQRS.Events; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Core.Operations.HandleRules.Triggers |
||||
|
{ |
||||
|
public sealed class ContentChangedTriggerTests |
||||
|
{ |
||||
|
private readonly IRuleTriggerHandler sut = new ContentChangedTriggerHandler(); |
||||
|
private static readonly NamedId<Guid> SchemaMatch = new NamedId<Guid>(Guid.NewGuid(), "my-schema1"); |
||||
|
private static readonly NamedId<Guid> SchemaNonMatch = new NamedId<Guid>(Guid.NewGuid(), "my-schema2"); |
||||
|
|
||||
|
public static IEnumerable<object[]> TestData |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
return new[] |
||||
|
{ |
||||
|
new object[] { 0, 1, 1, 1, 1, new RuleCreated() }, |
||||
|
new object[] { 0, 1, 1, 1, 1, new ContentCreated { SchemaId = SchemaNonMatch } }, |
||||
|
new object[] { 1, 1, 0, 0, 0, new ContentCreated { SchemaId = SchemaMatch } }, |
||||
|
new object[] { 0, 0, 0, 0, 0, new ContentCreated { SchemaId = SchemaMatch } }, |
||||
|
new object[] { 1, 0, 1, 0, 0, new ContentUpdated { SchemaId = SchemaMatch } }, |
||||
|
new object[] { 0, 0, 0, 0, 0, new ContentUpdated { SchemaId = SchemaMatch } }, |
||||
|
new object[] { 1, 0, 0, 1, 0, new ContentDeleted { SchemaId = SchemaMatch } }, |
||||
|
new object[] { 0, 0, 0, 0, 0, new ContentDeleted { SchemaId = SchemaMatch } }, |
||||
|
new object[] { 1, 0, 0, 0, 1, new ContentStatusChanged { SchemaId = SchemaMatch, Status = Status.Published } }, |
||||
|
new object[] { 0, 0, 0, 0, 0, new ContentStatusChanged { SchemaId = SchemaMatch, Status = Status.Published } }, |
||||
|
new object[] { 0, 1, 1, 1, 1, new ContentStatusChanged { SchemaId = SchemaMatch, Status = Status.Archived } }, |
||||
|
new object[] { 0, 1, 1, 1, 1, new ContentStatusChanged { SchemaId = SchemaMatch, Status = Status.Draft } }, |
||||
|
new object[] { 0, 1, 1, 1, 1, new SchemaCreated { SchemaId = SchemaNonMatch } } |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_return_false_when_trigger_contains_no_schemas() |
||||
|
{ |
||||
|
var trigger = new ContentChangedTrigger(); |
||||
|
|
||||
|
var result = sut.Triggers(new Envelope<AppEvent>(new ContentCreated()), trigger); |
||||
|
|
||||
|
Assert.False(result); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[MemberData(nameof(TestData))] |
||||
|
public void Should_return_result_depending_on_event(int expected, int sendCreate, int sendUpdate, int sendDelete, int sendPublish, AppEvent @event) |
||||
|
{ |
||||
|
var trigger = new ContentChangedTrigger |
||||
|
{ |
||||
|
Schemas = new List<ContentChangedTriggerSchema> |
||||
|
{ |
||||
|
new ContentChangedTriggerSchema |
||||
|
{ |
||||
|
SendCreate = sendCreate == 1, |
||||
|
SendUpdate = sendUpdate == 1, |
||||
|
SendDelete = sendDelete == 1, |
||||
|
SendPublish = sendPublish == 1, |
||||
|
SchemaId = SchemaMatch.Id |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var result = sut.Triggers(new Envelope<AppEvent>(@event), trigger); |
||||
|
|
||||
|
Assert.Equal(expected == 1, result); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue