Browse Source

Cleanup

pull/206/head
Sebastian Stehle 8 years ago
parent
commit
ee713b7bb4
  1. 31
      tests/Benchmarks/Benchmark.cs
  2. 26
      tests/Benchmarks/Benchmarks.csproj
  3. 96
      tests/Benchmarks/Program.cs
  4. 7
      tests/Benchmarks/Properties/launchSettings.json
  5. 145
      tests/Benchmarks/Services.cs
  6. 53
      tests/Benchmarks/Tests/AppendToEventStore.cs
  7. 52
      tests/Benchmarks/Tests/AppendToEventStoreWithManyWriters.cs
  8. 63
      tests/Benchmarks/Tests/HandleEvents.cs
  9. 70
      tests/Benchmarks/Tests/HandleEventsWithManyWriters.cs
  10. 102
      tests/Benchmarks/Tests/ReadSchemaState.cs
  11. 42
      tests/Benchmarks/Tests/TestData/MyAppState.cs
  12. 19
      tests/Benchmarks/Tests/TestData/MyEvent.cs
  13. 79
      tests/Benchmarks/Tests/TestData/MyEventConsumer.cs
  14. 21
      tests/Benchmarks/Utils/Helper.cs
  15. 51
      tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppEventTests.cs
  16. 70
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentEventTests.cs
  17. 3
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTests.cs
  18. 2
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/OData/ODataQueryTests.cs
  19. 150
      tests/Squidex.Domain.Apps.Read.Tests/Apps/ConfigAppLimitsProviderTests.cs
  20. 38
      tests/Squidex.Domain.Apps.Read.Tests/Apps/NoopAppPlanBillingManagerTests.cs
  21. 220
      tests/Squidex.Domain.Apps.Read.Tests/Contents/ContentQueryServiceTests.cs
  22. 689
      tests/Squidex.Domain.Apps.Read.Tests/Contents/GraphQLTests.cs
  23. 392
      tests/Squidex.Domain.Apps.Read.Tests/Contents/ODataQueryTests.cs
  24. 50
      tests/Squidex.Domain.Apps.Read.Tests/Contents/TestData/FakeAssetEntity.cs
  25. 33
      tests/Squidex.Domain.Apps.Read.Tests/Contents/TestData/FakeContentEntity.cs
  26. 40
      tests/Squidex.Domain.Apps.Read.Tests/Contents/TestData/FakeUrlGenerator.cs
  27. 99
      tests/Squidex.Domain.Apps.Read.Tests/Rules/RuleDequeuerTests.cs
  28. 102
      tests/Squidex.Domain.Apps.Read.Tests/Rules/RuleEnqueuerTests.cs
  29. 37
      tests/Squidex.Domain.Apps.Read.Tests/Squidex.Domain.Apps.Read.Tests.csproj
  30. 244
      tests/Squidex.Domain.Apps.Write.Tests/Apps/AppCommandMiddlewareTests.cs
  31. 288
      tests/Squidex.Domain.Apps.Write.Tests/Apps/AppDomainObjectTests.cs
  32. 51
      tests/Squidex.Domain.Apps.Write.Tests/Apps/AppEventTests.cs
  33. 142
      tests/Squidex.Domain.Apps.Write.Tests/Apps/Guards/GuardAppClientsTests.cs
  34. 158
      tests/Squidex.Domain.Apps.Write.Tests/Apps/Guards/GuardAppContributorsTests.cs
  35. 131
      tests/Squidex.Domain.Apps.Write.Tests/Apps/Guards/GuardAppLanguagesTests.cs
  36. 120
      tests/Squidex.Domain.Apps.Write.Tests/Apps/Guards/GuardAppTests.cs
  37. 139
      tests/Squidex.Domain.Apps.Write.Tests/Assets/AssetCommandMiddlewareTests.cs
  38. 213
      tests/Squidex.Domain.Apps.Write.Tests/Assets/AssetDomainObjectTests.cs
  39. 65
      tests/Squidex.Domain.Apps.Write.Tests/Assets/Guards/GuardAssetTests.cs
  40. 247
      tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentCommandMiddlewareTests.cs
  41. 280
      tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentDomainObjectTests.cs
  42. 70
      tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentEventTests.cs
  43. 140
      tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentVersionLoaderTests.cs
  44. 99
      tests/Squidex.Domain.Apps.Write.Tests/Contents/Guard/GuardContentTests.cs
  45. 48
      tests/Squidex.Domain.Apps.Write.Tests/Rules/Guards/Actions/WebhookActionTests.cs
  46. 168
      tests/Squidex.Domain.Apps.Write.Tests/Rules/Guards/GuardRuleTests.cs
  47. 84
      tests/Squidex.Domain.Apps.Write.Tests/Rules/Guards/Triggers/ContentChangedTriggerTests.cs
  48. 117
      tests/Squidex.Domain.Apps.Write.Tests/Rules/RuleCommandMiddlewareTests.cs
  49. 240
      tests/Squidex.Domain.Apps.Write.Tests/Rules/RuleDomainObjectTests.cs
  50. 104
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/AssetsFieldPropertiesTests.cs
  51. 34
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/BooleanFieldPropertiesTests.cs
  52. 126
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/DateTimeFieldPropertiesTests.cs
  53. 34
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/GeolocationFieldPropertiesTests.cs
  54. 27
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/JsonFieldPropertiesTests.cs
  55. 134
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/NumberFieldPropertiesTests.cs
  56. 34
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/ReferencesFieldPropertiesTests.cs
  57. 105
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/StringFieldPropertiesTests.cs
  58. 34
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/TagsFieldPropertiesTests.cs
  59. 247
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/GuardSchemaFieldTests.cs
  60. 201
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/GuardSchemaTests.cs
  61. 278
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaCommandMiddlewareTests.cs
  62. 656
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaDomainObjectTests.cs
  63. 29
      tests/Squidex.Domain.Apps.Write.Tests/Squidex.Domain.Apps.Write.Tests.csproj
  64. 45
      tests/Squidex.Domain.Apps.Write.Tests/TestHelpers/AssertHelper.cs
  65. 162
      tests/Squidex.Domain.Apps.Write.Tests/TestHelpers/HandlerTestBase.cs

31
tests/Benchmarks/Benchmark.cs

@ -1,31 +0,0 @@
// ==========================================================================
// IBenchmark.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
namespace Benchmarks
{
public abstract class Benchmark
{
public virtual void Initialize()
{
}
public virtual void RunInitialize()
{
}
public virtual void RunCleanup()
{
}
public virtual void Cleanup()
{
}
public abstract long Run();
}
}

26
tests/Benchmarks/Benchmarks.csproj

@ -1,26 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Read\Squidex.Domain.Apps.Read.csproj" />
<ProjectReference Include="..\..\src\Squidex.Infrastructure.MongoDb\Squidex.Infrastructure.MongoDb.csproj" />
<ProjectReference Include="..\..\src\Squidex.Infrastructure\Squidex.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MongoDB.Driver" Version="2.4.4" />
<PackageReference Include="NodaTime.Serialization.JsonNet" Version="2.0.0" />
<PackageReference Include="RefactoringEssentials" Version="5.4.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2" />
<PackageReference Include="System.ValueTuple" Version="4.4.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Extensions.DependencyInjection">
<HintPath>C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.dependencyinjection\2.0.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll</HintPath>
</Reference>
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\Squidex.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>

96
tests/Benchmarks/Program.cs

@ -1,96 +0,0 @@
// ==========================================================================
// Program.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Benchmarks.Tests;
namespace Benchmarks
{
public static class Program
{
private static readonly List<(string Name, Benchmark Benchmark)> Benchmarks = new Benchmark[]
{
new AppendToEventStore(),
new AppendToEventStoreWithManyWriters(),
new HandleEvents(),
new HandleEventsWithManyWriters(),
new ReadSchemaState()
}.Select(x => (x.GetType().Name, x)).ToList();
public static void Main(string[] args)
{
var name = "ReadSchemaState";
var selected = Benchmarks.Find(x => x.Name == name);
if (selected.Benchmark == null)
{
Console.WriteLine($"'{name}' is not a valid benchmark, please try: ");
foreach (var b in Benchmarks)
{
Console.WriteLine($" * {b.Name}");
}
}
else
{
const int numRuns = 3;
try
{
var elapsed = 0d;
var count = 0L;
Console.WriteLine($"{selected.Name}: Initialized");
selected.Benchmark.Initialize();
for (var run = 0; run < numRuns; run++)
{
try
{
selected.Benchmark.RunInitialize();
var watch = Stopwatch.StartNew();
count += selected.Benchmark.Run();
watch.Stop();
elapsed += watch.ElapsedMilliseconds;
Console.WriteLine($"{selected.Name}: Run {run + 1} finished");
}
finally
{
selected.Benchmark.RunCleanup();
}
}
var averageElapsed = TimeSpan.FromMilliseconds(elapsed / numRuns);
var averageSeconds = Math.Round(count / (numRuns * averageElapsed.TotalSeconds), 2);
Console.WriteLine($"{selected.Name}: Completed after {averageElapsed}, {averageSeconds} items/s");
}
catch (Exception e)
{
Console.WriteLine($"Benchmark failed with '{e.Message}'");
}
finally
{
selected.Benchmark.Cleanup();
}
}
Console.ReadLine();
}
}
}

7
tests/Benchmarks/Properties/launchSettings.json

@ -1,7 +0,0 @@
{
"profiles": {
"Benchmarks": {
"commandName": "Project"
}
}
}

145
tests/Benchmarks/Services.cs

@ -1,145 +0,0 @@
// ==========================================================================
// Services.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Benchmarks.Tests.TestData;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using MongoDB.Driver;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using NodaTime;
using NodaTime.Serialization.JsonNet;
using Squidex.Domain.Apps.Core.Apps.Json;
using Squidex.Domain.Apps.Core.Rules.Json;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Schemas.Json;
using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Json;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.MongoDb;
using Squidex.Infrastructure.States;
namespace Benchmarks
{
public static class Services
{
public static IServiceProvider Create()
{
var services = new ServiceCollection();
services.AddSingleton(CreateTypeNameRegistry());
services.AddSingleton<FieldRegistry>();
services.AddTransient<MyAppState>();
services.AddSingleton<IMongoClient>(
new MongoClient("mongodb://localhost"));
services.AddSingleton<ISemanticLog>(
new SemanticLog(new ILogChannel[0], new ILogAppender[0], () => new JsonLogWriter()));
services.AddSingleton<IMemoryCache>(
new MemoryCache(Options.Create(new MemoryCacheOptions())));
services.AddSingleton<IPubSub,
InMemoryPubSub>();
services.AddSingleton<IEventNotifier,
DefaultEventNotifier>();
services.AddSingleton<IEventStore,
MongoEventStore>();
services.AddSingleton<IEventDataFormatter,
JsonEventDataFormatter>();
services.AddSingleton<ISnapshotStore,
MongoSnapshotStore>();
services.AddSingleton<IStateFactory,
StateFactory>();
services.AddSingleton<IStreamNameResolver,
DefaultStreamNameResolver>();
services.AddSingleton<JsonSerializer>(c =>
JsonSerializer.Create(c.GetRequiredService<JsonSerializerSettings>()));
services.AddSingleton<JsonSerializerSettings>(c =>
CreateJsonSerializerSettings(c.GetRequiredService<TypeNameRegistry>(), c.GetRequiredService<FieldRegistry>()));
services.AddSingleton(c =>
c.GetRequiredService<IMongoClient>().GetDatabase(Guid.NewGuid().ToString()));
return services.BuildServiceProvider();
}
public static void Cleanup(this IServiceProvider services)
{
var mongoClient = services.GetRequiredService<IMongoClient>();
var mongoDatabase = services.GetRequiredService<IMongoDatabase>();
mongoClient.DropDatabase(mongoDatabase.DatabaseNamespace.DatabaseName);
if (services is IDisposable disposable)
{
disposable.Dispose();
}
}
private static TypeNameRegistry CreateTypeNameRegistry()
{
var result = new TypeNameRegistry();
result.Map(typeof(MyEvent));
return result;
}
private static JsonSerializerSettings CreateJsonSerializerSettings(TypeNameRegistry typeNameRegistry, FieldRegistry fieldRegistry)
{
var settings = new JsonSerializerSettings();
settings.SerializationBinder = new TypeNameSerializationBinder(typeNameRegistry);
settings.ContractResolver = new ConverterContractResolver(
new AppClientsConverter(),
new AppContributorsConverter(),
new ClaimsPrincipalConverter(),
new InstantConverter(),
new LanguageConverter(),
new LanguagesConfigConverter(),
new NamedGuidIdConverter(),
new NamedLongIdConverter(),
new NamedStringIdConverter(),
new PropertiesBagConverter<EnvelopeHeaders>(),
new PropertiesBagConverter<PropertiesBag>(),
new RefTokenConverter(),
new RuleConverter(),
new SchemaConverter(fieldRegistry),
new StringEnumConverter());
settings.NullValueHandling = NullValueHandling.Ignore;
settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
settings.DateParseHandling = DateParseHandling.None;
settings.TypeNameHandling = TypeNameHandling.Auto;
settings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
BsonJsonConvention.Register(JsonSerializer.Create(settings));
return settings;
}
}
}

53
tests/Benchmarks/Tests/AppendToEventStore.cs

@ -1,53 +0,0 @@
// ==========================================================================
// AppendToEventStore.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Benchmarks.Utils;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Infrastructure.EventSourcing;
namespace Benchmarks.Tests
{
public sealed class AppendToEventStore : Benchmark
{
private IServiceProvider services;
private IEventStore eventStore;
public override void RunInitialize()
{
services = Services.Create();
eventStore = services.GetRequiredService<IEventStore>();
}
public override long Run()
{
const long numCommits = 100;
const long numStreams = 20;
for (var streamId = 0; streamId < numStreams; streamId++)
{
var eventOffset = -1;
var streamName = streamId.ToString();
for (var commitId = 0; commitId < numCommits; commitId++)
{
eventStore.AppendEventsAsync(Guid.NewGuid(), streamName, eventOffset, new[] { Helper.CreateEventData() }).Wait();
eventOffset++;
}
}
return numCommits * numStreams;
}
public override void RunCleanup()
{
services.Cleanup();
}
}
}

52
tests/Benchmarks/Tests/AppendToEventStoreWithManyWriters.cs

@ -1,52 +0,0 @@
// ==========================================================================
// AppendToEventStoreWithManyWriters.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Benchmarks.Utils;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Infrastructure.EventSourcing;
namespace Benchmarks.Tests
{
public sealed class AppendToEventStoreWithManyWriters : Benchmark
{
private IServiceProvider services;
private IEventStore eventStore;
public override void RunInitialize()
{
services = Services.Create();
eventStore = services.GetRequiredService<IEventStore>();
}
public override long Run()
{
const long numCommits = 200;
const long numStreams = 100;
Parallel.For(0, numStreams, streamId =>
{
var streamName = streamId.ToString();
for (var commitId = 0; commitId < numCommits; commitId++)
{
eventStore.AppendEventsAsync(Guid.NewGuid(), streamName, new[] { Helper.CreateEventData() }).Wait();
}
});
return numCommits * numStreams;
}
public override void RunCleanup()
{
services.Cleanup();
}
}
}

63
tests/Benchmarks/Tests/HandleEvents.cs

@ -1,63 +0,0 @@
// ==========================================================================
// HandleEvents.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Benchmarks.Tests.TestData;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.EventSourcing.Grains;
using Squidex.Infrastructure.States;
namespace Benchmarks.Tests
{
public sealed class HandleEvents : Benchmark
{
private const int NumEvents = 5000;
private IServiceProvider services;
private IEventStore eventStore;
private IEventDataFormatter eventDataFormatter;
private EventConsumerGrain eventConsumerGrain;
private MyEventConsumer eventConsumer;
public override void RunInitialize()
{
services = Services.Create();
eventConsumer = new MyEventConsumer(NumEvents);
eventStore = services.GetRequiredService<IEventStore>();
eventDataFormatter = services.GetRequiredService<IEventDataFormatter>();
eventConsumerGrain = services.GetRequiredService<EventConsumerGrain>();
eventConsumerGrain.ActivateAsync("Test", services.GetRequiredService<IStore>()).Wait();
eventConsumerGrain.Activate(eventConsumer);
}
public override long Run()
{
var streamName = Guid.NewGuid().ToString();
for (var eventId = 0; eventId < NumEvents; eventId++)
{
var eventData = eventDataFormatter.ToEventData(new Envelope<IEvent>(new MyEvent { EventNumber = eventId + 1 }), Guid.NewGuid());
eventStore.AppendEventsAsync(Guid.NewGuid(), streamName, eventId - 1, new[] { eventData }).Wait();
}
eventConsumer.WaitAndVerify();
return NumEvents;
}
public override void RunCleanup()
{
services.Cleanup();
}
}
}

70
tests/Benchmarks/Tests/HandleEventsWithManyWriters.cs

@ -1,70 +0,0 @@
// ==========================================================================
// HandleEventsWithManyWriters.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Benchmarks.Tests.TestData;
using Microsoft.Extensions.DependencyInjection;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.EventSourcing.Grains;
using Squidex.Infrastructure.States;
namespace Benchmarks.Tests
{
public sealed class HandleEventsWithManyWriters : Benchmark
{
private const int NumCommits = 200;
private const int NumStreams = 10;
private IServiceProvider services;
private IEventStore eventStore;
private IEventDataFormatter eventDataFormatter;
private EventConsumerGrain eventConsumerGrain;
private MyEventConsumer eventConsumer;
public override void RunInitialize()
{
services = Services.Create();
eventConsumer = new MyEventConsumer(NumStreams * NumCommits);
eventStore = services.GetRequiredService<IEventStore>();
eventDataFormatter = services.GetRequiredService<IEventDataFormatter>();
eventConsumerGrain = services.GetRequiredService<EventConsumerGrain>();
eventConsumerGrain.ActivateAsync("Test", services.GetRequiredService<IStore>()).Wait();
eventConsumerGrain.Activate(eventConsumer);
}
public override long Run()
{
Parallel.For(0, NumStreams, streamId =>
{
var eventOffset = -1;
var streamName = streamId.ToString();
for (var commitId = 0; commitId < NumCommits; commitId++)
{
var eventData = eventDataFormatter.ToEventData(new Envelope<IEvent>(new MyEvent()), Guid.NewGuid());
eventStore.AppendEventsAsync(Guid.NewGuid(), streamName, eventOffset - 1, new[] { eventData }).Wait();
eventOffset++;
}
});
eventConsumer.WaitAndVerify();
return NumStreams * NumCommits;
}
public override void RunCleanup()
{
services.Cleanup();
}
}
}

102
tests/Benchmarks/Tests/ReadSchemaState.cs

@ -1,102 +0,0 @@
// ==========================================================================
// ReadSchemaState.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Immutable;
using Benchmarks.Tests.TestData;
using Microsoft.Extensions.DependencyInjection;
using NodaTime;
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Core.Rules.Actions;
using Squidex.Domain.Apps.Core.Rules.Triggers;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Read.State.Grains;
using Squidex.Infrastructure;
using Squidex.Infrastructure.States;
namespace Benchmarks.Tests
{
public class ReadSchemaState : Benchmark
{
private IServiceProvider services;
private MyAppState grain;
public override void Initialize()
{
services = Services.Create();
grain = services.GetRequiredService<IStateFactory>().GetSynchronizedAsync<MyAppState>("DEFAULT").Result;
var state = new AppStateGrainState
{
App = new JsonAppEntity
{
Id = Guid.NewGuid()
}
};
state.Schemas = ImmutableDictionary<Guid, JsonSchemaEntity>.Empty;
for (var i = 1; i <= 100; i++)
{
var schema = new JsonSchemaEntity
{
Id = Guid.NewGuid(),
Created = SystemClock.Instance.GetCurrentInstant(),
CreatedBy = new RefToken("user", "1"),
LastModified = SystemClock.Instance.GetCurrentInstant(),
LastModifiedBy = new RefToken("user", "1"),
SchemaDef = new Schema("Name")
};
for (var j = 1; j < 30; j++)
{
schema.SchemaDef = schema.SchemaDef.AddField(new StringField(j, j.ToString(), Partitioning.Invariant));
}
state.Schemas = state.Schemas.Add(schema.Id, schema);
}
state.Rules = ImmutableDictionary<Guid, JsonRuleEntity>.Empty;
for (var i = 0; i < 100; i++)
{
var rule = new JsonRuleEntity
{
Id = Guid.NewGuid(),
Created = SystemClock.Instance.GetCurrentInstant(),
CreatedBy = new RefToken("user", "1"),
LastModified = SystemClock.Instance.GetCurrentInstant(),
LastModifiedBy = new RefToken("user", "1"),
RuleDef = new Rule(new ContentChangedTrigger(), new WebhookAction())
};
state.Rules = state.Rules.Add(rule.Id, rule);
}
grain.SetState(state);
grain.WriteStateAsync().Wait();
}
public override long Run()
{
for (var i = 0; i < 10; i++)
{
grain.ReadStateAsync().Wait();
}
return 10;
}
public override void Cleanup()
{
services.Cleanup();
}
}
}

42
tests/Benchmarks/Tests/TestData/MyAppState.cs

@ -1,42 +0,0 @@
// ==========================================================================
// MyAppState.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Threading.Tasks;
using Squidex.Domain.Apps.Read.State.Grains;
using Squidex.Infrastructure.States;
namespace Benchmarks.Tests.TestData
{
public sealed class MyAppState : IStatefulObject
{
private IPersistence<AppStateGrainState> persistence;
private AppStateGrainState state;
public Task ActivateAsync(string key, IStore store)
{
persistence = store.WithSnapshots<MyAppState, AppStateGrainState>(key, s => state = s);
return persistence.ReadAsync();
}
public void SetState(AppStateGrainState state)
{
this.state = state;
}
public Task WriteStateAsync()
{
return persistence.WriteSnapshotAsync(state);
}
public Task ReadStateAsync()
{
return persistence.ReadAsync();
}
}
}

19
tests/Benchmarks/Tests/TestData/MyEvent.cs

@ -1,19 +0,0 @@
// ==========================================================================
// MyEvent.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing;
namespace Benchmarks.Tests.TestData
{
[TypeName("MyEvent")]
public sealed class MyEvent : IEvent
{
public int EventNumber { get; set; }
}
}

79
tests/Benchmarks/Tests/TestData/MyEventConsumer.cs

@ -1,79 +0,0 @@
// ==========================================================================
// MyEventConsumer.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Tasks;
namespace Benchmarks.Tests.TestData
{
public sealed class MyEventConsumer : IEventConsumer
{
private readonly TaskCompletionSource<object> completion = new TaskCompletionSource<object>();
private readonly int numEvents;
public List<int> EventNumbers { get; } = new List<int>();
public string Name
{
get { return typeof(MyEventConsumer).Name; }
}
public string EventsFilter
{
get { return string.Empty; }
}
public MyEventConsumer(int numEvents)
{
this.numEvents = numEvents;
}
public Task ClearAsync()
{
return TaskHelper.Done;
}
public void WaitAndVerify()
{
completion.Task.Wait();
if (EventNumbers.Count != numEvents)
{
throw new InvalidOperationException($"{EventNumbers.Count} Events have been handled");
}
for (var i = 0; i < EventNumbers.Count; i++)
{
var value = EventNumbers[i];
if (value != i + 1)
{
throw new InvalidOperationException($"Event[{i}] != value");
}
}
}
public Task On(Envelope<IEvent> @event)
{
if (@event.Payload is MyEvent myEvent)
{
EventNumbers.Add(myEvent.EventNumber);
if (myEvent.EventNumber == numEvents)
{
completion.SetResult(true);
}
}
return TaskHelper.Done;
}
}
}

21
tests/Benchmarks/Utils/Helper.cs

@ -1,21 +0,0 @@
// ==========================================================================
// Helper.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Squidex.Infrastructure.EventSourcing;
namespace Benchmarks.Utils
{
public static class Helper
{
public static EventData CreateEventData()
{
return new EventData { EventId = Guid.NewGuid(), Metadata = "EventMetdata", Payload = "EventPayload", Type = "MyEvent" };
}
}
}

51
tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppEventTests.cs

@ -1,51 +0,0 @@
// ==========================================================================
// AppEventTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Domain.Apps.Events;
using Squidex.Domain.Apps.Events.Apps;
using Squidex.Domain.Apps.Events.Apps.Old;
using Squidex.Infrastructure;
using Xunit;
#pragma warning disable CS0612 // Type or member is obsolete
namespace Squidex.Domain.Apps.Entities.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;
}
}
}

70
tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentEventTests.cs

@ -1,70 +0,0 @@
// ==========================================================================
// ContentEventTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Domain.Apps.Events.Contents;
using Squidex.Domain.Apps.Events.Contents.Old;
using Squidex.Infrastructure;
using Xunit;
#pragma warning disable CS0612 // Type or member is obsolete
namespace Squidex.Domain.Apps.Entities.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;
}
}
}

3
tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQLTests.cs → tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTests.cs

@ -23,7 +23,6 @@ using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Assets;
using Squidex.Domain.Apps.Entities.Assets.Repositories;
using Squidex.Domain.Apps.Entities.Contents.GraphQL;
using Squidex.Domain.Apps.Entities.Contents.TestData;
using Squidex.Domain.Apps.Entities.Schemas;
using Squidex.Infrastructure;
@ -31,7 +30,7 @@ using Xunit;
#pragma warning disable SA1311 // Static readonly fields must begin with upper-case letter
namespace Squidex.Domain.Apps.Entities.Contents
namespace Squidex.Domain.Apps.Entities.Contents.GraphQL
{
public class GraphQLTests
{

2
tests/Squidex.Domain.Apps.Entities.Tests/Contents/ODataQueryTests.cs → tests/Squidex.Domain.Apps.Entities.Tests/Contents/OData/ODataQueryTests.cs

@ -26,7 +26,7 @@ using Squidex.Infrastructure;
using Squidex.Infrastructure.MongoDb;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Contents
namespace Squidex.Domain.Apps.Entities.Contents.OData
{
public class ODataQueryTests
{

150
tests/Squidex.Domain.Apps.Read.Tests/Apps/ConfigAppLimitsProviderTests.cs

@ -1,150 +0,0 @@
// ==========================================================================
// ConfigAppLimitsProviderTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Linq;
using FakeItEasy;
using FluentAssertions;
using Squidex.Domain.Apps.Read.Apps.Services.Implementations;
using Xunit;
namespace Squidex.Domain.Apps.Read.Apps
{
public class ConfigAppLimitsProviderTests
{
private static readonly ConfigAppLimitsPlan InfinitePlan = new ConfigAppLimitsPlan
{
Id = "infinite",
Name = "Infinite",
MaxApiCalls = -1,
MaxAssetSize = -1,
MaxContributors = -1
};
private static readonly ConfigAppLimitsPlan FreePlan = new ConfigAppLimitsPlan
{
Id = "free",
Name = "Free",
MaxApiCalls = 50000,
MaxAssetSize = 1024 * 1024 * 10,
MaxContributors = 2
};
private static readonly ConfigAppLimitsPlan BasicPlan = new ConfigAppLimitsPlan
{
Id = "basic",
Name = "Basic",
MaxApiCalls = 150000,
MaxAssetSize = 1024 * 1024 * 2,
MaxContributors = 5
};
private static readonly ConfigAppLimitsPlan[] Plans = { BasicPlan, FreePlan };
[Fact]
public void Should_return_plans()
{
var sut = new ConfigAppPlansProvider(Plans);
Plans.OrderBy(x => x.MaxApiCalls).ShouldBeEquivalentTo(sut.GetAvailablePlans());
}
[Theory]
[InlineData(null)]
[InlineData("my-plan")]
public void Should_return_infinite_if_nothing_configured(string planId)
{
var sut = new ConfigAppPlansProvider(Enumerable.Empty<ConfigAppLimitsPlan>());
var plan = sut.GetPlanForApp(CreateApp(planId));
plan.ShouldBeEquivalentTo(InfinitePlan);
}
[Fact]
public void Should_return_fitting_app_plan()
{
var sut = new ConfigAppPlansProvider(Plans);
var plan = sut.GetPlanForApp(CreateApp("basic"));
plan.ShouldBeEquivalentTo(BasicPlan);
}
[Fact]
public void Should_smallest_plan_if_none_fits()
{
var sut = new ConfigAppPlansProvider(Plans);
var plan = sut.GetPlanForApp(CreateApp("enterprise"));
plan.ShouldBeEquivalentTo(FreePlan);
}
[Fact]
public void Should_return_second_plan_for_upgrade_if_plan_is_null()
{
var sut = new ConfigAppPlansProvider(Plans);
var upgradePlan = sut.GetPlanUpgrade(null);
upgradePlan.ShouldBeEquivalentTo(BasicPlan);
}
[Fact]
public void Should_return_second_plan_for_upgrade_if_plan_not_found()
{
var sut = new ConfigAppPlansProvider(Plans);
var upgradePlan = sut.GetPlanUpgradeForApp(CreateApp("enterprise"));
upgradePlan.ShouldBeEquivalentTo(BasicPlan);
}
[Fact]
public void Should_not_return_plan_for_upgrade_if_plan_is_highest_plan()
{
var sut = new ConfigAppPlansProvider(Plans);
var upgradePlan = sut.GetPlanUpgradeForApp(CreateApp("basic"));
Assert.Null(upgradePlan);
}
[Fact]
public void Should_return_next_plan_if_plan_is_upgradeable()
{
var sut = new ConfigAppPlansProvider(Plans);
var upgradePlan = sut.GetPlanUpgradeForApp(CreateApp("free"));
upgradePlan.ShouldBeEquivalentTo(BasicPlan);
}
[Fact]
public void Should_check_plan_exists()
{
var sut = new ConfigAppPlansProvider(Plans);
Assert.True(sut.IsConfiguredPlan("basic"));
Assert.True(sut.IsConfiguredPlan("free"));
Assert.False(sut.IsConfiguredPlan("infinite"));
Assert.False(sut.IsConfiguredPlan("invalid"));
Assert.False(sut.IsConfiguredPlan(null));
}
private static IAppEntity CreateApp(string plan)
{
var app = A.Dummy<IAppEntity>();
A.CallTo(() => app.PlanId).Returns(plan);
return app;
}
}
}

38
tests/Squidex.Domain.Apps.Read.Tests/Apps/NoopAppPlanBillingManagerTests.cs

@ -1,38 +0,0 @@
// ==========================================================================
// NoopAppPlanBillingManagerTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Read.Apps.Services.Implementations;
using Xunit;
namespace Squidex.Domain.Apps.Read.Apps
{
public class NoopAppPlanBillingManagerTests
{
private readonly NoopAppPlanBillingManager sut = new NoopAppPlanBillingManager();
[Fact]
public void Should_not_have_portal()
{
Assert.False(sut.HasPortal);
}
[Fact]
public async Task Should_do_nothing_when_changing_plan()
{
await sut.ChangePlanAsync(null, Guid.Empty, null, null);
}
[Fact]
public async Task Should_not_return_portal_link()
{
Assert.Equal(string.Empty, await sut.GetPortalLinkAsync(null));
}
}
}

220
tests/Squidex.Domain.Apps.Read.Tests/Contents/ContentQueryServiceTests.cs

@ -1,220 +0,0 @@
// ==========================================================================
// ContentQueryServiceTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using FakeItEasy;
using Microsoft.OData.UriParser;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Contents.Edm;
using Squidex.Domain.Apps.Read.Contents.Repositories;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Security;
using Xunit;
namespace Squidex.Domain.Apps.Read.Contents
{
public class ContentQueryServiceTests
{
private readonly IContentRepository contentRepository = A.Fake<IContentRepository>();
private readonly IScriptEngine scriptEngine = A.Fake<IScriptEngine>();
private readonly ISchemaEntity schema = A.Fake<ISchemaEntity>();
private readonly IContentEntity content = A.Fake<IContentEntity>();
private readonly IAppEntity app = A.Fake<IAppEntity>();
private readonly IAppProvider appProvider = A.Fake<IAppProvider>();
private readonly Guid appId = Guid.NewGuid();
private readonly Guid schemaId = Guid.NewGuid();
private readonly Guid contentId = Guid.NewGuid();
private readonly string appName = "my-app";
private readonly NamedContentData data = new NamedContentData();
private readonly NamedContentData transformedData = new NamedContentData();
private readonly ClaimsPrincipal user;
private readonly ClaimsIdentity identity = new ClaimsIdentity();
private readonly EdmModelBuilder modelBuilder = A.Fake<EdmModelBuilder>();
private readonly ContentQueryService sut;
public ContentQueryServiceTests()
{
user = new ClaimsPrincipal(identity);
A.CallTo(() => app.Id).Returns(appId);
A.CallTo(() => app.Name).Returns(appName);
A.CallTo(() => content.Id).Returns(contentId);
A.CallTo(() => content.Data).Returns(data);
A.CallTo(() => content.Status).Returns(Status.Published);
sut = new ContentQueryService(contentRepository, appProvider, scriptEngine, modelBuilder);
}
[Fact]
public async Task Should_return_schema_from_id_if_string_is_guid()
{
A.CallTo(() => appProvider.GetSchemaAsync(appName, schemaId, false))
.Returns(schema);
var result = await sut.FindSchemaAsync(app, schemaId.ToString());
Assert.Equal(schema, result);
}
[Fact]
public async Task Should_return_schema_from_name_if_string_not_guid()
{
A.CallTo(() => appProvider.GetSchemaAsync(appName, "my-schema", false))
.Returns(schema);
var result = await sut.FindSchemaAsync(app, "my-schema");
Assert.Equal(schema, result);
}
[Fact]
public async Task Should_throw_if_schema_not_found()
{
A.CallTo(() => appProvider.GetSchemaAsync(appName, "my-schema", false))
.Returns((ISchemaEntity)null);
await Assert.ThrowsAsync<DomainObjectNotFoundException>(() => sut.FindSchemaAsync(app, "my-schema"));
}
[Fact]
public async Task Should_return_content_from_repository_and_transform()
{
A.CallTo(() => appProvider.GetSchemaAsync(appName, schemaId, false))
.Returns(schema);
A.CallTo(() => contentRepository.FindContentAsync(app, schema, contentId))
.Returns(content);
A.CallTo(() => schema.ScriptQuery)
.Returns("<script-query>");
A.CallTo(() => scriptEngine.Transform(A<ScriptContext>.That.Matches(x => x.User == user && x.ContentId == contentId && ReferenceEquals(x.Data, data)), "<query-script>"))
.Returns(transformedData);
var result = await sut.FindContentAsync(app, schemaId.ToString(), user, contentId);
Assert.Equal(schema, result.Schema);
Assert.Equal(data, result.Content.Data);
Assert.Equal(content.Id, result.Content.Id);
}
[Fact]
public async Task Should_throw_if_content_to_find_does_not_exist()
{
A.CallTo(() => appProvider.GetSchemaAsync(appName, schemaId, false))
.Returns(schema);
A.CallTo(() => contentRepository.FindContentAsync(app, schema, contentId))
.Returns((IContentEntity)null);
await Assert.ThrowsAsync<DomainObjectNotFoundException>(async () => await sut.FindContentAsync(app, schemaId.ToString(), user, contentId));
}
[Fact]
public async Task Should_return_contents_with_ids_from_repository_and_transform()
{
await TestManyIdRequest(true, false, new HashSet<Guid> { Guid.NewGuid() }, Status.Draft, Status.Published);
}
[Fact]
public async Task Should_return_non_archived_contents_from_repository_and_transform()
{
await TestManyRequest(true, false, Status.Draft, Status.Published);
}
[Fact]
public async Task Should_return_archived_contents_from_repository_and_transform()
{
await TestManyRequest(true, true, Status.Archived);
}
[Fact]
public async Task Should_return_draft_contents_from_repository_and_transform()
{
await TestManyRequest(false, false, Status.Published);
}
[Fact]
public async Task Should_return_draft_contents_from_repository_and_transform_when_requesting_archive_as_non_frontend()
{
await TestManyRequest(false, true, Status.Published);
}
private async Task TestManyRequest(bool isFrontend, bool archive, params Status[] status)
{
SetupClaims(isFrontend);
SetupFakeWithOdataQuery(status);
SetupFakeWithScripting();
var result = await sut.QueryWithCountAsync(app, schemaId.ToString(), user, archive, string.Empty);
Assert.Equal(123, result.Total);
Assert.Equal(schema, result.Schema);
Assert.Equal(data, result.Items[0].Data);
Assert.Equal(content.Id, result.Items[0].Id);
}
private async Task TestManyIdRequest(bool isFrontend, bool archive, HashSet<Guid> ids, params Status[] status)
{
SetupClaims(isFrontend);
SetupFakeWithIdQuery(status, ids);
SetupFakeWithScripting();
var result = await sut.QueryWithCountAsync(app, schemaId.ToString(), user, archive, ids);
Assert.Equal(123, result.Total);
Assert.Equal(schema, result.Schema);
Assert.Equal(data, result.Items[0].Data);
Assert.Equal(content.Id, result.Items[0].Id);
}
private void SetupClaims(bool isFrontend)
{
if (isFrontend)
{
identity.AddClaim(new Claim(OpenIdClaims.ClientId, "squidex-frontend"));
}
}
private void SetupFakeWithIdQuery(Status[] status, HashSet<Guid> ids)
{
A.CallTo(() => appProvider.GetSchemaAsync(appName, schemaId, false))
.Returns(schema);
A.CallTo(() => contentRepository.QueryAsync(app, schema, A<Status[]>.That.IsSameSequenceAs(status), ids))
.Returns(new List<IContentEntity> { content });
A.CallTo(() => contentRepository.CountAsync(app, schema, A<Status[]>.That.IsSameSequenceAs(status), ids))
.Returns(123);
}
private void SetupFakeWithOdataQuery(Status[] status)
{
A.CallTo(() => appProvider.GetSchemaAsync(appName, schemaId, false))
.Returns(schema);
A.CallTo(() => contentRepository.QueryAsync(app, schema, A<Status[]>.That.IsSameSequenceAs(status), A<ODataUriParser>.Ignored))
.Returns(new List<IContentEntity> { content });
A.CallTo(() => contentRepository.CountAsync(app, schema, A<Status[]>.That.IsSameSequenceAs(status), A<ODataUriParser>.Ignored))
.Returns(123);
}
private void SetupFakeWithScripting()
{
A.CallTo(() => schema.ScriptQuery)
.Returns("<script-query>");
A.CallTo(() => scriptEngine.Transform(A<ScriptContext>.That.Matches(x => x.User == user && x.ContentId == contentId && ReferenceEquals(x.Data, data)), "<query-script>"))
.Returns(transformedData);
}
}
}

689
tests/Squidex.Domain.Apps.Read.Tests/Contents/GraphQLTests.cs

@ -1,689 +0,0 @@
// ==========================================================================
// GraphQLTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using FakeItEasy;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NodaTime.Extensions;
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Assets;
using Squidex.Domain.Apps.Read.Assets.Repositories;
using Squidex.Domain.Apps.Read.Contents.GraphQL;
using Squidex.Domain.Apps.Read.Contents.TestData;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Infrastructure;
using Xunit;
#pragma warning disable SA1311 // Static readonly fields must begin with upper-case letter
namespace Squidex.Domain.Apps.Read.Contents
{
public class GraphQLTests
{
private static readonly Guid schemaId = Guid.NewGuid();
private static readonly Guid appId = Guid.NewGuid();
private static readonly string appName = "my-app";
private readonly Schema schemaDef;
private readonly IContentQueryService contentQuery = A.Fake<IContentQueryService>();
private readonly IAssetRepository assetRepository = A.Fake<IAssetRepository>();
private readonly ISchemaEntity schema = A.Fake<ISchemaEntity>();
private readonly IMemoryCache cache = new MemoryCache(Options.Create(new MemoryCacheOptions()));
private readonly IAppProvider appProvider = A.Fake<IAppProvider>();
private readonly IAppEntity app = A.Dummy<IAppEntity>();
private readonly ClaimsPrincipal user = new ClaimsPrincipal();
private readonly IGraphQLService sut;
public GraphQLTests()
{
schemaDef =
new Schema("my-schema")
.AddField(new JsonField(1, "my-json", Partitioning.Invariant,
new JsonFieldProperties()))
.AddField(new StringField(2, "my-string", Partitioning.Language,
new StringFieldProperties()))
.AddField(new NumberField(3, "my-number", Partitioning.Invariant,
new NumberFieldProperties()))
.AddField(new AssetsField(4, "my-assets", Partitioning.Invariant,
new AssetsFieldProperties()))
.AddField(new BooleanField(5, "my-boolean", Partitioning.Invariant,
new BooleanFieldProperties()))
.AddField(new DateTimeField(6, "my-datetime", Partitioning.Invariant,
new DateTimeFieldProperties()))
.AddField(new ReferencesField(7, "my-references", Partitioning.Invariant,
new ReferencesFieldProperties { SchemaId = schemaId }))
.AddField(new ReferencesField(9, "my-invalid", Partitioning.Invariant,
new ReferencesFieldProperties { SchemaId = Guid.NewGuid() }))
.AddField(new GeolocationField(10, "my-geolocation", Partitioning.Invariant,
new GeolocationFieldProperties()))
.AddField(new TagsField(11, "my-tags", Partitioning.Invariant,
new TagsFieldProperties()));
A.CallTo(() => app.Id).Returns(appId);
A.CallTo(() => app.Name).Returns(appName);
A.CallTo(() => app.LanguagesConfig).Returns(LanguagesConfig.Build(Language.DE));
A.CallTo(() => schema.Id).Returns(schemaId);
A.CallTo(() => schema.Name).Returns(schemaDef.Name);
A.CallTo(() => schema.SchemaDef).Returns(schemaDef);
A.CallTo(() => schema.IsPublished).Returns(true);
A.CallTo(() => schema.ScriptQuery).Returns("<script-query>");
var allSchemas = new List<ISchemaEntity> { schema };
A.CallTo(() => appProvider.GetSchemasAsync(appName)).Returns(allSchemas);
sut = new CachingGraphQLService(cache, appProvider, assetRepository, contentQuery, new FakeUrlGenerator());
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public async Task Should_return_empty_object_for_empty_query(string query)
{
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
}
};
AssertJson(expected, new { data = result.Data });
}
[Fact]
public async Task Should_return_multiple_assets_when_querying_assets()
{
const string query = @"
query {
queryAssets(search: ""my-query"", top: 30, skip: 5) {
id
version
created
createdBy
lastModified
lastModifiedBy
url
thumbnailUrl
sourceUrl
mimeType
fileName
fileSize
fileVersion
isImage
pixelWidth
pixelHeight
}
}";
var asset = CreateAsset(Guid.NewGuid());
var assets = new List<IAssetEntity> { asset };
A.CallTo(() => assetRepository.QueryAsync(app.Id, null, null, "my-query", 30, 5))
.Returns(assets);
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
queryAssets = new dynamic[]
{
new
{
id = asset.Id,
version = 1,
created = asset.Created.ToDateTimeUtc(),
createdBy = "subject:user1",
lastModified = asset.LastModified.ToDateTimeUtc(),
lastModifiedBy = "subject:user2",
url = $"assets/{asset.Id}",
thumbnailUrl = $"assets/{asset.Id}?width=100",
sourceUrl = $"assets/source/{asset.Id}",
mimeType = "image/png",
fileName = "MyFile.png",
fileSize = 1024,
fileVersion = 123,
isImage = true,
pixelWidth = 800,
pixelHeight = 600
}
}
}
};
AssertJson(expected, new { data = result.Data });
}
[Fact]
public async Task Should_return_single_asset_when_finding_asset()
{
var assetId = Guid.NewGuid();
var asset = CreateAsset(Guid.NewGuid());
var query = $@"
query {{
findAsset(id: ""{assetId}"") {{
id
version
created
createdBy
lastModified
lastModifiedBy
url
thumbnailUrl
sourceUrl
mimeType
fileName
fileSize
fileVersion
isImage
pixelWidth
pixelHeight
}}
}}";
A.CallTo(() => assetRepository.FindAssetAsync(assetId))
.Returns(asset);
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
findAsset = new
{
id = asset.Id,
version = 1,
created = asset.Created.ToDateTimeUtc(),
createdBy = "subject:user1",
lastModified = asset.LastModified.ToDateTimeUtc(),
lastModifiedBy = "subject:user2",
url = $"assets/{asset.Id}",
thumbnailUrl = $"assets/{asset.Id}?width=100",
sourceUrl = $"assets/source/{asset.Id}",
mimeType = "image/png",
fileName = "MyFile.png",
fileSize = 1024,
fileVersion = 123,
isImage = true,
pixelWidth = 800,
pixelHeight = 600
}
}
};
AssertJson(expected, new { data = result.Data });
}
[Fact]
public async Task Should_return_multiple_contents_when_querying_contents()
{
const string query = @"
query {
queryMySchemaContents(top: 30, skip: 5) {
id
version
created
createdBy
lastModified
lastModifiedBy
url
data {
myString {
de
}
myNumber {
iv
}
myBoolean {
iv
}
myDatetime {
iv
}
myJson {
iv
}
myGeolocation {
iv
}
myTags {
iv
}
}
}
}";
var content = CreateContent(Guid.NewGuid(), Guid.Empty, Guid.Empty);
var contents = new List<IContentEntity> { content };
A.CallTo(() => contentQuery.QueryWithCountAsync(app, schema.Id.ToString(), user, false, "?$top=30&$skip=5"))
.Returns((schema, 0L, (IReadOnlyList<IContentEntity>)contents));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
queryMySchemaContents = new dynamic[]
{
new
{
id = content.Id,
version = 1,
created = content.Created.ToDateTimeUtc(),
createdBy = "subject:user1",
lastModified = content.LastModified.ToDateTimeUtc(),
lastModifiedBy = "subject:user2",
url = $"contents/my-schema/{content.Id}",
data = new
{
myString = new
{
de = "value"
},
myNumber = new
{
iv = 1
},
myBoolean = new
{
iv = true
},
myDatetime = new
{
iv = content.LastModified.ToDateTimeUtc()
},
myJson = new
{
iv = new
{
value = 1
}
},
myGeolocation = new
{
iv = new
{
latitude = 10,
longitude = 20
}
},
myTags = new
{
iv = new[]
{
"tag1",
"tag2"
}
}
}
}
}
}
};
AssertJson(expected, new { data = result.Data });
}
[Fact]
public async Task Should_return_single_content_when_finding_content()
{
var contentId = Guid.NewGuid();
var content = CreateContent(contentId, Guid.Empty, Guid.Empty);
var query = $@"
query {{
findMySchemaContent(id: ""{contentId}"") {{
id
version
created
createdBy
lastModified
lastModifiedBy
url
data {{
myString {{
de
}}
myNumber {{
iv
}}
myBoolean {{
iv
}}
myDatetime {{
iv
}}
myJson {{
iv
}}
myGeolocation {{
iv
}}
myTags {{
iv
}}
}}
}}
}}";
A.CallTo(() => contentQuery.FindContentAsync(app, schema.Id.ToString(), user, contentId))
.Returns((schema, content));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
findMySchemaContent = new
{
id = content.Id,
version = 1,
created = content.Created.ToDateTimeUtc(),
createdBy = "subject:user1",
lastModified = content.LastModified.ToDateTimeUtc(),
lastModifiedBy = "subject:user2",
url = $"contents/my-schema/{content.Id}",
data = new
{
myString = new
{
de = "value"
},
myNumber = new
{
iv = 1
},
myBoolean = new
{
iv = true
},
myDatetime = new
{
iv = content.LastModified.ToDateTimeUtc()
},
myJson = new
{
iv = new
{
value = 1
}
},
myGeolocation = new
{
iv = new
{
latitude = 10,
longitude = 20
}
},
myTags = new
{
iv = new[]
{
"tag1",
"tag2"
}
}
}
}
}
};
AssertJson(expected, new { data = result.Data });
}
[Fact]
public async Task Should_also_fetch_referenced_contents_when_field_is_included_in_query()
{
var contentRefId = Guid.NewGuid();
var contentRef = CreateContent(contentRefId, Guid.Empty, Guid.Empty);
var contentId = Guid.NewGuid();
var content = CreateContent(contentId, contentRefId, Guid.Empty);
var query = $@"
query {{
findMySchemaContent(id: ""{contentId}"") {{
id
data {{
myReferences {{
iv {{
id
}}
}}
}}
}}
}}";
var refContents = new List<IContentEntity> { contentRef };
A.CallTo(() => contentQuery.FindContentAsync(app, schema.Id.ToString(), user, contentId))
.Returns((schema, content));
A.CallTo(() => contentQuery.QueryWithCountAsync(app, schema.Id.ToString(), user, false, A<HashSet<Guid>>.That.Matches(x => x.Contains(contentRefId))))
.Returns((schema, 0L, (IReadOnlyList<IContentEntity>)refContents));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
findMySchemaContent = new
{
id = content.Id,
data = new
{
myReferences = new
{
iv = new[]
{
new
{
id = contentRefId
}
}
}
}
}
}
};
AssertJson(expected, new { data = result.Data });
}
[Fact]
public async Task Should_also_fetch_referenced_assets_when_field_is_included_in_query()
{
var assetRefId = Guid.NewGuid();
var assetRef = CreateAsset(assetRefId);
var contentId = Guid.NewGuid();
var content = CreateContent(contentId, Guid.Empty, assetRefId);
var query = $@"
query {{
findMySchemaContent(id: ""{contentId}"") {{
id
data {{
myAssets {{
iv {{
id
}}
}}
}}
}}
}}";
var refAssets = new List<IAssetEntity> { assetRef };
A.CallTo(() => contentQuery.FindContentAsync(app, schema.Id.ToString(), user, contentId))
.Returns((schema, content));
A.CallTo(() => assetRepository.QueryAsync(app.Id, null, A<HashSet<Guid>>.That.Matches(x => x.Contains(assetRefId)), null, int.MaxValue, 0))
.Returns(refAssets);
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = new
{
findMySchemaContent = new
{
id = content.Id,
data = new
{
myAssets = new
{
iv = new[]
{
new
{
id = assetRefId
}
}
}
}
}
}
};
AssertJson(expected, new { data = result.Data });
}
[Fact]
public async Task Should_not_return_data_when_field_not_part_of_content()
{
var contentId = Guid.NewGuid();
var content = CreateContent(contentId, Guid.Empty, Guid.Empty, new NamedContentData());
var query = $@"
query {{
findMySchemaContent(id: ""{contentId}"") {{
id
version
created
createdBy
lastModified
lastModifiedBy
url
data {{
myInvalid {{
iv
}}
}}
}}
}}";
A.CallTo(() => contentQuery.FindContentAsync(app, schema.Id.ToString(), user, contentId))
.Returns((schema, content));
var result = await sut.QueryAsync(app, user, new GraphQLQuery { Query = query });
var expected = new
{
data = (object)null
};
AssertJson(expected, new { data = result.Data });
}
private static IContentEntity CreateContent(Guid id, Guid refId, Guid assetId, NamedContentData data = null)
{
var now = DateTime.UtcNow.ToInstant();
data = data ??
new NamedContentData()
.AddField("my-json",
new ContentFieldData().AddValue("iv", JToken.FromObject(new { value = 1 })))
.AddField("my-string",
new ContentFieldData().AddValue("de", "value"))
.AddField("my-assets",
new ContentFieldData().AddValue("iv", JToken.FromObject(new[] { assetId })))
.AddField("my-number",
new ContentFieldData().AddValue("iv", 1))
.AddField("my-boolean",
new ContentFieldData().AddValue("iv", true))
.AddField("my-datetime",
new ContentFieldData().AddValue("iv", now.ToDateTimeUtc()))
.AddField("my-tags",
new ContentFieldData().AddValue("iv", JToken.FromObject(new[] { "tag1", "tag2" })))
.AddField("my-references",
new ContentFieldData().AddValue("iv", JToken.FromObject(new[] { refId })))
.AddField("my-geolocation",
new ContentFieldData().AddValue("iv", JToken.FromObject(new { latitude = 10, longitude = 20 })));
var content = new FakeContentEntity
{
Id = id,
Version = 1,
Created = now,
CreatedBy = new RefToken("subject", "user1"),
LastModified = now,
LastModifiedBy = new RefToken("subject", "user2"),
Data = data
};
return content;
}
private static IAssetEntity CreateAsset(Guid id)
{
var now = DateTime.UtcNow.ToInstant();
var asset = new FakeAssetEntity
{
Id = id,
Version = 1,
Created = now,
CreatedBy = new RefToken("subject", "user1"),
LastModified = now,
LastModifiedBy = new RefToken("subject", "user2"),
FileName = "MyFile.png",
FileSize = 1024,
FileVersion = 123,
MimeType = "image/png",
IsImage = true,
PixelWidth = 800,
PixelHeight = 600
};
return asset;
}
private static void AssertJson(object expected, object result)
{
var resultJson = JsonConvert.SerializeObject(result, Formatting.Indented);
var expectJson = JsonConvert.SerializeObject(expected, Formatting.Indented);
Assert.Equal(expectJson, resultJson);
}
}
}

392
tests/Squidex.Domain.Apps.Read.Tests/Contents/ODataQueryTests.cs

@ -1,392 +0,0 @@
// ==========================================================================
// ODataQueryTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Immutable;
using FakeItEasy;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using Microsoft.OData.Edm;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Contents.Edm;
using Squidex.Domain.Apps.Read.MongoDb.Contents;
using Squidex.Domain.Apps.Read.MongoDb.Contents.Visitors;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Infrastructure;
using Squidex.Infrastructure.MongoDb;
using Xunit;
namespace Squidex.Domain.Apps.Read.Contents
{
public class ODataQueryTests
{
private readonly Schema schemaDef;
private readonly IBsonSerializerRegistry registry = BsonSerializer.SerializerRegistry;
private readonly IBsonSerializer<MongoContentEntity> serializer = BsonSerializer.SerializerRegistry.GetSerializer<MongoContentEntity>();
private readonly IEdmModel edmModel;
private readonly LanguagesConfig languagesConfig = LanguagesConfig.Build(Language.EN, Language.DE);
static ODataQueryTests()
{
InstantSerializer.Register();
}
public ODataQueryTests()
{
schemaDef =
new Schema("user")
.AddField(new StringField(1, "firstName", Partitioning.Language,
new StringFieldProperties { Label = "FirstName", IsRequired = true, AllowedValues = ImmutableList.Create("1", "2") }))
.AddField(new StringField(2, "lastName", Partitioning.Language,
new StringFieldProperties { Hints = "Last Name", Editor = StringFieldEditor.Input }))
.AddField(new BooleanField(3, "isAdmin", Partitioning.Invariant,
new BooleanFieldProperties()))
.AddField(new NumberField(4, "age", Partitioning.Invariant,
new NumberFieldProperties { MinValue = 1, MaxValue = 10 }))
.AddField(new DateTimeField(5, "birthday", Partitioning.Invariant,
new DateTimeFieldProperties()))
.AddField(new AssetsField(6, "pictures", Partitioning.Invariant,
new AssetsFieldProperties()))
.AddField(new ReferencesField(7, "friends", Partitioning.Invariant,
new ReferencesFieldProperties()))
.AddField(new StringField(8, "dashed-field", Partitioning.Invariant,
new StringFieldProperties()))
.Update(new SchemaProperties { Hints = "The User" });
var builder = new EdmModelBuilder(new MemoryCache(Options.Create(new MemoryCacheOptions())));
var schema = A.Dummy<ISchemaEntity>();
A.CallTo(() => schema.Id).Returns(Guid.NewGuid());
A.CallTo(() => schema.Version).Returns(3);
A.CallTo(() => schema.SchemaDef).Returns(schemaDef);
var app = A.Dummy<IAppEntity>();
A.CallTo(() => app.Id).Returns(Guid.NewGuid());
A.CallTo(() => app.Version).Returns(3);
A.CallTo(() => app.LanguagesConfig).Returns(languagesConfig);
edmModel = builder.BuildEdmModel(schema, app);
}
[Fact]
public void Should_parse_query()
{
var parser = edmModel.ParseQuery("$filter=data/firstName/de eq 'Sebastian'");
Assert.NotNull(parser);
}
[Fact]
public void Should_make_query_with_underscore_field()
{
var i = F("$filter=data/dashed_field/iv eq 'Value'");
var o = C("{ 'do.8.iv' : 'Value' }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_not_operator()
{
var i = F("$filter=not endswith(data/firstName/de, 'Sebastian')");
var o = C("{ 'do.1.de' : { '$not' : /Sebastian$/i } }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_starts_with_query()
{
var i = F("$filter=startswith(data/firstName/de, 'Sebastian')");
var o = C("{ 'do.1.de' : /^Sebastian/i }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_ends_with_query()
{
var i = F("$filter=endswith(data/firstName/de, 'Sebastian')");
var o = C("{ 'do.1.de' : /Sebastian$/i }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_contains_query()
{
var i = F("$filter=contains(data/firstName/de, 'Sebastian')");
var o = C("{ 'do.1.de' : /Sebastian/i }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_contains_query_with_equals()
{
var i = F("$filter=contains(data/firstName/de, 'Sebastian') eq true");
var o = C("{ 'do.1.de' : /Sebastian/i }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_negated_contains_query_with_equals()
{
var i = F("$filter=contains(data/firstName/de, 'Sebastian') eq false");
var o = C("{ 'do.1.de' : { '$not' : /Sebastian/i } }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_negated_contains_query_and_other()
{
var i = F("$filter=contains(data/firstName/de, 'Sebastian') eq false and data/isAdmin/iv eq true");
var o = C("{ 'do.1.de' : { '$not' : /Sebastian/i }, 'do.3.iv' : true }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_string_equals_query()
{
var i = F("$filter=data/firstName/de eq 'Sebastian'");
var o = C("{ 'do.1.de' : 'Sebastian' }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_datetime_equals_query()
{
var i = F("$filter=data/birthday/iv eq 1988-01-19T12:00:00Z");
var o = C("{ 'do.5.iv' : ISODate(\"1988-01-19T12:00:00Z\") }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_boolean_equals_query()
{
var i = F("$filter=data/isAdmin/iv eq true");
var o = C("{ 'do.3.iv' : true }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_string_not_equals_query()
{
var i = F("$filter=data/firstName/de ne 'Sebastian'");
var o = C("{ '$or' : [{ 'do.1.de' : { '$exists' : false } }, { 'do.1.de' : { '$ne' : 'Sebastian' } }] }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_number_less_than_query()
{
var i = F("$filter=data/age/iv lt 1");
var o = C("{ 'do.4.iv' : { '$lt' : 1.0 } }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_number_less_equals_query()
{
var i = F("$filter=data/age/iv le 1");
var o = C("{ 'do.4.iv' : { '$lte' : 1.0 } }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_number_greater_than_query()
{
var i = F("$filter=data/age/iv gt 1");
var o = C("{ 'do.4.iv' : { '$gt' : 1.0 } }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_number_greater_equals_query()
{
var i = F("$filter=data/age/iv ge 1");
var o = C("{ 'do.4.iv' : { '$gte' : 1.0 } }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_equals_query_for_assets()
{
var i = F("$filter=data/pictures/iv eq 'guid'");
var o = C("{ 'do.6.iv' : 'guid' }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_equals_query_for_references()
{
var i = F("$filter=data/friends/iv eq 'guid'");
var o = C("{ 'do.7.iv' : 'guid' }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_and_query()
{
var i = F("$filter=data/age/iv eq 1 and data/age/iv eq 2");
var o = C("{ '$and' : [{ 'do.4.iv' : 1.0 }, { 'do.4.iv' : 2.0 }] }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_or_query()
{
var i = F("$filter=data/age/iv eq 1 or data/age/iv eq 2");
var o = C("{ '$or' : [{ 'do.4.iv' : 1.0 }, { 'do.4.iv' : 2.0 }] }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_full_text_query()
{
var i = F("$search=Hello my World");
var o = C("{ '$text' : { '$search' : 'Hello my World' } }");
Assert.Equal(o, i);
}
[Fact]
public void Should_create_full_text_query_with_and()
{
var i = F("$search=A and B");
var o = C("{ '$text' : { '$search' : 'A and B' } }");
Assert.Equal(o, i);
}
[Fact]
public void Should_convert_orderby_with_single_statements()
{
var i = S("$orderby=data/age/iv desc");
var o = C("{ 'do.4.iv' : -1 }");
Assert.Equal(o, i);
}
[Fact]
public void Should_convert_orderby_with_multiple_statements()
{
var i = S("$orderby=data/age/iv, data/firstName/en desc");
var o = C("{ 'do.4.iv' : 1, 'do.1.en' : -1 }");
Assert.Equal(o, i);
}
[Fact]
public void Should_set_top()
{
var parser = edmModel.ParseQuery("$top=3");
var cursor = A.Fake<IFindFluent<MongoContentEntity, MongoContentEntity>>();
cursor.Take(parser);
A.CallTo(() => cursor.Limit(3)).MustHaveHappened();
}
[Fact]
public void Should_set_max_top_if_larger()
{
var parser = edmModel.ParseQuery("$top=300");
var cursor = A.Fake<IFindFluent<MongoContentEntity, MongoContentEntity>>();
cursor.Take(parser);
A.CallTo(() => cursor.Limit(200)).MustHaveHappened();
}
[Fact]
public void Should_set_default_top()
{
var parser = edmModel.ParseQuery(string.Empty);
var cursor = A.Fake<IFindFluent<MongoContentEntity, MongoContentEntity>>();
cursor.Take(parser);
A.CallTo(() => cursor.Limit(20)).MustHaveHappened();
}
[Fact]
public void Should_set_skip()
{
var parser = edmModel.ParseQuery("$skip=3");
var cursor = A.Fake<IFindFluent<MongoContentEntity, MongoContentEntity>>();
cursor.Skip(parser);
A.CallTo(() => cursor.Skip(3)).MustHaveHappened();
}
[Fact]
public void Should_not_set_skip()
{
var parser = edmModel.ParseQuery(string.Empty);
var cursor = A.Fake<IFindFluent<MongoContentEntity, MongoContentEntity>>();
cursor.Take(parser);
A.CallTo(() => cursor.Skip(A<int>.Ignored)).MustNotHaveHappened();
}
private static string C(string value)
{
return value.Replace('\'', '"');
}
private string S(string value)
{
var parser = edmModel.ParseQuery(value);
var cursor = A.Fake<IFindFluent<MongoContentEntity, MongoContentEntity>>();
var i = string.Empty;
A.CallTo(() => cursor.Sort(A<SortDefinition<MongoContentEntity>>.Ignored))
.Invokes((SortDefinition<MongoContentEntity> sortDefinition) =>
{
i = sortDefinition.Render(serializer, registry).ToString();
});
cursor.Sort(parser, schemaDef);
return i;
}
private string F(string value)
{
var parser = edmModel.ParseQuery(value);
var query = FilterBuilder.Build(parser, schemaDef).Render(serializer, registry).ToString();
return query;
}
}
}

50
tests/Squidex.Domain.Apps.Read.Tests/Contents/TestData/FakeAssetEntity.cs

@ -1,50 +0,0 @@
// ==========================================================================
// MockupAssetEntity.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using NodaTime;
using Squidex.Domain.Apps.Read.Assets;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Read.Contents.TestData
{
public sealed class FakeAssetEntity : IAssetEntity
{
public Guid Id { get; set; }
public Guid AppId { get; set; }
public Guid AssetId { get; set; }
public Instant Created { get; set; }
public Instant LastModified { get; set; }
public RefToken CreatedBy { get; set; }
public RefToken LastModifiedBy { get; set; }
public long Version { get; set; }
public string MimeType { get; set; }
public string FileName { get; set; }
public long FileSize { get; set; }
public long FileVersion { get; set; }
public bool IsImage { get; set; }
public bool IsDeleted { get; set; }
public int? PixelWidth { get; set; }
public int? PixelHeight { get; set; }
}
}

33
tests/Squidex.Domain.Apps.Read.Tests/Contents/TestData/FakeContentEntity.cs

@ -1,33 +0,0 @@
// ==========================================================================
// FakeContentEntity.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using NodaTime;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Read.Contents.TestData
{
public sealed class FakeContentEntity : IContentEntity
{
public Guid Id { get; set; }
public Guid AppId { get; set; }
public long Version { get; set; }
public Instant Created { get; set; }
public Instant LastModified { get; set; }
public RefToken CreatedBy { get; set; }
public RefToken LastModifiedBy { get; set; }
public NamedContentData Data { get; set; }
public Status Status { get; set; }
}
}

40
tests/Squidex.Domain.Apps.Read.Tests/Contents/TestData/FakeUrlGenerator.cs

@ -1,40 +0,0 @@
// ==========================================================================
// FakeUrlGenerator.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Assets;
using Squidex.Domain.Apps.Read.Contents.GraphQL;
using Squidex.Domain.Apps.Read.Schemas;
namespace Squidex.Domain.Apps.Read.Contents.TestData
{
public sealed class FakeUrlGenerator : IGraphQLUrlGenerator
{
public bool CanGenerateAssetSourceUrl { get; } = true;
public string GenerateAssetUrl(IAppEntity app, IAssetEntity asset)
{
return $"assets/{asset.Id}";
}
public string GenerateAssetThumbnailUrl(IAppEntity app, IAssetEntity asset)
{
return $"assets/{asset.Id}?width=100";
}
public string GenerateAssetSourceUrl(IAppEntity app, IAssetEntity asset)
{
return $"assets/source/{asset.Id}";
}
public string GenerateContentUrl(IAppEntity app, ISchemaEntity schema, IContentEntity content)
{
return $"contents/{schema.Name}/{content.Id}";
}
}
}

99
tests/Squidex.Domain.Apps.Read.Tests/Rules/RuleDequeuerTests.cs

@ -1,99 +0,0 @@
// ==========================================================================
// RuleDequeuerGrainTests.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.Read.Rules.Repositories;
using Squidex.Infrastructure.Log;
using Xunit;
#pragma warning disable RECS0165 // Asynchronous methods should return a Task instead of void
namespace Squidex.Domain.Apps.Read.Rules
{
public class RuleDequeuerTests
{
private readonly IClock clock = A.Fake<IClock>();
private readonly ISemanticLog log = A.Fake<ISemanticLog>();
private readonly IAppProvider appProvider = A.Fake<IAppProvider>();
private readonly IRuleEventRepository ruleEventRepository = A.Fake<IRuleEventRepository>();
private readonly RuleService ruleService = A.Fake<RuleService>();
private readonly RuleDequeuer sut;
private readonly Instant now = SystemClock.Instance.GetCurrentInstant();
public RuleDequeuerTests()
{
A.CallTo(() => clock.GetCurrentInstant()).Returns(now);
sut = new RuleDequeuer(
ruleService,
ruleEventRepository,
log,
clock);
}
[Theory]
[InlineData(0, 0, RuleResult.Success, RuleJobResult.Success)]
[InlineData(0, 5, RuleResult.Timeout, RuleJobResult.Retry)]
[InlineData(1, 60, RuleResult.Timeout, RuleJobResult.Retry)]
[InlineData(2, 360, RuleResult.Failed, RuleJobResult.Retry)]
[InlineData(3, 720, RuleResult.Failed, RuleJobResult.Retry)]
[InlineData(4, 0, RuleResult.Failed, RuleJobResult.Failed)]
public async Task Should_set_next_attempt_based_on_num_calls(int calls, int minutes, RuleResult result, RuleJobResult jobResult)
{
var actionData = new RuleJobData();
var actionName = "MyAction";
var @event = CreateEvent(calls, actionName, actionData);
var requestElapsed = TimeSpan.FromMinutes(1);
var requestDump = "Dump";
A.CallTo(() => ruleService.InvokeAsync(@event.Job.ActionName, @event.Job.ActionData))
.Returns((requestDump, result, requestElapsed));
Instant? nextCall = null;
if (minutes > 0)
{
nextCall = now.Plus(Duration.FromMinutes(minutes));
}
await sut.HandleAsync(@event);
sut.Dispose();
A.CallTo(() => ruleEventRepository.MarkSentAsync(@event.Id, requestDump, result, jobResult, requestElapsed, nextCall))
.MustHaveHappened();
}
private IRuleEventEntity CreateEvent(int numCalls, string actionName, RuleJobData actionData)
{
var @event = A.Fake<IRuleEventEntity>();
var job = new RuleJob
{
RuleId = Guid.NewGuid(),
ActionData = actionData,
ActionName = actionName,
Created = now
};
A.CallTo(() => @event.Id).Returns(Guid.NewGuid());
A.CallTo(() => @event.Job).Returns(job);
A.CallTo(() => @event.Created).Returns(now);
A.CallTo(() => @event.NumCalls).Returns(numCalls);
return @event;
}
}
}

102
tests/Squidex.Domain.Apps.Read.Tests/Rules/RuleEnqueuerTests.cs

@ -1,102 +0,0 @@
// ==========================================================================
// RuleEnqueuerTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
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.Contents;
using Squidex.Domain.Apps.Read.Rules.Repositories;
using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing;
using Xunit;
namespace Squidex.Domain.Apps.Read.Rules
{
public class RuleEnqueuerTests
{
private readonly IAppProvider appProvider = A.Fake<IAppProvider>();
private readonly IRuleEventRepository ruleEventRepository = A.Fake<IRuleEventRepository>();
private readonly RuleService ruleService = A.Fake<RuleService>();
private readonly Instant now = SystemClock.Instance.GetCurrentInstant();
private readonly NamedId<Guid> appId = new NamedId<Guid>(Guid.NewGuid(), "my-app");
private readonly RuleEnqueuer sut;
public RuleEnqueuerTests()
{
sut = new RuleEnqueuer(
ruleEventRepository,
appProvider,
ruleService);
}
[Fact]
public void Should_return_contents_filter_for_events_filter()
{
Assert.Equal(".*", sut.EventsFilter);
}
[Fact]
public void Should_return_type_name_for_name()
{
Assert.Equal(typeof(RuleEnqueuer).Name, sut.Name);
}
[Fact]
public Task Should_do_nothing_on_clear()
{
return sut.ClearAsync();
}
[Fact]
public async Task Should_update_repositories_on_with_jobs_from_sender()
{
var @event = Envelope.Create(new ContentCreated { AppId = appId });
var rule1 = new Rule(new ContentChangedTrigger(), new WebhookAction { Url = new Uri("https://squidex.io") });
var rule2 = new Rule(new ContentChangedTrigger(), new WebhookAction { Url = new Uri("https://squidex.io") });
var rule3 = new Rule(new ContentChangedTrigger(), new WebhookAction { Url = new Uri("https://squidex.io") });
var job1 = new RuleJob { Created = now };
var job2 = new RuleJob { Created = now };
var ruleEntity1 = A.Fake<IRuleEntity>();
var ruleEntity2 = A.Fake<IRuleEntity>();
var ruleEntity3 = A.Fake<IRuleEntity>();
A.CallTo(() => ruleEntity1.RuleDef).Returns(rule1);
A.CallTo(() => ruleEntity2.RuleDef).Returns(rule2);
A.CallTo(() => ruleEntity3.RuleDef).Returns(rule3);
A.CallTo(() => appProvider.GetRulesAsync(appId.Name))
.Returns(new List<IRuleEntity> { ruleEntity1, ruleEntity2, ruleEntity3 });
A.CallTo(() => ruleService.CreateJob(rule1, @event))
.Returns(job1);
A.CallTo(() => ruleService.CreateJob(rule2, @event))
.Returns(job2);
A.CallTo(() => ruleService.CreateJob(rule3, @event))
.Returns(null);
await sut.On(@event);
A.CallTo(() => ruleEventRepository.EnqueueAsync(job1, now))
.MustHaveHappened();
A.CallTo(() => ruleEventRepository.EnqueueAsync(job2, now))
.MustHaveHappened();
}
}
}

37
tests/Squidex.Domain.Apps.Read.Tests/Squidex.Domain.Apps.Read.Tests.csproj

@ -1,37 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<RootNamespace>Squidex.Domain.Apps.Read</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Remove="MongoDb\**" />
<EmbeddedResource Remove="MongoDb\**" />
<None Remove="MongoDb\**" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Core.Model\Squidex.Domain.Apps.Core.Model.csproj" />
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Core.Operations\Squidex.Domain.Apps.Core.Operations.csproj" />
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Events\Squidex.Domain.Apps.Events.csproj" />
<ProjectReference Include="..\..\src\Squidex.Infrastructure\Squidex.Infrastructure.csproj" />
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Read\Squidex.Domain.Apps.Read.csproj" />
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Read.MongoDb\Squidex.Domain.Apps.Read.MongoDb.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FakeItEasy" Version="4.2.0" />
<PackageReference Include="FluentAssertions" Version="4.19.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="MongoDB.Driver" Version="2.4.4" />
<PackageReference Include="RefactoringEssentials" Version="5.4.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2" />
<PackageReference Include="System.ValueTuple" Version="4.4.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" />
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\Squidex.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>

244
tests/Squidex.Domain.Apps.Write.Tests/Apps/AppCommandMiddlewareTests.cs

@ -1,244 +0,0 @@
// ==========================================================================
// 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;
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.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.GetAppAsync(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")));
}
}
}

288
tests/Squidex.Domain.Apps.Write.Tests/Apps/AppDomainObjectTests.cs

@ -1,288 +0,0 @@
// ==========================================================================
// 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.Commands;
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();
}
}
}

51
tests/Squidex.Domain.Apps.Write.Tests/Apps/AppEventTests.cs

@ -1,51 +0,0 @@
// ==========================================================================
// 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;
}
}
}

142
tests/Squidex.Domain.Apps.Write.Tests/Apps/Guards/GuardAppClientsTests.cs

@ -1,142 +0,0 @@
// ==========================================================================
// GuardAppClientsTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Write.Apps.Commands;
using Squidex.Infrastructure;
using Xunit;
#pragma warning disable SA1310 // Field names must not contain underscore
namespace Squidex.Domain.Apps.Write.Apps.Guards
{
public class GuardAppClientsTests
{
private readonly AppClients clients_0 = AppClients.Empty;
[Fact]
public void CanAttach_should_throw_execption_if_client_id_is_null()
{
var command = new AttachClient();
Assert.Throws<ValidationException>(() => GuardAppClients.CanAttach(clients_0, command));
}
[Fact]
public void CanAttach_should_throw_exception_if_client_already_exists()
{
var command = new AttachClient { Id = "android" };
var clients_1 = clients_0.Add("android", "secret");
Assert.Throws<ValidationException>(() => GuardAppClients.CanAttach(clients_1, command));
}
[Fact]
public void CanAttach_should_not_throw_exception_if_client_is_free()
{
var command = new AttachClient { Id = "ios" };
var clients_1 = clients_0.Add("android", "secret");
GuardAppClients.CanAttach(clients_1, command);
}
[Fact]
public void CanRevoke_should_throw_execption_if_client_id_is_null()
{
var command = new RevokeClient();
Assert.Throws<ValidationException>(() => GuardAppClients.CanRevoke(clients_0, command));
}
[Fact]
public void CanRevoke_should_throw_exception_if_client_is_not_found()
{
var command = new RevokeClient { Id = "ios" };
Assert.Throws<DomainObjectNotFoundException>(() => GuardAppClients.CanRevoke(clients_0, command));
}
[Fact]
public void CanRevoke_should_not_throw_exception_if_client_is_found()
{
var command = new RevokeClient { Id = "ios" };
var clients_1 = clients_0.Add("ios", "secret");
GuardAppClients.CanRevoke(clients_1, command);
}
[Fact]
public void CanUpdate_should_throw_execption_if_client_id_is_null()
{
var command = new UpdateClient();
Assert.Throws<ValidationException>(() => GuardAppClients.CanUpdate(clients_0, command));
}
[Fact]
public void UpdateClient_should_throw_exception_if_client_is_not_found()
{
var command = new UpdateClient { Id = "ios", Name = "iOS" };
Assert.Throws<DomainObjectNotFoundException>(() => GuardAppClients.CanUpdate(clients_0, command));
}
[Fact]
public void UpdateClient_should_throw_exception_if_client_has_no_name_and_permission()
{
var command = new UpdateClient { Id = "ios" };
var clients_1 = clients_0.Add("ios", "secret");
Assert.Throws<ValidationException>(() => GuardAppClients.CanUpdate(clients_1, command));
}
[Fact]
public void UpdateClient_should_throw_exception_if_client_has_invalid_permission()
{
var command = new UpdateClient { Id = "ios", Permission = (AppClientPermission)10 };
var clients_1 = clients_0.Add("ios", "secret");
Assert.Throws<ValidationException>(() => GuardAppClients.CanUpdate(clients_1, command));
}
[Fact]
public void UpdateClient_should_throw_exception_if_client_has_same_name()
{
var command = new UpdateClient { Id = "ios", Name = "ios" };
var clients_1 = clients_0.Add("ios", "secret");
Assert.Throws<ValidationException>(() => GuardAppClients.CanUpdate(clients_1, command));
}
[Fact]
public void UpdateClient_should_throw_exception_if_client_has_same_permission()
{
var command = new UpdateClient { Id = "ios", Permission = AppClientPermission.Editor };
var clients_1 = clients_0.Add("ios", "secret");
Assert.Throws<ValidationException>(() => GuardAppClients.CanUpdate(clients_1, command));
}
[Fact]
public void UpdateClient_should_not_throw_exception_if_command_is_valid()
{
var command = new UpdateClient { Id = "ios", Name = "iOS", Permission = AppClientPermission.Reader };
var clients_1 = clients_0.Add("ios", "secret");
GuardAppClients.CanUpdate(clients_1, command);
}
}
}

158
tests/Squidex.Domain.Apps.Write.Tests/Apps/Guards/GuardAppContributorsTests.cs

@ -1,158 +0,0 @@
// ==========================================================================
// 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;
#pragma warning disable SA1310 // Field names must not contain underscore
namespace Squidex.Domain.Apps.Write.Apps.Guards
{
public class GuardAppContributorsTests
{
private readonly IUserResolver users = A.Fake<IUserResolver>();
private readonly IAppLimitsPlan appPlan = A.Fake<IAppLimitsPlan>();
private readonly AppContributors contributors_0 = AppContributors.Empty;
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();
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors_0, command, users, appPlan));
}
[Fact]
public Task CanAssign_should_throw_exception_if_permission_not_valid()
{
var command = new AssignContributor { ContributorId = "1", Permission = (AppContributorPermission)10 };
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors_0, 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_1 = contributors_0.Assign("1", AppContributorPermission.Owner);
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors_1, 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 };
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors_0, 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_1 = contributors_0.Assign("1", AppContributorPermission.Owner);
var contributors_2 = contributors_1.Assign("2", AppContributorPermission.Editor);
return Assert.ThrowsAsync<ValidationException>(() => GuardAppContributors.CanAssign(contributors_2, command, users, appPlan));
}
[Fact]
public Task CanAssign_should_not_throw_exception_if_user_found()
{
var command = new AssignContributor { ContributorId = "1" };
return GuardAppContributors.CanAssign(contributors_0, command, users, appPlan);
}
[Fact]
public Task CanAssign_should_not_throw_exception_if_contributor_has_another_permission()
{
var command = new AssignContributor { ContributorId = "1" };
var contributors_1 = contributors_0.Assign("1", AppContributorPermission.Editor);
return GuardAppContributors.CanAssign(contributors_1, 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_1 = contributors_0.Assign("1", AppContributorPermission.Editor);
var contributors_2 = contributors_1.Assign("2", AppContributorPermission.Editor);
return GuardAppContributors.CanAssign(contributors_2, command, users, appPlan);
}
[Fact]
public void CanRemove_should_throw_exception_if_contributor_id_is_null()
{
var command = new RemoveContributor();
Assert.Throws<ValidationException>(() => GuardAppContributors.CanRemove(contributors_0, command));
}
[Fact]
public void CanRemove_should_throw_exception_if_contributor_not_found()
{
var command = new RemoveContributor { ContributorId = "1" };
Assert.Throws<DomainObjectNotFoundException>(() => GuardAppContributors.CanRemove(contributors_0, command));
}
[Fact]
public void CanRemove_should_throw_exception_if_contributor_is_only_owner()
{
var command = new RemoveContributor { ContributorId = "1" };
var contributors_1 = contributors_0.Assign("1", AppContributorPermission.Owner);
var contributors_2 = contributors_1.Assign("2", AppContributorPermission.Editor);
Assert.Throws<ValidationException>(() => GuardAppContributors.CanRemove(contributors_2, command));
}
[Fact]
public void CanRemove_should_not_throw_exception_if_contributor_not_only_owner()
{
var command = new RemoveContributor { ContributorId = "1" };
var contributors_1 = contributors_0.Assign("1", AppContributorPermission.Owner);
var contributors_2 = contributors_1.Assign("2", AppContributorPermission.Owner);
GuardAppContributors.CanRemove(contributors_2, command);
}
}
}

131
tests/Squidex.Domain.Apps.Write.Tests/Apps/Guards/GuardAppLanguagesTests.cs

@ -1,131 +0,0 @@
// ==========================================================================
// GuardAppLanguagesTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Write.Apps.Commands;
using Squidex.Infrastructure;
using Xunit;
#pragma warning disable SA1310 // Field names must not contain underscore
namespace Squidex.Domain.Apps.Write.Apps.Guards
{
public class GuardAppLanguagesTests
{
private readonly LanguagesConfig languages_0 = LanguagesConfig.Build(Language.DE);
[Fact]
public void CanAddLanguage_should_throw_exception_if_language_is_null()
{
var command = new AddLanguage();
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanAdd(languages_0, command));
}
[Fact]
public void CanAddLanguage_should_throw_exception_if_language_already_added()
{
var command = new AddLanguage { Language = Language.DE };
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanAdd(languages_0, command));
}
[Fact]
public void CanAddLanguage_should_not_throw_exception_if_language_valid()
{
var command = new AddLanguage { Language = Language.EN };
GuardAppLanguages.CanAdd(languages_0, command);
}
[Fact]
public void CanRemoveLanguage_should_throw_exception_if_language_is_null()
{
var command = new RemoveLanguage();
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanRemove(languages_0, command));
}
[Fact]
public void CanRemoveLanguage_should_throw_exception_if_language_not_found()
{
var command = new RemoveLanguage { Language = Language.EN };
Assert.Throws<DomainObjectNotFoundException>(() => GuardAppLanguages.CanRemove(languages_0, command));
}
[Fact]
public void CanRemoveLanguage_should_throw_exception_if_language_is_master()
{
var command = new RemoveLanguage { Language = Language.DE };
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanRemove(languages_0, command));
}
[Fact]
public void CanRemoveLanguage_should_not_throw_exception_if_language_is_valid()
{
var command = new RemoveLanguage { Language = Language.EN };
var languages_1 = languages_0.Set(new LanguageConfig(Language.EN));
GuardAppLanguages.CanRemove(languages_1, command);
}
[Fact]
public void CanUpdateLanguage_should_throw_exception_if_language_is_null()
{
var command = new UpdateLanguage();
var languages_1 = languages_0.Set(new LanguageConfig(Language.EN));
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanUpdate(languages_1, 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_1 = languages_0.Set(new LanguageConfig(Language.EN));
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanUpdate(languages_1, 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_1 = languages_0.Set(new LanguageConfig(Language.EN));
Assert.Throws<ValidationException>(() => GuardAppLanguages.CanUpdate(languages_1, command));
}
[Fact]
public void CanUpdateLanguage_should_throw_exception_if_not_found()
{
var command = new UpdateLanguage { Language = Language.IT };
var languages_1 = languages_0.Set(new LanguageConfig(Language.EN));
Assert.Throws<DomainObjectNotFoundException>(() => GuardAppLanguages.CanUpdate(languages_1, 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_1 = languages_0.Set(new LanguageConfig(Language.EN));
GuardAppLanguages.CanUpdate(languages_1, command);
}
}
}

120
tests/Squidex.Domain.Apps.Write.Tests/Apps/Guards/GuardAppTests.cs

@ -1,120 +0,0 @@
// ==========================================================================
// 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;
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.GetAppAsync("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.GetAppAsync("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);
}
}
}

139
tests/Squidex.Domain.Apps.Write.Tests/Assets/AssetCommandMiddlewareTests.cs

@ -1,139 +0,0 @@
// ==========================================================================
// 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.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();
}
}
}

213
tests/Squidex.Domain.Apps.Write.Tests/Assets/AssetDomainObjectTests.cs

@ -1,213 +0,0 @@
// ==========================================================================
// 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.Commands;
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);
}
}
}

65
tests/Squidex.Domain.Apps.Write.Tests/Assets/Guards/GuardAssetTests.cs

@ -1,65 +0,0 @@
// ==========================================================================
// 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);
}
}
}

247
tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentCommandMiddlewareTests.cs

@ -1,247 +0,0 @@
// ==========================================================================
// 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.Apps;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Core.Scripting;
using Squidex.Domain.Apps.Read;
using Squidex.Domain.Apps.Read.Apps;
using Squidex.Domain.Apps.Read.Assets.Repositories;
using Squidex.Domain.Apps.Read.Contents.Repositories;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Domain.Apps.Write.Contents.Commands;
using Squidex.Domain.Apps.Write.TestHelpers;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Xunit;
namespace Squidex.Domain.Apps.Write.Contents
{
public class ContentCommandMiddlewareTests : HandlerTestBase<ContentDomainObject>
{
private readonly ContentCommandMiddleware sut;
private readonly ContentDomainObject content;
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")
.AddField(new NumberField(1, "my-field1", Partitioning.Invariant,
new NumberFieldProperties { IsRequired = true }))
.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>(), scriptEngine, A.Dummy<IContentRepository>());
A.CallTo(() => app.LanguagesConfig).Returns(languagesConfig);
A.CallTo(() => appProvider.GetAppAsync(AppName)).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(() => appProvider.GetAppWithSchemaAsync(AppName, SchemaId)).Returns((app, 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 });
}
}
}

280
tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentDomainObjectTests.cs

@ -1,280 +0,0 @@
// ==========================================================================
// 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.Commands;
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);
}
}
}

70
tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentEventTests.cs

@ -1,70 +0,0 @@
// ==========================================================================
// 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;
}
}
}

140
tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentVersionLoaderTests.cs

@ -1,140 +0,0 @@
// ==========================================================================
// 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.EventSourcing;
using Squidex.Infrastructure.States;
using Xunit;
namespace Squidex.Domain.Apps.Write.Contents
{
public class ContentVersionLoaderTests
{
private readonly IEventStore eventStore = A.Fake<IEventStore>();
private readonly IEventDataFormatter formatter = A.Fake<IEventDataFormatter>();
private readonly IStreamNameResolver nameResolver = A.Fake<IStreamNameResolver>();
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.ToString()))
.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, 0))
.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, 0))
.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, 0))
.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, 0))
.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, 0))
.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);
}
}
}

99
tests/Squidex.Domain.Apps.Write.Tests/Contents/Guard/GuardContentTests.cs

@ -1,99 +0,0 @@
// ==========================================================================
// GuardContentTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Write.Contents.Commands;
using Squidex.Domain.Apps.Write.Contents.Guards;
using Squidex.Infrastructure;
using Xunit;
namespace Squidex.Domain.Apps.Write.Contents.Guard
{
public class GuardContentTests
{
[Fact]
public void CanCreate_should_throw_exception_if_data_is_null()
{
var command = new CreateContent();
Assert.Throws<ValidationException>(() => GuardContent.CanCreate(command));
}
[Fact]
public void CanCreate_should_not_throw_exception_if_data_is_not_null()
{
var command = new CreateContent { Data = new NamedContentData() };
GuardContent.CanCreate(command);
}
[Fact]
public void CanUpdate_should_throw_exception_if_data_is_null()
{
var command = new UpdateContent();
Assert.Throws<ValidationException>(() => GuardContent.CanUpdate(command));
}
[Fact]
public void CanUpdate_should_not_throw_exception_if_data_is_not_null()
{
var command = new UpdateContent { Data = new NamedContentData() };
GuardContent.CanUpdate(command);
}
[Fact]
public void CanPatch_should_throw_exception_if_data_is_null()
{
var command = new PatchContent();
Assert.Throws<ValidationException>(() => GuardContent.CanPatch(command));
}
[Fact]
public void CanPatch_should_not_throw_exception_if_data_is_not_null()
{
var command = new PatchContent { Data = new NamedContentData() };
GuardContent.CanPatch(command);
}
[Fact]
public void CanChangeContentStatus_should_throw_exception_if_status_not_valid()
{
var command = new ChangeContentStatus { Status = (Status)10 };
Assert.Throws<ValidationException>(() => GuardContent.CanChangeContentStatus(Status.Archived, command));
}
[Fact]
public void CanChangeContentStatus_should_throw_exception_if_status_flow_not_valid()
{
var command = new ChangeContentStatus { Status = Status.Published };
Assert.Throws<ValidationException>(() => GuardContent.CanChangeContentStatus(Status.Archived, command));
}
[Fact]
public void CanChangeContentStatus_not_should_throw_exception_if_status_flow_valid()
{
var command = new ChangeContentStatus { Status = Status.Published };
GuardContent.CanChangeContentStatus(Status.Draft, command);
}
[Fact]
public void CanPatch_should_not_throw_exception()
{
var command = new DeleteContent();
GuardContent.CanDelete(command);
}
}
}

48
tests/Squidex.Domain.Apps.Write.Tests/Rules/Guards/Actions/WebhookActionTests.cs

@ -1,48 +0,0 @@
// ==========================================================================
// WebhookActionTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Rules.Actions;
using Xunit;
namespace Squidex.Domain.Apps.Write.Rules.Guards.Actions
{
public sealed class WebhookActionTests
{
[Fact]
public async Task Should_add_error_if_url_is_null()
{
var action = new WebhookAction { Url = null };
var errors = await RuleActionValidator.ValidateAsync(action);
Assert.NotEmpty(errors);
}
[Fact]
public async Task Should_add_error_if_url_is_relative()
{
var action = new WebhookAction { Url = new Uri("/invalid", UriKind.Relative) };
var errors = await RuleActionValidator.ValidateAsync(action);
Assert.NotEmpty(errors);
}
[Fact]
public async Task Should_not_add_error_if_url_is_absolute()
{
var action = new WebhookAction { Url = new Uri("https://squidex.io", UriKind.Absolute) };
var errors = await RuleActionValidator.ValidateAsync(action);
Assert.Empty(errors);
}
}
}

168
tests/Squidex.Domain.Apps.Write.Tests/Rules/Guards/GuardRuleTests.cs

@ -1,168 +0,0 @@
// ==========================================================================
// GuardRuleTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Immutable;
using System.Threading.Tasks;
using FakeItEasy;
using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Core.Rules.Actions;
using Squidex.Domain.Apps.Core.Rules.Triggers;
using Squidex.Domain.Apps.Read;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Domain.Apps.Write.Rules.Commands;
using Squidex.Infrastructure;
using Xunit;
#pragma warning disable SA1310 // Field names must not contain underscore
namespace Squidex.Domain.Apps.Write.Rules.Guards
{
public class GuardRuleTests
{
private readonly Uri validUrl = new Uri("https://squidex.io");
private readonly Rule rule_0 = new Rule(new ContentChangedTrigger(), new WebhookAction());
private readonly NamedId<Guid> appId = new NamedId<Guid>(Guid.NewGuid(), "my-app");
private readonly IAppProvider appProvider = A.Fake<IAppProvider>();
public GuardRuleTests()
{
A.CallTo(() => appProvider.GetSchemaAsync(appId.Name, A<Guid>.Ignored, false))
.Returns(A.Fake<ISchemaEntity>());
}
[Fact]
public async Task CanCreate_should_throw_exception_if_trigger_null()
{
var command = CreateCommand(new CreateRule
{
Trigger = null,
Action = new WebhookAction
{
Url = validUrl
}
});
await Assert.ThrowsAsync<ValidationException>(() => GuardRule.CanCreate(command, appProvider));
}
[Fact]
public async Task CanCreate_should_throw_exception_if_action_null()
{
var command = CreateCommand(new CreateRule
{
Trigger = new ContentChangedTrigger
{
Schemas = ImmutableList<ContentChangedTriggerSchema>.Empty
},
Action = null
});
await Assert.ThrowsAsync<ValidationException>(() => GuardRule.CanCreate(command, appProvider));
}
[Fact]
public async Task CanCreate_should_not_throw_exception_if_trigger_and_action_valid()
{
var command = CreateCommand(new CreateRule
{
Trigger = new ContentChangedTrigger
{
Schemas = ImmutableList<ContentChangedTriggerSchema>.Empty
},
Action = new WebhookAction
{
Url = validUrl
}
});
await GuardRule.CanCreate(command, appProvider);
}
[Fact]
public async Task CanUpdate_should_throw_exception_if_action_and_trigger_are_null()
{
var command = new UpdateRule();
await Assert.ThrowsAsync<ValidationException>(() => GuardRule.CanUpdate(command, appProvider));
}
[Fact]
public async Task CanUpdate_should_not_throw_exception_if_trigger_and_action_valid()
{
var command = CreateCommand(new UpdateRule
{
Trigger = new ContentChangedTrigger
{
Schemas = ImmutableList<ContentChangedTriggerSchema>.Empty
},
Action = new WebhookAction
{
Url = validUrl
}
});
await GuardRule.CanUpdate(command, appProvider);
}
[Fact]
public void CanEnable_should_throw_exception_if_rule_enabled()
{
var command = new EnableRule();
var rule_1 = rule_0.Enable();
Assert.Throws<ValidationException>(() => GuardRule.CanEnable(command, rule_1));
}
[Fact]
public void CanEnable_should_not_throw_exception_if_rule_disabled()
{
var command = new EnableRule();
var rule_1 = rule_0.Disable();
GuardRule.CanEnable(command, rule_1);
}
[Fact]
public void CanDisable_should_throw_exception_if_rule_disabled()
{
var command = new DisableRule();
var rule_1 = rule_0.Disable();
Assert.Throws<ValidationException>(() => GuardRule.CanDisable(command, rule_1));
}
[Fact]
public void CanDisable_should_not_throw_exception_if_rule_enabled()
{
var command = new DisableRule();
var rule_1 = rule_0.Enable();
GuardRule.CanDisable(command, rule_1);
}
[Fact]
public void CanDelete_should_not_throw_exception()
{
var command = new DeleteRule();
GuardRule.CanDelete(command);
}
private T CreateCommand<T>(T command) where T : AppCommand
{
command.AppId = appId;
return command;
}
}
}

84
tests/Squidex.Domain.Apps.Write.Tests/Rules/Guards/Triggers/ContentChangedTriggerTests.cs

@ -1,84 +0,0 @@
// ==========================================================================
// ContentChangedTriggerTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Immutable;
using System.Threading.Tasks;
using FakeItEasy;
using Squidex.Domain.Apps.Core.Rules.Triggers;
using Squidex.Domain.Apps.Read;
using Squidex.Domain.Apps.Read.Schemas;
using Xunit;
namespace Squidex.Domain.Apps.Write.Rules.Guards.Triggers
{
public class ContentChangedTriggerTests
{
private readonly IAppProvider appProvider = A.Fake<IAppProvider>();
private readonly string appName = "my-app";
[Fact]
public async Task Should_add_error_if_schemas_ids_are_not_valid()
{
A.CallTo(() => appProvider.GetSchemaAsync(appName, A<Guid>.Ignored, false))
.Returns(Task.FromResult<ISchemaEntity>(null));
var trigger = new ContentChangedTrigger
{
Schemas = ImmutableList.Create(
new ContentChangedTriggerSchema()
)
};
var errors = await RuleTriggerValidator.ValidateAsync(appName, trigger, appProvider);
Assert.NotEmpty(errors);
}
[Fact]
public async Task Should_not_add_error_if_schemas_is_null()
{
var trigger = new ContentChangedTrigger();
var errors = await RuleTriggerValidator.ValidateAsync(appName, trigger, appProvider);
Assert.Empty(errors);
}
[Fact]
public async Task Should_not_add_error_if_schemas_is_empty()
{
var trigger = new ContentChangedTrigger
{
Schemas = ImmutableList<ContentChangedTriggerSchema>.Empty
};
var errors = await RuleTriggerValidator.ValidateAsync(appName, trigger, appProvider);
Assert.Empty(errors);
}
[Fact]
public async Task Should_not_add_error_if_schemas_ids_are_valid()
{
A.CallTo(() => appProvider.GetSchemaAsync(appName, A<Guid>.Ignored, false))
.Returns(A.Fake<ISchemaEntity>());
var trigger = new ContentChangedTrigger
{
Schemas = ImmutableList.Create(
new ContentChangedTriggerSchema()
)
};
var errors = await RuleTriggerValidator.ValidateAsync(appName, trigger, appProvider);
Assert.Empty(errors);
}
}
}

117
tests/Squidex.Domain.Apps.Write.Tests/Rules/RuleCommandMiddlewareTests.cs

@ -1,117 +0,0 @@
// ==========================================================================
// RuleCommandMiddlewareTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Threading.Tasks;
using FakeItEasy;
using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Core.Rules.Actions;
using Squidex.Domain.Apps.Core.Rules.Triggers;
using Squidex.Domain.Apps.Read;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Domain.Apps.Write.Rules.Commands;
using Squidex.Domain.Apps.Write.TestHelpers;
using Squidex.Infrastructure.Commands;
using Xunit;
namespace Squidex.Domain.Apps.Write.Rules
{
public class RuleCommandMiddlewareTests : HandlerTestBase<RuleDomainObject>
{
private readonly IAppProvider appProvider = A.Fake<IAppProvider>();
private readonly RuleCommandMiddleware sut;
private readonly RuleDomainObject rule;
private readonly RuleTrigger ruleTrigger = new ContentChangedTrigger();
private readonly RuleAction ruleAction = new WebhookAction { Url = new Uri("https://squidex.io") };
private readonly Guid ruleId = Guid.NewGuid();
public RuleCommandMiddlewareTests()
{
A.CallTo(() => appProvider.GetSchemaAsync(A<string>.Ignored, A<Guid>.Ignored, false))
.Returns(A.Fake<ISchemaEntity>());
rule = new RuleDomainObject(ruleId, -1);
sut = new RuleCommandMiddleware(Handler, appProvider);
}
[Fact]
public async Task Create_should_create_domain_object()
{
var context = CreateContextForCommand(new CreateRule { Trigger = ruleTrigger, Action = ruleAction });
await TestCreate(rule, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task Update_should_update_domain_object()
{
var context = CreateContextForCommand(new UpdateRule { Trigger = ruleTrigger, Action = ruleAction });
CreateRule();
await TestUpdate(rule, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task Enable_should_update_domain_object()
{
CreateRule();
DisableRule();
var command = CreateContextForCommand(new EnableRule { RuleId = ruleId });
await TestUpdate(rule, async _ =>
{
await sut.HandleAsync(command);
});
}
[Fact]
public async Task Disable_should_update_domain_object()
{
CreateRule();
var command = CreateContextForCommand(new DisableRule { RuleId = ruleId });
await TestUpdate(rule, async _ =>
{
await sut.HandleAsync(command);
});
}
[Fact]
public async Task Delete_should_update_domain_object()
{
CreateRule();
var command = CreateContextForCommand(new DeleteRule { RuleId = ruleId });
await TestUpdate(rule, async _ =>
{
await sut.HandleAsync(command);
});
}
private void DisableRule()
{
rule.Disable(new DisableRule());
}
private void CreateRule()
{
rule.Create(new CreateRule { Trigger = ruleTrigger, Action = ruleAction });
}
}
}

240
tests/Squidex.Domain.Apps.Write.Tests/Rules/RuleDomainObjectTests.cs

@ -1,240 +0,0 @@
// ==========================================================================
// RuleDomainObjectTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Immutable;
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.Rules;
using Squidex.Domain.Apps.Write.Rules.Commands;
using Squidex.Domain.Apps.Write.TestHelpers;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Xunit;
namespace Squidex.Domain.Apps.Write.Rules
{
public class RuleDomainObjectTests : HandlerTestBase<RuleDomainObject>
{
private readonly RuleTrigger ruleTrigger = new ContentChangedTrigger();
private readonly RuleAction ruleAction = new WebhookAction { Url = new Uri("https://squidex.io") };
private readonly RuleDomainObject sut;
public Guid RuleId { get; } = Guid.NewGuid();
public RuleDomainObjectTests()
{
sut = new RuleDomainObject(RuleId, 0);
}
[Fact]
public void Create_should_throw_exception_if_created()
{
sut.Create(new CreateRule { Trigger = ruleTrigger, Action = ruleAction });
Assert.Throws<DomainException>(() =>
{
sut.Create(CreateRuleCommand(new CreateRule { Trigger = ruleTrigger, Action = ruleAction }));
});
}
[Fact]
public void Create_should_create_events()
{
var command = new CreateRule { Trigger = ruleTrigger, Action = ruleAction };
sut.Create(CreateRuleCommand(command));
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateRuleEvent(new RuleCreated { Trigger = ruleTrigger, Action = ruleAction })
);
}
[Fact]
public void Update_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.Update(CreateRuleCommand(new UpdateRule { Trigger = ruleTrigger, Action = ruleAction }));
});
}
[Fact]
public void Update_should_throw_exception_if_rule_is_deleted()
{
CreateRule();
DeleteRule();
Assert.Throws<DomainException>(() =>
{
sut.Update(CreateRuleCommand(new UpdateRule { Trigger = ruleTrigger, Action = ruleAction }));
});
}
[Fact]
public void Update_should_create_events()
{
var newTrigger = new ContentChangedTrigger
{
Schemas = ImmutableList<ContentChangedTriggerSchema>.Empty
};
var newAction = new WebhookAction
{
Url = new Uri("https://squidex.io/v2")
};
CreateRule();
var command = new UpdateRule { Trigger = newTrigger, Action = newAction };
sut.Update(CreateRuleCommand(command));
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateRuleEvent(new RuleUpdated { Trigger = newTrigger, Action = newAction })
);
}
[Fact]
public void Enable_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.Enable(CreateRuleCommand(new EnableRule()));
});
}
[Fact]
public void Enable_should_throw_exception_if_rule_is_deleted()
{
CreateRule();
DeleteRule();
Assert.Throws<DomainException>(() =>
{
sut.Enable(CreateRuleCommand(new EnableRule()));
});
}
[Fact]
public void Enable_should_create_events()
{
CreateRule();
var command = new EnableRule();
sut.Enable(CreateRuleCommand(command));
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateRuleEvent(new RuleEnabled())
);
}
[Fact]
public void Disable_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.Disable(CreateRuleCommand(new DisableRule()));
});
}
[Fact]
public void Disable_should_throw_exception_if_rule_is_deleted()
{
CreateRule();
DeleteRule();
Assert.Throws<DomainException>(() =>
{
sut.Disable(CreateRuleCommand(new DisableRule()));
});
}
[Fact]
public void Disable_should_create_events()
{
CreateRule();
var command = new DisableRule();
sut.Disable(CreateRuleCommand(command));
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateRuleEvent(new RuleDisabled())
);
}
[Fact]
public void Delete_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.Delete(CreateRuleCommand(new DeleteRule()));
});
}
[Fact]
public void Delete_should_throw_exception_if_already_deleted()
{
CreateRule();
DeleteRule();
Assert.Throws<DomainException>(() =>
{
sut.Delete(CreateRuleCommand(new DeleteRule()));
});
}
[Fact]
public void Delete_should_update_create_events()
{
CreateRule();
sut.Delete(CreateRuleCommand(new DeleteRule()));
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateRuleEvent(new RuleDeleted())
);
}
private void CreateRule()
{
sut.Create(CreateRuleCommand(new CreateRule { Trigger = ruleTrigger, Action = ruleAction }));
((IAggregate)sut).ClearUncommittedEvents();
}
private void DeleteRule()
{
sut.Delete(CreateRuleCommand(new DeleteRule()));
((IAggregate)sut).ClearUncommittedEvents();
}
protected T CreateRuleEvent<T>(T @event) where T : RuleEvent
{
@event.RuleId = RuleId;
return CreateEvent(@event);
}
protected T CreateRuleCommand<T>(T command) where T : RuleAggregateCommand
{
command.RuleId = RuleId;
return CreateCommand(command);
}
}
}

104
tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/AssetsFieldPropertiesTests.cs

@ -1,104 +0,0 @@
// ==========================================================================
// AssetsFieldPropertiesTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure;
using Xunit;
namespace Squidex.Domain.Apps.Write.Schemas.Guards.FieldProperties
{
public class AssetsFieldPropertiesTests
{
[Fact]
public void Should_add_error_if_min_items_greater_than_max_items()
{
var sut = new AssetsFieldProperties { MinItems = 10, MaxItems = 5 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Max items must be greater than min items.", "MinItems", "MaxItems")
});
}
[Fact]
public void Should_add_error_if_min_width_greater_than_max_width()
{
var sut = new AssetsFieldProperties { MinWidth = 10, MaxWidth = 5 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Max width must be greater than min width.", "MinWidth", "MaxWidth")
});
}
[Fact]
public void Should_add_error_if_min_height_greater_than_max_height()
{
var sut = new AssetsFieldProperties { MinHeight = 10, MaxHeight = 5 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Max height must be greater than min height.", "MinHeight", "MaxHeight")
});
}
[Fact]
public void Should_add_error_if_min_size_greater_than_max_size()
{
var sut = new AssetsFieldProperties { MinSize = 10, MaxSize = 5 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Max size must be greater than min size.", "MinSize", "MaxSize")
});
}
[Fact]
public void Should_add_error_if_only_aspect_width_is_defined()
{
var sut = new AssetsFieldProperties { AspectWidth = 10 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Aspect width and height must be defined.", "AspectWidth", "AspectHeight")
});
}
[Fact]
public void Should_add_error_if_only_aspect_height_is_defined()
{
var sut = new AssetsFieldProperties { AspectHeight = 10 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Aspect width and height must be defined.", "AspectWidth", "AspectHeight")
});
}
}
}

34
tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/BooleanFieldPropertiesTests.cs

@ -1,34 +0,0 @@
// ==========================================================================
// BooleanFieldPropertiesTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure;
using Xunit;
namespace Squidex.Domain.Apps.Write.Schemas.Guards.FieldProperties
{
public class BooleanFieldPropertiesTests
{
[Fact]
public void Should_add_error_if_editor_is_not_valid()
{
var sut = new BooleanFieldProperties { Editor = (BooleanFieldEditor)123 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Editor is not a valid value.", "Editor")
});
}
}
}

126
tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/DateTimeFieldPropertiesTests.cs

@ -1,126 +0,0 @@
// ==========================================================================
// DateTimeFieldPropertiesTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using NodaTime;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure;
using Xunit;
namespace Squidex.Domain.Apps.Write.Schemas.Guards.FieldProperties
{
public class DateTimeFieldPropertiesTests
{
[Fact]
public void Should_not_add_error_if_sut_is_valid()
{
var sut = new DateTimeFieldProperties
{
MinValue = FutureDays(10),
MaxValue = FutureDays(20),
DefaultValue = FutureDays(15)
};
var errors = FieldPropertiesValidator.Validate(sut).ToList();
Assert.Empty(errors);
}
[Fact]
public void Should_add_error_if_default_value_is_less_than_min()
{
var sut = new DateTimeFieldProperties { MinValue = FutureDays(10), DefaultValue = FutureDays(5) };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Default value must be greater than min value.", "DefaultValue")
});
}
[Fact]
public void Should_add_error_if_default_value_is_greater_than_min()
{
var sut = new DateTimeFieldProperties { MaxValue = FutureDays(10), DefaultValue = FutureDays(15) };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Default value must be less than max value.", "DefaultValue")
});
}
[Fact]
public void Should_add_error_if_min_greater_than_max()
{
var sut = new DateTimeFieldProperties { MinValue = FutureDays(10), MaxValue = FutureDays(5) };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Max value must be greater than min value.", "MinValue", "MaxValue")
});
}
[Fact]
public void Should_add_error_if_editor_is_not_valid()
{
var sut = new DateTimeFieldProperties { Editor = (DateTimeFieldEditor)123 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Editor is not a valid value.", "Editor")
});
}
[Fact]
public void Should_add_error_if_calculated_default_value_is_not_valid()
{
var sut = new DateTimeFieldProperties { CalculatedDefaultValue = (DateTimeCalculatedDefaultValue)123 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Calculated default value is not valid.", "CalculatedDefaultValue")
});
}
[Fact]
public void Should_add_error_if_calculated_default_value_default_value_is_defined()
{
var sut = new DateTimeFieldProperties { CalculatedDefaultValue = DateTimeCalculatedDefaultValue.Now, DefaultValue = FutureDays(10) };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Calculated default value and default value cannot be used together.", "CalculatedDefaultValue", "DefaultValue")
});
}
private static Instant FutureDays(int days)
{
return Instant.FromDateTimeUtc(DateTime.UtcNow.Date.AddDays(days));
}
}
}

34
tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/GeolocationFieldPropertiesTests.cs

@ -1,34 +0,0 @@
// ==========================================================================
// GeolocationPropertiesTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure;
using Xunit;
namespace Squidex.Domain.Apps.Write.Schemas.Guards.FieldProperties
{
public class GeolocationFieldPropertiesTests
{
[Fact]
public void Should_add_error_if_editor_is_not_valid()
{
var sut = new GeolocationFieldProperties { Editor = (GeolocationFieldEditor)123 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Editor is not a valid value.", "Editor")
});
}
}
}

27
tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/JsonFieldPropertiesTests.cs

@ -1,27 +0,0 @@
// ==========================================================================
// 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);
}
}
}

134
tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/NumberFieldPropertiesTests.cs

@ -1,134 +0,0 @@
// ==========================================================================
// NumberFieldPropertiesTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using FluentAssertions;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure;
using Xunit;
namespace Squidex.Domain.Apps.Write.Schemas.Guards.FieldProperties
{
public class NumberFieldPropertiesTests
{
[Fact]
public void Should_not_add_error_if_sut_is_valid()
{
var sut = new NumberFieldProperties
{
MinValue = 0,
MaxValue = 100,
DefaultValue = 5
};
var errors = FieldPropertiesValidator.Validate(sut).ToList();
Assert.Empty(errors);
}
[Fact]
public void Should_add_error_if_default_value_is_less_than_min()
{
var sut = new NumberFieldProperties { MinValue = 10, DefaultValue = 5 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Default value must be greater than min value.", "DefaultValue")
});
}
[Fact]
public void Should_add_error_if_default_value_is_greater_than_min()
{
var sut = new NumberFieldProperties { MaxValue = 0, DefaultValue = 5 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Default value must be less than max value.", "DefaultValue")
});
}
[Fact]
public void Should_add_error_if_min_greater_than_max()
{
var sut = new NumberFieldProperties { MinValue = 10, MaxValue = 5 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Max value must be greater than min value.", "MinValue", "MaxValue")
});
}
[Fact]
public void Should_add_error_if_allowed_values_and_max_value_is_specified()
{
var sut = new NumberFieldProperties { MaxValue = 10, AllowedValues = ImmutableList.Create(4d) };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Either allowed values or min and max value can be defined.", "AllowedValues", "MinValue", "MaxValue")
});
}
[Fact]
public void Should_add_error_if_allowed_values_and_min_value_is_specified()
{
var sut = new NumberFieldProperties { MinValue = 10, AllowedValues = ImmutableList.Create(4d) };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Either allowed values or min and max value can be defined.", "AllowedValues", "MinValue", "MaxValue")
});
}
[Fact]
public void Should_add_error_if_radio_button_has_no_allowed_values()
{
var sut = new NumberFieldProperties { Editor = NumberFieldEditor.Radio };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Radio buttons or dropdown list need allowed values.", "AllowedValues")
});
}
[Fact]
public void Should_add_error_if_editor_is_not_valid()
{
var sut = new NumberFieldProperties { Editor = (NumberFieldEditor)123 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Editor is not a valid value.", "Editor")
});
}
}
}

34
tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/ReferencesFieldPropertiesTests.cs

@ -1,34 +0,0 @@
// ==========================================================================
// ReferencesFieldPropertiesTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure;
using Xunit;
namespace Squidex.Domain.Apps.Write.Schemas.Guards.FieldProperties
{
public class ReferencesFieldPropertiesTests
{
[Fact]
public void Should_add_error_if_min_greater_than_max()
{
var sut = new ReferencesFieldProperties { MinItems = 10, MaxItems = 5 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Max items must be greater than min items.", "MinItems", "MaxItems")
});
}
}
}

105
tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/StringFieldPropertiesTests.cs

@ -1,105 +0,0 @@
// ==========================================================================
// StringFieldPropertiesTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using FluentAssertions;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure;
using Xunit;
namespace Squidex.Domain.Apps.Write.Schemas.Guards.FieldProperties
{
public class StringFieldPropertiesTests
{
[Fact]
public void Should_add_error_if_min_greater_than_max()
{
var sut = new StringFieldProperties { MinLength = 10, MaxLength = 5 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Max length must be greater than min length.", "MinLength", "MaxLength")
});
}
[Fact]
public void Should_add_error_if_allowed_values_and_max_value_is_specified()
{
var sut = new StringFieldProperties { MinLength = 10, AllowedValues = ImmutableList.Create("4") };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Either allowed values or min and max length can be defined.", "AllowedValues", "MinLength", "MaxLength")
});
}
[Fact]
public void Should_add_error_if_allowed_values_and_min_value_is_specified()
{
var sut = new StringFieldProperties { MaxLength = 10, AllowedValues = ImmutableList.Create("4") };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Either allowed values or min and max length can be defined.", "AllowedValues", "MinLength", "MaxLength")
});
}
[Fact]
public void Should_add_error_if_radio_button_has_no_allowed_values()
{
var sut = new StringFieldProperties { Editor = StringFieldEditor.Radio };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Radio buttons or dropdown list need allowed values.", "AllowedValues")
});
}
[Fact]
public void Should_add_error_if_editor_is_not_valid()
{
var sut = new StringFieldProperties { Editor = (StringFieldEditor)123 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Editor is not a valid value.", "Editor")
});
}
[Fact]
public void Should_add_error_if_pattern_is_not_valid_regex()
{
var sut = new StringFieldProperties { Pattern = "[0-9{1}" };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Pattern is not a valid expression.", "Pattern")
});
}
}
}

34
tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/FieldProperties/TagsFieldPropertiesTests.cs

@ -1,34 +0,0 @@
// ==========================================================================
// TagsFieldPropertiesTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure;
using Xunit;
namespace Squidex.Domain.Apps.Write.Schemas.Guards.FieldProperties
{
public class TagsFieldPropertiesTests
{
[Fact]
public void Should_add_error_if_min_greater_than_max()
{
var sut = new TagsFieldProperties { MinItems = 10, MaxItems = 5 };
var errors = FieldPropertiesValidator.Validate(sut).ToList();
errors.ShouldBeEquivalentTo(
new List<ValidationError>
{
new ValidationError("Max items must be greater than min items.", "MinItems", "MaxItems")
});
}
}
}

247
tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/GuardSchemaFieldTests.cs

@ -1,247 +0,0 @@
// ==========================================================================
// GuardSchemaFieldTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Write.Schemas.Commands;
using Squidex.Infrastructure;
using Xunit;
#pragma warning disable SA1310 // Field names must not contain underscore
namespace Squidex.Domain.Apps.Write.Schemas.Guards
{
public class GuardSchemaFieldTests
{
private readonly Schema schema_0;
private readonly StringFieldProperties validProperties = new StringFieldProperties();
private readonly StringFieldProperties invalidProperties = new StringFieldProperties { MinLength = 10, MaxLength = 5 };
public GuardSchemaFieldTests()
{
schema_0 =
new Schema("my-schema")
.AddField(new StringField(1, "field1", Partitioning.Invariant))
.AddField(new StringField(2, "field2", Partitioning.Invariant));
}
[Fact]
public void CanHide_should_throw_exception_if_already_hidden()
{
var command = new HideField { FieldId = 1 };
var schema_1 = schema_0.HideField(1);
Assert.Throws<DomainException>(() => GuardSchemaField.CanHide(schema_1, command));
}
[Fact]
public void CanHide_should_throw_exception_if_not_found()
{
var command = new HideField { FieldId = 3 };
Assert.Throws<DomainObjectNotFoundException>(() => GuardSchemaField.CanHide(schema_0, command));
}
[Fact]
public void CanHide_hould_not_throw_exception_if_visible()
{
var command = new HideField { FieldId = 1 };
GuardSchemaField.CanHide(schema_0, command);
}
[Fact]
public void CanDisable_should_throw_exception_if_already_disabled()
{
var command = new DisableField { FieldId = 1 };
var schema_1 = schema_0.DisableField(1);
Assert.Throws<DomainException>(() => GuardSchemaField.CanDisable(schema_1, command));
}
[Fact]
public void CanDisable_should_throw_exception_if_not_found()
{
var command = new DisableField { FieldId = 3 };
Assert.Throws<DomainObjectNotFoundException>(() => GuardSchemaField.CanDisable(schema_0, command));
}
[Fact]
public void CanDisable_Should_not_throw_exception_if_enabled()
{
var command = new DisableField { FieldId = 1 };
GuardSchemaField.CanDisable(schema_0, command);
}
[Fact]
public void CanShow_should_throw_exception_if_already_shown()
{
var command = new ShowField { FieldId = 1 };
Assert.Throws<DomainException>(() => GuardSchemaField.CanShow(schema_0, command));
}
[Fact]
public void CanShow_should_throw_exception_if_not_found()
{
var command = new ShowField { FieldId = 3 };
Assert.Throws<DomainObjectNotFoundException>(() => GuardSchemaField.CanShow(schema_0, command));
}
[Fact]
public void CanShow_should_not_throw_exception_if_hidden()
{
var command = new ShowField { FieldId = 1 };
var schema_1 = schema_0.HideField(1);
GuardSchemaField.CanShow(schema_1, command);
}
[Fact]
public void CanEnable_should_throw_exception_if_already_enabled()
{
var command = new EnableField { FieldId = 1 };
Assert.Throws<DomainException>(() => GuardSchemaField.CanEnable(schema_0, command));
}
[Fact]
public void CanEnable_should_throw_exception_if_not_found()
{
var command = new EnableField { FieldId = 3 };
Assert.Throws<DomainObjectNotFoundException>(() => GuardSchemaField.CanEnable(schema_0, command));
}
[Fact]
public void CanEnable_should_not_throw_exception_if_disabled()
{
var command = new EnableField { FieldId = 1 };
var schema_1 = schema_0.DisableField(1);
GuardSchemaField.CanEnable(schema_1, command);
}
[Fact]
public void CanLock_should_throw_exception_if_already_locked()
{
var command = new LockField { FieldId = 1 };
var schema_1 = schema_0.LockField(1);
Assert.Throws<DomainException>(() => GuardSchemaField.CanLock(schema_1, command));
}
[Fact]
public void LockField_should_throw_exception_if_not_found()
{
var command = new LockField { FieldId = 3 };
Assert.Throws<DomainObjectNotFoundException>(() => GuardSchemaField.CanLock(schema_0, command));
}
[Fact]
public void CanLock_should_not_throw_exception_if_not_locked()
{
var command = new LockField { FieldId = 1 };
GuardSchemaField.CanLock(schema_0, command);
}
[Fact]
public void CanDelete_should_throw_exception_if_not_found()
{
var command = new DeleteField { FieldId = 3 };
Assert.Throws<DomainObjectNotFoundException>(() => GuardSchemaField.CanDelete(schema_0, command));
}
[Fact]
public void CanDelete_should_throw_exception_if_locked()
{
var command = new DeleteField { FieldId = 1 };
var schema_1 = schema_0.LockField(1);
Assert.Throws<DomainException>(() => GuardSchemaField.CanDelete(schema_1, command));
}
[Fact]
public void CanDelete_should_not_throw_exception_if_not_locked()
{
var command = new DeleteField { FieldId = 1 };
GuardSchemaField.CanDelete(schema_0, command);
}
[Fact]
public void CanUpdate_should_throw_exception_if_locked()
{
var command = new UpdateField { FieldId = 1, Properties = new StringFieldProperties() };
var schema_1 = schema_0.LockField(1);
Assert.Throws<DomainException>(() => GuardSchemaField.CanUpdate(schema_1, command));
}
[Fact]
public void CanUpdate_should_not_throw_exception_if_not_locked()
{
var command = new UpdateField { FieldId = 1, Properties = new StringFieldProperties() };
GuardSchemaField.CanUpdate(schema_0, command);
}
[Fact]
public void CanAdd_should_throw_exception_if_field_already_exists()
{
var command = new AddField { Name = "field1", Properties = new StringFieldProperties() };
Assert.Throws<ValidationException>(() => GuardSchemaField.CanAdd(schema_0, command));
}
[Fact]
public void CanAdd_should_throw_exception_if_name_not_valid()
{
var command = new AddField { Name = "INVALID_NAME", Properties = validProperties };
Assert.Throws<ValidationException>(() => GuardSchemaField.CanAdd(schema_0, command));
}
[Fact]
public void CanAdd_should_throw_exception_if_properties_not_valid()
{
var command = new AddField { Name = "field3", Properties = invalidProperties };
Assert.Throws<ValidationException>(() => GuardSchemaField.CanAdd(schema_0, command));
}
[Fact]
public void CanAdd_should_throw_exception_if_partitioning_not_valid()
{
var command = new AddField { Name = "field3", Partitioning = "INVALID_PARTITIONING", Properties = validProperties };
Assert.Throws<ValidationException>(() => GuardSchemaField.CanAdd(schema_0, command));
}
[Fact]
public void CanAdd_should_not_throw_exception_if_field_not_exists()
{
var command = new AddField { Name = "field3", Properties = new StringFieldProperties() };
GuardSchemaField.CanAdd(schema_0, command);
}
}
}

201
tests/Squidex.Domain.Apps.Write.Tests/Schemas/Guards/GuardSchemaTests.cs

@ -1,201 +0,0 @@
// ==========================================================================
// GuardSchemaTests.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;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Read;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Domain.Apps.Write.Schemas.Commands;
using Squidex.Infrastructure;
using Xunit;
#pragma warning disable SA1310 // Field names must not contain underscore
namespace Squidex.Domain.Apps.Write.Schemas.Guards
{
public class GuardSchemaTests
{
private readonly IAppProvider appProvider = A.Fake<IAppProvider>();
private readonly Schema schema_0;
private readonly NamedId<Guid> appId = new NamedId<Guid>(Guid.NewGuid(), "my-app");
public GuardSchemaTests()
{
schema_0 =
new Schema("my-schema")
.AddField(new StringField(1, "field1", Partitioning.Invariant))
.AddField(new StringField(2, "field2", Partitioning.Invariant));
A.CallTo(() => appProvider.GetSchemaAsync(A<string>.Ignored, "new-schema", false))
.Returns(Task.FromResult<ISchemaEntity>(null));
}
[Fact]
public Task CanCreate_should_throw_exception_if_name_not_valid()
{
var command = new CreateSchema { AppId = appId, Name = "INVALID NAME" };
return Assert.ThrowsAsync<ValidationException>(() => GuardSchema.CanCreate(command, appProvider));
}
[Fact]
public Task CanCreate_should_throw_exception_if_name_already_in_use()
{
A.CallTo(() => appProvider.GetSchemaAsync(A<string>.Ignored, "new-schema", false))
.Returns(Task.FromResult(A.Fake<ISchemaEntity>()));
var command = new CreateSchema { AppId = appId, Name = "new-schema" };
return Assert.ThrowsAsync<ValidationException>(() => GuardSchema.CanCreate(command, appProvider));
}
[Fact]
public Task CanCreate_should_throw_exception_if_fields_not_valid()
{
var command = new CreateSchema
{
AppId = appId,
Fields = new List<CreateSchemaField>
{
new CreateSchemaField
{
Name = null,
Properties = null,
Partitioning = "invalid"
},
new CreateSchemaField
{
Name = null,
Properties = InvalidProperties(),
Partitioning = "invalid"
}
},
Name = "new-schema"
};
return Assert.ThrowsAsync<ValidationException>(() => GuardSchema.CanCreate(command, appProvider));
}
[Fact]
public Task CanCreate_should_throw_exception_if_fields_contain_duplicate_names()
{
var command = new CreateSchema
{
AppId = appId,
Fields = new List<CreateSchemaField>
{
new CreateSchemaField
{
Name = "field1",
Properties = ValidProperties(),
Partitioning = "invariant"
},
new CreateSchemaField
{
Name = "field1",
Properties = ValidProperties(),
Partitioning = "invariant"
}
},
Name = "new-schema"
};
return Assert.ThrowsAsync<ValidationException>(() => GuardSchema.CanCreate(command, appProvider));
}
[Fact]
public Task CanCreate_should_not_throw_exception_if_command_is_valid()
{
var command = new CreateSchema { AppId = appId, Name = "new-schema" };
return GuardSchema.CanCreate(command, appProvider);
}
[Fact]
public void CanPublish_should_throw_exception_if_already_published()
{
var command = new PublishSchema();
var schema_1 = schema_0.Publish();
Assert.Throws<DomainException>(() => GuardSchema.CanPublish(schema_1, command));
}
[Fact]
public void CanPublish_should_not_throw_exception_if_not_published()
{
var command = new PublishSchema();
GuardSchema.CanPublish(schema_0, command);
}
[Fact]
public void CanUnpublish_should_throw_exception_if_already_unpublished()
{
var command = new UnpublishSchema();
Assert.Throws<DomainException>(() => GuardSchema.CanUnpublish(schema_0, command));
}
[Fact]
public void CanUnpublish_should_not_throw_exception_if_already_published()
{
var command = new UnpublishSchema();
var schema_1 = schema_0.Publish();
GuardSchema.CanUnpublish(schema_1, command);
}
[Fact]
public void CanReorder_should_throw_exception_if_field_ids_contains_invalid_id()
{
var command = new ReorderFields { FieldIds = new List<long> { 1, 3 } };
Assert.Throws<ValidationException>(() => GuardSchema.CanReorder(schema_0, command));
}
[Fact]
public void CanReorder_should_throw_exception_if_field_ids_do_not_covers_all_fields()
{
var command = new ReorderFields { FieldIds = new List<long> { 1 } };
Assert.Throws<ValidationException>(() => GuardSchema.CanReorder(schema_0, command));
}
[Fact]
public void CanReorder_should_not_throw_exception_if_field_ids_are_valid()
{
var command = new ReorderFields { FieldIds = new List<long> { 1, 2 } };
GuardSchema.CanReorder(schema_0, command);
}
[Fact]
public void CanDelete_should_not_throw_exception()
{
var command = new DeleteSchema();
GuardSchema.CanDelete(schema_0, command);
}
private static StringFieldProperties ValidProperties()
{
return new StringFieldProperties { MinLength = 10, MaxLength = 20 };
}
private static StringFieldProperties InvalidProperties()
{
return new StringFieldProperties { MinLength = 20, MaxLength = 10 };
}
}
}

278
tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaCommandMiddlewareTests.cs

@ -1,278 +0,0 @@
// ==========================================================================
// SchemaCommandMiddlewareTests.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.Schemas;
using Squidex.Domain.Apps.Read;
using Squidex.Domain.Apps.Read.Schemas;
using Squidex.Domain.Apps.Write.Schemas.Commands;
using Squidex.Domain.Apps.Write.TestHelpers;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Xunit;
namespace Squidex.Domain.Apps.Write.Schemas
{
public class SchemaCommandMiddlewareTests : HandlerTestBase<SchemaDomainObject>
{
private readonly IAppProvider appProvider = A.Fake<IAppProvider>();
private readonly SchemaCommandMiddleware sut;
private readonly SchemaDomainObject schema;
private readonly FieldRegistry registry = new FieldRegistry(new TypeNameRegistry());
private readonly string fieldName = "age";
public SchemaCommandMiddlewareTests()
{
schema = new SchemaDomainObject(SchemaId, -1, registry);
sut = new SchemaCommandMiddleware(Handler, appProvider);
A.CallTo(() => appProvider.GetSchemaAsync(AppName, SchemaName, false))
.Returns((ISchemaEntity)null);
}
[Fact]
public async Task Create_should_create_schema_domain_object()
{
var context = CreateContextForCommand(new CreateSchema { Name = SchemaName, SchemaId = SchemaId });
await TestCreate(schema, async _ =>
{
await sut.HandleAsync(context);
});
Assert.Equal(SchemaId, context.Result<EntityCreatedResult<Guid>>().IdOrValue);
A.CallTo(() => appProvider.GetSchemaAsync(AppName, SchemaName, false)).MustHaveHappened();
}
[Fact]
public async Task UpdateSchema_should_update_domain_object()
{
CreateSchema();
var context = CreateContextForCommand(new UpdateSchema { Properties = new SchemaProperties() });
await TestUpdate(schema, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task ReorderSchema_should_update_domain_object()
{
CreateSchema();
var context = CreateContextForCommand(new ReorderFields { FieldIds = new List<long>() });
await TestUpdate(schema, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task PublishSchema_should_update_domain_object()
{
CreateSchema();
var context = CreateContextForCommand(new PublishSchema());
await TestUpdate(schema, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task UnpublishSchema_should_update_domain_object()
{
CreateSchema();
PublishSchema();
var context = CreateContextForCommand(new UnpublishSchema());
await TestUpdate(schema, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task ConfigureScripts_should_update_domain_object()
{
CreateSchema();
var context = CreateContextForCommand(new ConfigureScripts());
await TestUpdate(schema, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task DeleteSchema_should_update_domain_object()
{
CreateSchema();
var context = CreateContextForCommand(new DeleteSchema());
await TestUpdate(schema, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task Add_should_update_domain_object()
{
CreateSchema();
var context = CreateContextForCommand(new AddField { Name = fieldName, Properties = new NumberFieldProperties() });
await TestUpdate(schema, async _ =>
{
await sut.HandleAsync(context);
});
Assert.Equal(1, context.Result<EntityCreatedResult<long>>().IdOrValue);
}
[Fact]
public async Task UpdateField_should_update_domain_object()
{
CreateSchema();
CreateField();
var context = CreateContextForCommand(new UpdateField { FieldId = 1, Properties = new NumberFieldProperties() });
await TestUpdate(schema, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task LockField_should_update_domain_object()
{
CreateSchema();
CreateField();
var context = CreateContextForCommand(new LockField { FieldId = 1 });
await TestUpdate(schema, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task HideField_should_update_domain_object()
{
CreateSchema();
CreateField();
var context = CreateContextForCommand(new HideField { FieldId = 1 });
await TestUpdate(schema, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task ShowField_should_update_domain_object()
{
CreateSchema();
CreateField();
HideField();
var context = CreateContextForCommand(new ShowField { FieldId = 1 });
await TestUpdate(schema, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task DisableField_should_update_domain_object()
{
CreateSchema();
CreateField();
var context = CreateContextForCommand(new DisableField { FieldId = 1 });
await TestUpdate(schema, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task EnableField_should_update_domain_object()
{
CreateSchema();
CreateField();
DisableField();
var context = CreateContextForCommand(new EnableField { FieldId = 1 });
await TestUpdate(schema, async _ =>
{
await sut.HandleAsync(context);
});
}
[Fact]
public async Task DeleteField_should_update_domain_object()
{
CreateSchema();
CreateField();
var context = CreateContextForCommand(new DeleteField { FieldId = 1 });
await TestUpdate(schema, async _ =>
{
await sut.HandleAsync(context);
});
}
private void CreateSchema()
{
schema.Create(CreateCommand(new CreateSchema { Name = SchemaName }));
}
private void PublishSchema()
{
schema.Publish(CreateCommand(new PublishSchema()));
}
private void CreateField()
{
schema.Add(CreateCommand(new AddField { Name = fieldName, Properties = new NumberFieldProperties() }));
}
private void HideField()
{
schema.HideField(CreateCommand(new HideField { FieldId = 1 }));
}
private void DisableField()
{
schema.DisableField(CreateCommand(new DisableField { FieldId = 1 }));
}
}
}

656
tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaDomainObjectTests.cs

@ -1,656 +0,0 @@
// ==========================================================================
// SchemaDomainObjectTests.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Domain.Apps.Events.Schemas;
using Squidex.Domain.Apps.Write.Schemas.Commands;
using Squidex.Domain.Apps.Write.TestHelpers;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Xunit;
namespace Squidex.Domain.Apps.Write.Schemas
{
public class SchemaDomainObjectTests : HandlerTestBase<SchemaDomainObject>
{
private readonly string fieldName = "age";
private readonly NamedId<long> fieldId;
private readonly SchemaDomainObject sut;
public SchemaDomainObjectTests()
{
fieldId = new NamedId<long>(1, fieldName);
var fieldRegistry = new FieldRegistry(new TypeNameRegistry());
sut = new SchemaDomainObject(SchemaId, 0, fieldRegistry);
}
[Fact]
public void Create_should_throw_exception_if_created()
{
sut.Create(new CreateSchema { Name = SchemaName });
Assert.Throws<DomainException>(() =>
{
sut.Create(CreateCommand(new CreateSchema { Name = SchemaName }));
});
}
[Fact]
public void Create_should_create_schema_and_create_events()
{
var properties = new SchemaProperties();
sut.Create(CreateCommand(new CreateSchema { Name = SchemaName, Properties = properties }));
Assert.Equal(SchemaName, sut.Schema.Name);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new SchemaCreated { Name = SchemaName, Properties = properties })
);
}
[Fact]
public void Create_should_create_schema_with_initial_fields()
{
var properties = new SchemaProperties();
var fields = new List<CreateSchemaField>
{
new CreateSchemaField { Name = "field1", Properties = ValidProperties() },
new CreateSchemaField { Name = "field2", Properties = ValidProperties() }
};
sut.Create(CreateCommand(new CreateSchema { Name = SchemaName, Properties = properties, Fields = fields }));
var @event = (SchemaCreated)sut.GetUncomittedEvents().Single().Payload;
Assert.Equal(SchemaName, sut.Schema.Name);
Assert.Equal(2, @event.Fields.Count);
}
[Fact]
public void Update_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.Update(CreateCommand(new UpdateSchema { Properties = new SchemaProperties() }));
});
}
[Fact]
public void Update_should_throw_exception_if_schema_is_deleted()
{
CreateSchema();
DeleteSchema();
Assert.Throws<DomainException>(() =>
{
sut.Update(CreateCommand(new UpdateSchema { Properties = new SchemaProperties() }));
});
}
[Fact]
public void Update_should_refresh_properties_and_create_events()
{
var properties = new SchemaProperties();
CreateSchema();
sut.Update(CreateCommand(new UpdateSchema { Properties = properties }));
Assert.Equal(properties, sut.Schema.Properties);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new SchemaUpdated { Properties = properties })
);
}
[Fact]
public void ConfigureScripts_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.ConfigureScripts(CreateCommand(new ConfigureScripts()));
});
}
[Fact]
public void ConfigureScripts_should_throw_exception_if_schema_is_deleted()
{
CreateSchema();
DeleteSchema();
Assert.Throws<DomainException>(() =>
{
sut.ConfigureScripts(CreateCommand(new ConfigureScripts()));
});
}
[Fact]
public void ConfigureScripts_should_create_events()
{
CreateSchema();
sut.ConfigureScripts(CreateCommand(new ConfigureScripts
{
ScriptQuery = "<script-query>",
ScriptCreate = "<script-create>",
ScriptUpdate = "<script-update>",
ScriptDelete = "<script-delete>",
ScriptChange = "<script-change>"
}));
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new ScriptsConfigured
{
ScriptQuery = "<script-query>",
ScriptCreate = "<script-create>",
ScriptUpdate = "<script-update>",
ScriptDelete = "<script-delete>",
ScriptChange = "<script-change>"
})
);
}
[Fact]
public void Reorder_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.Reorder(CreateCommand(new ReorderFields { FieldIds = new List<long>() }));
});
}
[Fact]
public void Reorder_should_throw_exception_if_schema_is_deleted()
{
CreateSchema();
DeleteSchema();
Assert.Throws<DomainException>(() =>
{
sut.Reorder(CreateCommand(new ReorderFields { FieldIds = new List<long>() }));
});
}
[Fact]
public void Reorder_should_refresh_properties_and_create_events()
{
var fieldIds = new List<long> { 1, 2 };
CreateSchema();
sut.Add(new AddField { Name = "field1", Properties = ValidProperties() });
sut.Add(new AddField { Name = "field2", Properties = ValidProperties() });
((IAggregate)sut).ClearUncommittedEvents();
sut.Reorder(CreateCommand(new ReorderFields { FieldIds = fieldIds }));
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new SchemaFieldsReordered { FieldIds = fieldIds })
);
}
[Fact]
public void Publish_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.Publish(CreateCommand(new PublishSchema()));
});
}
[Fact]
public void Publish_should_throw_exception_if_schema_is_deleted()
{
CreateSchema();
DeleteSchema();
Assert.Throws<DomainException>(() =>
{
sut.Publish(CreateCommand(new PublishSchema()));
});
}
[Fact]
public void Publish_should_refresh_properties_and_create_events()
{
CreateSchema();
sut.Publish(CreateCommand(new PublishSchema()));
Assert.True(sut.Schema.IsPublished);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new SchemaPublished())
);
}
[Fact]
public void Unpublish_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.Unpublish(CreateCommand(new UnpublishSchema()));
});
}
[Fact]
public void Unpublish_should_throw_exception_if_schema_is_deleted()
{
CreateSchema();
DeleteSchema();
Assert.Throws<DomainException>(() =>
{
sut.Unpublish(CreateCommand(new UnpublishSchema()));
});
}
[Fact]
public void Unpublish_should_refresh_properties_and_create_events()
{
CreateSchema();
PublishSchema();
sut.Unpublish(CreateCommand(new UnpublishSchema()));
Assert.False(sut.Schema.IsPublished);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new SchemaUnpublished())
);
}
[Fact]
public void Delete_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.Delete(CreateCommand(new DeleteSchema()));
});
}
[Fact]
public void Delete_should_throw_exception_if_already_deleted()
{
CreateSchema();
DeleteSchema();
Assert.Throws<DomainException>(() =>
{
sut.Delete(CreateCommand(new DeleteSchema()));
});
}
[Fact]
public void Delete_should_refresh_properties_and_create_events()
{
CreateSchema();
sut.Delete(CreateCommand(new DeleteSchema()));
Assert.True(sut.IsDeleted);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new SchemaDeleted())
);
}
[Fact]
public void AddField_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.Add(CreateCommand(new AddField { Name = fieldName, Properties = ValidProperties() }));
});
}
[Fact]
public void AddField_should_throw_exception_if_schema_is_deleted()
{
CreateSchema();
DeleteSchema();
Assert.Throws<DomainException>(() =>
{
sut.Add(CreateCommand(new AddField { Name = fieldName, Properties = new NumberFieldProperties() }));
});
}
[Fact]
public void Add_should_update_schema_and_create_events()
{
var properties = new NumberFieldProperties();
CreateSchema();
sut.Add(CreateCommand(new AddField { Name = fieldName, Properties = properties }));
Assert.Equal(properties, sut.Schema.FieldsById[1].RawProperties);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new FieldAdded { Name = fieldName, FieldId = fieldId, Properties = properties })
);
}
[Fact]
public void UpdateField_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.UpdateField(CreateCommand(new UpdateField { FieldId = 1, Properties = new NumberFieldProperties() }));
});
}
[Fact]
public void UpdateField_should_throw_exception_if_schema_is_deleted()
{
CreateSchema();
DeleteSchema();
Assert.Throws<DomainException>(() =>
{
sut.UpdateField(CreateCommand(new UpdateField { FieldId = 1, Properties = new NumberFieldProperties() }));
});
}
[Fact]
public void UpdateField_should_update_schema_and_create_events()
{
var properties = new NumberFieldProperties();
CreateSchema();
CreateField();
sut.UpdateField(CreateCommand(new UpdateField { FieldId = 1, Properties = properties }));
Assert.Equal(properties, sut.Schema.FieldsById[1].RawProperties);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new FieldUpdated { FieldId = fieldId, Properties = properties })
);
}
[Fact]
public void LockField_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.LockField(CreateCommand(new LockField { FieldId = 1 }));
});
}
[Fact]
public void LockField_should_throw_exception_if_schema_is_deleted()
{
CreateSchema();
DeleteSchema();
Assert.Throws<DomainException>(() =>
{
sut.LockField(CreateCommand(new LockField { FieldId = 1 }));
});
}
[Fact]
public void LockField_should_update_schema_and_create_events()
{
CreateSchema();
CreateField();
sut.LockField(CreateCommand(new LockField { FieldId = 1 }));
Assert.False(sut.Schema.FieldsById[1].IsDisabled);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new FieldLocked { FieldId = fieldId })
);
}
[Fact]
public void HideField_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.HideField(CreateCommand(new HideField { FieldId = 1 }));
});
}
[Fact]
public void HideField_should_throw_exception_if_schema_is_deleted()
{
CreateSchema();
DeleteSchema();
Assert.Throws<DomainException>(() =>
{
sut.HideField(CreateCommand(new HideField { FieldId = 1 }));
});
}
[Fact]
public void HideField_should_update_schema_and_create_events()
{
CreateSchema();
CreateField();
sut.HideField(CreateCommand(new HideField { FieldId = 1 }));
Assert.True(sut.Schema.FieldsById[1].IsHidden);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new FieldHidden { FieldId = fieldId })
);
}
[Fact]
public void ShowField_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.ShowField(CreateCommand(new ShowField { FieldId = 1 }));
});
}
[Fact]
public void ShowField_should_throw_exception_if_schema_is_deleted()
{
CreateSchema();
DeleteSchema();
Assert.Throws<DomainException>(() =>
{
sut.ShowField(CreateCommand(new ShowField { FieldId = 1 }));
});
}
[Fact]
public void ShowField_should_update_schema_and_create_events()
{
CreateSchema();
CreateField();
sut.HideField(CreateCommand(new HideField { FieldId = 1 }));
sut.ShowField(CreateCommand(new ShowField { FieldId = 1 }));
Assert.False(sut.Schema.FieldsById[1].IsHidden);
sut.GetUncomittedEvents().Skip(1)
.ShouldHaveSameEvents(
CreateEvent(new FieldShown { FieldId = fieldId })
);
}
[Fact]
public void DisableField_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.DisableField(CreateCommand(new DisableField { FieldId = 1 }));
});
}
[Fact]
public void DisableField_should_throw_exception_if_schema_is_deleted()
{
CreateSchema();
DeleteSchema();
Assert.Throws<DomainException>(() =>
{
sut.DisableField(CreateCommand(new DisableField { FieldId = 1 }));
});
}
[Fact]
public void DisableField_should_update_schema_and_create_events()
{
CreateSchema();
CreateField();
sut.DisableField(CreateCommand(new DisableField { FieldId = 1 }));
Assert.True(sut.Schema.FieldsById[1].IsDisabled);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new FieldDisabled { FieldId = fieldId })
);
}
[Fact]
public void EnableField_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.EnableField(CreateCommand(new EnableField { FieldId = 1 }));
});
}
[Fact]
public void EnableField_should_throw_exception_if_schema_is_deleted()
{
CreateSchema();
DeleteSchema();
Assert.Throws<DomainException>(() =>
{
sut.EnableField(CreateCommand(new EnableField { FieldId = 1 }));
});
}
[Fact]
public void EnableField_should_update_schema_and_create_events()
{
CreateSchema();
CreateField();
sut.DisableField(CreateCommand(new DisableField { FieldId = 1 }));
sut.EnableField(CreateCommand(new EnableField { FieldId = 1 }));
Assert.False(sut.Schema.FieldsById[1].IsDisabled);
sut.GetUncomittedEvents().Skip(1)
.ShouldHaveSameEvents(
CreateEvent(new FieldEnabled { FieldId = fieldId })
);
}
[Fact]
public void DeleteField_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.DeleteField(CreateCommand(new DeleteField { FieldId = 1 }));
});
}
[Fact]
public void DeleteField_should_throw_exception_if_schema_is_deleted()
{
CreateSchema();
DeleteSchema();
Assert.Throws<DomainException>(() =>
{
sut.DeleteField(CreateCommand(new DeleteField { FieldId = 1 }));
});
}
[Fact]
public void DeleteField_should_update_schema_and_create_events()
{
CreateSchema();
CreateField();
sut.DeleteField(CreateCommand(new DeleteField { FieldId = 1 }));
Assert.False(sut.Schema.FieldsById.ContainsKey(1));
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateEvent(new FieldDeleted { FieldId = fieldId })
);
}
private void CreateField()
{
sut.Add(new AddField { Name = fieldName, Properties = new NumberFieldProperties() });
((IAggregate)sut).ClearUncommittedEvents();
}
private void CreateSchema()
{
sut.Create(CreateCommand(new CreateSchema { Name = SchemaName }));
((IAggregate)sut).ClearUncommittedEvents();
}
private void PublishSchema()
{
sut.Publish(CreateCommand(new PublishSchema()));
((IAggregate)sut).ClearUncommittedEvents();
}
private void DeleteSchema()
{
sut.Delete(CreateCommand(new DeleteSchema()));
((IAggregate)sut).ClearUncommittedEvents();
}
private static StringFieldProperties ValidProperties()
{
return new StringFieldProperties { MinLength = 10, MaxLength = 20 };
}
private static StringFieldProperties InvalidProperties()
{
return new StringFieldProperties { MinLength = 20, MaxLength = 10 };
}
}
}

29
tests/Squidex.Domain.Apps.Write.Tests/Squidex.Domain.Apps.Write.Tests.csproj

@ -1,29 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
<RootNamespace>Squidex.Domain.Apps.Write</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Core.Model\Squidex.Domain.Apps.Core.Model.csproj" />
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Core.Operations\Squidex.Domain.Apps.Core.Operations.csproj" />
<ProjectReference Include="..\..\src\Squidex.Domain.Apps.Write\Squidex.Domain.Apps.Write.csproj" />
<ProjectReference Include="..\..\src\Squidex.Infrastructure\Squidex.Infrastructure.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FakeItEasy" Version="4.2.0" />
<PackageReference Include="FluentAssertions" Version="4.19.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="RefactoringEssentials" Version="5.4.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2" />
<PackageReference Include="System.ValueTuple" Version="4.4.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" />
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\Squidex.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
</Project>

45
tests/Squidex.Domain.Apps.Write.Tests/TestHelpers/AssertHelper.cs

@ -1,45 +0,0 @@
// ==========================================================================
// AssertHelper.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using Squidex.Infrastructure.EventSourcing;
namespace Squidex.Domain.Apps.Write.TestHelpers
{
public static class AssertHelper
{
public static void ShouldHaveSameEvents(this IEnumerable<Envelope<IEvent>> events, params IEvent[] others)
{
var source = events.Select(x => x.Payload).ToArray();
source.Should().HaveSameCount(others);
for (var i = 0; i < source.Length; i++)
{
var lhs = source[i];
var rhs = others[i];
lhs.ShouldBeSameEvent(rhs);
}
}
public static void ShouldBeSameEvent(this IEvent lhs, IEvent rhs)
{
lhs.Should().BeOfType(rhs.GetType());
((object)lhs).ShouldBeEquivalentTo(rhs, o => o.IncludingAllDeclaredProperties());
}
public static void ShouldBeSameEventType(this IEvent lhs, IEvent rhs)
{
lhs.Should().BeOfType(rhs.GetType());
}
}
}

162
tests/Squidex.Domain.Apps.Write.Tests/TestHelpers/HandlerTestBase.cs

@ -1,162 +0,0 @@
// ==========================================================================
// HandlerTestBase.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Events;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
#pragma warning disable IDE0019 // Use pattern matching
namespace Squidex.Domain.Apps.Write.TestHelpers
{
public abstract class HandlerTestBase<T> where T : DomainObjectBase
{
private sealed class MockupHandler : IAggregateHandler
{
private T domainObject;
public bool IsCreated { get; private set; }
public bool IsUpdated { get; private set; }
public void Init(T newDomainObject)
{
domainObject = newDomainObject;
IsCreated = false;
IsUpdated = false;
}
public async Task<V> CreateAsync<V>(CommandContext context, Func<V, Task> creator) where V : class, IAggregate
{
IsCreated = true;
var @do = domainObject as V;
await creator(domainObject as V);
return @do;
}
public async Task<V> UpdateAsync<V>(CommandContext context, Func<V, Task> updater) where V : class, IAggregate
{
IsUpdated = true;
var @do = domainObject as V;
await updater(domainObject as V);
return @do;
}
}
private readonly MockupHandler handler = new MockupHandler();
protected RefToken User { get; } = new RefToken("subject", Guid.NewGuid().ToString());
protected Guid AppId { get; } = Guid.NewGuid();
protected Guid SchemaId { get; } = Guid.NewGuid();
protected string AppName { get; } = "my-app";
protected string SchemaName { get; } = "my-schema";
protected NamedId<Guid> AppNamedId
{
get { return new NamedId<Guid>(AppId, AppName); }
}
protected NamedId<Guid> SchemaNamedId
{
get { return new NamedId<Guid>(SchemaId, SchemaName); }
}
protected IAggregateHandler Handler
{
get { return handler; }
}
protected CommandContext CreateContextForCommand<TCommand>(TCommand command) where TCommand : SquidexCommand
{
return new CommandContext(CreateCommand(command));
}
protected async Task TestCreate(T domainObject, Func<T, Task> action, bool shouldCreate = true)
{
handler.Init(domainObject);
await action(domainObject);
if (!handler.IsCreated && shouldCreate)
{
throw new InvalidOperationException("Create not called.");
}
}
protected async Task TestUpdate(T domainObject, Func<T, Task> action, bool shouldUpdate = true)
{
handler.Init(domainObject);
await action(domainObject);
if (!handler.IsUpdated && shouldUpdate)
{
throw new InvalidOperationException("Update not called.");
}
}
protected TCommand CreateCommand<TCommand>(TCommand command) where TCommand : SquidexCommand
{
if (command.Actor == null)
{
command.Actor = User;
}
var appCommand = command as AppCommand;
if (appCommand != null && appCommand.AppId == null)
{
appCommand.AppId = AppNamedId;
}
var schemaCommand = command as SchemaCommand;
if (schemaCommand != null && schemaCommand.SchemaId == null)
{
schemaCommand.SchemaId = SchemaNamedId;
}
return command;
}
protected TEvent CreateEvent<TEvent>(TEvent @event) where TEvent : SquidexEvent
{
@event.Actor = User;
var appEvent = @event as AppEvent;
if (appEvent != null)
{
appEvent.AppId = AppNamedId;
}
var schemaEvent = @event as SchemaEvent;
if (schemaEvent != null)
{
schemaEvent.SchemaId = SchemaNamedId;
}
return @event;
}
}
}
#pragma warning restore IDE0019 // Use pattern matching
Loading…
Cancel
Save