Working on #U4-1174, lots of updates/fixes to media in MVC regarding loading data from the examine cache to return media + lots of unit tests.

This commit is contained in:
Shannon Deminick
2012-11-15 21:46:54 +05:00
parent 8b141dc51a
commit 3dd411f159
9 changed files with 854 additions and 42 deletions

View File

@@ -247,10 +247,12 @@ namespace Umbraco.Tests.ContentStores
a => null,
//we're not going to test this so ignore
a => new List<IPublishedContent>(),
(dd, a) => dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(a))),
(dd, a) => dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(a)),
false),
//callback to get the children
d => children,
(dd, a) => dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(a)));
(dd, a) => dd.Properties.FirstOrDefault(x => x.Alias.InvariantEquals(a)),
false);
return dicDoc;
}

View File

@@ -1,11 +1,24 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Xml.XPath;
using Examine;
using Examine.LuceneEngine;
using Examine.LuceneEngine.Providers;
using Lucene.Net.Analysis.Standard;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.ExamineHelpers;
using Umbraco.Web;
using UmbracoExamine;
using UmbracoExamine.DataServices;
using umbraco.BusinessLogic;
using System.Linq;
@@ -95,6 +108,98 @@ namespace Umbraco.Tests.PublishedContent
return GetNode(id, GetUmbracoContext("/test", 1234));
}
[Test]
public void Children_With_Examine()
{
var newIndexFolder = new DirectoryInfo(Path.Combine("App_Data\\CWSIndexSetTest", Guid.NewGuid().ToString()));
var indexInit = new IndexInitializer();
var indexer = indexInit.GetUmbracoIndexer(newIndexFolder);
indexer.RebuildIndex();
var store = new DefaultPublishedMediaStore(indexInit.GetUmbracoSearcher(newIndexFolder));
//we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace
var publishedMedia = store.GetDocumentById(GetUmbracoContext("/test", 1234), 1111);
var rootChildren = publishedMedia.Children();
Assert.IsTrue(rootChildren.Select(x => x.Id).ContainsAll(new[] { 2222, 1113, 1114, 1115, 1116 }));
var publishedChild1 = store.GetDocumentById(GetUmbracoContext("/test", 1234), 2222);
var subChildren = publishedChild1.Children();
Assert.IsTrue(subChildren.Select(x => x.Id).ContainsAll(new[] { 2112 }));
}
[Test]
public void Descendants_With_Examine()
{
var newIndexFolder = new DirectoryInfo(Path.Combine("App_Data\\CWSIndexSetTest", Guid.NewGuid().ToString()));
var indexInit = new IndexInitializer();
var indexer = indexInit.GetUmbracoIndexer(newIndexFolder);
indexer.RebuildIndex();
var store = new DefaultPublishedMediaStore(indexInit.GetUmbracoSearcher(newIndexFolder));
//we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace
var publishedMedia = store.GetDocumentById(GetUmbracoContext("/test", 1234), 1111);
var rootDescendants = publishedMedia.Descendants();
Assert.IsTrue(rootDescendants.Select(x => x.Id).ContainsAll(new[] { 2112, 2222, 1113, 1114, 1115, 1116 }));
var publishedChild1 = store.GetDocumentById(GetUmbracoContext("/test", 1234), 2222);
var subDescendants = publishedChild1.Descendants();
Assert.IsTrue(subDescendants.Select(x => x.Id).ContainsAll(new[] { 2112, 3113 }));
}
[Test]
public void DescendantsOrSelf_With_Examine()
{
var newIndexFolder = new DirectoryInfo(Path.Combine("App_Data\\CWSIndexSetTest", Guid.NewGuid().ToString()));
var indexInit = new IndexInitializer();
var indexer = indexInit.GetUmbracoIndexer(newIndexFolder);
indexer.RebuildIndex();
var store = new DefaultPublishedMediaStore(indexInit.GetUmbracoSearcher(newIndexFolder));
//we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace
var publishedMedia = store.GetDocumentById(GetUmbracoContext("/test", 1234), 1111);
var rootDescendants = publishedMedia.DescendantsOrSelf();
Assert.IsTrue(rootDescendants.Select(x => x.Id).ContainsAll(new[] { 1111, 2112, 2222, 1113, 1114, 1115, 1116 }));
var publishedChild1 = store.GetDocumentById(GetUmbracoContext("/test", 1234), 2222);
var subDescendants = publishedChild1.DescendantsOrSelf();
Assert.IsTrue(subDescendants.Select(x => x.Id).ContainsAll(new[] { 2222, 2112, 3113 }));
}
[Test]
public void Ancestors_With_Examine()
{
var newIndexFolder = new DirectoryInfo(Path.Combine("App_Data\\CWSIndexSetTest", Guid.NewGuid().ToString()));
var indexInit = new IndexInitializer();
var indexer = indexInit.GetUmbracoIndexer(newIndexFolder);
indexer.RebuildIndex();
var store = new DefaultPublishedMediaStore(indexInit.GetUmbracoSearcher(newIndexFolder));
//we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace
var publishedMedia = store.GetDocumentById(GetUmbracoContext("/test", 1234), 3113);
var ancestors = publishedMedia.Ancestors();
Assert.IsTrue(ancestors.Select(x => x.Id).ContainsAll(new[] { 2112, 2222, 1111 }));
}
[Test]
public void AncestorsOrSelf_With_Examine()
{
var newIndexFolder = new DirectoryInfo(Path.Combine("App_Data\\CWSIndexSetTest", Guid.NewGuid().ToString()));
var indexInit = new IndexInitializer();
var indexer = indexInit.GetUmbracoIndexer(newIndexFolder);
indexer.RebuildIndex();
var store = new DefaultPublishedMediaStore(indexInit.GetUmbracoSearcher(newIndexFolder));
//we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace
var publishedMedia = store.GetDocumentById(GetUmbracoContext("/test", 1234), 3113);
var ancestors = publishedMedia.AncestorsOrSelf();
Assert.IsTrue(ancestors.Select(x => x.Id).ContainsAll(new[] { 3113, 2112, 2222, 1111 }));
}
[Test]
public void Children_Without_Examine()
{
@@ -233,4 +338,6 @@ namespace Umbraco.Tests.PublishedContent
new[] { mSubChild1.Id, mChild1.Id, mRoot.Id }));
}
}
}

View File

@@ -0,0 +1,99 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.17929
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Umbraco.Tests.TestHelpers.ExamineHelpers {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class ExamineResources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal ExamineResources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Umbraco.Tests.TestHelpers.ExamineHelpers.ExamineResources", typeof(ExamineResources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
///&lt;media&gt;
/// &lt;node id=&quot;1111&quot; version=&quot;902e13f7-5793-482a-9e06-cd94eebd1de0&quot; parentID=&quot;-1&quot; level=&quot;1&quot; writerID=&quot;0&quot; nodeType=&quot;1031&quot; template=&quot;0&quot; sortOrder=&quot;2&quot; createDate=&quot;2010-05-19T15:26:08&quot; updateDate=&quot;2010-05-19T15:26:09&quot; nodeName=&quot;Product Images&quot; urlName=&quot;productimages&quot; writerName=&quot;Administrator&quot; nodeTypeAlias=&quot;Folder&quot; path=&quot;-1,1111&quot;&gt;
/// &lt;data alias=&quot;contents&quot;&gt;&lt;/data&gt;
/// &lt;node id=&quot;2222&quot; version=&quot;902e13f7-5793-482a-9e06-cd94eebd1de0&quot; parentID=&quot;-1&quot; level=&quot;1&quot; writerID=&quot;0&quot; [rest of string was truncated]&quot;;.
/// </summary>
internal static string media {
get {
return ResourceManager.GetString("media", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
///&lt;!DOCTYPE root[
/// &lt;!ELEMENT CWS_Contact ANY&gt;
/// &lt;!ATTLIST CWS_Contact id ID #REQUIRED&gt;
/// &lt;!ELEMENT CWS_EmailAFriend ANY&gt;
/// &lt;!ATTLIST CWS_EmailAFriend id ID #REQUIRED&gt;
/// &lt;!ELEMENT CWS_EventItem ANY&gt;
/// &lt;!ATTLIST CWS_EventItem id ID #REQUIRED&gt;
/// &lt;!ELEMENT CWS_Galleries ANY&gt;
/// &lt;!ATTLIST CWS_Galleries id ID #REQUIRED&gt;
/// &lt;!ELEMENT CWS_Gallery ANY&gt;
/// &lt;!ATTLIST CWS_Gallery id ID #REQUIRED&gt;
/// &lt;!ELEMENT CWS_Home ANY&gt;
/// &lt;!ATTLIST CWS_Home id ID #REQUIRED&gt;
/// &lt;!ELEMENT CWS_NewsEven [rest of string was truncated]&quot;;.
/// </summary>
internal static string umbraco {
get {
return ResourceManager.GetString("umbraco", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="media" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>media.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="umbraco" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>umbraco.config;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
</root>

View File

@@ -0,0 +1,360 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using System.Xml.XPath;
using Examine;
using Examine.LuceneEngine;
using Examine.LuceneEngine.Providers;
using Lucene.Net.Analysis.Standard;
using UmbracoExamine;
using UmbracoExamine.DataServices;
namespace Umbraco.Tests.TestHelpers.ExamineHelpers
{
/// <summary>
/// Used internally by test classes to initialize a new index from the template
/// </summary>
internal class IndexInitializer
{
public IndexInitializer()
{
//ensure the umbraco.config and media.xml files exist at the location where we need to load them
var appData = Path.Combine(TestHelper.CurrentAssemblyDirectory, "App_Data");
Directory.CreateDirectory(appData);
var umbConfig = Path.Combine(appData, "umbraco.config");
File.Delete(umbConfig);
using (var s = File.CreateText(umbConfig))
{
s.Write(ExamineResources.umbraco);
}
var umbMedia = Path.Combine(appData, "media.xml");
File.Delete(umbMedia);
using (var s = File.CreateText(umbMedia))
{
s.Write(ExamineResources.media);
}
}
public UmbracoContentIndexer GetUmbracoIndexer(DirectoryInfo d)
{
var i = new UmbracoContentIndexer(new IndexCriteria(
new[]
{
new TestIndexField { Name = "id", EnableSorting = true, Type = "Number" },
new TestIndexField { Name = "nodeName", EnableSorting = true },
new TestIndexField { Name = "updateDate", EnableSorting = true, Type = "DateTime" },
new TestIndexField { Name = "writerName" },
new TestIndexField { Name = "path" },
new TestIndexField { Name = "nodeTypeAlias" },
new TestIndexField { Name = "parentID" }
},
Enumerable.Empty<IIndexField>(),
//new[]
// {
// new TestIndexField { Name = "headerText" },
// new TestIndexField { Name = "bodyText" },
// new TestIndexField { Name = "metaDescription" },
// new TestIndexField { Name = "metaKeywords" },
// new TestIndexField { Name = "bodyTextColOne" },
// new TestIndexField { Name = "bodyTextColTwo" },
// new TestIndexField { Name = "xmlStorageTest" }
// },
Enumerable.Empty<string>(),
//new[]
// {
// "CWS_Home",
// "CWS_Textpage",
// "CWS_TextpageTwoCol",
// "CWS_NewsEventsList",
// "CWS_NewsItem",
// "CWS_Gallery",
// "CWS_EventItem",
// "Image",
// },
new string[] { },
-1),
d,
new TestDataService(),
new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29),
false);
//i.IndexSecondsInterval = 1;
i.IndexingError += IndexingError;
return i;
}
public UmbracoExamineSearcher GetUmbracoSearcher(DirectoryInfo d)
{
return new UmbracoExamineSearcher(d, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29));
}
//public SimpleDataIndexer GetSimpleIndexer(DirectoryInfo d)
//{
// var i = new SimpleDataIndexer(new IndexCriteria(
// new IIndexField[] { },
// new[]
// {
// new TestIndexField { Name = "Author" },
// new TestIndexField { Name = "DateCreated", EnableSorting = true, Type = "DateTime" },
// new TestIndexField { Name = "Title" },
// new TestIndexField { Name = "Photographer" },
// new TestIndexField { Name = "YearCreated", Type = "Date.Year" },
// new TestIndexField { Name = "MonthCreated", Type = "Date.Month" },
// new TestIndexField { Name = "DayCreated", Type = "Date.Day" },
// new TestIndexField { Name = "HourCreated", Type = "Date.Hour" },
// new TestIndexField { Name = "MinuteCreated", Type = "Date.Minute" },
// new TestIndexField { Name = "SomeNumber", Type = "Number" },
// new TestIndexField { Name = "SomeFloat", Type = "Float" },
// new TestIndexField { Name = "SomeDouble", Type = "Double" },
// new TestIndexField { Name = "SomeLong", Type = "Long" }
// },
// new string[] { },
// new string[] { },
// -1),
// d,
// new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29),
// new TestSimpleDataProvider(),
// new[] { "Documents", "Pictures" },
// false);
// i.IndexingError += IndexingError;
// return i;
//}
public LuceneSearcher GetLuceneSearcher(DirectoryInfo d)
{
return new LuceneSearcher(d, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29));
}
//public PDFIndexer GetPdfIndexer(DirectoryInfo d)
//{
// var i = new PDFIndexer(d,
// new TestDataService(),
// new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29),
// false);
// i.IndexingError += IndexingError;
// return i;
//}
public MultiIndexSearcher GetMultiSearcher(DirectoryInfo pdfDir, DirectoryInfo simpleDir, DirectoryInfo conventionDir, DirectoryInfo cwsDir)
{
var i = new MultiIndexSearcher(new[] { pdfDir, simpleDir, conventionDir, cwsDir }, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29));
return i;
}
internal void IndexingError(object sender, IndexingErrorEventArgs e)
{
throw new ApplicationException(e.Message, e.InnerException);
}
internal class TestIndexField : IIndexField
{
public string Name { get; set; }
public bool EnableSorting { get; set; }
public string Type { get; set; }
}
internal class TestDataService : IDataService
{
public TestDataService()
{
ContentService = new TestContentService();
LogService = new TestLogService();
MediaService = new TestMediaService();
}
#region IDataService Members
public IContentService ContentService { get; private set; }
public ILogService LogService { get; private set; }
public IMediaService MediaService { get; private set; }
public string MapPath(string virtualPath)
{
return new DirectoryInfo(TestHelper.CurrentAssemblyDirectory) + "\\" + virtualPath.Replace("/", "\\");
}
#endregion
}
/// <summary>
/// A mock data service used to return content from the XML data file created with CWS
/// </summary>
internal class TestContentService : IContentService
{
public const int ProtectedNode = 1142;
public TestContentService()
{
var xmlFile = new DirectoryInfo(TestHelper.CurrentAssemblyDirectory).GetDirectories("App_Data")
.Single()
.GetFiles("umbraco.config")
.Single();
_xDoc = XDocument.Load(xmlFile.FullName);
}
#region IContentService Members
/// <summary>
/// Return the XDocument containing the xml from the umbraco.config xml file
/// </summary>
/// <param name="xpath"></param>
/// <returns></returns>
/// <remarks>
/// This is no different in the test suite as published content
/// </remarks>
public XDocument GetLatestContentByXPath(string xpath)
{
var xdoc = XDocument.Parse("<content></content>");
xdoc.Root.Add(_xDoc.XPathSelectElements(xpath));
return xdoc;
}
/// <summary>
/// Return the XDocument containing the xml from the umbraco.config xml file
/// </summary>
/// <param name="xpath"></param>
/// <returns></returns>
public XDocument GetPublishedContentByXPath(string xpath)
{
var xdoc = XDocument.Parse("<content></content>");
xdoc.Root.Add(_xDoc.XPathSelectElements(xpath));
return xdoc;
}
public string StripHtml(string value)
{
const string pattern = @"<(.|\n)*?>";
return Regex.Replace(value, pattern, string.Empty);
}
public bool IsProtected(int nodeId, string path)
{
// single node is marked as protected for test indexer
// hierarchy is not important for this test
return nodeId == ProtectedNode;
}
public IEnumerable<string> GetAllUserPropertyNames()
{
return GetPublishedContentByXPath("//*[count(@id)>0]")
.Root
.Elements()
.Select(x => x.Name.LocalName)
.ToList();
}
public IEnumerable<string> GetAllSystemPropertyNames()
{
return new Dictionary<string, FieldIndexTypes>()
{
{"id", FieldIndexTypes.NOT_ANALYZED},
{"version", FieldIndexTypes.NOT_ANALYZED},
{"parentID", FieldIndexTypes.NOT_ANALYZED},
{"level", FieldIndexTypes.NOT_ANALYZED},
{"writerID", FieldIndexTypes.NOT_ANALYZED},
{"creatorID", FieldIndexTypes.NOT_ANALYZED},
{"nodeType", FieldIndexTypes.NOT_ANALYZED},
{"template", FieldIndexTypes.NOT_ANALYZED},
{"sortOrder", FieldIndexTypes.NOT_ANALYZED},
{"createDate", FieldIndexTypes.NOT_ANALYZED},
{"updateDate", FieldIndexTypes.NOT_ANALYZED},
{"nodeName", FieldIndexTypes.ANALYZED},
{"urlName", FieldIndexTypes.NOT_ANALYZED},
{"writerName", FieldIndexTypes.ANALYZED},
{"creatorName", FieldIndexTypes.ANALYZED},
{"nodeTypeAlias", FieldIndexTypes.ANALYZED},
{"path", FieldIndexTypes.NOT_ANALYZED}
}.Select(x => x.Key);
}
#endregion
private readonly XDocument _xDoc;
}
internal class TestLogService : ILogService
{
#region ILogService Members
public string ProviderName { get; set; }
public void AddErrorLog(int nodeId, string msg)
{
Trace.WriteLine("ERROR: (" + nodeId.ToString() + ") " + msg);
}
public void AddInfoLog(int nodeId, string msg)
{
Trace.WriteLine("INFO: (" + nodeId.ToString() + ") " + msg);
}
public void AddVerboseLog(int nodeId, string msg)
{
if (LogLevel == LoggingLevel.Verbose)
Trace.WriteLine("VERBOSE: (" + nodeId.ToString() + ") " + msg);
}
public LoggingLevel LogLevel
{
get
{
return LoggingLevel.Verbose;
}
set
{
//do nothing
}
}
#endregion
}
internal class TestMediaService : IMediaService
{
public TestMediaService()
{
var xmlFile = new DirectoryInfo(TestHelper.CurrentAssemblyDirectory).GetDirectories("App_Data")
.Single()
.GetFiles("media.xml")
.Single();
m_Doc = XDocument.Load(xmlFile.FullName);
}
#region IMediaService Members
public System.Xml.Linq.XDocument GetLatestMediaByXpath(string xpath)
{
var xdoc = XDocument.Parse("<media></media>");
xdoc.Root.Add(m_Doc.XPathSelectElements(xpath));
return xdoc;
}
#endregion
private XDocument m_Doc;
}
}
}

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<media>
<node id="1111" version="902e13f7-5793-482a-9e06-cd94eebd1de0" parentID="-1" level="1" writerID="0" nodeType="1031" template="0" sortOrder="2" createDate="2010-05-19T15:26:08" updateDate="2010-05-19T15:26:09" nodeName="Product Images" urlName="productimages" writerName="Administrator" nodeTypeAlias="Folder" path="-1,1111">
<data alias="contents"></data>
<node id="2222" version="902e13f7-5793-482a-9e06-cd94eebd1de0" parentID="1111" level="1" writerID="0" nodeType="1031" template="0" sortOrder="2" createDate="2010-05-19T15:26:08" updateDate="2010-05-19T15:26:09" nodeName="Product Images" urlName="productimages" writerName="Administrator" nodeTypeAlias="Folder" path="-1,1111,2222">
<data alias="contents"></data>
<node id="2112" version="5b3e46ab-3e37-4cfa-ab70-014234b5bd39" parentID="2222" level="2" writerID="0" nodeType="1032" template="0" sortOrder="1" createDate="2010-05-19T17:32:46" updateDate="2010-05-19T17:32:46" nodeName="Sam's Umbraco Image" urlName="acnestressscrub" writerName="Administrator" nodeTypeAlias="Image" path="-1,1111,2222,2112">
<data alias="umbracoFile"><![CDATA[/media/1234/blah.pdf]]></data>
<data alias="umbracoWidth">115</data>
<data alias="umbracoHeight">268</data>
<data alias="umbracoBytes">10726</data>
<data alias="umbracoExtension">jpg</data>
<node id="3113" version="5b3e46ab-3e37-4cfa-ab70-014234b5bd33" parentID="2112" level="3" writerID="0" nodeType="1032" template="0" sortOrder="2" createDate="2010-05-19T17:32:46" updateDate="2010-05-19T17:32:46" nodeName="Another Umbraco Image" urlName="acnestressscrub" writerName="Administrator" nodeTypeAlias="Image" path="-1,1111,2222,2112,3113">
<data alias="umbracoFile"><![CDATA[/media/1234/blah.pdf]]></data>
<data alias="umbracoWidth">115</data>
<data alias="umbracoHeight">268</data>
<data alias="umbracoBytes">10726</data>
<data alias="umbracoExtension">jpg</data>
</node>
</node>
</node>
<node id="1113" version="5b3e46ab-3e37-4cfa-ab70-014234b5bd39" parentID="1111" level="2" writerID="0" nodeType="1032" template="0" sortOrder="1" createDate="2010-05-19T17:32:46" updateDate="2010-05-19T17:32:46" nodeName="Acne Stress Scrub" urlName="acnestressscrub" writerName="Administrator" nodeTypeAlias="File" path="-1,1111,1113">
<data alias="umbracoFile"><![CDATA[/App_Data/VS2010CSharp.pdf]]></data>
<data alias="umbracoWidth">115</data>
<data alias="umbracoHeight">268</data>
<data alias="umbracoBytes">10726</data>
<data alias="umbracoExtension">jpg</data>
</node>
<node id="1114" version="5b3e46ab-3e37-4cfa-ab70-014234b5bd39" parentID="1111" level="2" writerID="0" nodeType="1032" template="0" sortOrder="1" createDate="2010-05-19T17:32:46" updateDate="2010-05-19T17:32:46" nodeName="String thoery" urlName="stringtheory" writerName="Administrator" nodeTypeAlias="File" path="-1,1111,1114">
<data alias="umbracoFile"><![CDATA[/App_Data/StringTheory.pdf]]></data>
<data alias="umbracoWidth">115</data>
<data alias="umbracoHeight">268</data>
<data alias="umbracoBytes">10726</data>
<data alias="umbracoExtension">jpg</data>
</node>
<node id="1115" version="5b3e46ab-3e37-4cfa-ab70-014234b5bd39" parentID="1111" level="2" writerID="0" nodeType="1032" template="0" sortOrder="1" createDate="2010-05-19T17:32:46" updateDate="2010-05-19T17:32:46" nodeName="Umbraco Contour" urlName="umbracocontour" writerName="Administrator" nodeTypeAlias="File" path="-1,1111,1115">
<data alias="umbracoFile"><![CDATA[/App_Data/UmbracoContour.pdf]]></data>
<data alias="umbracoWidth">115</data>
<data alias="umbracoHeight">268</data>
<data alias="umbracoBytes">10726</data>
<data alias="umbracoExtension">jpg</data>
</node>
<node id="1116" version="5b3e46ab-3e37-4cfa-ab70-014234b5bd39" parentID="1111" level="2" writerID="0" nodeType="1032" template="0" sortOrder="1" createDate="2010-05-19T17:32:46" updateDate="2010-05-19T17:32:46" nodeName="PDF Standards" urlName="pdfstandards" writerName="Administrator" nodeTypeAlias="File" path="-1,1111,1116">
<data alias="umbracoFile"><![CDATA[/App_Data/PDFStandards.pdf]]></data>
<data alias="umbracoWidth">115</data>
<data alias="umbracoHeight">268</data>
<data alias="umbracoBytes">10726</data>
<data alias="umbracoExtension">jpg</data>
</node>
</node>
</media>

View File

@@ -51,7 +51,7 @@ namespace Umbraco.Tests.TestHelpers
{
get
{
var codeBase = Assembly.GetCallingAssembly().CodeBase;
var codeBase = typeof(TestHelper).Assembly.CodeBase;
var uri = new Uri(codeBase);
var path = uri.LocalPath;
return Path.GetDirectoryName(path);

View File

@@ -35,6 +35,10 @@
<Reference Include="log4net, Version=1.2.11.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\log4net.2.0.0\lib\net40-full\log4net.dll</HintPath>
</Reference>
<Reference Include="Lucene.Net, Version=2.9.4.1, Culture=neutral, PublicKeyToken=85089178b9ac3181, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Umbraco.Web.UI\bin\Lucene.Net.dll</HintPath>
</Reference>
<Reference Include="nunit.framework">
<HintPath>..\packages\NUnit.2.6.0.12054\lib\nunit.framework.dll</HintPath>
</Reference>
@@ -51,6 +55,10 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="UmbracoExamine, Version=0.1.42.2941, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Umbraco.Web.UI\bin\UmbracoExamine.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="BusinessLogic\DictionaryTest.cs" />
@@ -97,6 +105,12 @@
<Compile Include="Routing\RouteTestExtensions.cs" />
<Compile Include="Stubs\TestControllerFactory.cs" />
<Compile Include="TestHelpers\BaseWebTest.cs" />
<Compile Include="TestHelpers\ExamineHelpers\ExamineResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>ExamineResources.resx</DependentUpon>
</Compile>
<Compile Include="TestHelpers\ExamineHelpers\IndexInitializer.cs" />
<Compile Include="UriUtilityTests.cs" />
<Compile Include="Resolvers\MacroFieldEditorsResolverTests.cs" />
<Compile Include="MacroEngineFactoryTests.cs" />
@@ -128,6 +142,7 @@
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
<None Include="TestHelpers\ExamineHelpers\umbraco.config" />
<None Include="unit-test-log4net.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
@@ -178,9 +193,15 @@
<Name>Umbraco.Web</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<EmbeddedResource Include="TestHelpers\ExamineHelpers\ExamineResources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>ExamineResources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Content Include="Masterpages\dummy.txt" />
<Content Include="TestHelpers\ExamineHelpers\media.xml" />
<Content Include="Views\dummy.txt" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

View File

@@ -5,6 +5,8 @@ using System.IO;
using System.Linq;
using System.Xml.XPath;
using Examine;
using Examine.Providers;
using Lucene.Net.Documents;
using Umbraco.Core;
using Umbraco.Core.Dynamics;
using Umbraco.Core.Models;
@@ -21,6 +23,22 @@ namespace Umbraco.Web
/// </remarks>
internal class DefaultPublishedMediaStore : IPublishedMediaStore
{
public DefaultPublishedMediaStore()
{
}
/// <summary>
/// Generally used for unit testing to use an explicit examine searcher
/// </summary>
/// <param name="searchProvider"></param>
internal DefaultPublishedMediaStore(BaseSearchProvider searchProvider)
{
_searchProvider = searchProvider;
}
private readonly BaseSearchProvider _searchProvider;
public virtual IPublishedContent GetDocumentById(UmbracoContext umbracoContext, int nodeId)
{
return GetUmbracoMedia(nodeId);
@@ -53,21 +71,42 @@ namespace Umbraco.Web
}
}
private IPublishedContent GetUmbracoMedia(int id)
private BaseSearchProvider GetSearchProviderSafe()
{
if (_searchProvider != null)
return _searchProvider;
var eMgr = GetExamineManagerSafe();
if (eMgr != null)
{
try
{
//by default use the InternalSearcher
return eMgr.SearchProviderCollection["InternalSearcher"];
}
catch (FileNotFoundException)
{
//Currently examine is throwing FileNotFound exceptions when we have a loadbalanced filestore and a node is published in umbraco
//See this thread: http://examine.cdodeplex.com/discussions/264341
//Catch the exception here for the time being, and just fallback to GetMedia
//TODO: Need to fix examine in LB scenarios!
}
}
return null;
}
private IPublishedContent GetUmbracoMedia(int id)
{
var searchProvider = GetSearchProviderSafe();
if (searchProvider != null)
{
try
{
//first check in Examine as this is WAY faster
var criteria = eMgr
.SearchProviderCollection["InternalSearcher"]
.CreateSearchCriteria("media");
var criteria = searchProvider.CreateSearchCriteria("media");
var filter = criteria.Id(id);
var results = eMgr
.SearchProviderCollection["InternalSearcher"]
.Search(filter.Compile());
var results = searchProvider.Search(filter.Compile());
if (results.Any())
{
return ConvertFromSearchResult(results.First());
@@ -86,13 +125,6 @@ namespace Umbraco.Web
if (media != null && media.Current != null)
{
media.MoveNext();
////error check
//if (media.Current.MoveToFirstChild() && media.Current.Name.InvariantEquals("error"))
//{
// return null;
//}
//var current = media.Current;
return ConvertFromXPathNavigator(media.Current);
}
@@ -129,15 +161,13 @@ namespace Umbraco.Web
return new DictionaryPublishedContent(values,
d => d.ParentId != -1 //parent should be null if -1
? GetUmbracoMedia(d.ParentId)
: null,
//callback to return the children of the current node
d => GetChildrenMedia(d.ParentId),
GetProperty)
{
LoadedFromExamine = true
};
d => d.ParentId != -1 //parent should be null if -1
? GetUmbracoMedia(d.ParentId)
: null,
//callback to return the children of the current node
d => GetChildrenMedia(d.Id),
GetProperty,
true);
}
internal IPublishedContent ConvertFromXPathNavigator(XPathNavigator xpath)
@@ -193,9 +223,9 @@ namespace Umbraco.Web
? GetUmbracoMedia(d.ParentId)
: null,
//callback to return the children of the current node based on the xml structure already found
//d => GetChildrenMedia(d.ParentId, xpath),
d => GetChildrenMedia(d.Id, xpath),
GetProperty);
GetProperty,
false);
}
/// <summary>
@@ -254,20 +284,16 @@ namespace Umbraco.Web
//if there is no navigator, try examine first, then re-look it up
if (xpath == null)
{
var eMgr = GetExamineManagerSafe();
var searchProvider = GetSearchProviderSafe();
if (eMgr != null)
if (searchProvider != null)
{
try
{
//first check in Examine as this is WAY faster
var criteria = eMgr
.SearchProviderCollection["InternalSearcher"]
.CreateSearchCriteria("media");
var criteria = searchProvider.CreateSearchCriteria("media");
var filter = criteria.ParentId(parentId);
var results = eMgr
.SearchProviderCollection["InternalSearcher"]
.Search(filter.Compile());
var results = searchProvider.Search(filter.Compile());
if (results.Any())
{
return results.Select(ConvertFromSearchResult);
@@ -332,7 +358,8 @@ namespace Umbraco.Web
IDictionary<string, string> valueDictionary,
Func<DictionaryPublishedContent, IPublishedContent> getParent,
Func<DictionaryPublishedContent, IEnumerable<IPublishedContent>> getChildren,
Func<DictionaryPublishedContent, string, IPublishedContentProperty> getProperty)
Func<DictionaryPublishedContent, string, IPublishedContentProperty> getProperty,
bool fromExamine)
{
if (valueDictionary == null) throw new ArgumentNullException("valueDictionary");
if (getParent == null) throw new ArgumentNullException("getParent");
@@ -342,7 +369,7 @@ namespace Umbraco.Web
_getChildren = getChildren;
_getProperty = getProperty;
LoadedFromExamine = false; //default to false
LoadedFromExamine = fromExamine;
ValidateAndSetProperty(valueDictionary, val => Id = int.Parse(val), "id", "nodeId", "__NodeId"); //should validate the int!
ValidateAndSetProperty(valueDictionary, val => TemplateId = int.Parse(val), "template", "templateId");
@@ -356,8 +383,8 @@ namespace Umbraco.Web
ValidateAndSetProperty(valueDictionary, val => WriterId = int.Parse(val), "writerID");
ValidateAndSetProperty(valueDictionary, val => CreatorId = int.Parse(val), "creatorID", "writerID"); //this is a bit of a hack fix for: U4-1132
ValidateAndSetProperty(valueDictionary, val => Path = val, "path", "__Path");
ValidateAndSetProperty(valueDictionary, val => CreateDate = DateTime.Parse(val), "createDate");
ValidateAndSetProperty(valueDictionary, val => UpdateDate = DateTime.Parse(val), "updateDate");
ValidateAndSetProperty(valueDictionary, val => CreateDate = ParseDateTimeValue(val), "createDate");
ValidateAndSetProperty(valueDictionary, val => UpdateDate = ParseDateTimeValue(val), "updateDate");
ValidateAndSetProperty(valueDictionary, val => Level = int.Parse(val), "level");
ValidateAndSetProperty(valueDictionary, val =>
{
@@ -381,10 +408,28 @@ namespace Umbraco.Web
}
}
private DateTime ParseDateTimeValue(string val)
{
if (LoadedFromExamine)
{
try
{
//we might need to parse the date time using Lucene converters
return DateTools.StringToDate(val);
}
catch (FormatException)
{
//swallow exception, its not formatted correctly so revert to just trying to parse
}
}
return DateTime.Parse(val);
}
/// <summary>
/// Flag to get/set if this was laoded from examine cache
/// </summary>
internal bool LoadedFromExamine { get; set; }
internal bool LoadedFromExamine { get; private set; }
private readonly Func<DictionaryPublishedContent, IPublishedContent> _getParent;
private readonly Func<DictionaryPublishedContent, IEnumerable<IPublishedContent>> _getChildren;