From c4760a25354b6983ac066bc2440ec93e5cc2ba25 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 5 Dec 2019 09:08:16 +0100 Subject: [PATCH] Tests improved --- .../Contents/Text/TextIndexerBenchmark.cs | 2 +- .../Text/TextIndexerGrainTestsBase.cs | 230 ++++++++++-------- 2 files changed, 126 insertions(+), 106 deletions(-) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerBenchmark.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerBenchmark.cs index 5dc9f60d0..4e7b997e8 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerBenchmark.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerBenchmark.cs @@ -28,7 +28,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text sut.ActivateAsync(schemaId).Wait(); } - [Fact(Skip = "Only used for benchmarks")] + [Fact]// (Skip = "Only used for benchmarks")] public async Task Should_index_many_documents() { var text = new Dictionary diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerGrainTestsBase.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerGrainTestsBase.cs index 7037c1f0d..349ca2ff8 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerGrainTestsBase.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerGrainTestsBase.cs @@ -7,23 +7,23 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using FakeItEasy; using Squidex.Infrastructure.Log; using Squidex.Infrastructure.Validation; using Xunit; +#pragma warning disable SA1115 // Parameter should follow comma #pragma warning disable RECS0021 // Warns about calls to virtual member functions occuring in the constructor namespace Squidex.Domain.Apps.Entities.Contents.Text { - public abstract class TextIndexerGrainTestsBase : IDisposable + public abstract class TextIndexerGrainTestsBase { - private readonly Guid schemaId = Guid.NewGuid(); private readonly List ids1 = new List { Guid.NewGuid() }; private readonly List ids2 = new List { Guid.NewGuid() }; private readonly SearchContext context; - private readonly TextIndexerGrain sut; public abstract IIndexStorage Storage { get; } @@ -33,176 +33,157 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text { Languages = new HashSet { "de", "en" } }; - - var factory = new IndexManager(Storage, A.Fake()); - - sut = new TextIndexerGrain(factory); - sut.ActivateAsync(schemaId).Wait(); - } - - public void Dispose() - { - sut.OnDeactivateAsync().Wait(); } [Fact] public async Task Should_throw_exception_for_invalid_query() { - await Assert.ThrowsAsync(() => sut.SearchAsync("~hello", context)); - } - - [Fact] - public async Task Should_read_index_and_retrieve() - { - await AddInvariantContent("Hello", "World", false); - - await sut.OnDeactivateAsync(); - - var other = new TextIndexerGrain(new IndexManager(Storage, A.Fake())); - try - { - await other.ActivateAsync(schemaId); - - await TestSearchAsync(ids1, "Hello", grain: other); - await TestSearchAsync(ids2, "World", grain: other); - } - finally + await ExecuteAsync(Guid.NewGuid(), async sut => { - await other.OnDeactivateAsync(); - } + await Assert.ThrowsAsync(() => sut.SearchAsync("~hello", context)); + }); } [Fact] public async Task Should_index_invariant_content_and_retrieve() { - await AddInvariantContent("Hello", "World", false); + await SearchWithGrains( + g => AddInvariantContent(g, "Hello", "World", false), - await TestSearchAsync(ids1, "Hello"); - await TestSearchAsync(ids2, "World"); + g => TestSearchAsync(g, expected: ids1, text: "Hello"), + g => TestSearchAsync(g, expected: ids2, text: "World")); } [Fact] public async Task Should_index_invariant_content_and_retrieve_with_fuzzy() { - await AddInvariantContent("Hello", "World", false); + await SearchWithGrains( + g => AddInvariantContent(g, "Hello", "World", false), - await TestSearchAsync(ids1, "helo~"); - await TestSearchAsync(ids2, "wold~"); + g => TestSearchAsync(g, expected: ids1, text: "helo~"), + g => TestSearchAsync(g, expected: ids2, text: "wold~")); } [Fact] public async Task Should_update_draft_only() { - await AddInvariantContent("Hello", "World", false); - await AddInvariantContent("Hallo", "Welt", false); + await SearchWithGrains( + g => AddInvariantContent(g, text1: "Hello", text2: "World", onlyDraft: false), + g => AddInvariantContent(g, text1: "Hallo", text2: "Welt", onlyDraft: false), - await TestSearchAsync(null, "Hello", Scope.Draft); - await TestSearchAsync(null, "Hello", Scope.Published); + g => TestSearchAsync(g, expected: null, text: "Hello", target: Scope.Draft), + g => TestSearchAsync(g, expected: null, text: "Hello", target: Scope.Published), - await TestSearchAsync(ids1, "Hallo", Scope.Draft); - await TestSearchAsync(null, "Hallo", Scope.Published); + g => TestSearchAsync(g, expected: ids1, text: "Hallo", target: Scope.Draft), + g => TestSearchAsync(g, expected: null, text: "Hallo", target: Scope.Published)); } [Fact] public async Task Should_also_update_published_after_copy() { - await AddInvariantContent("Hello", "World", false); + await SearchWithGrains( + g => AddInvariantContent(g, text1: "Hello", text2: "World", onlyDraft: false), - await CopyAsync(true); + g => CopyAsync(g, fromDraft: true), - await AddInvariantContent("Hallo", "Welt", false); + g => AddInvariantContent(g, text1: "Hallo", text2: "Welt", onlyDraft: false), - await TestSearchAsync(null, "Hello", Scope.Draft); - await TestSearchAsync(null, "Hello", Scope.Published); + g => TestSearchAsync(g, expected: null, text: "Hello", target: Scope.Draft), + g => TestSearchAsync(g, expected: null, text: "Hello", target: Scope.Published), - await TestSearchAsync(ids1, "Hallo", Scope.Draft); - await TestSearchAsync(ids1, "Hallo", Scope.Published); + g => TestSearchAsync(g, expected: ids1, text: "Hallo", target: Scope.Draft), + g => TestSearchAsync(g, expected: ids1, text: "Hallo", target: Scope.Published)); } [Fact] public async Task Should_simulate_content_reversion() { - await AddInvariantContent("Hello", "World", false); + await SearchWithGrains( + g => AddInvariantContent(g, text1: "Hello", text2: "World", onlyDraft: false), - await CopyAsync(true); + g => CopyAsync(g, fromDraft: true), - await AddInvariantContent("Hallo", "Welt", true); + g => AddInvariantContent(g, text1: "Hallo", text2: "Welt", onlyDraft: true), - await TestSearchAsync(null, "Hello", Scope.Draft); - await TestSearchAsync(ids1, "Hello", Scope.Published); + g => TestSearchAsync(g, expected: null, text: "Hello", target: Scope.Draft), + g => TestSearchAsync(g, expected: ids1, text: "Hello", target: Scope.Published), - await TestSearchAsync(ids1, "Hallo", Scope.Draft); - await TestSearchAsync(null, "Hallo", Scope.Published); + g => TestSearchAsync(g, expected: ids1, text: "Hallo", target: Scope.Draft), + g => TestSearchAsync(g, expected: null, text: "Hallo", target: Scope.Published), - await CopyAsync(false); + g => CopyAsync(g, fromDraft: false), - await TestSearchAsync(ids1, "Hello", Scope.Draft); - await TestSearchAsync(ids1, "Hello", Scope.Published); + g => TestSearchAsync(g, expected: ids1, text: "Hello", target: Scope.Draft), + g => TestSearchAsync(g, expected: ids1, text: "Hello", target: Scope.Published), - await TestSearchAsync(null, "Hallo", Scope.Draft); - await TestSearchAsync(null, "Hallo", Scope.Published); + g => TestSearchAsync(g, expected: null, text: "Hallo", target: Scope.Draft), + g => TestSearchAsync(g, expected: null, text: "Hallo", target: Scope.Published), - await AddInvariantContent("Guten Morgen", "Welt", true); + g => AddInvariantContent(g, text1: "Guten Morgen", text2: "Welt", onlyDraft: true), - await TestSearchAsync(null, "Hello", Scope.Draft); - await TestSearchAsync(ids1, "Hello", Scope.Published); + g => TestSearchAsync(g, expected: null, text: "Hello", target: Scope.Draft), + g => TestSearchAsync(g, expected: ids1, text: "Hello", target: Scope.Published), - await TestSearchAsync(ids1, "Guten Morgen", Scope.Draft); - await TestSearchAsync(null, "Guten Morgen", Scope.Published); + g => TestSearchAsync(g, expected: ids1, text: "Guten Morgen", target: Scope.Draft), + g => TestSearchAsync(g, expected: null, text: "Guten Morgen", target: Scope.Published)); } [Fact] public async Task Should_also_retrieve_published_content_after_copy() { - await AddInvariantContent("Hello", "World", false); + await SearchWithGrains( + g => AddInvariantContent(g, text1: "Hello", text2: "World", onlyDraft: false), - await TestSearchAsync(ids1, "Hello", Scope.Draft); - await TestSearchAsync(null, "Hello", Scope.Published); + g => TestSearchAsync(g, expected: ids1, text: "Hello", target: Scope.Draft), + g => TestSearchAsync(g, expected: null, text: "Hello", target: Scope.Published), - await CopyAsync(true); + g => CopyAsync(g, fromDraft: true), - await TestSearchAsync(ids1, "Hello", Scope.Draft); - await TestSearchAsync(ids1, "Hello", Scope.Published); + g => TestSearchAsync(g, expected: ids1, text: "Hello", target: Scope.Draft), + g => TestSearchAsync(g, expected: ids1, text: "Hello", target: Scope.Published)); } [Fact] public async Task Should_delete_documents_from_index() { - await AddInvariantContent("Hello", "World", false); + await SearchWithGrains( + g => AddInvariantContent(g, text1: "Hello", text2: "World", onlyDraft: false), - await TestSearchAsync(ids1, "Hello"); - await TestSearchAsync(ids2, "World"); + g => TestSearchAsync(g, expected: ids1, text: "Hello"), + g => TestSearchAsync(g, expected: ids2, text: "World"), - await DeleteAsync(ids1[0]); + g => DeleteAsync(g, id: ids1[0]), - await TestSearchAsync(null, "Hello"); - await TestSearchAsync(ids2, "World"); + g => TestSearchAsync(g, expected: null, text: "Hello"), + g => TestSearchAsync(g, expected: ids2, text: "World")); } [Fact] public async Task Should_search_by_field() { - await AddLocalizedContent(); + await SearchWithGrains( + g => AddLocalizedContent(g), - await TestSearchAsync(null, "de:city"); - await TestSearchAsync(null, "en:Stadt"); + g => TestSearchAsync(g, expected: null, text: "de:city"), + g => TestSearchAsync(g, expected: null, text: "en:Stadt")); } [Fact] public async Task Should_index_localized_content_and_retrieve() { - await AddLocalizedContent(); + await SearchWithGrains( + g => AddLocalizedContent(g), - await TestSearchAsync(ids1, "Stadt"); - await TestSearchAsync(ids1, "and"); - await TestSearchAsync(ids2, "und"); + g => TestSearchAsync(g, expected: ids1, text: "Stadt"), + g => TestSearchAsync(g, expected: ids1, text: "and"), + g => TestSearchAsync(g, expected: ids2, text: "und"), - await TestSearchAsync(ids2, "City"); - await TestSearchAsync(ids2, "und"); - await TestSearchAsync(ids1, "and"); + g => TestSearchAsync(g, expected: ids2, text: "City"), + g => TestSearchAsync(g, expected: ids2, text: "und"), + g => TestSearchAsync(g, expected: ids1, text: "and")); } - private async Task AddLocalizedContent() + private async Task AddLocalizedContent(TextIndexerGrain grain) { var germanText = new Dictionary { @@ -214,11 +195,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text ["en"] = "City and Surroundings und sonstiges" }; - await sut.IndexAsync(new Update { Id = ids1[0], Text = germanText, OnlyDraft = true }); - await sut.IndexAsync(new Update { Id = ids2[0], Text = englishText, OnlyDraft = true }); + await grain.IndexAsync(new Update { Id = ids1[0], Text = germanText, OnlyDraft = true }); + await grain.IndexAsync(new Update { Id = ids2[0], Text = englishText, OnlyDraft = true }); } - private async Task AddInvariantContent(string text1, string text2, bool onlyDraft = false) + private async Task AddInvariantContent(TextIndexerGrain grain, string text1, string text2, bool onlyDraft = false) { var content1 = new Dictionary { @@ -230,26 +211,26 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text ["iv"] = text2 }; - await sut.IndexAsync(new Update { Id = ids1[0], Text = content1, OnlyDraft = onlyDraft }); - await sut.IndexAsync(new Update { Id = ids2[0], Text = content2, OnlyDraft = onlyDraft }); + await grain.IndexAsync(new Update { Id = ids1[0], Text = content1, OnlyDraft = onlyDraft }); + await grain.IndexAsync(new Update { Id = ids2[0], Text = content2, OnlyDraft = onlyDraft }); } - private async Task DeleteAsync(Guid id) + private async Task DeleteAsync(TextIndexerGrain grain, Guid id) { - await sut.DeleteAsync(id); + await grain.DeleteAsync(id); } - private async Task CopyAsync(bool fromDraft) + private async Task CopyAsync(TextIndexerGrain grain, bool fromDraft) { - await sut.CopyAsync(ids1[0], fromDraft); - await sut.CopyAsync(ids2[0], fromDraft); + await grain.CopyAsync(ids1[0], fromDraft); + await grain.CopyAsync(ids2[0], fromDraft); } - private async Task TestSearchAsync(List? expected, string text, Scope target = Scope.Draft, TextIndexerGrain? grain = null) + private async Task TestSearchAsync(TextIndexerGrain grain, List? expected, string text, Scope target = Scope.Draft) { context.Scope = target; - var result = await (grain ?? sut).SearchAsync(text, context); + var result = await grain.SearchAsync(text, context); if (expected != null) { @@ -260,5 +241,44 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text Assert.Empty(result); } } + + private async Task SearchWithGrains(params Func[] actions) + { + for (var i = 0; i < actions.Length; i++) + { + var schemaId = Guid.NewGuid(); + + await ExecuteAsync(schemaId, async sut => + { + foreach (var action in actions.Take(i)) + { + await action(sut); + } + }); + + await ExecuteAsync(schemaId, async sut => + { + foreach (var action in actions.Skip(i)) + { + await action(sut); + } + }); + } + } + + private async Task ExecuteAsync(Guid id, Func action) + { + var sut = new TextIndexerGrain(new IndexManager(Storage, A.Fake())); + try + { + await sut.ActivateAsync(id); + + await action(sut); + } + finally + { + await sut.OnDeactivateAsync(); + } + } } }