Files
Umbraco-CMS/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs

347 lines
15 KiB
C#

using System.Linq;
using System.Threading;
using Examine;
using Examine.LuceneEngine.Providers;
using Lucene.Net.Index;
using Lucene.Net.Search;
using NUnit.Framework;
using Umbraco.Tests.Testing;
using Umbraco.Examine;
using Umbraco.Core.Composing;
using Umbraco.Core.PropertyEditors;
using Umbraco.Tests.TestHelpers.Entities;
using Umbraco.Core.Models;
using Newtonsoft.Json;
using System.Collections.Generic;
using System;
using Umbraco.Core;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.UmbracoExamine
{
/// <summary>
/// Tests the standard indexing capabilities
/// </summary>
[TestFixture]
[Apartment(ApartmentState.STA)]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
public class IndexTest : ExamineBaseTest
{
[Test]
public void Index_Property_Data_With_Value_Indexer()
{
var contentValueSetBuilder = IndexInitializer.GetContentValueSetBuilder(Factory.GetInstance<PropertyEditorCollection>(), false);
using (var luceneDir = new RandomIdRamDirectory())
using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, IOHelper, RuntimeState, luceneDir,
validator: new ContentValueSetValidator(false)))
using (indexer.ProcessNonAsync())
{
indexer.CreateIndex();
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.AddPropertyType(new PropertyType(TestHelper.ShortStringHelper, "test", ValueStorageType.Ntext)
{
Alias = "grid",
Name = "Grid",
PropertyEditorAlias = Core.Constants.PropertyEditors.Aliases.Grid
});
var content = MockedContent.CreateBasicContent(contentType);
content.Id = 555;
content.Path = "-1,555";
var gridVal = new GridValue
{
Name = "n1",
Sections = new List<GridValue.GridSection>
{
new GridValue.GridSection
{
Grid = "g1",
Rows = new List<GridValue.GridRow>
{
new GridValue.GridRow
{
Id = Guid.NewGuid(),
Name = "row1",
Areas = new List<GridValue.GridArea>
{
new GridValue.GridArea
{
Grid = "g2",
Controls = new List<GridValue.GridControl>
{
new GridValue.GridControl
{
Editor = new GridValue.GridEditor
{
Alias = "editor1",
View = "view1"
},
Value = "value1"
},
new GridValue.GridControl
{
Editor = new GridValue.GridEditor
{
Alias = "editor1",
View = "view1"
},
Value = "value2"
}
}
}
}
}
}
}
}
};
var json = JsonConvert.SerializeObject(gridVal);
content.Properties["grid"].SetValue(json);
var valueSet = contentValueSetBuilder.GetValueSets(content);
indexer.IndexItems(valueSet);
var searcher = indexer.GetSearcher();
var results = searcher.CreateQuery().Id(555).Execute();
Assert.AreEqual(1, results.TotalItemCount);
var result = results.First();
Assert.IsTrue(result.Values.ContainsKey("grid.row1"));
Assert.AreEqual("value1", result.AllValues["grid.row1"][0]);
Assert.AreEqual("value2", result.AllValues["grid.row1"][1]);
Assert.IsTrue(result.Values.ContainsKey("grid"));
Assert.AreEqual("value1 value2 ", result["grid"]);
Assert.IsTrue(result.Values.ContainsKey($"{UmbracoExamineFieldNames.RawFieldPrefix}grid"));
Assert.AreEqual(json, result[$"{UmbracoExamineFieldNames.RawFieldPrefix}grid"]);
}
}
[Test]
public void Rebuild_Index()
{
var contentRebuilder = IndexInitializer.GetContentIndexRebuilder(Factory.GetInstance<PropertyEditorCollection>(), IndexInitializer.GetMockContentService(), ScopeProvider.SqlContext, false);
var mediaRebuilder = IndexInitializer.GetMediaIndexRebuilder(Factory.GetInstance<PropertyEditorCollection>(), IndexInitializer.GetMockMediaService());
using (var luceneDir = new RandomIdRamDirectory())
using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, IOHelper, RuntimeState, luceneDir,
validator: new ContentValueSetValidator(false)))
using (indexer.ProcessNonAsync())
{
var searcher = indexer.GetSearcher();
//create the whole thing
contentRebuilder.Populate(indexer);
mediaRebuilder.Populate(indexer);
var result = searcher.CreateQuery().All().Execute();
Assert.AreEqual(29, result.TotalItemCount);
}
}
///// <summary>
/// <summary>
/// Check that the node signalled as protected in the content service is not present in the index.
/// </summary>
[Test]
public void Index_Protected_Content_Not_Indexed()
{
var rebuilder = IndexInitializer.GetContentIndexRebuilder(Factory.GetInstance<PropertyEditorCollection>(), IndexInitializer.GetMockContentService(), ScopeProvider.SqlContext, false);
using (var luceneDir = new RandomIdRamDirectory())
using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, IOHelper, RuntimeState, luceneDir))
using (indexer.ProcessNonAsync())
using (var searcher = ((LuceneSearcher)indexer.GetSearcher()).GetLuceneSearcher())
{
//create the whole thing
rebuilder.Populate(indexer);
var protectedQuery = new BooleanQuery();
protectedQuery.Add(
new BooleanClause(
new TermQuery(new Term(ExamineFieldNames.CategoryFieldName, IndexTypes.Content)),
Occur.MUST));
protectedQuery.Add(
new BooleanClause(
new TermQuery(new Term(ExamineFieldNames.ItemIdFieldName, ExamineDemoDataContentService.ProtectedNode.ToString())),
Occur.MUST));
var collector = TopScoreDocCollector.Create(100, true);
searcher.Search(protectedQuery, collector);
Assert.AreEqual(0, collector.TotalHits, "Protected node should not be indexed");
}
}
[Test]
public void Index_Move_Media_From_Non_Indexable_To_Indexable_ParentID()
{
// create a validator with
// publishedValuesOnly false
// parentId 1116 (only content under that parent will be indexed)
var validator = new ContentValueSetValidator(false, 1116);
using (var luceneDir = new RandomIdRamDirectory())
using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, IOHelper, RuntimeState, luceneDir, validator: validator))
using (indexer.ProcessNonAsync())
{
var searcher = indexer.GetSearcher();
//get a node from the data repo (this one exists underneath 2222)
var node = _mediaService.GetLatestMediaByXpath("//*[string-length(@id)>0 and number(@id)>0]")
.Root.Elements()
.First(x => (int) x.Attribute("id") == 2112);
var currPath = (string)node.Attribute("path"); //should be : -1,1111,2222,2112
Assert.AreEqual("-1,1111,2222,2112", currPath);
//ensure it's indexed
indexer.IndexItem(node.ConvertToValueSet(IndexTypes.Media));
//it will not exist because it exists under 2222
var results = searcher.CreateQuery().Id(2112).Execute();
Assert.AreEqual(0, results.Count());
//now mimic moving 2112 to 1116
//node.SetAttributeValue("path", currPath.Replace("2222", "1116"));
node.SetAttributeValue("path", "-1,1116,2112");
node.SetAttributeValue("parentID", "1116");
//now reindex the node, this should first delete it and then WILL add it because of the parent id constraint
indexer.IndexItems(new[] { node.ConvertToValueSet(IndexTypes.Media) });
//now ensure it exists
results = searcher.CreateQuery().Id(2112).Execute();
Assert.AreEqual(1, results.Count());
}
}
[Test]
public void Index_Move_Media_To_Non_Indexable_ParentID()
{
// create a validator with
// publishedValuesOnly false
// parentId 2222 (only content under that parent will be indexed)
var validator = new ContentValueSetValidator(false, 2222);
using (var luceneDir = new RandomIdRamDirectory())
using (var indexer1 = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, IOHelper, RuntimeState, luceneDir, validator: validator))
using (indexer1.ProcessNonAsync())
{
var searcher = indexer1.GetSearcher();
//get a node from the data repo (this one exists underneath 2222)
var node = _mediaService.GetLatestMediaByXpath("//*[string-length(@id)>0 and number(@id)>0]")
.Root.Elements()
.First(x => (int) x.Attribute("id") == 2112);
var currPath = (string)node.Attribute("path"); //should be : -1,1111,2222,2112
Assert.AreEqual("-1,1111,2222,2112", currPath);
//ensure it's indexed
indexer1.IndexItem(node.ConvertToValueSet(IndexTypes.Media));
//it will exist because it exists under 2222
var results = searcher.CreateQuery().Id(2112).Execute();
Assert.AreEqual(1, results.Count());
//now mimic moving the node underneath 1116 instead of 2222
node.SetAttributeValue("path", currPath.Replace("2222", "1116"));
node.SetAttributeValue("parentID", "1116");
//now reindex the node, this should first delete it and then NOT add it because of the parent id constraint
indexer1.IndexItems(new[] { node.ConvertToValueSet(IndexTypes.Media) });
//now ensure it's deleted
results = searcher.CreateQuery().Id(2112).Execute();
Assert.AreEqual(0, results.Count());
}
}
/// <summary>
/// This will ensure that all 'Content' (not media) is cleared from the index using the Lucene API directly.
/// We then call the Examine method to re-index Content and do some comparisons to ensure that it worked correctly.
/// </summary>
[Test]
public void Index_Reindex_Content()
{
var rebuilder = IndexInitializer.GetContentIndexRebuilder(Factory.GetInstance<PropertyEditorCollection>(), IndexInitializer.GetMockContentService(), ScopeProvider.SqlContext, false);
using (var luceneDir = new RandomIdRamDirectory())
using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, IOHelper, RuntimeState, luceneDir,
validator: new ContentValueSetValidator(false)))
using (indexer.ProcessNonAsync())
{
var searcher = indexer.GetSearcher();
//create the whole thing
rebuilder.Populate(indexer);
var result = searcher.CreateQuery().Field(ExamineFieldNames.CategoryFieldName, IndexTypes.Content).Execute();
Assert.AreEqual(21, result.TotalItemCount);
//delete all content
foreach (var r in result)
{
indexer.DeleteFromIndex(r.Id);
}
//ensure it's all gone
result = searcher.CreateQuery().Field(ExamineFieldNames.CategoryFieldName, IndexTypes.Content).Execute();
Assert.AreEqual(0, result.TotalItemCount);
//call our indexing methods
rebuilder.Populate(indexer);
result = searcher.CreateQuery().Field(ExamineFieldNames.CategoryFieldName, IndexTypes.Content).Execute();
Assert.AreEqual(21, result.TotalItemCount);
}
}
/// <summary>
/// This will delete an item from the index and ensure that all children of the node are deleted too!
/// </summary>
[Test]
public void Index_Delete_Index_Item_Ensure_Heirarchy_Removed()
{
var rebuilder = IndexInitializer.GetContentIndexRebuilder(Factory.GetInstance<PropertyEditorCollection>(), IndexInitializer.GetMockContentService(), ScopeProvider.SqlContext, false);
using (var luceneDir = new RandomIdRamDirectory())
using (var indexer = IndexInitializer.GetUmbracoIndexer(ProfilingLogger, IOHelper, RuntimeState, luceneDir))
using (indexer.ProcessNonAsync())
{
var searcher = indexer.GetSearcher();
//create the whole thing
rebuilder.Populate(indexer);
//now delete a node that has children
indexer.DeleteFromIndex(1140.ToString());
//this node had children: 1141 & 1142, let's ensure they are also removed
var results = searcher.CreateQuery().Id(1141).Execute();
Assert.AreEqual(0, results.Count());
results = searcher.CreateQuery().Id(1142).Execute();
Assert.AreEqual(0, results.Count());
}
}
private readonly ExamineDemoDataMediaService _mediaService = new ExamineDemoDataMediaService();
}
}