Browse Source

Cleaner middleware, tests and service registration.

pull/309/head
Sebastian 8 years ago
parent
commit
ee3afe88cb
  1. 9
      src/Squidex.Domain.Apps.Entities/Backup/CleanerGrain.cs
  2. 44
      src/Squidex.Domain.Apps.Entities/Backup/EnqueueAppToCleanerMiddleware.cs
  3. 18
      src/Squidex.Domain.Apps.Entities/Backup/ICleanerGrain.cs
  4. 14
      src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesByAppIndexGrain.cs
  5. 14
      src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasByAppIndexGrain.cs
  6. 29
      src/Squidex.Domain.Apps.Entities/Tags/GrainTagService.cs
  7. 8
      src/Squidex.Domain.Apps.Entities/Tags/ITagService.cs
  8. 12
      src/Squidex.Domain.Apps.Entities/Tags/TagGrain.cs
  9. 60
      src/Squidex/Config/Domain/EntitiesServices.cs
  10. 48
      tests/Squidex.Domain.Apps.Entities.Tests/Backup/EnqueueAppToCleanerMiddlewareTests.cs
  11. 11
      tests/Squidex.Domain.Apps.Entities.Tests/Tags/GrainTagServiceTests.cs
  12. 15
      tests/Squidex.Domain.Apps.Entities.Tests/Tags/TagGrainTests.cs

9
src/Squidex.Domain.Apps.Entities/Backup/CleanerGrain.cs

@ -25,7 +25,7 @@ using Squidex.Infrastructure.States;
namespace Squidex.Domain.Apps.Entities.Backup
{
[Reentrant]
public sealed class CleanerGrain : GrainOfString, IRemindable, IBackgroundGrain
public sealed class CleanerGrain : GrainOfString, IRemindable, ICleanerGrain
{
private readonly IGrainFactory grainFactory;
private readonly IStore<Guid> store;
@ -72,6 +72,13 @@ namespace Squidex.Domain.Apps.Entities.Backup
await CleanAsync();
}
public Task EnqueueAppAsync(Guid appId)
{
state.Apps.Add(appId);
return persistence.WriteSnapshotAsync(state);
}
public Task ActivateAsync()
{
return CleanAsync();

44
src/Squidex.Domain.Apps.Entities/Backup/EnqueueAppToCleanerMiddleware.cs

@ -0,0 +1,44 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Orleans;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Orleans;
namespace Squidex.Domain.Apps.Entities.Backup
{
public sealed class EnqueueAppToCleanerMiddleware : ICommandMiddleware
{
private readonly ICleanerGrain cleaner;
public EnqueueAppToCleanerMiddleware(IGrainFactory grainFactory)
{
Guard.NotNull(grainFactory, nameof(grainFactory));
cleaner = grainFactory.GetGrain<ICleanerGrain>(SingleGrain.Id);
}
public async Task HandleAsync(CommandContext context, Func<Task> next)
{
if (context.IsCompleted)
{
switch (context.Command)
{
case ArchiveApp archiveApp:
await cleaner.EnqueueAppAsync(archiveApp.AppId);
break;
}
}
await next();
}
}
}

18
src/Squidex.Domain.Apps.Entities/Backup/ICleanerGrain.cs

@ -0,0 +1,18 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
using Squidex.Infrastructure.Orleans;
namespace Squidex.Domain.Apps.Entities.Backup
{
public interface ICleanerGrain : IBackgroundGrain
{
Task EnqueueAppAsync(Guid appId);
}
}

14
src/Squidex.Domain.Apps.Entities/Rules/Indexes/RulesByAppIndexGrain.cs

@ -44,6 +44,13 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes
return persistence.ReadAsync();
}
public Task ClearAsync()
{
state = new State();
return persistence.DeleteAsync();
}
public Task RebuildAsync(HashSet<Guid> rules)
{
state = new State { Rules = rules };
@ -65,13 +72,6 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes
return persistence.WriteSnapshotAsync(state);
}
public Task ClearAsync()
{
state = new State();
return persistence.DeleteAsync();
}
public Task<List<Guid>> GetRuleIdsAsync()
{
return Task.FromResult(state.Rules.ToList());

14
src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasByAppIndexGrain.cs

@ -44,6 +44,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
return persistence.ReadAsync();
}
public Task ClearAsync()
{
state = new State();
return persistence.DeleteAsync();
}
public Task RebuildAsync(Dictionary<string, Guid> schemas)
{
state = new State { Schemas = schemas };
@ -72,13 +79,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
return Task.FromResult(schemaId);
}
public Task ClearAsync()
{
state = new State();
return persistence.DeleteAsync();
}
public Task<List<Guid>> GetSchemaIdsAsync()
{
return Task.FromResult(state.Schemas.Values.ToList());

29
src/Squidex.Domain.Apps.Entities/Tags/GrainTagService.cs

@ -13,7 +13,7 @@ using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Entities.Tags
{
public sealed class GrainTagService : ITagService
public sealed class GrainTagService : ITagService, IAppStorage
{
private readonly IGrainFactory grainFactory;
@ -24,31 +24,36 @@ namespace Squidex.Domain.Apps.Entities.Tags
this.grainFactory = grainFactory;
}
public Task<HashSet<string>> NormalizeTagsAsync(Guid appId, string category, HashSet<string> names, HashSet<string> ids)
public Task<HashSet<string>> NormalizeTagsAsync(Guid appId, string group, HashSet<string> names, HashSet<string> ids)
{
return GetGrain(appId, category).NormalizeTagsAsync(names, ids);
return GetGrain(appId, group).NormalizeTagsAsync(names, ids);
}
public Task<HashSet<string>> GetTagIdsAsync(Guid appId, string category, HashSet<string> names)
public Task<HashSet<string>> GetTagIdsAsync(Guid appId, string group, HashSet<string> names)
{
return GetGrain(appId, category).GetTagIdsAsync(names);
return GetGrain(appId, group).GetTagIdsAsync(names);
}
public Task<Dictionary<string, string>> DenormalizeTagsAsync(Guid appId, string category, HashSet<string> ids)
public Task<Dictionary<string, string>> DenormalizeTagsAsync(Guid appId, string group, HashSet<string> ids)
{
return GetGrain(appId, category).DenormalizeTagsAsync(ids);
return GetGrain(appId, group).DenormalizeTagsAsync(ids);
}
public Task<Dictionary<string, int>> GetTagsAsync(Guid appId, string category)
public Task<Dictionary<string, int>> GetTagsAsync(Guid appId, string group)
{
return GetGrain(appId, category).GetTagsAsync();
return GetGrain(appId, group).GetTagsAsync();
}
private ITagGrain GetGrain(Guid appId, string category)
public Task ClearAsync(Guid appId)
{
Guard.NotNullOrEmpty(category, nameof(category));
return GetGrain(appId, TagGroups.Assets).ClearAsync();
}
private ITagGrain GetGrain(Guid appId, string group)
{
Guard.NotNullOrEmpty(group, nameof(group));
return grainFactory.GetGrain<ITagGrain>($"{appId}_{category}");
return grainFactory.GetGrain<ITagGrain>($"{appId}_{group}");
}
}
}

8
src/Squidex.Domain.Apps.Entities/Tags/ITagService.cs

@ -13,12 +13,12 @@ namespace Squidex.Domain.Apps.Entities.Tags
{
public interface ITagService
{
Task<HashSet<string>> NormalizeTagsAsync(Guid appId, string category, HashSet<string> names, HashSet<string> ids);
Task<HashSet<string>> NormalizeTagsAsync(Guid appId, string group, HashSet<string> names, HashSet<string> ids);
Task<HashSet<string>> GetTagIdsAsync(Guid appId, string category, HashSet<string> names);
Task<HashSet<string>> GetTagIdsAsync(Guid appId, string group, HashSet<string> names);
Task<Dictionary<string, string>> DenormalizeTagsAsync(Guid appId, string category, HashSet<string> ids);
Task<Dictionary<string, string>> DenormalizeTagsAsync(Guid appId, string group, HashSet<string> ids);
Task<Dictionary<string, int>> GetTagsAsync(Guid appId, string category);
Task<Dictionary<string, int>> GetTagsAsync(Guid appId, string group);
}
}

12
src/Squidex.Domain.Apps.Entities/Tags/TagGrain.cs

@ -51,6 +51,13 @@ namespace Squidex.Domain.Apps.Entities.Tags
return persistence.ReadAsync();
}
public Task ClearAsync()
{
state = new State();
return persistence.DeleteAsync();
}
public async Task<HashSet<string>> NormalizeTagsAsync(HashSet<string> names, HashSet<string> ids)
{
var result = new HashSet<string>();
@ -147,10 +154,5 @@ namespace Squidex.Domain.Apps.Entities.Tags
{
return Task.FromResult(state.Tags.Values.ToDictionary(x => x.Name, x => x.Count));
}
public Task ClearAsync()
{
return persistence.DeleteAsync();
}
}
}

60
src/Squidex/Config/Domain/EntitiesServices.cs

@ -86,7 +86,7 @@ namespace Squidex.Config.Domain
.AsSelf();
services.AddSingletonAs<GrainTagService>()
.As<ITagService>();
.As<ITagService>().As<IAppStorage>();
services.AddSingletonAs<FileTypeTagGenerator>()
.As<ITagGenerator<CreateAsset>>();
@ -94,6 +94,40 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<ImageTagGenerator>()
.As<ITagGenerator<CreateAsset>>();
services.AddSingletonAs<RuleIndexCleaner>()
.As<IAppStorage>();
services.AddSingletonAs<SchemaIndexCleaner>()
.As<IAppStorage>();
services.AddSingletonAs<JintScriptEngine>()
.As<IScriptEngine>();
AddCommandPipeline(services);
services.AddSingleton<Func<IGrainCallContext, string>>(DomainObjectGrainFormatter.Format);
services.AddSingleton(c =>
{
var uiOptions = c.GetRequiredService<IOptions<MyUIOptions>>();
var result = new InitialPatterns();
foreach (var pattern in uiOptions.Value.RegexSuggestions)
{
if (!string.IsNullOrWhiteSpace(pattern.Key) &&
!string.IsNullOrWhiteSpace(pattern.Value))
{
result[Guid.NewGuid()] = new AppPattern(pattern.Key, pattern.Value);
}
}
return result;
});
}
private static void AddCommandPipeline(IServiceCollection services)
{
services.AddSingletonAs<InMemoryCommandBus>()
.As<ICommandBus>();
@ -151,28 +185,8 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<CreateProfileCommandMiddleware>()
.As<ICommandMiddleware>();
services.AddSingletonAs<JintScriptEngine>()
.As<IScriptEngine>();
services.AddSingleton<Func<IGrainCallContext, string>>(DomainObjectGrainFormatter.Format);
services.AddSingleton(c =>
{
var uiOptions = c.GetRequiredService<IOptions<MyUIOptions>>();
var result = new InitialPatterns();
foreach (var pattern in uiOptions.Value.RegexSuggestions)
{
if (!string.IsNullOrWhiteSpace(pattern.Key) &&
!string.IsNullOrWhiteSpace(pattern.Value))
{
result[Guid.NewGuid()] = new AppPattern(pattern.Key, pattern.Value);
}
}
return result;
});
services.AddSingletonAs<EnqueueAppToCleanerMiddleware>()
.As<ICommandMiddleware>();
}
public static void AddMyMigrationServices(this IServiceCollection services)

48
tests/Squidex.Domain.Apps.Entities.Tests/Backup/EnqueueAppToCleanerMiddlewareTests.cs

@ -0,0 +1,48 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Threading.Tasks;
using FakeItEasy;
using Orleans;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure.Commands;
using Squidex.Infrastructure.Orleans;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Backup
{
public class EnqueueAppToCleanerMiddlewareTests
{
private readonly IGrainFactory grainFactory = A.Fake<IGrainFactory>();
private readonly ICommandBus commandBus = A.Fake<ICommandBus>();
private readonly ICleanerGrain index = A.Fake<ICleanerGrain>();
private readonly Guid appId = Guid.NewGuid();
private readonly EnqueueAppToCleanerMiddleware sut;
public EnqueueAppToCleanerMiddlewareTests()
{
A.CallTo(() => grainFactory.GetGrain<ICleanerGrain>(SingleGrain.Id, null))
.Returns(index);
sut = new EnqueueAppToCleanerMiddleware(grainFactory);
}
[Fact]
public async Task Should_enqueue_for_cleanup_on_archive()
{
var context =
new CommandContext(new ArchiveApp { AppId = appId }, commandBus)
.Complete();
await sut.HandleAsync(context);
A.CallTo(() => index.EnqueueAppAsync(appId))
.MustHaveHappened();
}
}
}

11
tests/Squidex.Domain.Apps.Entities.Tests/Tags/GrainTagServiceTests.cs

@ -30,7 +30,16 @@ namespace Squidex.Domain.Apps.Entities.Tags
}
[Fact]
public async Task Should_call_grain_when_retrieving_tas()
public async Task Should_call_grain_when_clearing()
{
await sut.ClearAsync(appId);
A.CallTo(() => grain.ClearAsync())
.MustHaveHappened();
}
[Fact]
public async Task Should_call_grain_when_retrieving_tags()
{
await sut.GetTagsAsync(appId, TagGroups.Assets);

15
tests/Squidex.Domain.Apps.Entities.Tests/Tags/TagGrainTests.cs

@ -30,6 +30,21 @@ namespace Squidex.Domain.Apps.Entities.Tags
sut.OnActivateAsync(string.Empty).Wait();
}
[Fact]
public async Task Should_delete_and_reset_state_when_cleaning()
{
await sut.NormalizeTagsAsync(HashSet.Of("tag1", "tag2"), null);
await sut.NormalizeTagsAsync(HashSet.Of("tag2", "tag3"), null);
await sut.ClearAsync();
var allTags = await sut.GetTagsAsync();
Assert.Empty(allTags);
A.CallTo(() => persistence.DeleteAsync())
.MustHaveHappened();
}
[Fact]
public async Task Should_add_tags_to_grain()
{

Loading…
Cancel
Save