Migrating tests that depend on Published Cache from the old test project (#11242)

* starts cleaning up old test project, removing ones we'll never convert, moves new test to where it should be.

* Makes ContentNodeKit immutable properties, moves first nucache tests over

* Gets the Nucache unit tests working and refactors a bit to use builder pattern for models.

* Migrates first xml based cache test to use nucache.

* Migrates a bunch more

* Migrates remaining tests for PublishedContentTests

* Moves PublishedRouterTests

* Moves PublishedContentExtensionTests

* Moves more tests.

* committing wip

* committing wip

* Gets PublishedContentLanguageVariantTests converted and working.

* Fixes DataTable ext method and moves PublishedContentDataTableTests

* Moves PublishedMediaTests

* wip - moving EntityXmlSerializerTests

* Moves more tests

* moves more tests

* moves more tests

* Move another test

* Moves more tests

* Fix test

* move another test

* Moves more tests

* Moves more tests

* Moves more tests

* wip before merge

* More tests

* More tests

* More tests

* More tests

* More tests

* More tests

* Cleanup and moving classes.

* Remove unused code

* Fixed failing tests, due to new null checks, that did not exist in v8

* Avoid breaking changes

* Unbreak more things, even that it the old solution was crazy..

* Fixed bug where ordering of stream readings was changed..

* cleanup

Co-authored-by: Bjarke Berg <mail@bergmania.dk>
This commit is contained in:
Shannon Deminick
2021-10-19 23:11:54 +11:00
committed by GitHub
parent 49e1aec71c
commit c77dc5dc00
171 changed files with 5400 additions and 17944 deletions

View File

@@ -13,19 +13,24 @@ using Umbraco.Cms.Core.Xml;
using Umbraco.Cms.Core.Xml.XPath;
using Umbraco.Cms.Infrastructure.PublishedCache.Navigable;
using Umbraco.Extensions;
using Constants = Umbraco.Cms.Core.Constants;
namespace Umbraco.Cms.Infrastructure.PublishedCache
{
public class ContentCache : PublishedCacheBase, IPublishedContentCache, INavigableData, IDisposable
{
private readonly IDomainCache _domainCache;
private readonly IAppCache _elementsCache;
private readonly GlobalSettings _globalSettings;
private readonly ContentStore.Snapshot _snapshot;
private readonly IAppCache _snapshotCache;
private readonly IAppCache _elementsCache;
private readonly IDomainCache _domainCache;
private readonly GlobalSettings _globalSettings;
private readonly IVariationContextAccessor _variationContextAccessor;
#region IDisposable
public void Dispose() => _snapshot.Dispose();
#endregion
#region Constructor
// TODO: figure this out
@@ -33,7 +38,9 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
// it's too late for UmbracoContext which has captured previewDefault and stuff into these ctor vars
// but, no, UmbracoContext returns snapshot.Content which comes from elements SO a resync should create a new cache
public ContentCache(bool previewDefault, ContentStore.Snapshot snapshot, IAppCache snapshotCache, IAppCache elementsCache, IDomainCache domainCache, IOptions<GlobalSettings> globalSettings, IVariationContextAccessor variationContextAccessor)
public ContentCache(bool previewDefault, ContentStore.Snapshot snapshot, IAppCache snapshotCache,
IAppCache elementsCache, IDomainCache domainCache, IOptions<GlobalSettings> globalSettings,
IVariationContextAccessor variationContextAccessor)
: base(previewDefault)
{
_snapshot = snapshot;
@@ -59,18 +66,23 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
// at the moment we try our best to be backward compatible, but really,
// should get rid of hideTopLevelNode and other oddities entirely, eventually
public IPublishedContent GetByRoute(string route, bool? hideTopLevelNode = null, string culture = null)
{
return GetByRoute(PreviewDefault, route, hideTopLevelNode, culture);
}
public IPublishedContent GetByRoute(string route, bool? hideTopLevelNode = null, string culture = null) =>
GetByRoute(PreviewDefault, route, hideTopLevelNode, culture);
public IPublishedContent GetByRoute(bool preview, string route, bool? hideTopLevelNode = null, string culture = null)
public IPublishedContent GetByRoute(bool preview, string route, bool? hideTopLevelNode = null,
string culture = null)
{
if (route == null) throw new ArgumentNullException(nameof(route));
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
var cache = preview == false || PublishedSnapshotService.FullCacheWhenPreviewing ? _elementsCache : _snapshotCache;
IAppCache cache = preview == false || PublishedSnapshotService.FullCacheWhenPreviewing
? _elementsCache
: _snapshotCache;
var key = CacheKeys.ContentCacheContentByRoute(route, preview, culture);
return cache.GetCacheItem<IPublishedContent>(key, () => GetByRouteInternal(preview, route, hideTopLevelNode, culture));
return cache.GetCacheItem(key, () => GetByRouteInternal(preview, route, hideTopLevelNode, culture));
}
private IPublishedContent GetByRouteInternal(bool preview, string route, bool? hideTopLevelNode, string culture)
@@ -108,8 +120,10 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
// hideTopLevelNode = support legacy stuff, look for /*/path/to/node
// else normal, look for /path/to/node
content = hideTopLevelNode.Value
? GetAtRoot(preview).SelectMany(x => x.Children(_variationContextAccessor, culture)).FirstOrDefault(x => x.UrlSegment(_variationContextAccessor, culture) == parts[0])
: GetAtRoot(preview).FirstOrDefault(x => x.UrlSegment(_variationContextAccessor, culture) == parts[0]);
? GetAtRoot(preview).SelectMany(x => x.Children(_variationContextAccessor, culture))
.FirstOrDefault(x => x.UrlSegment(_variationContextAccessor, culture) == parts[0])
: GetAtRoot(preview)
.FirstOrDefault(x => x.UrlSegment(_variationContextAccessor, culture) == parts[0]);
content = FollowRoute(content, parts, 1, culture);
}
@@ -118,59 +132,72 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
// have to look for /foo (see note in ApplyHideTopLevelNodeFromPath).
if (content == null && hideTopLevelNode.Value && parts.Length == 1)
{
content = GetAtRoot(preview).FirstOrDefault(x => x.UrlSegment(_variationContextAccessor, culture) == parts[0]);
content = GetAtRoot(preview)
.FirstOrDefault(x => x.UrlSegment(_variationContextAccessor, culture) == parts[0]);
}
return content;
}
public string GetRouteById(int contentId, string culture = null)
{
return GetRouteById(PreviewDefault, contentId, culture);
}
public string GetRouteById(int contentId, string culture = null) =>
GetRouteById(PreviewDefault, contentId, culture);
public string GetRouteById(bool preview, int contentId, string culture = null)
{
var cache = (preview == false || PublishedSnapshotService.FullCacheWhenPreviewing) ? _elementsCache : _snapshotCache;
IAppCache cache = preview == false || PublishedSnapshotService.FullCacheWhenPreviewing
? _elementsCache
: _snapshotCache;
var key = CacheKeys.ContentCacheRouteByContent(contentId, preview, culture);
return cache.GetCacheItem<string>(key, () => GetRouteByIdInternal(preview, contentId, null, culture));
return cache.GetCacheItem(key, () => GetRouteByIdInternal(preview, contentId, null, culture));
}
private string GetRouteByIdInternal(bool preview, int contentId, bool? hideTopLevelNode, string culture)
{
var node = GetById(preview, contentId);
IPublishedContent node = GetById(preview, contentId);
if (node == null)
{
return null;
}
hideTopLevelNode = hideTopLevelNode ?? HideTopLevelNodeFromPath; // default = settings
// walk up from that node until we hit a node with a domain,
// or we reach the content root, collecting URLs in the way
var pathParts = new List<string>();
var n = node;
IPublishedContent n = node;
var urlSegment = n.UrlSegment(_variationContextAccessor, culture);
var hasDomains = _domainCache.HasAssigned(n.Id);
var hasDomains = _domainCache.GetAssignedWithCulture(culture, n.Id);
while (hasDomains == false && n != null) // n is null at root
{
// no segment indicates this is not published when this is a variant
if (urlSegment.IsNullOrWhiteSpace()) return null;
if (urlSegment.IsNullOrWhiteSpace())
{
return null;
}
pathParts.Add(urlSegment);
// move to parent node
n = n.Parent;
if (n != null)
{
urlSegment = n.UrlSegment(_variationContextAccessor, culture);
}
hasDomains = n != null && _domainCache.HasAssigned(n.Id);
hasDomains = n != null && _domainCache.GetAssignedWithCulture(culture, n.Id);
}
// at this point this will be the urlSegment of the root, no segment indicates this is not published when this is a variant
if (urlSegment.IsNullOrWhiteSpace()) return null;
if (urlSegment.IsNullOrWhiteSpace())
{
return null;
}
// no domain, respect HideTopLevelNodeFromPath for legacy purposes
if (hasDomains == false && hideTopLevelNode.Value)
{
ApplyHideTopLevelNodeFromPath(node, pathParts, preview);
}
// assemble the route
pathParts.Reverse();
@@ -182,7 +209,8 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
return route;
}
private IPublishedContent FollowRoute(IPublishedContent content, IReadOnlyList<string> parts, int start, string culture)
private IPublishedContent FollowRoute(IPublishedContent content, IReadOnlyList<string> parts, int start,
string culture)
{
var i = start;
while (content != null && i < parts.Count)
@@ -194,6 +222,7 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
return urlSegment == part;
});
}
return content;
}
@@ -209,11 +238,16 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
// that's the way it works pre-4.10 and we try to be backward compat for the time being
if (content.Parent == null)
{
var rootNode = GetByRoute(preview, "/", true);
IPublishedContent rootNode = GetByRoute(preview, "/", true);
if (rootNode == null)
{
throw new Exception("Failed to get node at /.");
}
if (rootNode.Id == content.Id) // remove only if we're the default node
{
segments.RemoveAt(segments.Count - 1);
}
}
else
{
@@ -227,13 +261,13 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
public override IPublishedContent GetById(bool preview, int contentId)
{
var node = _snapshot.Get(contentId);
ContentNode node = _snapshot.Get(contentId);
return GetNodePublishedContent(node, preview);
}
public override IPublishedContent GetById(bool preview, Guid contentId)
{
var node = _snapshot.Get(contentId);
ContentNode node = _snapshot.Get(contentId);
return GetNodePublishedContent(node, preview);
}
@@ -241,18 +275,26 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
{
var guidUdi = contentId as GuidUdi;
if (guidUdi == null)
{
throw new ArgumentException($"Udi must be of type {typeof(GuidUdi).Name}.", nameof(contentId));
}
if (guidUdi.EntityType != Constants.UdiEntityType.Document)
throw new ArgumentException($"Udi entity type must be \"{Constants.UdiEntityType.Document}\".", nameof(contentId));
{
throw new ArgumentException($"Udi entity type must be \"{Constants.UdiEntityType.Document}\".",
nameof(contentId));
}
return GetById(preview, guidUdi.Guid);
}
public override bool HasById(bool preview, int contentId)
{
var n = _snapshot.Get(contentId);
if (n == null) return false;
ContentNode n = _snapshot.Get(contentId);
if (n == null)
{
return false;
}
return preview || n.PublishedModel != null;
}
@@ -263,7 +305,9 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
{
// handle context culture for variant
if (culture == null)
{
culture = _variationContextAccessor?.VariationContext?.Culture ?? "";
}
// _snapshot.GetAtRoot() returns all ContentNode at root
// both .Draft and .Published cannot be null at the same time
@@ -272,13 +316,15 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
// GetNodePublishedContent may return null if !preview and there is no
// published model, so we need to filter these nulls out
var atRoot = _snapshot.GetAtRoot()
IEnumerable<IPublishedContent> atRoot = _snapshot.GetAtRoot()
.Select(n => GetNodePublishedContent(n, preview))
.WhereNotNull();
// if a culture is specified, we must ensure that it is avail/published
if (culture != "*")
{
atRoot = atRoot.Where(x => x.IsInvariantOrHasCulture(culture));
}
return atRoot;
}
@@ -286,7 +332,9 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
private static IPublishedContent GetNodePublishedContent(ContentNode node, bool preview)
{
if (node == null)
{
return null;
}
// both .Draft and .Published cannot be null at the same time
@@ -299,7 +347,10 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
// this is for published content when previewing
private static IPublishedContent GetPublishedContentAsDraft(IPublishedContent content /*, bool preview*/)
{
if (content == null /*|| preview == false*/) return null; //content;
if (content == null /*|| preview == false*/)
{
return null; //content;
}
// an object in the cache is either an IPublishedContentOrMedia,
// or a model inheriting from PublishedContentExtended - in which
@@ -309,12 +360,10 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
return inner.AsDraft();
}
public override bool HasContent(bool preview)
{
return preview
public override bool HasContent(bool preview) =>
preview
? _snapshot.IsEmpty == false
: _snapshot.GetAtRoot().Any(x => x.PublishedModel != null);
}
#endregion
@@ -322,21 +371,24 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
public override IPublishedContent GetSingleByXPath(bool preview, string xpath, XPathVariable[] vars)
{
var navigator = CreateNavigator(preview);
var iterator = navigator.Select(xpath, vars);
XPathNavigator navigator = CreateNavigator(preview);
XPathNodeIterator iterator = navigator.Select(xpath, vars);
return GetSingleByXPath(iterator);
}
public override IPublishedContent GetSingleByXPath(bool preview, XPathExpression xpath, XPathVariable[] vars)
{
var navigator = CreateNavigator(preview);
var iterator = navigator.Select(xpath, vars);
XPathNavigator navigator = CreateNavigator(preview);
XPathNodeIterator iterator = navigator.Select(xpath, vars);
return GetSingleByXPath(iterator);
}
private static IPublishedContent GetSingleByXPath(XPathNodeIterator iterator)
{
if (iterator.MoveNext() == false) return null;
if (iterator.MoveNext() == false)
{
return null;
}
var xnav = iterator.Current as NavigableNavigator;
var xcontent = xnav?.UnderlyingObject as NavigableContent;
@@ -345,15 +397,16 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
public override IEnumerable<IPublishedContent> GetByXPath(bool preview, string xpath, XPathVariable[] vars)
{
var navigator = CreateNavigator(preview);
var iterator = navigator.Select(xpath, vars);
XPathNavigator navigator = CreateNavigator(preview);
XPathNodeIterator iterator = navigator.Select(xpath, vars);
return GetByXPath(iterator);
}
public override IEnumerable<IPublishedContent> GetByXPath(bool preview, XPathExpression xpath, XPathVariable[] vars)
public override IEnumerable<IPublishedContent> GetByXPath(bool preview, XPathExpression xpath,
XPathVariable[] vars)
{
var navigator = CreateNavigator(preview);
var iterator = navigator.Select(xpath, vars);
XPathNavigator navigator = CreateNavigator(preview);
XPathNodeIterator iterator = navigator.Select(xpath, vars);
return GetByXPath(iterator);
}
@@ -364,7 +417,10 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
{
var xnav = iterator.Current as NavigableNavigator;
var xcontent = xnav?.UnderlyingObject as NavigableContent;
if (xcontent == null) continue;
if (xcontent == null)
{
continue;
}
yield return xcontent.InnerContent;
}
@@ -395,14 +451,5 @@ namespace Umbraco.Cms.Infrastructure.PublishedCache
public override IPublishedContentType GetContentType(Guid key) => _snapshot.GetContentType(key);
#endregion
#region IDisposable
public void Dispose()
{
_snapshot.Dispose();
}
#endregion
}
}