diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Apps/MongoAppEntity.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Apps/MongoAppEntity.cs index 64f694162..bee8118bb 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Apps/MongoAppEntity.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Apps/MongoAppEntity.cs @@ -9,6 +9,7 @@ using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using Squidex.Domain.Apps.Entities.Apps.State; +using Squidex.Infrastructure.MongoDb; namespace Squidex.Domain.Apps.Entities.MongoDb.Apps { @@ -21,14 +22,19 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Apps [BsonElement] [BsonRequired] - public AppState State { get; set; } + public int Version { get; set; } [BsonElement] [BsonRequired] - public int Version { get; set; } + public string Name { get; set; } [BsonElement] [BsonRequired] public string[] UserIds { get; set; } + + [BsonJson] + [BsonElement] + [BsonRequired] + public AppState State { get; set; } } } diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Apps/MongoAppRepository.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Apps/MongoAppRepository.cs index ee186a620..f77ab41fa 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Apps/MongoAppRepository.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Apps/MongoAppRepository.cs @@ -25,18 +25,24 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Apps { } - protected override Task SetupCollectionAsync(IMongoCollection collection) + protected override string CollectionName() { - return collection.Indexes.CreateOneAsync(Index.Ascending(x => x.UserIds)); + return "Snapshots_Apps"; + } + + protected override async Task SetupCollectionAsync(IMongoCollection collection) + { + await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.UserIds)); + await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.Name)); } public async Task FindAppIdByNameAsync(string name) { var appEntity = - await Collection.Find(x => x.State.Name == name).Only(x => x.Id) + await Collection.Find(x => x.Name == name).Only(x => x.Id) .FirstOrDefaultAsync(); - return appEntity != null ? Guid.Parse(appEntity.Id) : Guid.Empty; + return appEntity != null ? Guid.Parse(appEntity["_id"].AsString) : Guid.Empty; } public async Task> QueryUserAppIdsAsync(string userId) @@ -45,7 +51,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Apps await Collection.Find(x => x.UserIds.Contains(userId)).Only(x => x.Id) .ToListAsync(); - return appEntities.Select(x => Guid.Parse(x.Id)).ToList(); + return appEntities.Select(x => Guid.Parse(x["_id"].AsString)).ToList(); } public async Task> QueryUserAppNamesAsync(string userId) @@ -75,9 +81,12 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Apps { try { + value.Version = newVersion; + await Collection.UpdateOneAsync(x => x.Id == key && x.Version == oldVersion, Update .Set(x => x.UserIds, value.Contributors.Keys.ToArray()) + .Set(x => x.Name, value.Name) .Set(x => x.State, value) .Set(x => x.Version, newVersion), Upsert); diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs index 445ebe747..36dc642cb 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetRepository.cs @@ -116,6 +116,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets { try { + value.Version = newVersion; + await Collection.UpdateOneAsync(x => x.Id == key && x.Version == oldVersion, Update .Set(x => x.State, value) @@ -132,7 +134,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Assets if (existingVersion != null) { - throw new InconsistentStateException(existingVersion.Version, oldVersion, ex); + throw new InconsistentStateException(existingVersion["Version"].AsInt64, oldVersion, ex); } } else diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs index 8b927faf5..bac856632 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs @@ -45,7 +45,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents protected override string CollectionName() { - return "Snapshots_Assets"; + return "Snapshots_Contents"; } protected override async Task SetupCollectionAsync(IMongoCollection collection) @@ -89,6 +89,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents try { + value.Version = newVersion; + await Collection.InsertOneAsync(document); } catch (MongoWriteException ex) @@ -101,7 +103,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents if (existingVersion != null) { - throw new InconsistentStateException(existingVersion.Version, oldVersion, ex); + throw new InconsistentStateException(existingVersion["Version"].AsInt64, oldVersion, ex); } } else @@ -206,7 +208,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents await Collection.Find(x => contentIds.Contains(x.Id) && x.AppId == appId).Only(x => x.Id) .ToListAsync(); - return contentIds.Except(contentEntities.Select(x => x.Id)).ToList(); + return contentIds.Except(contentEntities.Select(x => Guid.Parse(x["_id"].AsString))).ToList(); } public async Task FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id, long version) diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEntity.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEntity.cs index 304e5d01a..c1ba83cbe 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEntity.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleEntity.cs @@ -6,9 +6,11 @@ // All rights reserved. // ========================================================================== +using System; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using Squidex.Domain.Apps.Entities.Rules.State; +using Squidex.Infrastructure.MongoDb; namespace Squidex.Domain.Apps.Entities.MongoDb.Rules { @@ -21,10 +23,19 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules [BsonElement] [BsonRequired] - public RuleState State { get; set; } + public int Version { get; set; } [BsonElement] [BsonRequired] - public int Version { get; set; } + public Guid AppId { get; set; } + + [BsonElement] + [BsonRequired] + public bool IsDeleted { get; set; } + + [BsonJson] + [BsonElement] + [BsonRequired] + public RuleState State { get; set; } } } diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleRepository.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleRepository.cs index 895bc54db..13f5f31b6 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleRepository.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Rules/MongoRuleRepository.cs @@ -27,13 +27,13 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules protected override string CollectionName() { - return "States_Rules"; + return "Snapshots_Rules"; } protected override async Task SetupCollectionAsync(IMongoCollection collection) { - await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.State.AppId)); - await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.State.IsDeleted)); + await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.AppId)); + await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.IsDeleted)); } public async Task<(RuleState Value, long Version)> ReadAsync(string key) @@ -53,19 +53,23 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules public async Task> QueryRuleIdsAsync(Guid appId) { var ruleEntities = - await Collection.Find(x => x.State.AppId == appId && !x.State.IsDeleted).Only(x => x.Id) + await Collection.Find(x => x.AppId == appId && !x.IsDeleted).Only(x => x.Id) .ToListAsync(); - return ruleEntities.Select(x => Guid.Parse(x.Id)).ToList(); + return ruleEntities.Select(x => Guid.Parse(x["_id"].AsString)).ToList(); } public async Task WriteAsync(string key, RuleState value, long oldVersion, long newVersion) { try { + value.Version = newVersion; + await Collection.UpdateOneAsync(x => x.Id == key && x.Version == oldVersion, Update .Set(x => x.State, value) + .Set(x => x.AppId, value.AppId) + .Set(x => x.IsDeleted, value.IsDeleted) .Set(x => x.Version, newVersion), Upsert); } @@ -79,7 +83,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Rules if (existingVersion != null) { - throw new InconsistentStateException(existingVersion.Version, oldVersion, ex); + throw new InconsistentStateException(existingVersion["Version"].AsInt64, oldVersion, ex); } } else diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaEntity.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaEntity.cs index 541575cef..3efb1a83f 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaEntity.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaEntity.cs @@ -6,9 +6,11 @@ // All rights reserved. // ========================================================================== +using System; using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using Squidex.Domain.Apps.Entities.Schemas.State; +using Squidex.Infrastructure.MongoDb; namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas { @@ -21,10 +23,19 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas [BsonElement] [BsonRequired] - public SchemaState State { get; set; } + public string Name { get; set; } [BsonElement] [BsonRequired] public int Version { get; set; } + + [BsonElement] + [BsonRequired] + public Guid AppId { get; set; } + + [BsonJson] + [BsonElement] + [BsonRequired] + public SchemaState State { get; set; } } } diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaRepository.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaRepository.cs index b1c14d9e9..e7174a83f 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaRepository.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Schemas/MongoSchemaRepository.cs @@ -32,8 +32,8 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas protected override async Task SetupCollectionAsync(IMongoCollection collection) { - await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.State.AppId)); - await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.State.Name)); + await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.AppId)); + await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.Name)); } public async Task<(SchemaState Value, long Version)> ReadAsync(string key) @@ -53,10 +53,10 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas public async Task FindSchemaIdAsync(Guid appId, string name) { var schemaEntity = - await Collection.Find(x => x.State.Name == name).Only(x => x.Id) + await Collection.Find(x => x.Name == name).Only(x => x.Id) .FirstOrDefaultAsync(); - return schemaEntity != null ? Guid.Parse(schemaEntity.Id) : Guid.Empty; + return schemaEntity != null ? Guid.Parse(schemaEntity["_id"].AsString) : Guid.Empty; } public async Task> QuerySchemaIdsAsync(Guid appId) @@ -65,16 +65,20 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas await Collection.Find(x => x.State.AppId == appId).Only(x => x.Id) .ToListAsync(); - return schemaEntities.Select(x => Guid.Parse(x.Id)).ToList(); + return schemaEntities.Select(x => Guid.Parse(x["_id"].AsString)).ToList(); } public async Task WriteAsync(string key, SchemaState value, long oldVersion, long newVersion) { try { + value.Version = newVersion; + await Collection.UpdateOneAsync(x => x.Id == key && x.Version == oldVersion, Update .Set(x => x.State, value) + .Set(x => x.AppId, value.AppId) + .Set(x => x.Name, value.Name) .Set(x => x.Version, newVersion), Upsert); } @@ -88,7 +92,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Schemas if (existingVersion != null) { - throw new InconsistentStateException(existingVersion.Version, oldVersion, ex); + throw new InconsistentStateException(existingVersion["Version"].AsInt64, oldVersion, ex); } } else diff --git a/src/Squidex.Domain.Apps.Entities/AppProvider.cs b/src/Squidex.Domain.Apps.Entities/AppProvider.cs index 6d494f377..dd9fc35ee 100644 --- a/src/Squidex.Domain.Apps.Entities/AppProvider.cs +++ b/src/Squidex.Domain.Apps.Entities/AppProvider.cs @@ -24,8 +24,6 @@ namespace Squidex.Domain.Apps.Entities { public sealed class AppProvider : IAppProvider { - private readonly ConcurrentDictionary appIds = new ConcurrentDictionary(); - private readonly ConcurrentDictionary, Guid> schemaIds = new ConcurrentDictionary, Guid>(); private readonly IAppRepository appRepository; private readonly IRuleRepository ruleRepository; private readonly ISchemaRepository schemaRepository; @@ -52,33 +50,23 @@ namespace Squidex.Domain.Apps.Entities { var app = await stateFactory.GetSingleAsync(appId.ToString()); - if (app.Version < 0) + if (IsNotFound(app)) { - throw new DomainObjectNotFoundException(appId.ToString(), typeof(SchemaDomainObject)); + return (null, null); } var schema = await stateFactory.GetSingleAsync(id.ToString()); - if (schema.Version < 0 || schema.State.IsDeleted) - { - throw new DomainObjectNotFoundException(id.ToString(), typeof(SchemaDomainObject)); - } - - return (app.State, schema.State); + return IsNotFound(false, schema) ? (null, null) : (app.State, schema.State); } public async Task GetAppAsync(string appName) { var appId = await GetAppIdAsync(appName); - var app = await stateFactory.GetSingleAsync(appName); - - if (app.Version < 0) - { - throw new DomainObjectNotFoundException(appName, typeof(SchemaDomainObject)); - } + var app = await stateFactory.GetSingleAsync(appId.ToString()); - return app.State; + return IsNotFound(app) ? null : app.State; } public async Task GetSchemaAsync(Guid appId, string name, bool provideDeleted = false) @@ -87,24 +75,14 @@ namespace Squidex.Domain.Apps.Entities var schema = await stateFactory.GetSingleAsync(schemaId.ToString()); - if (schema.Version < 0 || (schema.State.IsDeleted && !provideDeleted)) - { - throw new DomainObjectNotFoundException(schemaId.ToString(), typeof(SchemaDomainObject)); - } - - return schema.State; + return IsNotFound(provideDeleted, schema) ? null : schema.State; } public async Task GetSchemaAsync(Guid appId, Guid id, bool provideDeleted = false) { var schema = await stateFactory.GetSingleAsync(id.ToString()); - if (schema.Version < 0 || (schema.State.IsDeleted && !provideDeleted)) - { - throw new DomainObjectNotFoundException(id.ToString(), typeof(SchemaDomainObject)); - } - - return schema.State; + return IsNotFound(provideDeleted, schema) ? null : schema.State; } public async Task> GetSchemasAsync(Guid appId) @@ -140,32 +118,24 @@ namespace Squidex.Domain.Apps.Entities return apps.Select(a => (IAppEntity)a.State).ToList(); } - private async Task GetAppIdAsync(string name) + private Task GetAppIdAsync(string name) { - var key = name; - - if (!appIds.TryGetValue(key, out var id)) - { - id = await appRepository.FindAppIdByNameAsync(name); - - appIds[key] = id; - } - - return id; + return appRepository.FindAppIdByNameAsync(name); } - private async Task GetSchemaIdAsync(Guid appId, string name) + private Task GetSchemaIdAsync(Guid appId, string name) { - var key = Tuple.Create(appId, name); - - if (!schemaIds.TryGetValue(key, out var id)) - { - id = await schemaRepository.FindSchemaIdAsync(appId, name); + return schemaRepository.FindSchemaIdAsync(appId, name); + } - schemaIds[key] = id; - } + private static bool IsNotFound(AppDomainObject app) + { + return app.Version < 0; + } - return id; + private static bool IsNotFound(bool provideDeleted, SchemaDomainObject schema) + { + return schema.Version < 0 || (schema.State.IsDeleted && !provideDeleted); } } } diff --git a/src/Squidex.Domain.Apps.Entities/EntityMapper.cs b/src/Squidex.Domain.Apps.Entities/EntityMapper.cs index 3e6243a34..77c711a05 100644 --- a/src/Squidex.Domain.Apps.Entities/EntityMapper.cs +++ b/src/Squidex.Domain.Apps.Entities/EntityMapper.cs @@ -23,7 +23,6 @@ namespace Squidex.Domain.Apps.Entities SetCreatedBy(entity, @event); SetLastModified(entity, headers); SetLastModifiedBy(entity, @event); - SetVersion(entity, headers); updater?.Invoke(entity); @@ -38,14 +37,6 @@ namespace Squidex.Domain.Apps.Entities } } - private static void SetVersion(IEntity entity, EnvelopeHeaders headers) - { - if (entity is IUpdateableEntityWithVersion withVersion) - { - withVersion.Version = headers.EventStreamNumber(); - } - } - private static void SetCreated(IEntity entity, EnvelopeHeaders headers) { if (entity is IUpdateableEntity updateable && updateable.Created == default(Instant)) diff --git a/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs b/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs index 6228da562..8a8d068bf 100644 --- a/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs +++ b/src/Squidex.Infrastructure.MongoDb/MongoDb/MongoExtensions.cs @@ -9,6 +9,7 @@ using System; using System.Linq.Expressions; using System.Threading.Tasks; +using MongoDB.Bson; using MongoDB.Driver; namespace Squidex.Infrastructure.MongoDb @@ -34,25 +35,25 @@ namespace Squidex.Infrastructure.MongoDb return true; } - public static IFindFluent Only(this IFindFluent find, + public static IFindFluent Only(this IFindFluent find, Expression> include) { - return find.Project(Builders.Projection.Include(include)); + return find.Project(Builders.Projection.Include(include)); } - public static IFindFluent Only(this IFindFluent find, + public static IFindFluent Only(this IFindFluent find, Expression> include1, Expression> include2) { - return find.Project(Builders.Projection.Include(include1).Include(include2)); + return find.Project(Builders.Projection.Include(include1).Include(include2)); } - public static IFindFluent Only(this IFindFluent find, + public static IFindFluent Only(this IFindFluent find, Expression> include1, Expression> include2, Expression> include3) { - return find.Project(Builders.Projection.Include(include1).Include(include2).Include(include3)); + return find.Project(Builders.Projection.Include(include1).Include(include2).Include(include3)); } } } diff --git a/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs b/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs index 393c41e6c..68f354dde 100644 --- a/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs +++ b/src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs @@ -64,7 +64,7 @@ namespace Squidex.Infrastructure.States if (existingVersion != null) { - throw new InconsistentStateException(existingVersion.Version, oldVersion, ex); + throw new InconsistentStateException(existingVersion["Version"].AsInt64, oldVersion, ex); } } else diff --git a/src/Squidex.Infrastructure/Commands/AggregateHandler.cs b/src/Squidex.Infrastructure/Commands/AggregateHandler.cs index ba32106a4..530f22591 100644 --- a/src/Squidex.Infrastructure/Commands/AggregateHandler.cs +++ b/src/Squidex.Infrastructure/Commands/AggregateHandler.cs @@ -69,6 +69,8 @@ namespace Squidex.Infrastructure.Commands var domainObjectId = domainObjectCommand.AggregateId; var domainObject = await stateFactory.CreateAsync(domainObjectId.ToString()); + await handler(domainObject); + await domainObject.WriteAsync(log); if (!context.IsCompleted) diff --git a/src/Squidex.Infrastructure/Commands/DomainObjectBase.cs b/src/Squidex.Infrastructure/Commands/DomainObjectBase.cs index d3cee9702..96c96fa00 100644 --- a/src/Squidex.Infrastructure/Commands/DomainObjectBase.cs +++ b/src/Squidex.Infrastructure/Commands/DomainObjectBase.cs @@ -18,12 +18,13 @@ namespace Squidex.Infrastructure.Commands public abstract class DomainObjectBase : IDomainObject where TState : new() { private readonly List> uncomittedEvents = new List>(); + private Guid id; private TState state = new TState(); private IPersistence persistence; public long Version { - get { return persistence.Version; } + get { return persistence?.Version ?? -1; } } public TState State @@ -43,6 +44,8 @@ namespace Squidex.Infrastructure.Commands public Task ActivateAsync(string key, IStore store) { + id = Guid.Parse(key); + persistence = store.WithSnapshots(key, s => state = s); return persistence.ReadAsync(); @@ -57,6 +60,8 @@ namespace Squidex.Infrastructure.Commands { Guard.NotNull(@event, nameof(@event)); + @event.SetAggregateId(id); + OnRaised(@event.To()); uncomittedEvents.Add(@event.To()); @@ -73,19 +78,24 @@ namespace Squidex.Infrastructure.Commands public async Task WriteAsync(ISemanticLog log) { - await persistence.WriteSnapshotAsync(state); + var newVersion = Version + uncomittedEvents.Count; - try - { - await persistence.WriteEventsAsync(uncomittedEvents.ToArray()); - } - catch (Exception ex) - { - log.LogFatal(ex, w => w.WriteProperty("action", "writeEvents")); - } - finally + if (newVersion != Version) { - uncomittedEvents.Clear(); + await persistence.WriteSnapshotAsync(state, newVersion); + + try + { + await persistence.WriteEventsAsync(uncomittedEvents.ToArray()); + } + catch (Exception ex) + { + log.LogFatal(ex, w => w.WriteProperty("action", "writeEvents")); + } + finally + { + uncomittedEvents.Clear(); + } } } } diff --git a/src/Squidex.Infrastructure/States/IPersistence.cs b/src/Squidex.Infrastructure/States/IPersistence.cs index 51b17312c..25787a561 100644 --- a/src/Squidex.Infrastructure/States/IPersistence.cs +++ b/src/Squidex.Infrastructure/States/IPersistence.cs @@ -6,6 +6,7 @@ // All rights reserved. // ========================================================================== +using System.Collections.Generic; using System.Threading.Tasks; using Squidex.Infrastructure.EventSourcing; @@ -15,9 +16,9 @@ namespace Squidex.Infrastructure.States { long Version { get; } - Task WriteEventsAsync(params Envelope[] @events); + Task WriteEventsAsync(IEnumerable> @events); - Task WriteSnapshotAsync(TState state); + Task WriteSnapshotAsync(TState state, long newVersion = -1); Task ReadAsync(long? expectedVersion = null); } diff --git a/src/Squidex.Infrastructure/States/Persistence.cs b/src/Squidex.Infrastructure/States/Persistence.cs index 5be140a1c..5e91a3905 100644 --- a/src/Squidex.Infrastructure/States/Persistence.cs +++ b/src/Squidex.Infrastructure/States/Persistence.cs @@ -7,6 +7,7 @@ // ========================================================================== using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Squidex.Infrastructure.EventSourcing; @@ -55,7 +56,7 @@ namespace Squidex.Infrastructure.States positionSnapshot = -1; positionEvent = -1; - if (snapshotStore != null) + if (applyState != null) { var (state, position) = await snapshotStore.ReadAsync(ownerKey); @@ -68,7 +69,7 @@ namespace Squidex.Infrastructure.States } } - if (eventStore != null && streamNameResolver != null) + if (applyEvent != null && streamNameResolver != null) { var events = await eventStore.GetEventsAsync(GetStreamName(), positionEvent + 1); @@ -105,51 +106,56 @@ namespace Squidex.Infrastructure.States } } - public async Task WriteSnapshotAsync(TState state) + public async Task WriteSnapshotAsync(TState state, long newVersion = -1) { - var newPosition = - eventStore != null ? - positionEvent : - positionSnapshot + 1; + if (newVersion < 0) + { + newVersion = + applyEvent != null ? + positionEvent : + positionSnapshot + 1; + } - if (newPosition != positionSnapshot) + if (newVersion != positionSnapshot) { try { - await snapshotStore.WriteAsync(ownerKey, state, positionSnapshot, newPosition); + await snapshotStore.WriteAsync(ownerKey, state, positionSnapshot, newVersion); } catch (InconsistentStateException ex) { throw new DomainObjectVersionException(ownerKey, typeof(TOwner), ex.CurrentVersion, ex.ExpectedVersion); } - positionSnapshot = newPosition; + positionSnapshot = newVersion; } invalidate?.Invoke(); } - public async Task WriteEventsAsync(params Envelope[] @events) + public async Task WriteEventsAsync(IEnumerable> events) { Guard.NotNull(events, nameof(@events)); - if (@events.Length > 0) + var eventArray = events.ToArray(); + + if (eventArray.Length > 0) { var commitId = Guid.NewGuid(); var eventStream = GetStreamName(); - var eventData = GetEventData(events, commitId); + var eventData = GetEventData(eventArray, commitId); try { - await eventStore.AppendEventsAsync(commitId, GetStreamName(), positionEvent, eventData); + await eventStore.AppendEventsAsync(commitId, GetStreamName(), Version, eventData); } catch (WrongEventVersionException ex) { throw new DomainObjectVersionException(ownerKey, typeof(TOwner), ex.CurrentVersion, ex.ExpectedVersion); } - positionEvent += events.Length; + positionEvent += eventArray.Length; } invalidate?.Invoke(); diff --git a/src/Squidex/Config/Domain/StoreServices.cs b/src/Squidex/Config/Domain/StoreServices.cs index a66dd3078..06a5257c7 100644 --- a/src/Squidex/Config/Domain/StoreServices.cs +++ b/src/Squidex/Config/Domain/StoreServices.cs @@ -31,6 +31,7 @@ using Squidex.Domain.Apps.Entities.MongoDb.Schemas; using Squidex.Domain.Apps.Entities.Rules.Repositories; using Squidex.Domain.Apps.Entities.Rules.State; using Squidex.Domain.Apps.Entities.Schemas.Repositories; +using Squidex.Domain.Apps.Entities.Schemas.State; using Squidex.Domain.Users; using Squidex.Domain.Users.MongoDb; using Squidex.Domain.Users.MongoDb.Infrastructure; @@ -100,19 +101,20 @@ namespace Squidex.Config.Domain .As>() .As(); - services.AddSingletonAs(c => new MongoContentRepository(mongoContentDatabase, c.GetService())) - .As() - .As>() - .As(); - services.AddSingletonAs(c => new MongoRuleRepository(mongoContentDatabase)) .As() .As>() - .As(); + .As(); services.AddSingletonAs(c => new MongoSchemaRepository(mongoDatabase)) .As() - .As>() + .As>() + .As(); + + services.AddSingletonAs(c => new MongoContentRepository(mongoContentDatabase, c.GetService())) + .As() + .As>() + .As() .As(); services.AddSingletonAs(c => new MongoHistoryEventRepository(mongoDatabase, c.GetServices())) diff --git a/tests/Squidex.Infrastructure.Tests/Commands/AggregateHandlerTests.cs b/tests/Squidex.Infrastructure.Tests/Commands/AggregateHandlerTests.cs index e95fca91e..3285fed20 100644 --- a/tests/Squidex.Infrastructure.Tests/Commands/AggregateHandlerTests.cs +++ b/tests/Squidex.Infrastructure.Tests/Commands/AggregateHandlerTests.cs @@ -7,6 +7,7 @@ // ========================================================================== using System; +using System.Collections.Generic; using System.Threading.Tasks; using FakeItEasy; using Squidex.Infrastructure.Commands.TestHelpers; @@ -32,32 +33,40 @@ namespace Squidex.Infrastructure.Commands private readonly MyDomainObject domainObject = new MyDomainObject(); private readonly AggregateHandler sut; + public sealed class MyEvent : IEvent + { + } + public AggregateHandlerTests() { context = new CommandContext(new MyCommand { AggregateId = domainObjectId }); - A.CallTo(() => store.WithEventSourcing(domainObjectId.ToString(), A, Task>>.Ignored)) + A.CallTo(() => store.WithSnapshots(domainObjectId.ToString(), A>.Ignored)) .Returns(persistence); A.CallTo(() => stateFactory.CreateAsync(domainObjectId.ToString())) .Returns(Task.FromResult(domainObject)); sut = new AggregateHandler(stateFactory, serviceProvider, log); + + domainObject.ActivateAsync(domainObjectId.ToString(), store).Wait(); } [Fact] - public Task Create_async_should_throw_exception_if_not_aggregate_command() + public Task Create_with_task_should_throw_exception_if_not_aggregate_command() { return Assert.ThrowsAnyAsync(() => sut.CreateAsync(new CommandContext(A.Dummy()), x => TaskHelper.False)); } [Fact] - public async Task Create_async_should_create_domain_object_and_save() + public async Task Create_with_task_should_create_domain_object_and_save() { MyDomainObject passedDomainObject = null; await sut.CreateAsync(context, async x => { + x.RaiseEvent(new MyEvent()); + await Task.Yield(); passedDomainObject = x; @@ -66,46 +75,44 @@ namespace Squidex.Infrastructure.Commands Assert.Equal(domainObject, passedDomainObject); Assert.NotNull(context.Result>()); - A.CallTo(() => persistence.ReadAsync(-1)) - .MustHaveHappened(); - - A.CallTo(() => persistence.WriteEventsAsync(A[]>.Ignored)) + A.CallTo(() => persistence.WriteEventsAsync(A>>.Ignored)) .MustHaveHappened(); } [Fact] - public async Task Create_sync_should_create_domain_object_and_save() + public async Task Create_should_create_domain_object_and_save() { MyDomainObject passedDomainObject = null; await sut.CreateAsync(context, x => { + x.RaiseEvent(new MyEvent()); + passedDomainObject = x; }); Assert.Equal(domainObject, passedDomainObject); Assert.NotNull(context.Result>()); - A.CallTo(() => persistence.ReadAsync(-1)) - .MustHaveHappened(); - - A.CallTo(() => persistence.WriteEventsAsync(A[]>.Ignored)) + A.CallTo(() => persistence.WriteEventsAsync(A>>.Ignored)) .MustHaveHappened(); } [Fact] - public Task Update_async_should_throw_exception_if_not_aggregate_command() + public Task Update_with_task_should_throw_exception_if_not_aggregate_command() { return Assert.ThrowsAnyAsync(() => sut.UpdateAsync(new CommandContext(A.Dummy()), x => TaskHelper.False)); } [Fact] - public async Task Update_async_should_create_domain_object_and_save() + public async Task Update_with_task_should_create_domain_object_and_save() { MyDomainObject passedDomainObject = null; await sut.UpdateAsync(context, async x => { + x.RaiseEvent(new MyEvent()); + await Task.Yield(); passedDomainObject = x; @@ -114,30 +121,26 @@ namespace Squidex.Infrastructure.Commands Assert.Equal(domainObject, passedDomainObject); Assert.NotNull(context.Result()); - A.CallTo(() => persistence.ReadAsync(null)) - .MustHaveHappened(); - - A.CallTo(() => persistence.WriteEventsAsync(A[]>.Ignored)) + A.CallTo(() => persistence.WriteEventsAsync(A>>.Ignored)) .MustHaveHappened(); } [Fact] - public async Task Update_sync_should_create_domain_object_and_save() + public async Task Update_should_create_domain_object_and_save() { MyDomainObject passedDomainObject = null; await sut.UpdateAsync(context, x => { + x.RaiseEvent(new MyEvent()); + passedDomainObject = x; }); Assert.Equal(domainObject, passedDomainObject); Assert.NotNull(context.Result()); - A.CallTo(() => persistence.ReadAsync(null)) - .MustHaveHappened(); - - A.CallTo(() => persistence.WriteEventsAsync(A[]>.Ignored)) + A.CallTo(() => persistence.WriteEventsAsync(A>>.Ignored)) .MustHaveHappened(); } } diff --git a/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectBaseTests.cs b/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectBaseTests.cs index 903a2837a..661d2f8e8 100644 --- a/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectBaseTests.cs +++ b/tests/Squidex.Infrastructure.Tests/Commands/DomainObjectBaseTests.cs @@ -7,60 +7,115 @@ // ========================================================================== using System; +using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; +using FakeItEasy; using Squidex.Infrastructure.Commands.TestHelpers; using Squidex.Infrastructure.EventSourcing; +using Squidex.Infrastructure.Log; +using Squidex.Infrastructure.States; using Xunit; namespace Squidex.Infrastructure.Commands { public class DomainObjectBaseTests { + private readonly IStore store = A.Fake(); + private readonly IPersistence persistence = A.Fake>(); + private readonly Guid id = Guid.NewGuid(); + private readonly MyDomainObject sut = new MyDomainObject(); + + public DomainObjectBaseTests() + { + A.CallTo(() => store.WithSnapshots(id.ToString(), A>.Ignored)) + .Returns(persistence); + } + [Fact] public void Should_instantiate() { - var domainObjectId = Guid.NewGuid(); - var domainObjectVersion = 123; + Assert.Equal(-1, sut.Version); + } - var sut = new MyDomainObject(); + [Fact] + public void Should_add_event_to_uncommitted_events_and_not_increase_version_when_raised() + { + var event1 = new MyEvent(); + var event2 = new MyEvent(); + + sut.RaiseEvent(event1); + sut.RaiseEvent(event2); + + Assert.Equal(-1, sut.Version); + Assert.Equal(new IEvent[] { event1, event2 }, sut.GetUncomittedEvents().Select(x => x.Payload).ToArray()); - Assert.Equal(domainObjectId, sut.Id); - Assert.Equal(domainObjectVersion, sut.Version); + sut.ClearUncommittedEvents(); + + Assert.Equal(0, sut.GetUncomittedEvents().Count); } [Fact] - public void Should_add_event_to_uncommitted_events_and_increase_version_when_raised() + public async Task Should_write_state_and_events_when_saved() { + A.CallTo(() => persistence.Version) + .Returns(100); + + await sut.ActivateAsync(id.ToString(), store); + + Assert.Equal(100, sut.Version); + var event1 = new MyEvent(); var event2 = new MyEvent(); - var sut = new MyDomainObject(); + sut.RaiseEvent(event1); + sut.RaiseEvent(event2); - sut.RaiseNewEvent(event1); - sut.RaiseNewEvent(event2); + var newState = "STATE"; - Assert.Equal(12, sut.Version); + sut.UpdateState(newState); - Assert.Equal(new IEvent[] { event1, event2 }, sut.GetUncomittedEvents().Select(x => x.Payload).ToArray()); + await sut.WriteAsync(A.Fake()); - sut.ClearUncommittedEvents(); + A.CallTo(() => persistence.WriteSnapshotAsync(newState, 102)) + .MustHaveHappened(); + A.CallTo(() => persistence.WriteEventsAsync(A>>.That.Matches(x => x.Count() == 2))) + .MustHaveHappened(); - Assert.Equal(0, sut.GetUncomittedEvents().Count); + Assert.Empty(sut.GetUncomittedEvents()); } [Fact] - public void Should_not_add_event_to_uncommitted_events_and_increase_version_when_raised() + public async Task Should_ignore_exception_when_saving() { + A.CallTo(() => persistence.Version) + .Returns(100); + + A.CallTo(() => persistence.WriteEventsAsync(A>>.Ignored)) + .Throws(new InvalidOperationException()); + + await sut.ActivateAsync(id.ToString(), store); + + Assert.Equal(100, sut.Version); + var event1 = new MyEvent(); var event2 = new MyEvent(); - var sut = new MyDomainObject(); + sut.RaiseEvent(event1); + sut.RaiseEvent(event2); - sut.RaiseEvent(new Envelope(event1)); - sut.RaiseEvent(new Envelope(event2)); + var newState = "STATE"; - Assert.Equal(12, sut.Version); - Assert.Equal(0, sut.GetUncomittedEvents().Count); + sut.UpdateState(newState); + + await sut.WriteAsync(A.Fake()); + + A.CallTo(() => persistence.WriteSnapshotAsync(newState, 102)) + .MustHaveHappened(); + A.CallTo(() => persistence.WriteEventsAsync(A>>.That.Matches(x => x.Count() == 2))) + .MustHaveHappened(); + + Assert.Empty(sut.GetUncomittedEvents()); } } } diff --git a/tests/Squidex.Infrastructure.Tests/Commands/TestHelpers/MyDomainObject.cs b/tests/Squidex.Infrastructure.Tests/Commands/TestHelpers/MyDomainObject.cs index c1eeb3c4b..a725a7a13 100644 --- a/tests/Squidex.Infrastructure.Tests/Commands/TestHelpers/MyDomainObject.cs +++ b/tests/Squidex.Infrastructure.Tests/Commands/TestHelpers/MyDomainObject.cs @@ -6,25 +6,11 @@ // All rights reserved. // ========================================================================== -using System; using Squidex.Infrastructure.EventSourcing; namespace Squidex.Infrastructure.Commands.TestHelpers { internal sealed class MyDomainObject : DomainObjectBase { - public MyDomainObject RaiseNewEvent(IEvent @event) - { - RaiseEvent(@event); - - return this; - } - - public MyDomainObject RaiseNewEvent(Envelope @event) - { - RaiseEvent(@event); - - return this; - } } } diff --git a/tests/Squidex.Infrastructure.Tests/DispatchingTests.cs b/tests/Squidex.Infrastructure.Tests/DispatchingTests.cs index 0eee5acf1..bd8a5a8b4 100644 --- a/tests/Squidex.Infrastructure.Tests/DispatchingTests.cs +++ b/tests/Squidex.Infrastructure.Tests/DispatchingTests.cs @@ -208,7 +208,7 @@ namespace Squidex.Infrastructure } [Fact] - public async Task Should_invoke_correct_event_asynchronously() + public async Task Should_invoke_correct_event_with_taskhronously() { var consumer = new MyAsyncConsumer(); @@ -222,7 +222,7 @@ namespace Squidex.Infrastructure } [Fact] - public async Task Should_invoke_correct_event_with_context_asynchronously() + public async Task Should_invoke_correct_event_with_context_with_taskhronously() { var consumer = new MyAsyncConsumer(); @@ -264,7 +264,7 @@ namespace Squidex.Infrastructure } [Fact] - public async Task Should_invoke_correct_event_and_return_synchronously() + public async Task Should_invoke_correct_event_and_returnhronously() { var consumer = new MyAsyncFuncConsumer(); @@ -278,7 +278,7 @@ namespace Squidex.Infrastructure } [Fact] - public async Task Should_invoke_correct_event_with_context_and_return_synchronously() + public async Task Should_invoke_correct_event_with_context_and_returnhronously() { var consumer = new MyAsyncFuncConsumer(); diff --git a/tests/Squidex.Infrastructure.Tests/EventSourcing/Grains/EventConsumerGrainTests.cs b/tests/Squidex.Infrastructure.Tests/EventSourcing/Grains/EventConsumerGrainTests.cs index b5537df60..1915c6a08 100644 --- a/tests/Squidex.Infrastructure.Tests/EventSourcing/Grains/EventConsumerGrainTests.cs +++ b/tests/Squidex.Infrastructure.Tests/EventSourcing/Grains/EventConsumerGrainTests.cs @@ -70,8 +70,8 @@ namespace Squidex.Infrastructure.EventSourcing.Grains A.CallTo(() => persistence.ReadAsync(null)) .Invokes(new Action(s => apply(state))); - A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored)) - .Invokes(new Action(s => state = s)); + A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored, -1)) + .Invokes(new Action((s, v) => state = s)); A.CallTo(() => formatter.Parse(eventData, true)).Returns(envelope); @@ -132,7 +132,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains state.ShouldBeEquivalentTo(new EventConsumerState { IsStopped = true, Position = initialPosition, Error = null }); - A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored)) + A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored, -1)) .MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => eventSubscription.StopAsync()) @@ -150,7 +150,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains state.ShouldBeEquivalentTo(new EventConsumerState { IsStopped = false, Position = null, Error = null }); - A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored)) + A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored, -1)) .MustHaveHappened(Repeated.Exactly.Twice); A.CallTo(() => eventConsumer.ClearAsync()) @@ -180,7 +180,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains state.ShouldBeEquivalentTo(new EventConsumerState { IsStopped = false, Position = @event.EventPosition, Error = null }); - A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored)) + A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored, -1)) .MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => eventConsumer.On(envelope)) @@ -204,7 +204,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains state.ShouldBeEquivalentTo(new EventConsumerState { IsStopped = false, Position = @event.EventPosition, Error = null }); - A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored)) + A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored, -1)) .MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => eventConsumer.On(envelope)) @@ -243,7 +243,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains state.ShouldBeEquivalentTo(new EventConsumerState { IsStopped = false, Position = initialPosition, Error = null }); - A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored)) + A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored, -1)) .MustNotHaveHappened(); } @@ -263,7 +263,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains state.ShouldBeEquivalentTo(new EventConsumerState { IsStopped = true, Position = initialPosition, Error = ex.ToString() }); - A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored)) + A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored, -1)) .MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => eventSubscription.StopAsync()) @@ -292,7 +292,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains A.CallTo(() => eventConsumer.On(envelope)) .MustHaveHappened(); - A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored)) + A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored, -1)) .MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => eventSubscription.StopAsync()) @@ -323,7 +323,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains A.CallTo(() => eventConsumer.On(envelope)) .MustNotHaveHappened(); - A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored)) + A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored, -1)) .MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => eventSubscription.StopAsync()) @@ -354,7 +354,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains A.CallTo(() => eventConsumer.On(envelope)) .MustHaveHappened(); - A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored)) + A.CallTo(() => persistence.WriteSnapshotAsync(A.Ignored, -1)) .MustHaveHappened(Repeated.Exactly.Twice); A.CallTo(() => eventSubscription.StopAsync()) diff --git a/tests/Squidex.Infrastructure.Tests/States/StateEventSourcingTests.cs b/tests/Squidex.Infrastructure.Tests/States/StateEventSourcingTests.cs index b23a80a3b..cb1d48e71 100644 --- a/tests/Squidex.Infrastructure.Tests/States/StateEventSourcingTests.cs +++ b/tests/Squidex.Infrastructure.Tests/States/StateEventSourcingTests.cs @@ -52,13 +52,13 @@ namespace Squidex.Infrastructure.States private class MyStatefulObjectWithSnapshot : IStatefulObject { - private IPersistence persistence; + private IPersistence persistence; public long? ExpectedVersion { get; set; } public Task ActivateAsync(string key, IStore store) { - persistence = store.WithSnapshotsAndEventSourcing(key, s => TaskHelper.Done, s => TaskHelper.Done); + persistence = store.WithSnapshotsAndEventSourcing(key, s => TaskHelper.Done, s => TaskHelper.Done); return persistence.ReadAsync(ExpectedVersion); } @@ -72,7 +72,7 @@ namespace Squidex.Infrastructure.States private readonly IMemoryCache cache = new MemoryCache(Options.Create(new MemoryCacheOptions())); private readonly IPubSub pubSub = new InMemoryPubSub(true); private readonly IServiceProvider services = A.Fake(); - private readonly ISnapshotStore snapshotStore = A.Fake>(); + private readonly ISnapshotStore snapshotStore = A.Fake>(); private readonly IStreamNameResolver streamNameResolver = A.Fake(); private readonly StateFactory sut; @@ -82,7 +82,7 @@ namespace Squidex.Infrastructure.States .Returns(statefulObject); A.CallTo(() => services.GetService(typeof(MyStatefulObjectWithSnapshot))) .Returns(statefulObjectWithSnapShot); - A.CallTo(() => services.GetService(typeof(ISnapshotStore))) + A.CallTo(() => services.GetService(typeof(ISnapshotStore))) .Returns(snapshotStore); A.CallTo(() => streamNameResolver.GetStreamName(typeof(MyStatefulObject), key)) @@ -278,7 +278,7 @@ namespace Squidex.Infrastructure.States statefulObject.ExpectedVersion = null; A.CallTo(() => snapshotStore.ReadAsync(key)) - .ReturnsLazily(() => Task.Delay(1).ContinueWith(x => (1, 1L))); + .ReturnsLazily(() => Task.Delay(1).ContinueWith(x => ((object)1, 1L))); var tasks = new List>(); diff --git a/tests/Squidex.Infrastructure.Tests/Tasks/SingleThreadedDispatcherTests.cs b/tests/Squidex.Infrastructure.Tests/Tasks/SingleThreadedDispatcherTests.cs index 5e110745c..25f0d5d7f 100644 --- a/tests/Squidex.Infrastructure.Tests/Tasks/SingleThreadedDispatcherTests.cs +++ b/tests/Squidex.Infrastructure.Tests/Tasks/SingleThreadedDispatcherTests.cs @@ -18,7 +18,7 @@ namespace Squidex.Infrastructure.Tasks private readonly SingleThreadedDispatcher sut = new SingleThreadedDispatcher(); [Fact] - public async Task Should_handle_async_messages_sequentially() + public async Task Should_handle_with_task_messages_sequentially() { var source = Enumerable.Range(1, 100); var target = new List(); @@ -39,7 +39,7 @@ namespace Squidex.Infrastructure.Tasks } [Fact] - public async Task Should_handle_sync_messages_sequentially() + public async Task Should_handle_messages_sequentially() { var source = Enumerable.Range(1, 100); var target = new List();