Skip to content

Commit c44bed6

Browse files
committed
Use Lucene for new and rebuilt indexes
1 parent 55dd1fa commit c44bed6

2 files changed

Lines changed: 196 additions & 36 deletions

File tree

‎src/ServiceControl.Audit.Persistence.Tests.RavenDB/IndexSetupTests.cs‎

Lines changed: 121 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ namespace ServiceControl.Audit.Persistence.Tests;
1010
using Raven.Client.Documents.Operations.Indexes;
1111
using Raven.Client.Exceptions;
1212
using Raven.Client.Exceptions.Documents.Indexes;
13+
using Raven.Client.ServerWide.Operations;
14+
using Raven.Client.ServerWide.Operations.Configuration;
1315
using ServiceControl.RavenDB;
1416

1517
[TestFixture]
@@ -70,7 +72,7 @@ public async Task Free_text_search_index_can_be_opted_out_from()
7072
}
7173

7274
[Test]
73-
public async Task New_indexes_should_be_created_with_lucene()
75+
public async Task New_index_should_inherit_lucene_from_a_lucene_database()
7476
{
7577
var index = new FailedAuditImportIndex();
7678

@@ -79,9 +81,27 @@ public async Task New_indexes_should_be_created_with_lucene()
7981
await DatabaseSetup.CreateIndexes(configuration.DocumentStore, true, TestTimeoutCancellationToken);
8082

8183
var definition = await configuration.DocumentStore.Maintenance.SendAsync(new GetIndexOperation(index.IndexName), TestTimeoutCancellationToken);
84+
var stats = await configuration.DocumentStore.Maintenance.SendAsync(new GetIndexStatisticsOperation(index.IndexName), TestTimeoutCancellationToken);
8285

83-
// The search engine is set on the index, not inherited. It then also applies to databases that default to Corax.
84-
Assert.That(definition.Configuration, Does.ContainKey(IndexDeployment.StaticSearchEngineTypeKey).WithValue(SearchEngineType.Lucene.ToString()));
86+
Assert.That(stats.SearchEngineType, Is.EqualTo(SearchEngineType.Lucene));
87+
Assert.That(definition.Configuration, Does.Not.ContainKey(IndexDeployment.StaticSearchEngineTypeKey), "The database is set to Lucene, so the index inherits it");
88+
}
89+
90+
[Test]
91+
public async Task New_index_in_a_corax_database_should_be_pinned_to_lucene()
92+
{
93+
var index = new FailedAuditImportIndex();
94+
95+
await configuration.DocumentStore.Maintenance.SendAsync(new DeleteIndexOperation(index.IndexName), TestTimeoutCancellationToken);
96+
await SetDatabaseSearchEngine(SearchEngineType.Corax);
97+
98+
await DatabaseSetup.CreateIndexes(configuration.DocumentStore, true, TestTimeoutCancellationToken);
99+
100+
var definition = await configuration.DocumentStore.Maintenance.SendAsync(new GetIndexOperation(index.IndexName), TestTimeoutCancellationToken);
101+
var stats = await configuration.DocumentStore.Maintenance.SendAsync(new GetIndexStatisticsOperation(index.IndexName), TestTimeoutCancellationToken);
102+
103+
Assert.That(stats.SearchEngineType, Is.EqualTo(SearchEngineType.Lucene));
104+
Assert.That(definition.Configuration, Does.ContainKey(IndexDeployment.StaticSearchEngineTypeKey).WithValue(nameof(SearchEngineType.Lucene)), "The database is set to Corax, so Lucene is set on the index");
85105
}
86106

87107
[TestCase(true, TestName = "Search engine set in the index definition through SearchEngineType should take precedence over the one on the server")]
@@ -169,6 +189,65 @@ public async Task Pending_replacement_using_the_database_default_should_be_disca
169189
}
170190
}
171191

192+
[Test]
193+
public async Task Changed_index_without_a_search_engine_setting_in_a_corax_database_should_be_pinned_to_lucene()
194+
{
195+
// The index runs on Lucene, the database default, without a setting of its own: the state after an operator migrated
196+
// the whole database and reset the indexes.
197+
var statsBefore = await PutIndexWithoutSearchEngineSetting(customize: true);
198+
199+
Assert.That(statsBefore.SearchEngineType, Is.EqualTo(SearchEngineType.Lucene));
200+
201+
// Versions 6.20.0 to 6.21.2 then set the database default back to Corax.
202+
await SetDatabaseSearchEngine(SearchEngineType.Corax);
203+
204+
await DatabaseSetup.CreateIndexes(configuration.DocumentStore, true, TestTimeoutCancellationToken);
205+
206+
var statsAfter = await WaitForIndexDefinitionUpdate(statsBefore);
207+
var definitionAfter = await configuration.DocumentStore.Maintenance.SendAsync(new GetIndexOperation(statsBefore.Name), TestTimeoutCancellationToken);
208+
209+
Assert.That(definitionAfter.Fields, Does.Not.ContainKey(CustomizedField), "The definition change should be applied");
210+
Assert.That(statsAfter.SearchEngineType, Is.EqualTo(SearchEngineType.Lucene), "The rebuilt index should use Lucene, not the database default");
211+
Assert.That(definitionAfter.Configuration, Does.ContainKey(IndexDeployment.StaticSearchEngineTypeKey).WithValue(nameof(SearchEngineType.Lucene)));
212+
}
213+
214+
[Test]
215+
public async Task Changed_corax_index_without_a_search_engine_setting_in_a_lucene_database_should_inherit_lucene()
216+
{
217+
// A Corax index without a setting of its own, the state of an existing database before any migration.
218+
await SetDatabaseSearchEngine(SearchEngineType.Corax);
219+
var statsBefore = await PutIndexWithoutSearchEngineSetting(customize: true);
220+
221+
Assert.That(statsBefore.SearchEngineType, Is.EqualTo(SearchEngineType.Corax));
222+
223+
// The operator sets the database to Lucene. The next definition change moves the index to Lucene.
224+
await SetDatabaseSearchEngine(SearchEngineType.Lucene);
225+
226+
await DatabaseSetup.CreateIndexes(configuration.DocumentStore, true, TestTimeoutCancellationToken);
227+
228+
var statsAfter = await WaitForIndexDefinitionUpdate(statsBefore);
229+
var definitionAfter = await configuration.DocumentStore.Maintenance.SendAsync(new GetIndexOperation(statsBefore.Name), TestTimeoutCancellationToken);
230+
231+
Assert.That(statsAfter.SearchEngineType, Is.EqualTo(SearchEngineType.Lucene));
232+
Assert.That(definitionAfter.Configuration, Does.Not.ContainKey(IndexDeployment.StaticSearchEngineTypeKey), "The database is set to Lucene, so the rebuilt index inherits it");
233+
}
234+
235+
[Test]
236+
public async Task Unchanged_index_without_a_search_engine_setting_should_not_be_rebuilt_on_setup()
237+
{
238+
var statsBefore = await PutIndexWithoutSearchEngineSetting(customize: false);
239+
240+
await DatabaseSetup.CreateIndexes(configuration.DocumentStore, true, TestTimeoutCancellationToken);
241+
242+
var replacement = await configuration.DocumentStore.Maintenance.SendAsync(new GetIndexOperation(Constants.Documents.Indexing.SideBySideIndexNamePrefix + statsBefore.Name), TestTimeoutCancellationToken);
243+
var statsAfter = await configuration.DocumentStore.Maintenance.SendAsync(new GetIndexStatisticsOperation(statsBefore.Name), TestTimeoutCancellationToken);
244+
var definitionAfter = await configuration.DocumentStore.Maintenance.SendAsync(new GetIndexOperation(statsBefore.Name), TestTimeoutCancellationToken);
245+
246+
Assert.That(replacement, Is.Null, "Adding a search engine setting to an unchanged index would make RavenDB rebuild it");
247+
Assert.That(statsAfter.CreatedTimestamp, Is.EqualTo(statsBefore.CreatedTimestamp));
248+
Assert.That(definitionAfter.Configuration, Does.Not.ContainKey(IndexDeployment.StaticSearchEngineTypeKey));
249+
}
250+
172251
[Test]
173252
public async Task Indexes_should_not_be_reset_on_setup_when_locked_as_ignore()
174253
{
@@ -211,6 +290,45 @@ async Task<IndexStats> PutCustomizedIndex(SearchEngineType searchEngineType, Ind
211290
return await WaitForIndexDefinitionUpdate(statsBefore);
212291
}
213292

293+
// Simulates an index that inherits the search engine from the database, for example after a reset in RavenDB Studio.
294+
async Task<IndexStats> PutIndexWithoutSearchEngineSetting(bool customize)
295+
{
296+
var index = new MessagesViewIndexWithFullTextSearch { Conventions = configuration.DocumentStore.Conventions };
297+
var definition = index.CreateIndexDefinition();
298+
definition.Name = index.IndexName;
299+
300+
if (customize)
301+
{
302+
definition.Fields[CustomizedField] = new IndexFieldOptions { Storage = FieldStorage.Yes };
303+
}
304+
305+
var statsBefore = await configuration.DocumentStore.Maintenance.SendAsync(new GetIndexStatisticsOperation(index.IndexName), TestTimeoutCancellationToken);
306+
var definitionBefore = await configuration.DocumentStore.Maintenance.SendAsync(new GetIndexOperation(index.IndexName), TestTimeoutCancellationToken);
307+
308+
await configuration.DocumentStore.Maintenance.SendAsync(new PutIndexesOperation(definition), TestTimeoutCancellationToken);
309+
310+
// In a Lucene database setup creates the index without a setting of its own. The put is then a no-op and there is no update to wait for.
311+
var stats = definitionBefore.Compare(definition) == IndexDefinitionCompareDifferences.None ? statsBefore : await WaitForIndexDefinitionUpdate(statsBefore);
312+
var storedDefinition = await configuration.DocumentStore.Maintenance.SendAsync(new GetIndexOperation(index.IndexName), TestTimeoutCancellationToken);
313+
314+
Assert.That(storedDefinition.Configuration, Does.Not.ContainKey(IndexDeployment.StaticSearchEngineTypeKey));
315+
316+
return stats;
317+
}
318+
319+
async Task SetDatabaseSearchEngine(SearchEngineType searchEngineType)
320+
{
321+
var store = configuration.DocumentStore;
322+
var record = await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(store.Database), TestTimeoutCancellationToken);
323+
324+
record.Settings["Indexing.Auto.SearchEngineType"] = searchEngineType.ToString();
325+
record.Settings["Indexing.Static.SearchEngineType"] = searchEngineType.ToString();
326+
327+
await store.Maintenance.ForDatabase(store.Database).SendAsync(new PutDatabaseSettingsOperation(store.Database, record.Settings), TestTimeoutCancellationToken);
328+
await store.Maintenance.Server.SendAsync(new ToggleDatabasesStateOperation(store.Database, true), TestTimeoutCancellationToken);
329+
await store.Maintenance.Server.SendAsync(new ToggleDatabasesStateOperation(store.Database, false), TestTimeoutCancellationToken);
330+
}
331+
214332
async Task<IndexStats> UpdateIndex(IAbstractIndexCreationTask index)
215333
{
216334
var statsBefore = await configuration.DocumentStore.Maintenance.SendAsync(new GetIndexStatisticsOperation(index.IndexName), TestTimeoutCancellationToken);

0 commit comments

Comments
 (0)