mirror of https://github.com/Squidex/squidex.git
37 changed files with 307 additions and 228 deletions
@ -0,0 +1,16 @@ |
|||||
|
{ |
||||
|
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", |
||||
|
"settings": { |
||||
|
"orderingRules": { |
||||
|
"usingDirectivesPlacement": "outsideNamespace" |
||||
|
}, |
||||
|
"documentationRules": { |
||||
|
"companyName": "Squidex UG (haftungsbeschraenkt)", |
||||
|
"copyrightText": "==========================================================================\n Squidex Headless CMS\n==========================================================================\n Copyright (c) {companyName}\n All rights reserved. Licensed under the {licenseName} license.\n==========================================================================", |
||||
|
"variables": { |
||||
|
"licenseName": "MIT" |
||||
|
}, |
||||
|
"xmlHeader": false |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,146 @@ |
|||||
|
// ==========================================================================
|
||||
|
// StateSnapshotTests.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using FakeItEasy; |
||||
|
using Microsoft.Extensions.Caching.Memory; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Squidex.Infrastructure.EventSourcing; |
||||
|
using Squidex.Infrastructure.Tasks; |
||||
|
using Xunit; |
||||
|
|
||||
|
#pragma warning disable RECS0002 // Convert anonymous method to method group
|
||||
|
|
||||
|
namespace Squidex.Infrastructure.States |
||||
|
{ |
||||
|
public class StateFactoryTests : IDisposable |
||||
|
{ |
||||
|
private class MyStatefulObject : IStatefulObject<string> |
||||
|
{ |
||||
|
public Task ActivateAsync(string key, IStore<string> store) |
||||
|
{ |
||||
|
return TaskHelper.Done; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private readonly string key = Guid.NewGuid().ToString(); |
||||
|
private readonly MyStatefulObject statefulObject = new MyStatefulObject(); |
||||
|
private readonly IEventDataFormatter eventDataFormatter = A.Fake<IEventDataFormatter>(); |
||||
|
private readonly IEventStore eventStore = A.Fake<IEventStore>(); |
||||
|
private readonly IMemoryCache cache = new MemoryCache(Options.Create(new MemoryCacheOptions())); |
||||
|
private readonly IPubSub pubSub = new InMemoryPubSub(true); |
||||
|
private readonly IServiceProvider services = A.Fake<IServiceProvider>(); |
||||
|
private readonly ISnapshotStore<int, string> snapshotStore = A.Fake<ISnapshotStore<int, string>>(); |
||||
|
private readonly IStreamNameResolver streamNameResolver = A.Fake<IStreamNameResolver>(); |
||||
|
private readonly StateFactory sut; |
||||
|
|
||||
|
public StateFactoryTests() |
||||
|
{ |
||||
|
A.CallTo(() => services.GetService(typeof(MyStatefulObject))) |
||||
|
.Returns(statefulObject); |
||||
|
A.CallTo(() => services.GetService(typeof(ISnapshotStore<int, string>))) |
||||
|
.Returns(snapshotStore); |
||||
|
|
||||
|
sut = new StateFactory(pubSub, cache, eventStore, eventDataFormatter, services, streamNameResolver); |
||||
|
sut.Initialize(); |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
sut.Dispose(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_provide_state_from_services_and_add_to_cache() |
||||
|
{ |
||||
|
var actualObject = await sut.GetSingleAsync<MyStatefulObject, string>(key); |
||||
|
|
||||
|
Assert.Same(statefulObject, actualObject); |
||||
|
Assert.NotNull(cache.Get<object>(key)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_serve_next_request_from_cache() |
||||
|
{ |
||||
|
var actualObject1 = await sut.GetSingleAsync<MyStatefulObject, string>(key); |
||||
|
|
||||
|
Assert.Same(statefulObject, actualObject1); |
||||
|
Assert.NotNull(cache.Get<object>(key)); |
||||
|
|
||||
|
var actualObject2 = await sut.GetSingleAsync<MyStatefulObject, string>(key); |
||||
|
|
||||
|
A.CallTo(() => services.GetService(typeof(MyStatefulObject))) |
||||
|
.MustHaveHappened(Repeated.Exactly.Once); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_not_serve_next_request_from_cache_when_detached() |
||||
|
{ |
||||
|
var actualObject1 = await sut.CreateAsync<MyStatefulObject, string>(key); |
||||
|
|
||||
|
Assert.Same(statefulObject, actualObject1); |
||||
|
Assert.Null(cache.Get<object>(key)); |
||||
|
|
||||
|
var actualObject2 = await sut.CreateAsync<MyStatefulObject, string>(key); |
||||
|
|
||||
|
A.CallTo(() => services.GetService(typeof(MyStatefulObject))) |
||||
|
.MustHaveHappened(Repeated.Exactly.Twice); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_remove_from_cache_when_invalidation_message_received() |
||||
|
{ |
||||
|
var actualObject = await sut.GetSingleAsync<MyStatefulObject, string>(key); |
||||
|
|
||||
|
await InvalidateCacheAsync(); |
||||
|
|
||||
|
Assert.False(cache.TryGetValue(key, out var t)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_remove_from_cache_when_method_called() |
||||
|
{ |
||||
|
var actualObject = await sut.GetSingleAsync<MyStatefulObject>(key); |
||||
|
|
||||
|
sut.Remove<MyStatefulObject, string>(key); |
||||
|
|
||||
|
Assert.False(cache.TryGetValue(key, out var t)); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_send_invalidation_message_on_refresh() |
||||
|
{ |
||||
|
InvalidateMessage message = null; |
||||
|
|
||||
|
pubSub.Subscribe<InvalidateMessage>(m => |
||||
|
{ |
||||
|
message = m; |
||||
|
}); |
||||
|
|
||||
|
sut.Synchronize<MyStatefulObject, string>(key); |
||||
|
|
||||
|
Assert.NotNull(message); |
||||
|
Assert.Equal(key, message.Key); |
||||
|
} |
||||
|
|
||||
|
private async Task RemoveFromCacheAsync() |
||||
|
{ |
||||
|
cache.Remove(key); |
||||
|
|
||||
|
await Task.Delay(400); |
||||
|
} |
||||
|
|
||||
|
private async Task InvalidateCacheAsync() |
||||
|
{ |
||||
|
pubSub.Publish(new InvalidateMessage { Key = key }, true); |
||||
|
|
||||
|
await Task.Delay(400); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue