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