@ -21,7 +21,6 @@ using Squidex.Infrastructure.Json.Objects;
using Xunit ;
using Xunit ;
#pragma warning disable SA1401 // Fields should be private
#pragma warning disable SA1401 // Fields should be private
#pragma warning disable SA1115 // Parameter should follow comma
namespace Squidex.Domain.Apps.Entities.Contents.Text
namespace Squidex.Domain.Apps.Entities.Contents.Text
{
{
@ -33,18 +32,11 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
private readonly NamedId < DomainId > appId = NamedId . Of ( DomainId . NewGuid ( ) , "my-app" ) ;
private readonly NamedId < DomainId > appId = NamedId . Of ( DomainId . NewGuid ( ) , "my-app" ) ;
private readonly NamedId < DomainId > schemaId = NamedId . Of ( DomainId . NewGuid ( ) , "my-schema" ) ;
private readonly NamedId < DomainId > schemaId = NamedId . Of ( DomainId . NewGuid ( ) , "my-schema" ) ;
private readonly IAppEntity app ;
private readonly IAppEntity app ;
private readonly TextIndexingProcess sut ;
protected delegate Task IndexOperation ( TextIndexingProcess process ) ;
public virtual bool SupportsQuerySyntax = > true ;
public abstract IIndexerFactory Factory { get ; }
public virtual bool SupportsGeo = > false ;
public virtual bool SupportsCleanup { get ; set ; } = false ;
public virtual bool SupportsQuerySyntax { get ; set ; } = true ;
public virtual bool SupportsGeo { get ; set ; } = false ;
public virtual InMemoryTextIndexerState State { get ; } = new InMemoryTextIndexerState ( ) ;
protected TextIndexerTestsBase ( )
protected TextIndexerTestsBase ( )
{
{
@ -52,20 +44,32 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
Mocks . App ( appId ,
Mocks . App ( appId ,
Language . DE ,
Language . DE ,
Language . EN ) ;
Language . EN ) ;
#pragma warning disable MA0056 // Do not call overridable members in constructor
sut = new TextIndexingProcess ( TestUtils . DefaultSerializer , CreateIndex ( ) , new InMemoryTextIndexerState ( ) ) ;
#pragma warning restore MA0056 // Do not call overridable members in constructor
}
}
public abstract ITextIndex CreateIndex ( ) ;
[SkippableFact]
[SkippableFact]
public async Task Should_index_invariant_content_and_retrieve_with_fuzzy ( )
public async Task Should_index_invariant_content_and_retrieve_with_fuzzy ( )
{
{
Skip . IfNot ( SupportsQuerySyntax ) ;
Skip . IfNot ( SupportsQuerySyntax ) ;
await TestCombinations (
await CreateTextAsync ( ids1 [ 0 ] , "iv" , "Hello" ) ;
CreateText ( ids1 [ 0 ] , "iv" , "Hello" ) ,
CreateText ( ids2 [ 0 ] , "iv" , "World" ) ,
await SearchText ( expected : ids1 , text : "helo~" ) ;
}
[SkippableFact]
public async Task Should_index_invariant_content_and_retrieve_with_fuzzy_with_full_scope ( )
{
Skip . IfNot ( SupportsQuerySyntax ) ;
await CreateTextAsync ( ids2 [ 0 ] , "iv" , "World" ) ;
SearchText ( expected : ids1 , text : "helo~" ) ,
await SearchText ( expected : ids2 , text : "wold~" , SearchScope . All ) ;
SearchText ( expected : ids2 , text : "wold~" , SearchScope . All )
) ;
}
}
[SkippableFact]
[SkippableFact]
@ -73,13 +77,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
{
{
Skip . IfNot ( SupportsQuerySyntax ) ;
Skip . IfNot ( SupportsQuerySyntax ) ;
await TestCombinations (
await CreateTextAsync ( ids1 [ 0 ] , "en" , "City" ) ;
CreateText ( ids1 [ 0 ] , "en" , "City" ) ,
CreateText ( ids2 [ 0 ] , "de" , "Stadt" ) ,
SearchText ( expected : ids1 , text : "en:city" ) ,
await SearchText ( expected : ids1 , text : "en:city" ) ;
SearchText ( expected : ids2 , text : "de:Stadt" )
) ;
}
}
[SkippableFact]
[SkippableFact]
@ -87,394 +87,322 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
{
{
Skip . IfNot ( SupportsGeo ) ;
Skip . IfNot ( SupportsGeo ) ;
await TestCombinations (
// Within radius
CreateGeo ( ids1 [ 0 ] , "geo" , 5 1.343391192211506 , 1 2.401476788622826 ) , // Within radius
await CreateGeoAsync ( ids1 [ 0 ] , "geo" , 5 1.343391192211506 , 1 2.401476788622826 ) ;
CreateGeo ( ids2 [ 0 ] , "geo" , 5 1.30765141427311 , 1 2.379631713912486 ) , // Not in radius
// Not in radius
await CreateGeoAsync ( ids2 [ 0 ] , "geo" , 5 1.30765141427311 , 1 2.379631713912486 ) ;
SearchGeo ( expected : ids1 , "geo.iv" , 5 1.34641682574934 , 1 2.401965298137707 ) ,
await SearchGeo ( expected : ids1 , "geo.iv" , 5 1.34641682574934 , 1 2.401965298137707 ) ;
SearchGeo ( expected : null , "abc.iv" , 5 1.48596429889613 , 1 2.102629469505713 ) // Wrong field
) ;
// Wrong field
await SearchGeo ( expected : null , "abc.iv" , 5 1.48596429889613 , 1 2.102629469505713 ) ;
}
}
[Fact]
[Fact]
public async Task Should_index_invariant_content_and_retrieve ( )
public async Task Should_index_invariant_content_and_retrieve ( )
{
{
await TestCombinations (
await CreateTextAsync ( ids1 [ 0 ] , "iv" , "Hello" ) ;
CreateText ( ids1 [ 0 ] , "iv" , "Hello" ) ,
await CreateTextAsync ( ids2 [ 0 ] , "iv" , "World" ) ;
CreateText ( ids2 [ 0 ] , "iv" , "World" ) ,
SearchText ( expected : ids1 , text : "Hello" ) ,
await SearchText ( expected : ids1 , text : "Hello" ) ;
SearchText ( expected : ids2 , text : "World" ) ,
await SearchText ( expected : ids2 , text : "World" ) ;
SearchText ( expected : null , text : "Hello" , SearchScope . Published ) ,
await SearchText ( expected : null , text : "Hello" , SearchScope . Published ) ;
SearchText ( expected : null , text : "World" , SearchScope . Published )
await SearchText ( expected : null , text : "World" , SearchScope . Published ) ;
) ;
}
}
[Fact]
[Fact]
public async Task Should_update_draft_only ( )
public async Task Should_update_draft_only ( )
{
{
await TestCombinations (
await CreateTextAsync ( ids1 [ 0 ] , "iv" , "V1" ) ;
CreateText ( ids1 [ 0 ] , "iv" , "V1" ) ,
UpdateText ( ids1 [ 0 ] , "iv" , "V2" ) ,
await UpdateTextAsync ( ids1 [ 0 ] , "iv" , "V2" ) ;
SearchText ( expected : null , text : "V1" , target : SearchScope . All ) ,
await SearchText ( expected : null , text : "V1" , target : SearchScope . All ) ;
SearchText ( expected : null , text : "V1" , target : SearchScope . Published ) ,
await SearchText ( expected : null , text : "V1" , target : SearchScope . Published ) ;
SearchText ( expected : ids1 , text : "V2" , target : SearchScope . All ) ,
await SearchText ( expected : ids1 , text : "V2" , target : SearchScope . All ) ;
SearchText ( expected : null , text : "V2" , target : SearchScope . Published )
await SearchText ( expected : null , text : "V2" , target : SearchScope . Published ) ;
) ;
}
}
[Fact]
[Fact]
public async Task Should_update_draft_only_multiple_times ( )
public async Task Should_update_draft_only_multiple_times ( )
{
{
await TestCombinations (
await CreateTextAsync ( ids1 [ 0 ] , "iv" , "V1" ) ;
CreateText ( ids1 [ 0 ] , "iv" , "V1" ) ,
UpdateText ( ids1 [ 0 ] , "iv" , "V2" ) ,
await UpdateTextAsync ( ids1 [ 0 ] , "iv" , "V2" ) ;
UpdateText ( ids1 [ 0 ] , "iv" , "V3" ) ,
await UpdateTextAsync ( ids1 [ 0 ] , "iv" , "V3" ) ;
SearchText ( expected : null , text : "V2" , target : SearchScope . All ) ,
await SearchText ( expected : null , text : "V2" , target : SearchScope . All ) ;
SearchText ( expected : null , text : "V2" , target : SearchScope . Published ) ,
await SearchText ( expected : null , text : "V2" , target : SearchScope . Published ) ;
SearchText ( expected : ids1 , text : "V3" , target : SearchScope . All ) ,
await SearchText ( expected : ids1 , text : "V3" , target : SearchScope . All ) ;
SearchText ( expected : null , text : "V3" , target : SearchScope . Published )
await SearchText ( expected : null , text : "V3" , target : SearchScope . Published ) ;
) ;
}
}
[Fact]
[Fact]
public async Task Should_also_serve_published_after_publish ( )
public async Task Should_also_serve_published_after_publish ( )
{
{
await TestCombinations (
await CreateTextAsync ( ids1 [ 0 ] , "iv" , "V1" ) ;
CreateText ( ids1 [ 0 ] , "iv" , "V1" ) ,
Publish ( ids1 [ 0 ] ) ,
await PublishAsync ( ids1 [ 0 ] ) ;
SearchText ( expected : ids1 , text : "V1" , target : SearchScope . All ) ,
await SearchText ( expected : ids1 , text : "V1" , target : SearchScope . All ) ;
SearchText ( expected : ids1 , text : "V1" , target : SearchScope . Published )
await SearchText ( expected : ids1 , text : "V1" , target : SearchScope . Published ) ;
) ;
}
}
[Fact]
[Fact]
public async Task Should_also_update_published_content ( )
public async Task Should_also_update_published_content ( )
{
{
await TestCombinations (
await CreateTextAsync ( ids1 [ 0 ] , "iv" , "V1" ) ;
CreateText ( ids1 [ 0 ] , "iv" , "V1" ) ,
Publish ( ids1 [ 0 ] ) ,
await PublishAsync ( ids1 [ 0 ] ) ;
UpdateText ( ids1 [ 0 ] , "iv" , "V2" ) ,
await UpdateTextAsync ( ids1 [ 0 ] , "iv" , "V2" ) ;
SearchText ( expected : null , text : "V1" , target : SearchScope . All ) ,
await SearchText ( expected : null , text : "V1" , target : SearchScope . All ) ;
SearchText ( expected : null , text : "V1" , target : SearchScope . Published ) ,
await SearchText ( expected : null , text : "V1" , target : SearchScope . Published ) ;
SearchText ( expected : ids1 , text : "V2" , target : SearchScope . All ) ,
await SearchText ( expected : ids1 , text : "V2" , target : SearchScope . All ) ;
SearchText ( expected : ids1 , text : "V2" , target : SearchScope . Published )
await SearchText ( expected : ids1 , text : "V2" , target : SearchScope . Published ) ;
) ;
}
}
[Fact]
[Fact]
public async Task Should_also_update_published_content_multiple_times ( )
public async Task Should_also_update_published_content_multiple_times ( )
{
{
await TestCombinations (
await CreateTextAsync ( ids1 [ 0 ] , "iv" , "V1" ) ;
CreateText ( ids1 [ 0 ] , "iv" , "V1" ) ,
Publish ( ids1 [ 0 ] ) ,
await PublishAsync ( ids1 [ 0 ] ) ;
UpdateText ( ids1 [ 0 ] , "iv" , "V2" ) ,
await UpdateTextAsync ( ids1 [ 0 ] , "iv" , "V2" ) ;
UpdateText ( ids1 [ 0 ] , "iv" , "V3" ) ,
await UpdateTextAsync ( ids1 [ 0 ] , "iv" , "V3" ) ;
SearchText ( expected : null , text : "V2" , target : SearchScope . All ) ,
await SearchText ( expected : null , text : "V2" , target : SearchScope . All ) ;
SearchText ( expected : null , text : "V2" , target : SearchScope . Published ) ,
await SearchText ( expected : null , text : "V2" , target : SearchScope . Published ) ;
SearchText ( expected : ids1 , text : "V3" , target : SearchScope . All ) ,
await SearchText ( expected : ids1 , text : "V3" , target : SearchScope . All ) ;
SearchText ( expected : ids1 , text : "V3" , target : SearchScope . Published )
await SearchText ( expected : ids1 , text : "V3" , target : SearchScope . Published ) ;
) ;
}
}
[Fact]
[Fact]
public async Task Should_simulate_new_version ( )
public async Task Should_simulate_new_version ( )
{
{
await TestCombinations ( 0 ,
await CreateTextAsync ( ids1 [ 0 ] , "iv" , "V1" ) ;
CreateText ( ids1 [ 0 ] , "iv" , "V1" ) ,
// Publish the content.
// Publish the content.
Publish ( ids1 [ 0 ] ) ,
await PublishAsync ( ids1 [ 0 ] ) ;
SearchText ( expected : ids1 , text : "V1" , target : SearchScope . All ) ,
await SearchText ( expected : ids1 , text : "V1" , target : SearchScope . All ) ;
SearchText ( expected : ids1 , text : "V1" , target : SearchScope . Published ) ,
await SearchText ( expected : ids1 , text : "V1" , target : SearchScope . Published ) ;
// Create a new version, the value is still the same as old version.
// Create a new version, the value is still the same as old version.
CreateDraft ( ids1 [ 0 ] ) ,
await CreateDraftAsync ( ids1 [ 0 ] ) ;
SearchText ( expected : ids1 , text : "V1" , target : SearchScope . All ) ,
await SearchText ( expected : ids1 , text : "V1" , target : SearchScope . All ) ;
SearchText ( expected : ids1 , text : "V1" , target : SearchScope . Published ) ,
await SearchText ( expected : ids1 , text : "V1" , target : SearchScope . Published ) ;
// Make an update, this updates the new version only.
// Make an update, this updates the new version only.
UpdateText ( ids1 [ 0 ] , "iv" , "V2" ) ,
await UpdateTextAsync ( ids1 [ 0 ] , "iv" , "V2" ) ;
SearchText ( expected : null , text : "V1" , target : SearchScope . All ) ,
await SearchText ( expected : null , text : "V1" , target : SearchScope . All ) ;
SearchText ( expected : ids1 , text : "V1" , target : SearchScope . Published ) ,
await SearchText ( expected : ids1 , text : "V1" , target : SearchScope . Published ) ;
SearchText ( expected : ids1 , text : "V2" , target : SearchScope . All ) ,
await SearchText ( expected : ids1 , text : "V2" , target : SearchScope . All ) ;
SearchText ( expected : null , text : "V2" , target : SearchScope . Published ) ,
await SearchText ( expected : null , text : "V2" , target : SearchScope . Published ) ;
// Publish the new version to get rid of the "V1" version.
// Publish the new version to get rid of the "V1" version.
Publish ( ids1 [ 0 ] ) ,
await PublishAsync ( ids1 [ 0 ] ) ;
SearchText ( expected : null , text : "V1" , target : SearchScope . All ) ,
await SearchText ( expected : null , text : "V1" , target : SearchScope . All ) ;
SearchText ( expected : null , text : "V1" , target : SearchScope . Published ) ,
await SearchText ( expected : null , text : "V1" , target : SearchScope . Published ) ;
SearchText ( expected : ids1 , text : "V2" , target : SearchScope . All ) ,
await SearchText ( expected : ids1 , text : "V2" , target : SearchScope . All ) ;
SearchText ( expected : ids1 , text : "V2" , target : SearchScope . Published ) ,
await SearchText ( expected : ids1 , text : "V2" , target : SearchScope . Published ) ;
// Unpublish the version
// Unpublish the version
Unpublish ( ids1 [ 0 ] ) ,
await UnpublishAsync ( ids1 [ 0 ] ) ;
SearchText ( expected : ids1 , text : "V2" , target : SearchScope . All ) ,
await SearchText ( expected : ids1 , text : "V2" , target : SearchScope . All ) ;
SearchText ( expected : null , text : "V2" , target : SearchScope . Published )
await SearchText ( expected : null , text : "V2" , target : SearchScope . Published ) ;
) ;
}
}
[Fact]
[Fact]
public async Task Should_simulate_new_version_with_migration ( )
public async Task Should_simulate_new_version_with_migration ( )
{
{
await TestCombinations ( 0 ,
await CreateTextAsync ( ids1 [ 0 ] , "iv" , "V1" ) ;
CreateText ( ids1 [ 0 ] , "iv" , "V1" ) ,
// Publish the content.
// Publish the content.
Publish ( ids1 [ 0 ] ) ,
await PublishAsync ( ids1 [ 0 ] ) ;
SearchText ( expected : ids1 , text : "V1" , target : SearchScope . All ) ,
await SearchText ( expected : ids1 , text : "V1" , target : SearchScope . All ) ;
SearchText ( expected : ids1 , text : "V1" , target : SearchScope . Published ) ,
await SearchText ( expected : ids1 , text : "V1" , target : SearchScope . Published ) ;
// Create a new version, his updates the new version also.
// Create a new version, his updates the new version also.
CreateDraftWithText ( ids1 [ 0 ] , "iv" , "V2" ) ,
await CreateDraftWithTextAsync ( ids1 [ 0 ] , "iv" , "V2" ) ;
SearchText ( expected : null , text : "V1" , target : SearchScope . All ) ,
await SearchText ( expected : null , text : "V1" , target : SearchScope . All ) ;
SearchText ( expected : ids1 , text : "V1" , target : SearchScope . Published ) ,
await SearchText ( expected : ids1 , text : "V1" , target : SearchScope . Published ) ;
SearchText ( expected : ids1 , text : "V2" , target : SearchScope . All ) ,
await SearchText ( expected : ids1 , text : "V2" , target : SearchScope . All ) ;
SearchText ( expected : null , text : "V2" , target : SearchScope . Published )
await SearchText ( expected : null , text : "V2" , target : SearchScope . Published ) ;
) ;
}
}
[Fact]
[Fact]
public async Task Should_simulate_content_reversion ( )
public async Task Should_simulate_content_reversion ( )
{
{
await TestCombinations (
await CreateTextAsync ( ids1 [ 0 ] , "iv" , "V1" ) ;
CreateText ( ids1 [ 0 ] , "iv" , "V1" ) ,
// Publish the content.
// Publish the content.
Publish ( ids1 [ 0 ] ) ,
await PublishAsync ( ids1 [ 0 ] ) ;
// Create a new version, the value is still the same as old version.
// Create a new version, the value is still the same as old version.
CreateDraft ( ids1 [ 0 ] ) ,
await CreateDraftAsync ( ids1 [ 0 ] ) ;
// Make an update, this updates the new version only.
// Make an update, this updates the new version only.
UpdateText ( ids1 [ 0 ] , "iv" , "V2" ) ,
await UpdateTextAsync ( ids1 [ 0 ] , "iv" , "V2" ) ;
// Make an update, this updates the new version only.
// Make an update, this updates the new version only.
DeleteDraft ( ids1 [ 0 ] ) ,
await DeleteDraftAsync ( ids1 [ 0 ] ) ;
SearchText ( expected : ids1 , text : "V1" , target : SearchScope . All ) ,
await SearchText ( expected : ids1 , text : "V1" , target : SearchScope . All ) ;
SearchText ( expected : ids1 , text : "V1" , target : SearchScope . Published ) ,
await SearchText ( expected : ids1 , text : "V1" , target : SearchScope . Published ) ;
SearchText ( expected : null , text : "V2" , target : SearchScope . All ) ,
await SearchText ( expected : null , text : "V2" , target : SearchScope . All ) ;
SearchText ( expected : null , text : "V2" , target : SearchScope . Published ) ,
await SearchText ( expected : null , text : "V2" , target : SearchScope . Published ) ;
// Make an update, this updates the current version only.
// Make an update, this updates the current version only.
UpdateText ( ids1 [ 0 ] , "iv" , "V3" ) ,
await UpdateTextAsync ( ids1 [ 0 ] , "iv" , "V3" ) ;
SearchText ( expected : ids1 , text : "V3" , target : SearchScope . All ) ,
await SearchText ( expected : ids1 , text : "V3" , target : SearchScope . All ) ;
SearchText ( expected : ids1 , text : "V3" , target : SearchScope . Published )
await SearchText ( expected : ids1 , text : "V3" , target : SearchScope . Published ) ;
) ;
}
}
[Fact]
[Fact]
public async Task Should_delete_documents_from_index ( )
public async Task Should_delete_documents_from_index ( )
{
{
await TestCombinations (
await CreateTextAsync ( ids1 [ 0 ] , "iv" , "V1_1" ) ;
CreateText ( ids1 [ 0 ] , "iv" , "V1_1" ) ,
await CreateTextAsync ( ids2 [ 0 ] , "iv" , "V2_1" ) ;
CreateText ( ids2 [ 0 ] , "iv" , "V2_1" ) ,
SearchText ( expected : ids1 , text : "V1_1" ) ,
await SearchText ( expected : ids1 , text : "V1_1" ) ;
SearchText ( expected : ids2 , text : "V2_1" ) ,
await SearchText ( expected : ids2 , text : "V2_1" ) ;
Delete ( ids1 [ 0 ] ) ,
await DeleteAsync ( ids1 [ 0 ] ) ;
SearchText ( expected : null , text : "V1_1" ) ,
await SearchText ( expected : null , text : "V1_1" ) ;
SearchText ( expected : ids2 , text : "V2_1" )
await SearchText ( expected : ids2 , text : "V2_1" ) ;
) ;
}
}
protected IndexOperation CreateText ( DomainId id , string language , string text )
protected Task CreateTextAsync ( DomainId id , string language , string text )
{
{
var data = TextData ( language , text ) ;
var data = TextData ( language , text ) ;
return Op ( id , new ContentCreated { Data = data } ) ;
return UpdateAsync ( id , new ContentCreated { Data = data } ) ;
}
}
protected IndexOperation CreateGeo ( DomainId id , string field , double latitude , double longitude )
protected Task CreateGeoAsync ( DomainId id , string field , double latitude , double longitude )
{
{
var data = GeoData ( field , latitude , longitude ) ;
var data = GeoData ( field , latitude , longitude ) ;
return Op ( id , new ContentCreated { Data = data } ) ;
return UpdateAsync ( id , new ContentCreated { Data = data } ) ;
}
}
protected IndexOperation UpdateText ( DomainId id , string language , string text )
protected Task UpdateTextAsync ( DomainId id , string language , string text )
{
{
var data = TextData ( language , text ) ;
var data = TextData ( language , text ) ;
return Op ( id , new ContentUpdated { Data = data } ) ;
return UpdateAsync ( id , new ContentUpdated { Data = data } ) ;
}
}
protected IndexOperation CreateDraftWithText ( DomainId id , string language , string text )
protected Task CreateDraftWithTextAsync ( DomainId id , string language , string text )
{
{
var data = TextData ( language , text ) ;
var data = TextData ( language , text ) ;
return Op ( id , new ContentDraftCreated { MigratedData = data } ) ;
return UpdateAsync ( id , new ContentDraftCreated { MigratedData = data } ) ;
}
}
private static ContentData TextData ( string language , string text )
protected Task CreateDraftAsync ( DomainId id )
{
{
return new ContentData ( )
return UpdateAsync ( id , new ContentDraftCreated ( ) ) ;
. AddField ( "text" ,
new ContentFieldData ( )
. AddLocalized ( language , text ) ) ;
}
}
private static ContentData GeoData ( string field , double latitude , double longitude )
protected Task PublishAsync ( DomainId id )
{
{
return new ContentData ( )
return UpdateAsync ( id , new ContentStatusChanged { Status = Status . Published } ) ;
. AddField ( field ,
new ContentFieldData ( )
. AddInvariant ( JsonValue . Object ( ) . Add ( "latitude" , latitude ) . Add ( "longitude" , longitude ) ) ) ;
}
}
protected IndexOperation CreateDraft ( DomainId id )
protected Task UnpublishAsync ( DomainId id )
{
{
return Op ( id , new ContentDraftCreated ( ) ) ;
return UpdateAsync ( id , new ContentStatusChanged { Status = Status . Draft } ) ;
}
}
protected IndexOperation Publish ( DomainId id )
protected Task DeleteDraftAsync ( DomainId id )
{
{
return Op ( id , new ContentStatusChanged { Status = Status . Published } ) ;
return UpdateAsync ( id , new ContentDraftDeleted ( ) ) ;
}
}
protected IndexOperation Unpublish ( DomainId id )
protected Task DeleteAsync ( DomainId id )
{
{
return Op ( id , new ContentStatusChanged { Status = Status . Draft } ) ;
return UpdateAsync ( id , new ContentDeleted ( ) ) ;
}
}
protected IndexOperation DeleteDraft ( DomainId id )
private Task UpdateAsync ( DomainId id , ContentEvent contentEvent )
{
return Op ( id , new ContentDraftDeleted ( ) ) ;
}
protected IndexOperation Delete ( DomainId id )
{
return Op ( id , new ContentDeleted ( ) ) ;
}
private IndexOperation Op ( DomainId id , ContentEvent contentEvent )
{
{
contentEvent . ContentId = id ;
contentEvent . ContentId = id ;
contentEvent . AppId = appId ;
contentEvent . AppId = appId ;
contentEvent . SchemaId = schemaId ;
contentEvent . SchemaId = schemaId ;
return p = > p . On ( Enumerable . Repeat ( Envelope . Create < IEvent > ( contentEvent ) , 1 ) ) ;
return sut . On ( Enumerable . Repeat ( Envelope . Create < IEvent > ( contentEvent ) , 1 ) ) ;
}
}
protected IndexOperation SearchGeo ( List < DomainId > ? expected , string field , double latitude , double longitude , SearchScope target = SearchScope . All )
private static ContentData TextData ( string language , string text )
{
{
return async p = >
return new ContentData ( )
{
. AddField ( "text" ,
var query = new GeoQuery ( schemaId . Id , field , latitude , longitude , 1 0 0 0 , 1 0 0 0 ) ;
new ContentFieldData ( )
. AddLocalized ( language , text ) ) ;
var result = await p . TextIndex . SearchAsync ( app , query , target ) ;
if ( expected ! = null )
{
result . Should ( ) . BeEquivalentTo ( expected . ToHashSet ( ) ) ;
}
else
{
result . Should ( ) . BeEmpty ( ) ;
}
} ;
}
}
protected IndexOperation SearchText ( List < DomainId > ? expected , string text , SearchScope target = SearchScope . All )
private static ContentData GeoData ( string field , double latitude , double longitude )
{
{
return async p = >
return new ContentData ( )
{
. AddField ( field ,
var query = new TextQuery ( text , 1 0 0 0 )
new ContentFieldData ( )
{
. AddInvariant ( JsonValue . Object ( ) . Add ( "latitude" , latitude ) . Add ( "longitude" , longitude ) ) ) ;
RequiredSchemaIds = new List < DomainId > { schemaId . Id }
} ;
var result = await p . TextIndex . SearchAsync ( app , query , target ) ;
if ( expected ! = null )
{
result . Should ( ) . BeEquivalentTo ( expected . ToHashSet ( ) ) ;
}
else
{
result . Should ( ) . BeEmpty ( ) ;
}
} ;
}
}
protected async Task TestCombinations ( params IndexOperation [ ] actions )
protected async Task SearchGeo ( List < DomainId > ? expected , string field , double latitude , double longitude , SearchScope target = SearchScope . All )
{
{
if ( SupportsCleanup )
var query = new GeoQuery ( schemaId . Id , field , latitude , longitude , 1 0 0 0 , 1 0 0 0 ) ;
var result = await sut . TextIndex . SearchAsync ( app , query , target ) ;
if ( expected ! = null )
{
{
for ( var i = 0 ; i < actions . Length ; i + + )
result . Should ( ) . BeEquivalentTo ( expected . ToHashSet ( ) ) ;
{
await TestCombinations ( i , actions ) ;
}
}
}
else
else
{
{
await TestCombinations ( 0 , actions ) ;
result . Should ( ) . BeEmpty ( ) ;
}
}
}
}
protected async Task TestCombinations ( int firstSteps , params IndexOperation [ ] actions )
protected async Task SearchText ( List < DomainId > ? expected , string text , SearchScope target = SearchScope . All )
{
{
await ExecuteAsync ( async sut = >
var query = new TextQuery ( text , 1 0 0 0 )
{
{
foreach ( var action in actions . Take ( firstSteps ) )
RequiredSchemaIds = new List < DomainId > { schemaId . Id }
{
} ;
await action ( sut ) ;
}
} ) ;
await ExecuteAsync ( async sut = >
var result = await sut . TextIndex . SearchAsync ( app , query , target ) ;
{
foreach ( var action in actions . Skip ( firstSteps ) )
{
await action ( sut ) ;
}
} ) ;
}
private async Task ExecuteAsync ( IndexOperation action )
if ( expected ! = null )
{
var indexer = await Factory . CreateAsync ( schemaId . Id ) ;
try
{
{
var sut = new TextIndexingProcess ( TestUtils . DefaultSerializer , indexer , State ) ;
result . Should ( ) . BeEquivalentTo ( expected . ToHashSet ( ) ) ;
await action ( sut ) ;
}
}
finally
else
{
{
await Factory . CleanupAsync ( ) ;
result . Should ( ) . BeEmpty ( ) ;
}
}
}
}
}
}