diff --git a/AzurePackage.proj b/AzurePackage.proj index 202ec1827..a5bc7ccfa 100644 --- a/AzurePackage.proj +++ b/AzurePackage.proj @@ -3,19 +3,19 @@ - - $(MSBuildProjectDirectory)\lib - $(MSBuildProjectDirectory)\src - $(MSBuildProjectDirectory)\build - $(MSBuildProjectDirectory)\artifacts\Azure - - $(BuildFolder)\Compile - $(CompileFolder)\Orchard.Azure.CloudService.csx - $(ServiceFolder)\roles\Orchard.Azure.Web\approot - $(CompileFolder)\_PublishedWebsites - $(BuildFolder)\Stage - - + + $(MSBuildProjectDirectory)\lib + $(MSBuildProjectDirectory)\src + $(MSBuildProjectDirectory)\build + $(MSBuildProjectDirectory)\buildtasks + $(MSBuildProjectDirectory)\artifacts\Azure + + $(BuildFolder)\Compile + $(CompileFolder)\Orchard.Azure.CloudService.csx + $(ServiceFolder)\roles\Orchard.Azure.Web\approot + $(CompileFolder)\_PublishedWebsites + $(BuildFolder)\Stage + @@ -39,10 +39,10 @@ - - - - + + + + - - - - - + + + + - + + + @@ -112,6 +113,24 @@ XPath="/log4net/root/priority/@value" Value="ERROR" /> + + + + + + + + + + + + - + diff --git a/Orchard.proj b/Orchard.proj index 0d10ebf37..8a85e521a 100644 --- a/Orchard.proj +++ b/Orchard.proj @@ -231,6 +231,24 @@ XPath="/log4net/root/priority/@value" Value="ERROR" /> + + + + + + + + + + + + diff --git a/src/Orchard.Azure/AzureFileSystem.cs b/src/Orchard.Azure/AzureFileSystem.cs index 05a42e61e..519a7477c 100644 --- a/src/Orchard.Azure/AzureFileSystem.cs +++ b/src/Orchard.Azure/AzureFileSystem.cs @@ -29,7 +29,7 @@ namespace Orchard.Azure { _storageAccount = storageAccount; ContainerName = containerName; _root = String.IsNullOrEmpty(root) ? "": root + "/"; - _absoluteRoot = _storageAccount.BlobEndpoint.AbsoluteUri + "/" + containerName + "/" + root; + _absoluteRoot = Combine(Combine(_storageAccount.BlobEndpoint.AbsoluteUri, containerName), root); using ( new HttpContextWeaver() ) { diff --git a/src/Orchard.Azure/Orchard.Azure.Web/Default.aspx b/src/Orchard.Azure/Orchard.Azure.Web/Default.aspx deleted file mode 100644 index fcae21248..000000000 --- a/src/Orchard.Azure/Orchard.Azure.Web/Default.aspx +++ /dev/null @@ -1,3 +0,0 @@ -<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Orchard.Azure.Web._Default" %> - -<%-- Please do not delete this file. It is used to ensure that ASP.NET MVC is activated by IIS when a user makes a "/" request to the server. --%> diff --git a/src/Orchard.Azure/Orchard.Azure.Web/Default.aspx.cs b/src/Orchard.Azure/Orchard.Azure.Web/Default.aspx.cs deleted file mode 100644 index 924ecd969..000000000 --- a/src/Orchard.Azure/Orchard.Azure.Web/Default.aspx.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Web; -using System.Web.Mvc; -using System.Web.UI; - -namespace Orchard.Azure.Web { - public class _Default : Page { - public void Page_Load(object sender, EventArgs e) { - // Change the current path so that the Routing handler can correctly interpret - // the request, then restore the original path so that the OutputCache module - // can correctly process the response (if caching is enabled). - - var originalPath = Request.Path; - HttpContext.Current.RewritePath(Request.ApplicationPath, false); - IHttpHandler httpHandler = new MvcHttpHandler(); - httpHandler.ProcessRequest(HttpContext.Current); - HttpContext.Current.RewritePath(originalPath, false); - } - } -} \ No newline at end of file diff --git a/src/Orchard.Azure/Orchard.Azure.Web/Orchard.Azure.Web.csproj b/src/Orchard.Azure/Orchard.Azure.Web/Orchard.Azure.Web.csproj index dd2703ca9..31d043fba 100644 --- a/src/Orchard.Azure/Orchard.Azure.Web/Orchard.Azure.Web.csproj +++ b/src/Orchard.Azure/Orchard.Azure.Web/Orchard.Azure.Web.csproj @@ -140,10 +140,6 @@ - - Default.aspx - ASPXCodeBehind - Global.asax @@ -151,7 +147,6 @@ - diff --git a/src/Orchard.Azure/Orchard.Azure.Web/Web.config b/src/Orchard.Azure/Orchard.Azure.Web/Web.config index 92583c3f9..7c86d8a39 100644 --- a/src/Orchard.Azure/Orchard.Azure.Web/Web.config +++ b/src/Orchard.Azure/Orchard.Azure.Web/Web.config @@ -53,7 +53,7 @@ affects performance, set this value to true only during development. --> - + @@ -116,7 +116,6 @@ - @@ -133,7 +132,6 @@ - @@ -142,7 +140,8 @@ - + + diff --git a/src/Orchard.Tests.Modules/Indexing/LuceneIndexProviderTests.cs b/src/Orchard.Tests.Modules/Indexing/LuceneIndexProviderTests.cs new file mode 100644 index 000000000..41a43c632 --- /dev/null +++ b/src/Orchard.Tests.Modules/Indexing/LuceneIndexProviderTests.cs @@ -0,0 +1,296 @@ +using System; +using System.IO; +using System.Linq; +using Autofac; +using Lucene.Services; +using NUnit.Framework; +using Orchard.Environment.Configuration; +using Orchard.FileSystems.AppData; +using Orchard.Indexing; +using Orchard.Indexing.Services; +using Orchard.Tests.FileSystems.AppData; + +namespace Orchard.Tests.Modules.Indexing { + public class LuceneIndexProviderTests { + private IContainer _container; + private IIndexProvider _provider; + private IAppDataFolder _appDataFolder; + private ShellSettings _shellSettings; + private readonly string _basePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + + [TestFixtureTearDown] + public void Clean() { + if (Directory.Exists(_basePath)) { + Directory.Delete(_basePath, true); + } + } + + [SetUp] + public void Setup() { + if (Directory.Exists(_basePath)) { + Directory.Delete(_basePath, true); + } + Directory.CreateDirectory(_basePath); + + _appDataFolder = AppDataFolderTests.CreateAppDataFolder(_basePath); + + var builder = new ContainerBuilder(); + builder.RegisterType().As(); + builder.RegisterInstance(_appDataFolder).As(); + + // setting up a ShellSettings instance + _shellSettings = new ShellSettings { Name = "My Site" }; + builder.RegisterInstance(_shellSettings).As(); + + _container = builder.Build(); + _provider = _container.Resolve(); + } + + private string[] Indexes() { + return new DirectoryInfo(Path.Combine(_basePath, "Sites", "My Site", "Indexes")).GetDirectories().Select(d => d.Name).ToArray(); + } + + [Test] + public void IndexProviderShouldCreateNewIndex() { + Assert.That(Indexes().Length, Is.EqualTo(0)); + + _provider.CreateIndex("default"); + Assert.That(Indexes().Length, Is.EqualTo(1)); + } + + [Test] + public void IndexProviderShouldOverwriteAlreadyExistingIndex() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("body", null)); + Assert.That(_provider.IsEmpty("default"), Is.False); + + _provider.CreateIndex("default"); + Assert.That(_provider.IsEmpty("default"), Is.True); + } + + [Test] + public void IndexProviderShouldDeleteExistingIndex() { + Assert.That(Indexes().Length, Is.EqualTo(0)); + + _provider.CreateIndex("default"); + Assert.That(Indexes().Length, Is.EqualTo(1)); + + _provider.DeleteIndex("default"); + Assert.That(Indexes().Length, Is.EqualTo(0)); + } + + [Test] + public void IndexProviderShouldListExistingIndexes() { + Assert.That(Indexes().Length, Is.EqualTo(0)); + + _provider.CreateIndex("default"); + Assert.That(Indexes().Length, Is.EqualTo(1)); + Assert.That(Indexes()[0], Is.EqualTo("default")); + + _provider.CreateIndex("foo"); + Assert.That(Indexes().Length, Is.EqualTo(2)); + } + + [Test] + public void ANewIndexShouldBeEmpty() { + _provider.CreateIndex("default"); + var searchBuilder = _provider.CreateSearchBuilder("default"); + var hits = searchBuilder.Search(); + + Assert.That(hits.Count(), Is.EqualTo(0)); + } + + [Test] + public void DocumentsShouldBeSearchableById() { + _provider.CreateIndex("default"); + + _provider.Store("default", _provider.New(42)); + + var searchBuilder = _provider.CreateSearchBuilder("default"); + + var hit = searchBuilder.Get(42); + Assert.IsNotNull(hit); + Assert.That(hit.ContentItemId, Is.EqualTo(42)); + + hit = searchBuilder.Get(1); + Assert.IsNull(hit); + } + + [Test] + public void PropertiesShouldNotBeLost() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(42).Add("prop1", "value1").Store()); + + var hit = _provider.CreateSearchBuilder("default").Get(42); + + Assert.IsNotNull(hit); + Assert.That(hit.ContentItemId, Is.EqualTo(42)); + Assert.That(hit.GetString("prop1"), Is.EqualTo("value1")); + + } + + [Test] + public void ShouldHandleMultipleIndexes() { + _provider.CreateIndex("default1"); + _provider.Store("default1", _provider.New(1)); + + _provider.CreateIndex("default2"); + _provider.Store("default2", _provider.New(2)); + + _provider.CreateIndex("default3"); + _provider.Store("default3", _provider.New(3)); + + Assert.IsNotNull(_provider.CreateSearchBuilder("default1").Get(1)); + Assert.IsNotNull(_provider.CreateSearchBuilder("default2").Get(2)); + Assert.IsNotNull(_provider.CreateSearchBuilder("default3").Get(3)); + + Assert.IsNull(_provider.CreateSearchBuilder("default1").Get(2)); + Assert.IsNull(_provider.CreateSearchBuilder("default2").Get(3)); + Assert.IsNull(_provider.CreateSearchBuilder("default3").Get(1)); + + } + + [Test] + public void IdentifierShouldNotCollide() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("field", "value1")); + _provider.Store("default", _provider.New(11).Add("field", "value11")); + _provider.Store("default", _provider.New(111).Add("field", "value111")); + + var searchBuilder = _provider.CreateSearchBuilder("default"); + + Assert.That(searchBuilder.Get(1).ContentItemId, Is.EqualTo(1)); + Assert.That(searchBuilder.Get(11).ContentItemId, Is.EqualTo(11)); + Assert.That(searchBuilder.Get(111).ContentItemId, Is.EqualTo(111)); + } + + [Test] + public void TagsShouldBeRemoved() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("body", "
some content").Analyze()); + _provider.Store("default", _provider.New(2).Add("body", "
some content").RemoveTags().Analyze()); + + var searchBuilder = _provider.CreateSearchBuilder("default"); + + Assert.That(searchBuilder.WithField("body", "hr").Search().Count(), Is.EqualTo(1)); + Assert.That(searchBuilder.WithField("body", "hr").Search().First().ContentItemId, Is.EqualTo(1)); + } + + [Test] public void ShouldAllowNullOrEmptyStrings() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("body", null)); + _provider.Store("default", _provider.New(2).Add("body", "")); + _provider.Store("default", _provider.New(3).Add("body", "
").RemoveTags()); + + var searchBuilder = _provider.CreateSearchBuilder("default"); + + Assert.That(searchBuilder.Get(1).ContentItemId, Is.EqualTo(1)); + Assert.That(searchBuilder.Get(2).ContentItemId, Is.EqualTo(2)); + Assert.That(searchBuilder.Get(3).ContentItemId, Is.EqualTo(3)); + } + + [Test] + public void ProviderShouldStoreSettings() { + _provider.CreateIndex("default"); + Assert.That(_provider.GetLastIndexUtc("default"), Is.Null); + + _provider.SetLastIndexUtc("default", new DateTime(2010, 1, 1, 1, 1, 1, 1)); + Assert.That(_provider.GetLastIndexUtc("default"), Is.EqualTo(new DateTime(2010, 1, 1, 1, 1, 1, 0))); + + _provider.SetLastIndexUtc("default", new DateTime(1901, 1, 1, 1, 1, 1, 1)); + Assert.That(_provider.GetLastIndexUtc("default"), Is.EqualTo(LuceneIndexProvider.DefaultMinDateTime)); + } + + [Test] + public void IsEmptyShouldBeTrueForNoneExistingIndexes() { + _provider.IsEmpty("dummy"); + Assert.That(_provider.IsEmpty("default"), Is.True); + } + + [Test] + public void IsEmptyShouldBeTrueForJustNewIndexes() { + _provider.CreateIndex("default"); + Assert.That(_provider.IsEmpty("default"), Is.True); + } + + [Test] + public void IsEmptyShouldBeFalseWhenThereIsADocument() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("body", null)); + Assert.That(_provider.IsEmpty("default"), Is.False); + } + + [Test] + public void IsDirtyShouldBeFalseForNewDocuments() { + IDocumentIndex doc = _provider.New(1); + Assert.That(doc.IsDirty, Is.False); + } + + + [Test] + public void IsDirtyShouldBeTrueWhenIndexIsModified() { + IDocumentIndex doc; + + doc = _provider.New(1); + doc.Add("foo", "value"); + Assert.That(doc.IsDirty, Is.True); + + doc = _provider.New(1); + doc.Add("foo", false); + Assert.That(doc.IsDirty, Is.True); + + doc = _provider.New(1); + doc.Add("foo", (float)1.0); + Assert.That(doc.IsDirty, Is.True); + + doc = _provider.New(1); + doc.Add("foo", 1); + Assert.That(doc.IsDirty, Is.True); + + doc = _provider.New(1); + doc.Add("foo", DateTime.Now); + Assert.That(doc.IsDirty, Is.True); + + } + + [Test] + public void DocumentsShouldBeDeleted() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("field", "value1")); + _provider.Store("default", _provider.New(11).Add("field", "value11")); + _provider.Store("default", _provider.New(111).Add("field", "value111")); + + var searchBuilder = _provider.CreateSearchBuilder("default"); + + Assert.That(searchBuilder.Get(1).ContentItemId, Is.EqualTo(1)); + Assert.That(searchBuilder.Get(11).ContentItemId, Is.EqualTo(11)); + Assert.That(searchBuilder.Get(111).ContentItemId, Is.EqualTo(111)); + + _provider.Delete("default", 1); + + Assert.That(searchBuilder.Get(1), Is.Null); + Assert.That(searchBuilder.Get(11).ContentItemId, Is.EqualTo(11)); + Assert.That(searchBuilder.Get(111).ContentItemId, Is.EqualTo(111)); + + _provider.Delete("default", new int[] {1, 11, 111 }); + + Assert.That(searchBuilder.Get(1), Is.Null); + Assert.That(searchBuilder.Get(11), Is.Null); + Assert.That(searchBuilder.Get(111), Is.Null); + + } + + [Test] + public void SameContentItemShouldNotBeIndexedTwice() { + _provider.CreateIndex("default"); + + var searchBuilder = _provider.CreateSearchBuilder("default"); + + _provider.Store("default", _provider.New(1).Add("field", "value1")); + Assert.That(searchBuilder.WithField("id", "1").Count(), Is.EqualTo(1)); + + _provider.Store("default", _provider.New(1).Add("field", "value2")); + Assert.That(searchBuilder.WithField("id", "1").Count(), Is.EqualTo(1)); + } + } +} diff --git a/src/Orchard.Tests.Modules/Indexing/LuceneSearchBuilderTests.cs b/src/Orchard.Tests.Modules/Indexing/LuceneSearchBuilderTests.cs new file mode 100644 index 000000000..1b1d19aee --- /dev/null +++ b/src/Orchard.Tests.Modules/Indexing/LuceneSearchBuilderTests.cs @@ -0,0 +1,337 @@ +using System; +using System.IO; +using System.Linq; +using Autofac; +using Lucene.Services; +using NUnit.Framework; +using Orchard.Environment.Configuration; +using Orchard.FileSystems.AppData; +using Orchard.Indexing; +using Orchard.Indexing.Services; +using Orchard.Tests.FileSystems.AppData; + +namespace Orchard.Tests.Modules.Indexing { + public class LuceneSearchBuilderTests { + private IContainer _container; + private IIndexProvider _provider; + private IAppDataFolder _appDataFolder; + private ShellSettings _shellSettings; + private readonly string _basePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + + [TestFixtureTearDown] + public void Clean() { + if (Directory.Exists(_basePath)) { + Directory.Delete(_basePath, true); + } + } + + [SetUp] + public void Setup() { + if (Directory.Exists(_basePath)) { + Directory.Delete(_basePath, true); + } + Directory.CreateDirectory(_basePath); + + _appDataFolder = AppDataFolderTests.CreateAppDataFolder(_basePath); + + var builder = new ContainerBuilder(); + builder.RegisterType().As(); + builder.RegisterInstance(_appDataFolder).As(); + + // setting up a ShellSettings instance + _shellSettings = new ShellSettings { Name = "My Site" }; + builder.RegisterInstance(_shellSettings).As(); + + _container = builder.Build(); + _provider = _container.Resolve(); + } + + private ISearchBuilder _searchBuilder { get { return _provider.CreateSearchBuilder("default"); } } + + [Test] + public void SearchTermsShouldBeFoundInMultipleFields() { + _provider.CreateIndex("default"); + _provider.Store("default", + _provider.New(42) + .Add("title", "title1 title2 title3").Analyze() + .Add("date", new DateTime(2010, 05, 28, 14, 13, 56, 123)) + ); + + Assert.IsNotNull(_provider.CreateSearchBuilder("default").Get(42)); + + Assert.IsNotNull(_provider.CreateSearchBuilder("default").WithField("title", "title1").Search().FirstOrDefault()); + Assert.IsNotNull(_provider.CreateSearchBuilder("default").WithField("title", "title2").Search().FirstOrDefault()); + Assert.IsNotNull(_provider.CreateSearchBuilder("default").WithField("title", "title3").Search().FirstOrDefault()); + Assert.IsNull(_provider.CreateSearchBuilder("default").WithField("title", "title4").Search().FirstOrDefault()); + + } + + [Test] + public void ShouldSearchById() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1)); + _provider.Store("default", _provider.New(2)); + _provider.Store("default", _provider.New(3)); + + + Assert.That(_searchBuilder.Get(1).ContentItemId, Is.EqualTo(1)); + Assert.That(_searchBuilder.Get(2).ContentItemId, Is.EqualTo(2)); + Assert.That(_searchBuilder.Get(3).ContentItemId, Is.EqualTo(3)); + } + + [Test] + public void ShouldSearchWithField() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("title", "cat")); + _provider.Store("default", _provider.New(2).Add("title", "dog")); + _provider.Store("default", _provider.New(3).Add("title", "cat")); + + + Assert.That(_searchBuilder.WithField("title", "cat").Search().Count(), Is.EqualTo(2)); + Assert.That(_searchBuilder.WithField("title", "cat").Search().Any(hit => new[] { 1, 3 }.Contains(hit.ContentItemId)), Is.True); + + } + + [Test] + public void ShouldCountResultsOnly() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("title", "cat")); + _provider.Store("default", _provider.New(2).Add("title", "dog")); + _provider.Store("default", _provider.New(3).Add("title", "cat")); + + Assert.That(_searchBuilder.WithField("title", "dog").Count(), Is.EqualTo(1)); + Assert.That(_searchBuilder.WithField("title", "cat").Count(), Is.EqualTo(2)); + } + + [Test] + public void ShouldFilterByDate() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("date", new DateTime(2010, 05, 28, 12, 30, 15))); + _provider.Store("default", _provider.New(2).Add("date", new DateTime(2010, 05, 28, 12, 30, 30))); + _provider.Store("default", _provider.New(3).Add("date", new DateTime(2010, 05, 28, 12, 30, 45))); + + Assert.That(_searchBuilder.WithinRange("date", new DateTime(2010, 05, 28, 12, 30, 15), DateTime.MaxValue).Count(), Is.EqualTo(3)); + Assert.That(_searchBuilder.WithinRange("date", DateTime.MinValue, new DateTime(2010, 05, 28, 12, 30, 45)).Count(), Is.EqualTo(3)); + Assert.That(_searchBuilder.WithinRange("date", new DateTime(2010, 05, 28, 12, 30, 15), new DateTime(2010, 05, 28, 12, 30, 45)).Count(), Is.EqualTo(3)); + Assert.That(_searchBuilder.WithinRange("date", new DateTime(2010, 05, 28, 12, 30, 16), new DateTime(2010, 05, 28, 12, 30, 44)).Count(), Is.EqualTo(1)); + Assert.That(_searchBuilder.WithinRange("date", new DateTime(2010, 05, 28, 12, 30, 46), DateTime.MaxValue).Count(), Is.EqualTo(0)); + Assert.That(_searchBuilder.WithinRange("date", DateTime.MinValue, new DateTime(2010, 05, 28, 12, 30, 1)).Count(), Is.EqualTo(0)); + } + + [Test] + public void ShouldSliceResults() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1)); + _provider.Store("default", _provider.New(22)); + _provider.Store("default", _provider.New(333)); + _provider.Store("default", _provider.New(4444)); + _provider.Store("default", _provider.New(55555)); + + + Assert.That(_searchBuilder.Count(), Is.EqualTo(5)); + Assert.That(_searchBuilder.Slice(0, 3).Count(), Is.EqualTo(3)); + Assert.That(_searchBuilder.Slice(1, 3).Count(), Is.EqualTo(3)); + Assert.That(_searchBuilder.Slice(3, 3).Count(), Is.EqualTo(2)); + + // Count() and Search() should return the same results + Assert.That(_searchBuilder.Search().Count(), Is.EqualTo(5)); + Assert.That(_searchBuilder.Slice(0, 3).Search().Count(), Is.EqualTo(3)); + Assert.That(_searchBuilder.Slice(1, 3).Search().Count(), Is.EqualTo(3)); + Assert.That(_searchBuilder.Slice(3, 3).Search().Count(), Is.EqualTo(2)); + } + + [Test] + public void ShouldSortByRelevance() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("body", "michael is in the kitchen").Analyze()); + _provider.Store("default", _provider.New(2).Add("body", "michael as a cousin named michel").Analyze()); + _provider.Store("default", _provider.New(3).Add("body", "speak inside the mic").Analyze()); + _provider.Store("default", _provider.New(4).Add("body", "a dog is pursuing a cat").Analyze()); + _provider.Store("default", _provider.New(5).Add("body", "the elephant can't catch up the dog").Analyze()); + + var michael = _searchBuilder.WithField("body", "michael").Search().ToList(); + Assert.That(michael.Count(), Is.EqualTo(2)); + Assert.That(michael[0].Score >= michael[1].Score, Is.True); + + // Sorting on score is always descending + michael = _searchBuilder.WithField("body", "michael").Ascending().Search().ToList(); + Assert.That(michael.Count(), Is.EqualTo(2)); + Assert.That(michael[0].Score >= michael[1].Score, Is.True); + } + + [Test] + public void ShouldSortByDate() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("date", new DateTime(2010, 05, 28, 12, 30, 15)).Store()); + _provider.Store("default", _provider.New(2).Add("date", new DateTime(2010, 05, 28, 12, 30, 30)).Store()); + _provider.Store("default", _provider.New(3).Add("date", new DateTime(2010, 05, 28, 12, 30, 45)).Store()); + + var date = _searchBuilder.SortBy("date").Search().ToList(); + Assert.That(date.Count(), Is.EqualTo(3)); + Assert.That(date[0].GetDateTime("date") > date[1].GetDateTime("date"), Is.True); + Assert.That(date[1].GetDateTime("date") > date[2].GetDateTime("date"), Is.True); + + date = _searchBuilder.SortBy("date").Ascending().Search().ToList(); + Assert.That(date.Count(), Is.EqualTo(3)); + Assert.That(date[0].GetDateTime("date") < date[1].GetDateTime("date"), Is.True); + Assert.That(date[1].GetDateTime("date") < date[2].GetDateTime("date"), Is.True); + } + + [Test] + public void ShouldEscapeSpecialChars() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("body", "Orchard has been developped in C#").Analyze()); + _provider.Store("default", _provider.New(2).Add("body", "Windows has been developped in C++").Analyze()); + + var cs = _searchBuilder.Parse("body", "C#").Search().ToList(); + Assert.That(cs.Count(), Is.EqualTo(2)); + + var cpp = _searchBuilder.Parse("body", "C++").Search().ToList(); + Assert.That(cpp.Count(), Is.EqualTo(2)); + + } + + [Test] + public void ShouldHandleMandatoryFields() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("body", "Orchard has been developped in C#").Analyze()); + _provider.Store("default", _provider.New(2).Add("body", "Windows has been developped in C++").Analyze()); + + Assert.That(_searchBuilder.WithField("body", "develop").Search().ToList().Count(), Is.EqualTo(2)); + Assert.That(_searchBuilder.WithField("body", "develop").WithField("body", "Orchard").Search().ToList().Count(), Is.EqualTo(2)); + Assert.That(_searchBuilder.WithField("body", "develop").WithField("body", "Orchard").Mandatory().Search().ToList().Count(), Is.EqualTo(1)); + Assert.That(_searchBuilder.WithField("body", "develop").WithField("body", "Orchard").Mandatory().Search().First().ContentItemId, Is.EqualTo(1)); + } + + [Test] + public void ShouldHandleForbiddenFields() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("body", "Orchard has been developped in C#").Analyze()); + _provider.Store("default", _provider.New(2).Add("body", "Windows has been developped in C++").Analyze()); + + Assert.That(_searchBuilder.WithField("body", "developped").Search().ToList().Count(), Is.EqualTo(2)); + Assert.That(_searchBuilder.WithField("body", "developped").WithField("body", "Orchard").Search().ToList().Count(), Is.EqualTo(2)); + Assert.That(_searchBuilder.WithField("body", "developped").WithField("body", "Orchard").Forbidden().Search().ToList().Count(), Is.EqualTo(1)); + Assert.That(_searchBuilder.WithField("body", "developped").WithField("body", "Orchard").Forbidden().Search().First().ContentItemId, Is.EqualTo(2)); + } + + [Test] + public void ShouldHandleWeight() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("body", "Orchard has been developped in C#").Analyze()); + _provider.Store("default", _provider.New(2).Add("body", "Windows has been developped in C++").Analyze()); + + Assert.That(_searchBuilder.WithField("body", "developped").WithField("body", "Orchard").Weighted(2).Search().First().ContentItemId, Is.EqualTo(1)); + } + + [Test] + public void ShouldParseLuceneQueries() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("body", "Bradley is in the kitchen.").Analyze().Add("title", "Beer and takos").Analyze()); + _provider.Store("default", _provider.New(2).Add("body", "Renaud is also in the kitchen.").Analyze().Add("title", "A love affair").Analyze()); + _provider.Store("default", _provider.New(3).Add("body", "Bertrand is a little bit jealous.").Analyze().Add("title", "Soap opera").Analyze()); + + Assert.That(_searchBuilder.Parse(new[] { "body" }, "kitchen").Count(), Is.EqualTo(2)); + Assert.That(_searchBuilder.Parse(new[] { "body" }, "kitchen bertrand").Count(), Is.EqualTo(3)); + Assert.That(_searchBuilder.Parse(new[] { "body" }, "kitchen +bertrand").Count(), Is.EqualTo(1)); + Assert.That(_searchBuilder.Parse(new[] { "body" }, "+kitchen +bertrand").Count(), Is.EqualTo(0)); + Assert.That(_searchBuilder.Parse(new[] { "body" }, "kit").Count(), Is.EqualTo(0)); + Assert.That(_searchBuilder.Parse(new[] { "body" }, "kit*").Count(), Is.EqualTo(2)); + Assert.That(_searchBuilder.Parse(new[] { "body", "title" }, "bradley love^3 soap").Count(), Is.EqualTo(3)); + Assert.That(_searchBuilder.Parse(new[] { "body", "title" }, "bradley love^3 soap").Search().First().ContentItemId, Is.EqualTo(2)); + } + + [Test] + public void ShouldFilterIntValues() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("field", 1)); + _provider.Store("default", _provider.New(2).Add("field", 22)); + _provider.Store("default", _provider.New(3).Add("field", 333)); + + Assert.That(_searchBuilder.WithField("field", 1).ExactMatch().Count(), Is.EqualTo(1)); + Assert.That(_searchBuilder.WithField("field", 22).ExactMatch().Count(), Is.EqualTo(1)); + Assert.That(_searchBuilder.WithField("field", 333).ExactMatch().Count(), Is.EqualTo(1)); + + Assert.That(_searchBuilder.WithField("field", 0).ExactMatch().Count(), Is.EqualTo(0)); + Assert.That(_searchBuilder.WithField("field", 2).ExactMatch().Count(), Is.EqualTo(0)); + Assert.That(_searchBuilder.WithField("field", 3).ExactMatch().Count(), Is.EqualTo(0)); + } + + [Test] + public void ShouldFilterStoredIntValues() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("field", 1).Store()); + _provider.Store("default", _provider.New(2).Add("field", 22).Store()); + _provider.Store("default", _provider.New(3).Add("field", 333).Store()); + + Assert.That(_searchBuilder.WithField("field", 1).ExactMatch().Count(), Is.EqualTo(1)); + Assert.That(_searchBuilder.WithField("field", 22).ExactMatch().Count(), Is.EqualTo(1)); + Assert.That(_searchBuilder.WithField("field", 333).ExactMatch().Count(), Is.EqualTo(1)); + + Assert.That(_searchBuilder.WithField("field", 0).ExactMatch().Count(), Is.EqualTo(0)); + Assert.That(_searchBuilder.WithField("field", 2).ExactMatch().Count(), Is.EqualTo(0)); + Assert.That(_searchBuilder.WithField("field", 3).ExactMatch().Count(), Is.EqualTo(0)); + } + + [Test] + public void ShouldProvideAvailableFields() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("a", "Home").Analyze()); + _provider.Store("default", _provider.New(2).Add("b", DateTime.Now).Store()); + _provider.Store("default", _provider.New(3).Add("c", 333)); + + Assert.That(_provider.GetFields("default").Count(), Is.EqualTo(4)); + Assert.That(_provider.GetFields("default").OrderBy(s => s).ToArray(), Is.EqualTo(new [] { "a", "b", "c", "id"})); + } + + [Test] + public void FiltersShouldNotAlterResults() { + _provider.CreateIndex("default"); + _provider.Store("default", _provider.New(1).Add("body", "Orchard has been developped by Mirosoft in C#").Analyze().Add("culture", 1033)); + _provider.Store("default", _provider.New(2).Add("body", "Windows a été développé par Mirosoft en C++").Analyze().Add("culture", 1036)); + _provider.Store("default", _provider.New(3).Add("title", "Home").Analyze().Add("culture", 1033)); + + Assert.That(_searchBuilder.WithField("body", "Mirosoft").Count(), Is.EqualTo(2)); + Assert.That(_searchBuilder.WithField("body", "Mirosoft").WithField("culture", 1033).Count(), Is.EqualTo(3)); + Assert.That(_searchBuilder.WithField("body", "Mirosoft").WithField("culture", 1033).AsFilter().Count(), Is.EqualTo(1)); + + Assert.That(_searchBuilder.WithField("body", "Orchard").WithField("culture", 1036).Count(), Is.EqualTo(2)); + Assert.That(_searchBuilder.WithField("body", "Orchard").WithField("culture", 1036).AsFilter().Count(), Is.EqualTo(0)); + + Assert.That(_searchBuilder.WithField("culture", 1033).Count(), Is.EqualTo(2)); + Assert.That(_searchBuilder.WithField("culture", 1033).AsFilter().Count(), Is.EqualTo(2)); + + Assert.That(_searchBuilder.WithField("body", "blabla").WithField("culture", 1033).Count(), Is.EqualTo(2)); + Assert.That(_searchBuilder.WithField("body", "blabla").WithField("culture", 1033).AsFilter().Count(), Is.EqualTo(0)); + + Assert.That(_searchBuilder.Parse("title", "home").Count(), Is.EqualTo(1)); + Assert.That(_searchBuilder.Parse("title", "home").WithField("culture", 1033).AsFilter().Count(), Is.EqualTo(1)); + } + + [Test] + public void FieldsCanContainMultipleValue() { + _provider.CreateIndex("default"); + var documentIndex = _provider.New(1) + .Add("tag-id", 1) + .Add("tag-id", 2) + .Add("tag-id", 3) + .Add("tag-value", "tag1") + .Add("tag-value", "tag2") + .Add("tag-value", "tag3"); + + _provider.Store("default", documentIndex); + + Assert.That(_searchBuilder.WithField("tag-id", 0).Count(), Is.EqualTo(0)); + Assert.That(_searchBuilder.WithField("tag-id", 1).Count(), Is.EqualTo(1)); + Assert.That(_searchBuilder.WithField("tag-id", 2).Count(), Is.EqualTo(1)); + Assert.That(_searchBuilder.WithField("tag-id", 3).Count(), Is.EqualTo(1)); + + Assert.That(_searchBuilder.WithField("tag-value", "tag").ExactMatch().Count(), Is.EqualTo(0)); + Assert.That(_searchBuilder.WithField("tag-value", "tag1").ExactMatch().Count(), Is.EqualTo(1)); + Assert.That(_searchBuilder.WithField("tag-value", "tag2").ExactMatch().Count(), Is.EqualTo(1)); + Assert.That(_searchBuilder.WithField("tag-value", "tag3").ExactMatch().Count(), Is.EqualTo(1)); + + Assert.That(_searchBuilder.WithField("tag-value", "tag").Count(), Is.EqualTo(1)); + } + } +} diff --git a/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj b/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj index 02b5112a1..65360fa8e 100644 --- a/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj +++ b/src/Orchard.Tests.Modules/Orchard.Tests.Modules.csproj @@ -136,6 +136,8 @@ + + @@ -176,6 +178,10 @@ {9916839C-39FC-4CEB-A5AF-89CA7E87119F} Orchard.Core + + {D5D447D7-EF8E-43A6-B9A4-3B025DD9F45D} + Lucene + {C0C45321-B51D-4D8D-9B7B-AA4C2E0B2962} Orchard.CodeGeneration @@ -184,6 +190,10 @@ {14C049FD-B35B-415A-A824-87F26B26E7FD} Orchard.Comments + + {EA2B9121-EF54-40A6-A53E-6593C86EE696} + Orchard.Indexing + {D9A7B330-CD22-4DA1-A95A-8DE1982AD8EB} Orchard.Media diff --git a/src/Orchard.Web/Config/log4net.config b/src/Orchard.Web/Config/log4net.config index e25fa3c7f..3dc7e72bd 100644 --- a/src/Orchard.Web/Config/log4net.config +++ b/src/Orchard.Web/Config/log4net.config @@ -8,7 +8,7 @@ - + @@ -28,7 +28,6 @@ - - - + + - - - - - - - - - - - - - - - - - - + + + @@ -70,10 +54,29 @@ - + + + + + + + + + + + + + + + + + + + + - + diff --git a/src/Orchard.Web/Core/Containers/Controllers/ItemController.cs b/src/Orchard.Web/Core/Containers/Controllers/ItemController.cs index 6bb1e3618..da09b9d91 100644 --- a/src/Orchard.Web/Core/Containers/Controllers/ItemController.cs +++ b/src/Orchard.Web/Core/Containers/Controllers/ItemController.cs @@ -9,9 +9,9 @@ using Orchard.Core.Routable.Models; using Orchard.DisplayManagement; using Orchard.Themes; using Orchard.UI.Navigation; +using Orchard.Settings; namespace Orchard.Core.Containers.Controllers { - using Orchard.Settings; public class ItemController : Controller { private readonly IContentManager _contentManager; diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs index 3d8206ff1..4e3687d25 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogAdminController.cs @@ -14,9 +14,9 @@ using Orchard.Localization; using Orchard.UI.Admin; using Orchard.UI.Navigation; using Orchard.UI.Notify; +using Orchard.Settings; namespace Orchard.Blogs.Controllers { - using Orchard.Settings; [ValidateInput(false), Admin] public class BlogAdminController : Controller, IUpdateModel { diff --git a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogController.cs b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogController.cs index 43a78d750..a200fa074 100644 --- a/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogController.cs +++ b/src/Orchard.Web/Modules/Orchard.Blogs/Controllers/BlogController.cs @@ -11,9 +11,9 @@ using Orchard.Logging; using Orchard.Services; using Orchard.Themes; using Orchard.UI.Navigation; +using Orchard.Settings; namespace Orchard.Blogs.Controllers { - using Orchard.Settings; [Themed] public class BlogController : Controller { diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Service References/GalleryServer/Reference.cs b/src/Orchard.Web/Modules/Orchard.Packaging/Service References/GalleryServer/Reference.cs index 6fb1ab90c..cd11a7266 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Service References/GalleryServer/Reference.cs +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Service References/GalleryServer/Reference.cs @@ -9,7 +9,7 @@ //------------------------------------------------------------------------------ // Original file name: -// Generation date: 12/8/2010 3:18:34 PM +// Generation date: 12/13/2010 12:55:40 PM namespace Orchard.Packaging.GalleryServer { @@ -127,7 +127,7 @@ namespace Orchard.Packaging.GalleryServer /// Initial value of DownloadCount. /// Initial value of PackageSize. /// Initial value of Rating. - /// Initial value of RatingCount. + /// Initial value of RatingsCount. /// Initial value of Price. /// Initial value of RequireLicenseAcceptance. /// Initial value of IsLatestVersion. @@ -135,7 +135,7 @@ namespace Orchard.Packaging.GalleryServer /// Initial value of LastUpdated. /// Initial value of Published. [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Services.Design", "1.0.0")] - public static PublishedPackage CreatePublishedPackage(string ID, string version, int downloadCount, long packageSize, double rating, int ratingCount, decimal price, bool requireLicenseAcceptance, bool isLatestVersion, global::System.DateTime created, global::System.DateTime lastUpdated, global::System.DateTime published) + public static PublishedPackage CreatePublishedPackage(string ID, string version, int downloadCount, long packageSize, double rating, int ratingsCount, decimal price, bool requireLicenseAcceptance, bool isLatestVersion, global::System.DateTime created, global::System.DateTime lastUpdated, global::System.DateTime published) { PublishedPackage publishedPackage = new PublishedPackage(); publishedPackage.Id = ID; @@ -143,7 +143,7 @@ namespace Orchard.Packaging.GalleryServer publishedPackage.DownloadCount = downloadCount; publishedPackage.PackageSize = packageSize; publishedPackage.Rating = rating; - publishedPackage.RatingCount = ratingCount; + publishedPackage.RatingsCount = ratingsCount; publishedPackage.Price = price; publishedPackage.RequireLicenseAcceptance = requireLicenseAcceptance; publishedPackage.IsLatestVersion = isLatestVersion; @@ -426,26 +426,26 @@ namespace Orchard.Packaging.GalleryServer partial void OnRatingChanging(double value); partial void OnRatingChanged(); /// - /// There are no comments for Property RatingCount in the schema. + /// There are no comments for Property RatingsCount in the schema. /// [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Services.Design", "1.0.0")] - public int RatingCount + public int RatingsCount { get { - return this._RatingCount; + return this._RatingsCount; } set { - this.OnRatingCountChanging(value); - this._RatingCount = value; - this.OnRatingCountChanged(); + this.OnRatingsCountChanging(value); + this._RatingsCount = value; + this.OnRatingsCountChanged(); } } [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Data.Services.Design", "1.0.0")] - private int _RatingCount; - partial void OnRatingCountChanging(int value); - partial void OnRatingCountChanged(); + private int _RatingsCount; + partial void OnRatingsCountChanging(int value); + partial void OnRatingsCountChanged(); /// /// There are no comments for Property Price in the schema. /// diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Service References/GalleryServer/service.edmx b/src/Orchard.Web/Modules/Orchard.Packaging/Service References/GalleryServer/service.edmx index 514d12de3..edd4b0cbb 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Service References/GalleryServer/service.edmx +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Service References/GalleryServer/service.edmx @@ -19,7 +19,7 @@ - + diff --git a/src/Orchard.Web/Themes/TheAdmin/Styles/site.css b/src/Orchard.Web/Themes/TheAdmin/Styles/site.css index 9a41675c6..77a6ce198 100644 --- a/src/Orchard.Web/Themes/TheAdmin/Styles/site.css +++ b/src/Orchard.Web/Themes/TheAdmin/Styles/site.css @@ -872,9 +872,9 @@ fieldset.save-button { clear:left; } fieldset.publish-button { - margin: 0 12px; + margin: 0 12px 0 0; padding: 0 12px; - border-left:1px solid #ccc; + border-right:1px solid #ccc; } fieldset.delete-button { margin: 0 0 0 12px; diff --git a/src/Orchard/Environment/Extensions/ExtensionLoaderCoordinator.cs b/src/Orchard/Environment/Extensions/ExtensionLoaderCoordinator.cs index 138ca86a4..0c6360197 100644 --- a/src/Orchard/Environment/Extensions/ExtensionLoaderCoordinator.cs +++ b/src/Orchard/Environment/Extensions/ExtensionLoaderCoordinator.cs @@ -165,7 +165,7 @@ namespace Orchard.Environment.Extensions { foreach(var dup in duplicates) { sb.Append(T("Extension '{0}' has been found from the following locations: {1}.\r\n", dup.Key, string.Join(", ", dup.Select(e => e.Location + "/" + e.Id)))); } - sb.Append(T("This issue can be usually by solved by removing or renaming the conflicting extension.")); + sb.Append(T("This issue can be usually solved by removing or renaming the conflicting extension.")); Logger.Error(sb.ToString()); throw new OrchardException(new LocalizedString(sb.ToString())); }