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 namespace Squidex.Domain.Apps.Entities.Backup
{ {
[Reentrant] [Reentrant]
public sealed class CleanerGrain : GrainOfString, IRemindable, IBackgroundGrain public sealed class CleanerGrain : GrainOfString, IRemindable, ICleanerGrain
{ {
private readonly IGrainFactory grainFactory; private readonly IGrainFactory grainFactory;
private readonly IStore<Guid> store; private readonly IStore<Guid> store;
@ -72,6 +72,13 @@ namespace Squidex.Domain.Apps.Entities.Backup
await CleanAsync(); await CleanAsync();
} }
public Task EnqueueAppAsync(Guid appId)
{
state.Apps.Add(appId);
return persistence.WriteSnapshotAsync(state);
}
public Task ActivateAsync() public Task ActivateAsync()
{ {
return CleanAsync(); 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(); return persistence.ReadAsync();
} }
public Task ClearAsync()
{
state = new State();
return persistence.DeleteAsync();
}
public Task RebuildAsync(HashSet<Guid> rules) public Task RebuildAsync(HashSet<Guid> rules)
{ {
state = new State { Rules = rules }; state = new State { Rules = rules };
@ -65,13 +72,6 @@ namespace Squidex.Domain.Apps.Entities.Rules.Indexes
return persistence.WriteSnapshotAsync(state); return persistence.WriteSnapshotAsync(state);
} }
public Task ClearAsync()
{
state = new State();
return persistence.DeleteAsync();
}
public Task<List<Guid>> GetRuleIdsAsync() public Task<List<Guid>> GetRuleIdsAsync()
{ {
return Task.FromResult(state.Rules.ToList()); 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(); return persistence.ReadAsync();
} }
public Task ClearAsync()
{
state = new State();
return persistence.DeleteAsync();
}
public Task RebuildAsync(Dictionary<string, Guid> schemas) public Task RebuildAsync(Dictionary<string, Guid> schemas)
{ {
state = new State { Schemas = schemas }; state = new State { Schemas = schemas };
@ -72,13 +79,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes
return Task.FromResult(schemaId); return Task.FromResult(schemaId);
} }
public Task ClearAsync()
{
state = new State();
return persistence.DeleteAsync();
}
public Task<List<Guid>> GetSchemaIdsAsync() public Task<List<Guid>> GetSchemaIdsAsync()
{ {
return Task.FromResult(state.Schemas.Values.ToList()); 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 namespace Squidex.Domain.Apps.Entities.Tags
{ {
public sealed class GrainTagService : ITagService public sealed class GrainTagService : ITagService, IAppStorage
{ {
private readonly IGrainFactory grainFactory; private readonly IGrainFactory grainFactory;
@ -24,31 +24,36 @@ namespace Squidex.Domain.Apps.Entities.Tags
this.grainFactory = grainFactory; 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 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(); return persistence.ReadAsync();
} }
public Task ClearAsync()
{
state = new State();
return persistence.DeleteAsync();
}
public async Task<HashSet<string>> NormalizeTagsAsync(HashSet<string> names, HashSet<string> ids) public async Task<HashSet<string>> NormalizeTagsAsync(HashSet<string> names, HashSet<string> ids)
{ {
var result = new HashSet<string>(); 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)); 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(); .AsSelf();
services.AddSingletonAs<GrainTagService>() services.AddSingletonAs<GrainTagService>()
.As<ITagService>(); .As<ITagService>().As<IAppStorage>();
services.AddSingletonAs<FileTypeTagGenerator>() services.AddSingletonAs<FileTypeTagGenerator>()
.As<ITagGenerator<CreateAsset>>(); .As<ITagGenerator<CreateAsset>>();
@ -94,6 +94,40 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<ImageTagGenerator>() services.AddSingletonAs<ImageTagGenerator>()
.As<ITagGenerator<CreateAsset>>(); .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>() services.AddSingletonAs<InMemoryCommandBus>()
.As<ICommandBus>(); .As<ICommandBus>();
@ -151,28 +185,8 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<CreateProfileCommandMiddleware>() services.AddSingletonAs<CreateProfileCommandMiddleware>()
.As<ICommandMiddleware>(); .As<ICommandMiddleware>();
services.AddSingletonAs<JintScriptEngine>() services.AddSingletonAs<EnqueueAppToCleanerMiddleware>()
.As<IScriptEngine>(); .As<ICommandMiddleware>();
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;
});
} }
public static void AddMyMigrationServices(this IServiceCollection services) 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] [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); 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(); 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] [Fact]
public async Task Should_add_tags_to_grain() public async Task Should_add_tags_to_grain()
{ {

Loading…
Cancel
Save