Browse Source

Tests for grain text indexer.

pull/349/head
Sebastian 7 years ago
parent
commit
0c37c4de67
  1. 2
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs
  2. 7
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs
  3. 40
      src/Squidex.Domain.Apps.Entities/Contents/Text/GrainTextIndexer.cs
  4. 3
      src/Squidex.Domain.Apps.Entities/Contents/Text/ITextIndexer.cs
  5. 144
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/GrainTextIndexerTests.cs

2
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs

@ -57,7 +57,7 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
{
var useDraft = RequiresPublished(status);
var fullTextIds = await indexer.SearchAsync(query.FullText, app, schema, useDraft);
var fullTextIds = await indexer.SearchAsync(query.FullText, app, schema.Id, useDraft);
if (fullTextIds?.Count == 0)
{

7
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository_SnapshotStore.cs

@ -59,9 +59,16 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
await contents.UpsertAsync(content, oldVersion);
if (value.IsDeleted)
{
await indexer.DeleteAsync(value.SchemaId.Id, value.Id);
}
else
{
await indexer.IndexAsync(value.SchemaId.Id, value.Id, value.Data, value.DataDraft);
}
}
}
private async Task<ISchemaEntity> GetSchemaAsync(Guid appId, Guid schemaId)
{

40
src/Squidex.Domain.Apps.Entities/Contents/Text/GrainTextIndexer.cs

@ -21,25 +21,45 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
public sealed class GrainTextIndexer : ITextIndexer
{
private readonly IGrainFactory grainFactory;
private readonly ISemanticLog log;
public GrainTextIndexer(IGrainFactory grainFactory)
public GrainTextIndexer(IGrainFactory grainFactory, ISemanticLog log)
{
Guard.NotNull(grainFactory, nameof(grainFactory));
Guard.NotNull(log, nameof(log));
this.grainFactory = grainFactory;
this.log = log;
}
public Task DeleteAsync(Guid schemaId, Guid id)
public async Task DeleteAsync(Guid schemaId, Guid id)
{
var index = grainFactory.GetGrain<ITextIndexerGrain>(schemaId);
return index.DeleteAsync(id);
using (Profiler.TraceMethod<GrainTextIndexer>())
{
try
{
await index.DeleteAsync(id);
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "DeleteTextEntry")
.WriteProperty("status", "Failed"));
}
}
}
public async Task IndexAsync(Guid schemaId, Guid id, NamedContentData data, NamedContentData dataDraft)
{
var index = grainFactory.GetGrain<ITextIndexerGrain>(schemaId);
using (Profiler.TraceMethod<GrainTextIndexer>())
{
try
{
if (data != null)
{
await index.IndexAsync(id, new IndexData { Data = data });
@ -50,17 +70,25 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
await index.IndexAsync(id, new IndexData { Data = dataDraft, IsDraft = true });
}
}
catch (Exception ex)
{
log.LogError(ex, w => w
.WriteProperty("action", "UpdateTextEntry")
.WriteProperty("status", "Failed"));
}
}
}
public async Task<List<Guid>> SearchAsync(string queryText, IAppEntity app, ISchemaEntity schema, bool useDraft = false)
public async Task<List<Guid>> SearchAsync(string queryText, IAppEntity app, Guid schemaId, bool useDraft = false)
{
if (string.IsNullOrWhiteSpace(queryText))
{
return null;
}
var index = grainFactory.GetGrain<ITextIndexerGrain>(schema.Id);
var index = grainFactory.GetGrain<ITextIndexerGrain>(schemaId);
using (Profiler.TraceMethod<GrainTextIndexer>("SearchAsync"))
using (Profiler.TraceMethod<GrainTextIndexer>())
{
var context = CreateContext(app, useDraft);

3
src/Squidex.Domain.Apps.Entities/Contents/Text/ITextIndexer.cs

@ -10,7 +10,6 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Schemas;
namespace Squidex.Domain.Apps.Entities.Contents.Text
{
@ -20,6 +19,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
Task IndexAsync(Guid schemaId, Guid id, NamedContentData data, NamedContentData dataDraft);
Task<List<Guid>> SearchAsync(string queryText, IAppEntity app, ISchemaEntity schema, bool useDraft = false);
Task<List<Guid>> SearchAsync(string queryText, IAppEntity app, Guid schemaId, bool useDraft = false);
}
}

144
tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/GrainTextIndexerTests.cs

@ -0,0 +1,144 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using FakeItEasy;
using Orleans;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Log;
using Squidex.Infrastructure.Orleans;
using Xunit;
namespace Squidex.Domain.Apps.Entities.Contents.Text
{
public class GrainTextIndexerTests
{
private readonly IGrainFactory grainFactory = A.Fake<IGrainFactory>();
private readonly ITextIndexerGrain grain = A.Fake<ITextIndexerGrain>();
private readonly Guid schemaId = Guid.NewGuid();
private readonly Guid contentId = Guid.NewGuid();
private readonly GrainTextIndexer sut;
public GrainTextIndexerTests()
{
A.CallTo(() => grainFactory.GetGrain<ITextIndexerGrain>(schemaId, null))
.Returns(grain);
sut = new GrainTextIndexer(grainFactory, A.Fake<ISemanticLog>());
}
[Fact]
public async Task Should_call_grain_when_deleting_entry()
{
await sut.DeleteAsync(schemaId, contentId);
A.CallTo(() => grain.DeleteAsync(contentId))
.MustHaveHappened();
}
[Fact]
public async Task Should_catch_exception_when_deleting_failed()
{
A.CallTo(() => grain.DeleteAsync(contentId))
.Throws(new InvalidOperationException());
await sut.DeleteAsync(schemaId, contentId);
}
[Fact]
public async Task Should_call_grain_when_indexing_data()
{
var data = new NamedContentData();
var dataDraft = new NamedContentData();
await sut.IndexAsync(schemaId, contentId, data, dataDraft);
A.CallTo(() => grain.IndexAsync(contentId, A<J<IndexData>>.That.Matches(x => x.Value.Data == data && !x.Value.IsDraft)))
.MustHaveHappened();
A.CallTo(() => grain.IndexAsync(contentId, A<J<IndexData>>.That.Matches(x => x.Value.Data == dataDraft && x.Value.IsDraft)))
.MustHaveHappened();
}
[Fact]
public async Task Should_not_call_grain_when_data_is_null()
{
var dataDraft = new NamedContentData();
await sut.IndexAsync(schemaId, contentId, null, dataDraft);
A.CallTo(() => grain.IndexAsync(contentId, A<J<IndexData>>.That.Matches(x => !x.Value.IsDraft)))
.MustNotHaveHappened();
A.CallTo(() => grain.IndexAsync(contentId, A<J<IndexData>>.That.Matches(x => x.Value.Data == dataDraft && x.Value.IsDraft)))
.MustHaveHappened();
}
[Fact]
public async Task Should_not_call_grain_when_data_draft_is_null()
{
var data = new NamedContentData();
await sut.IndexAsync(schemaId, contentId, data, null);
A.CallTo(() => grain.IndexAsync(contentId, A<J<IndexData>>.That.Matches(x => x.Value.Data == data && !x.Value.IsDraft)))
.MustHaveHappened();
A.CallTo(() => grain.IndexAsync(contentId, A<J<IndexData>>.That.Matches(x => x.Value.IsDraft)))
.MustNotHaveHappened();
}
[Fact]
public async Task Should_catch_exception_when_indexing_failed()
{
var data = new NamedContentData();
A.CallTo(() => grain.IndexAsync(contentId, A<J<IndexData>>.Ignored))
.Throws(new InvalidOperationException());
await sut.IndexAsync(schemaId, contentId, data, null);
}
[Fact]
public async Task Should_call_grain_when_searching()
{
var foundIds = new List<Guid> { Guid.NewGuid() };
A.CallTo(() => grain.SearchAsync("Search", A<SearchContext>.Ignored))
.Returns(foundIds);
var ids = await sut.SearchAsync("Search", GetApp(), schemaId, true);
Assert.Equal(foundIds, ids);
}
[Fact]
public async Task Should_not_call_grain_when_input_is_empty()
{
var ids = await sut.SearchAsync(string.Empty, GetApp(), schemaId, false);
Assert.Null(ids);
A.CallTo(() => grain.SearchAsync(A<string>.Ignored, A<SearchContext>.Ignored))
.MustNotHaveHappened();
}
private static IAppEntity GetApp()
{
var app = A.Fake<IAppEntity>();
A.CallTo(() => app.LanguagesConfig).Returns(LanguagesConfig.Build(Language.EN, Language.DE));
return app;
}
}
}
Loading…
Cancel
Save