Files
Umbraco-CMS/tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/IndexInitializer.cs
Kenn Jacobsen ae2c59b703 Make the indexing batch size configurable (#20543)
* Introduce configurable batch size for indexing

* Stop using Examine indexing events for reporting index rebuild operation completeness (it is volatile)
2025-10-17 15:45:03 +02:00

290 lines
12 KiB
C#

using Examine;
using Examine.Lucene;
using Examine.Lucene.Directories;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.Logging;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Persistence.Querying;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Infrastructure.Examine;
using Umbraco.Cms.Infrastructure.Persistence;
using Directory = Lucene.Net.Store.Directory;
using StaticServiceProvider = Umbraco.Cms.Core.DependencyInjection.StaticServiceProvider;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Examine.Lucene.UmbracoExamine;
/// <summary>
/// Used internally by test classes to initialize a new index from the template
/// </summary>
public class IndexInitializer
{
private readonly IOptions<ContentSettings> _contentSettings;
private readonly ILocalizationService _localizationService;
private readonly ILoggerFactory _loggerFactory;
private readonly MediaUrlGeneratorCollection _mediaUrlGenerators;
private readonly PropertyEditorCollection _propertyEditors;
private readonly IScopeProvider _scopeProvider;
private readonly IShortStringHelper _shortStringHelper;
private readonly IContentTypeService _contentTypeService;
private readonly IDocumentUrlService _documentUrlService;
private readonly ILanguageService _languageService;
private readonly IOptionsMonitor<IndexingSettings> _indexSettings;
public IndexInitializer(
IShortStringHelper shortStringHelper,
PropertyEditorCollection propertyEditors,
MediaUrlGeneratorCollection mediaUrlGenerators,
IScopeProvider scopeProvider,
ILoggerFactory loggerFactory,
IOptions<ContentSettings> contentSettings,
ILocalizationService localizationService,
IContentTypeService contentTypeService,
IDocumentUrlService documentUrlService,
ILanguageService languageService,
IOptionsMonitor<IndexingSettings> indexSettings)
{
_shortStringHelper = shortStringHelper;
_propertyEditors = propertyEditors;
_mediaUrlGenerators = mediaUrlGenerators;
_scopeProvider = scopeProvider;
_loggerFactory = loggerFactory;
_contentSettings = contentSettings;
_localizationService = localizationService;
_contentTypeService = contentTypeService;
_documentUrlService = documentUrlService;
_languageService = languageService;
_indexSettings = indexSettings;
}
public ContentValueSetBuilder GetContentValueSetBuilder(bool publishedValuesOnly)
{
var contentValueSetBuilder = new ContentValueSetBuilder(
_propertyEditors,
new UrlSegmentProviderCollection(() => new[] { new DefaultUrlSegmentProvider(_shortStringHelper) }),
GetMockUserService(),
_shortStringHelper,
_scopeProvider,
publishedValuesOnly,
_localizationService,
_contentTypeService,
_loggerFactory.CreateLogger<ContentValueSetBuilder>(),
_documentUrlService,
_languageService);
return contentValueSetBuilder;
}
public ContentIndexPopulator GetContentIndexRebuilder(IContentService contentService, bool publishedValuesOnly, IUmbracoDatabaseFactory umbracoDatabaseFactory)
{
var contentValueSetBuilder = GetContentValueSetBuilder(publishedValuesOnly);
var contentIndexDataSource = new ContentIndexPopulator(
_loggerFactory.CreateLogger<ContentIndexPopulator>(),
publishedValuesOnly,
null,
contentService,
umbracoDatabaseFactory,
contentValueSetBuilder,
_indexSettings);
return contentIndexDataSource;
}
public MediaIndexPopulator GetMediaIndexRebuilder(IMediaService mediaService)
{
var mediaValueSetBuilder = new MediaValueSetBuilder(
_propertyEditors,
new UrlSegmentProviderCollection(() => new[] { new DefaultUrlSegmentProvider(_shortStringHelper) }),
_mediaUrlGenerators,
GetMockUserService(),
_shortStringHelper,
_contentSettings,
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>());
var mediaIndexDataSource = new MediaIndexPopulator(null, mediaService, mediaValueSetBuilder, _indexSettings);
return mediaIndexDataSource;
}
public static IContentService GetMockContentService()
{
long longTotalRecs;
var demoData = new ExamineDemoDataContentService();
var allRecs = demoData.GetLatestContentByXPath("//*[@isDoc]")
.Root
.Elements()
.Select((xmlElement, index) => Mock.Of<IContent>(
m =>
m.Id == (int)xmlElement.Attribute("id") &&
// have every second one published and include the special one
m.Published == (ExamineDemoDataContentService.ProtectedNode == (int)xmlElement.Attribute("id") ||
(index % 2 == 0 ? true : false)) &&
m.ParentId == (int)xmlElement.Attribute("parentID") &&
m.Level == (int)xmlElement.Attribute("level") &&
m.CreatorId == 0 &&
m.SortOrder == (int)xmlElement.Attribute("sortOrder") &&
m.CreateDate == (DateTime)xmlElement.Attribute("createDate") &&
m.UpdateDate == (DateTime)xmlElement.Attribute("updateDate") &&
m.Name == (string)xmlElement.Attribute(UmbracoExamineFieldNames.NodeNameFieldName) &&
m.GetCultureName(It.IsAny<string>()) ==
(string)xmlElement.Attribute(UmbracoExamineFieldNames.NodeNameFieldName) &&
m.Path == (string)xmlElement.Attribute("path") &&
m.Properties == new PropertyCollection() &&
m.ContentType == Mock.Of<ISimpleContentType>(mt =>
mt.Icon == "test" &&
mt.Alias == xmlElement.Name.LocalName &&
mt.Id == (int)xmlElement.Attribute("nodeType"))))
.ToArray();
return Mock.Of<IContentService>(
x => x.GetPagedDescendants(It.IsAny<int>(), It.IsAny<long>(), It.IsAny<int>(), out longTotalRecs, It.IsAny<IQuery<IContent>>(), It.IsAny<Ordering>())
== allRecs);
}
public IUserService GetMockUserService() => Mock.Of<IUserService>(x =>
x.GetProfileById(It.IsAny<int>()) == Mock.Of<IProfile>(p => p.Id == 0 && p.Name == "admin"));
public static IMediaService GetMockMediaService()
{
long totalRecs;
var demoData = new ExamineDemoDataMediaService();
var allRecs = demoData.GetLatestMediaByXpath("//node")
.Root
.Elements()
.Select(x => Mock.Of<IMedia>(
m =>
m.Id == (int)x.Attribute("id") &&
m.ParentId == (int)x.Attribute("parentID") &&
m.Level == (int)x.Attribute("level") &&
m.CreatorId == 0 &&
m.SortOrder == (int)x.Attribute("sortOrder") &&
m.CreateDate == (DateTime)x.Attribute("createDate") &&
m.UpdateDate == (DateTime)x.Attribute("updateDate") &&
m.Name == (string)x.Attribute(UmbracoExamineFieldNames.NodeNameFieldName) &&
m.GetCultureName(It.IsAny<string>()) ==
(string)x.Attribute(UmbracoExamineFieldNames.NodeNameFieldName) &&
m.Path == (string)x.Attribute("path") &&
m.Properties == new PropertyCollection() &&
m.ContentType == Mock.Of<ISimpleContentType>(mt =>
mt.Alias == (string)x.Attribute("nodeTypeAlias") &&
mt.Id == (int)x.Attribute("nodeType"))))
.ToArray();
// MOCK!
var mediaServiceMock = new Mock<IMediaService>();
mediaServiceMock
.Setup(x => x.GetPagedDescendants(
It.IsAny<int>(),
It.IsAny<long>(),
It.IsAny<int>(),
out totalRecs,
It.IsAny<IQuery<IMedia>>(),
It.IsAny<Ordering>()))
.Returns(() => allRecs);
//mediaServiceMock.Setup(service => service.GetPagedXmlEntries(It.IsAny<string>(), It.IsAny<long>(), It.IsAny<int>(), out longTotalRecs))
// .Returns(() => allRecs.Select(x => x.ToXml()));
return mediaServiceMock.Object;
}
public ILocalizationService GetMockLocalizationService() =>
Mock.Of<ILocalizationService>(x => x.GetAllLanguages() == Array.Empty<ILanguage>());
public static IMediaTypeService GetMockMediaTypeService(IShortStringHelper shortStringHelper)
{
var mediaTypeServiceMock = new Mock<IMediaTypeService>();
mediaTypeServiceMock.Setup(x => x.GetAll())
.Returns(new List<IMediaType>
{
new MediaType(shortStringHelper, -1)
{
Alias = "Folder", Name = "Folder", Id = 1031, Icon = "icon-folder"
},
new MediaType(shortStringHelper, -1)
{
Alias = "Image", Name = "Image", Id = 1032, Icon = "icon-picture"
}
});
return mediaTypeServiceMock.Object;
}
public IProfilingLogger GetMockProfilingLogger() =>
new ProfilingLogger(Mock.Of<ILogger<ProfilingLogger>>(), Mock.Of<IProfiler>());
public UmbracoContentIndex GetUmbracoIndexer(
IHostingEnvironment hostingEnvironment,
IRuntimeState runtimeState,
Directory luceneDir,
Analyzer analyzer = null,
ILocalizationService languageService = null,
IContentValueSetValidator validator = null)
{
if (languageService == null)
{
languageService = GetMockLocalizationService();
}
if (analyzer == null)
{
analyzer = new StandardAnalyzer(LuceneInfo.CurrentVersion);
}
if (validator == null)
{
validator = new ContentValueSetValidator(true);
}
var options = GetOptions(
"testIndexer",
new LuceneDirectoryIndexOptions
{
Analyzer = analyzer,
Validator = validator,
DirectoryFactory = new GenericDirectoryFactory(s => luceneDir),
FieldDefinitions = new UmbracoFieldDefinitionCollection()
});
var i = new UmbracoContentIndex(
_loggerFactory,
"testIndexer",
options,
hostingEnvironment,
runtimeState,
languageService);
i.IndexingError += IndexingError;
i.IndexOperationComplete += I_IndexOperationComplete;
return i;
}
private void I_IndexOperationComplete(object sender, IndexOperationEventArgs e)
{
}
//public static MultiIndexSearcher GetMultiSearcher(Directory pdfDir, Directory simpleDir, Directory conventionDir, Directory cwsDir)
//{
// var i = new MultiIndexSearcher("testSearcher", new[] { pdfDir, simpleDir, conventionDir, cwsDir }, new StandardAnalyzer(Version.LUCENE_29));
// return i;
//}
public static IOptionsMonitor<LuceneDirectoryIndexOptions> GetOptions(string indexName, LuceneDirectoryIndexOptions options)
=> Mock.Of<IOptionsMonitor<LuceneDirectoryIndexOptions>>(x => x.Get(indexName) == options);
internal void IndexingError(object sender, IndexingErrorEventArgs e) =>
throw new ApplicationException(e.Message, e.Exception);
}