From 1ff0338d35af5a7d059f4b298fd9b41e88b7cff6 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 18 Jul 2017 19:24:27 +0200 Subject: [PATCH] NuCache+Scope - tests --- src/Umbraco.Core/Services/ContentService.cs | 25 ++++--- .../Integration/ContentEventsTests.cs | 7 ++ .../Scoping/ScopedNuCacheTests.cs | 67 +++++++++++++------ .../PublishedCache/NuCache/ContentStore.cs | 21 ++++-- .../PublishedCache/NuCache/FacadeService.cs | 28 ++++++-- 5 files changed, 108 insertions(+), 40 deletions(-) diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index d3a7527314..c3d15c3c5b 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -1857,11 +1857,11 @@ namespace Umbraco.Core.Services if (raiseEvents) uow.Events.Dispatch(Saved, this, new SaveEventArgs(saved, false)); + uow.Events.Dispatch(TreeChanged, this, saved.Select(x => new TreeChange(x, TreeChangeTypes.RefreshNode)).ToEventArgs()); + if (raiseEvents && published.Any()) uow.Events.Dispatch(Published, this, new PublishEventArgs(published, false, false), "Published"); - uow.Events.Dispatch(TreeChanged, this, saved.Select(x => new TreeChange(x, TreeChangeTypes.RefreshNode)).ToEventArgs()); - Audit(uow, AuditType.Sort, "Sorting content performed by user", userId, 0); uow.Complete(); @@ -1969,8 +1969,8 @@ namespace Umbraco.Core.Services publishedItems.Add(publishedItem); } - uow.Events.Dispatch(Published, this, new PublishEventArgs(publishedItems, false, false), "Published"); uow.Events.Dispatch(TreeChanged, this, new TreeChange(content, TreeChangeTypes.RefreshBranch).ToEventArgs()); + uow.Events.Dispatch(Published, this, new PublishEventArgs(publishedItems, false, false), "Published"); Audit(uow, AuditType.Publish, "Publish with Children performed by user", userId, content.Id); uow.Complete(); @@ -2075,24 +2075,23 @@ namespace Umbraco.Core.Services return status; } + if (isNew == false && previouslyPublished == false) + changeType = TreeChangeTypes.RefreshBranch; // whole branch + + // invalidate the node/branch + uow.Events.Dispatch(TreeChanged, this, new TreeChange(content, changeType).ToEventArgs()); + uow.Events.Dispatch(Published, this, new PublishEventArgs(content, false, false), "Published"); // if was not published and now is... descendants that were 'published' (but // had an unpublished ancestor) are 're-published' ie not explicitely published // but back as 'published' nevertheless - if (isNew == false && previouslyPublished == false) + if (isNew == false && previouslyPublished == false &&HasChildren(content.Id)) { - if (HasChildren(content.Id)) - { - var descendants = GetPublishedDescendantsLocked(uow, repository, content).ToArray(); - uow.Events.Dispatch(Published, this, new PublishEventArgs(descendants, false, false), "Published"); - } - changeType = TreeChangeTypes.RefreshBranch; // whole branch + var descendants = GetPublishedDescendantsLocked(uow, repository, content).ToArray(); + uow.Events.Dispatch(Published, this, new PublishEventArgs(descendants, false, false), "Published"); } - // invalidate the node/branch - uow.Events.Dispatch(TreeChanged, this, new TreeChange(content, changeType).ToEventArgs()); - Audit(uow, AuditType.Publish, "Save and Publish performed by user", userId, content.Id); uow.Complete(); diff --git a/src/Umbraco.Tests/Integration/ContentEventsTests.cs b/src/Umbraco.Tests/Integration/ContentEventsTests.cs index 1cd4ea02d3..c659f84d73 100644 --- a/src/Umbraco.Tests/Integration/ContentEventsTests.cs +++ b/src/Umbraco.Tests/Integration/ContentEventsTests.cs @@ -313,6 +313,13 @@ namespace Umbraco.Tests.Integration _msgCount++; } + private void WriteEvents() + { + Console.WriteLine("EVENTS"); + foreach (var e in _events) + Console.WriteLine(e); + } + #endregion #region Save, Publish & UnPublish single content diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index 9800fc5905..bc0c26c1cd 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Web.Routing; using LightInject; @@ -8,7 +9,9 @@ using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Events; using Umbraco.Core.Models; +using Umbraco.Core.Services; using Umbraco.Core.Sync; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.Testing; @@ -48,10 +51,17 @@ namespace Umbraco.Tests.Scoping _cacheRefresher?.Unbind(); _cacheRefresher = null; - //_onPublishedAssertAction = null; - //ContentService.Published -= OnPublishedAssert; + _onPublishedAssertAction = null; + ContentService.Published -= OnPublishedAssert; } + private void OnPublishedAssert(IContentService sender, PublishEventArgs args) + { + _onPublishedAssertAction?.Invoke(); + } + + private Action _onPublishedAssertAction; + protected override IFacadeService CreateFacadeService() { var options = new FacadeService.Options { IgnoreLocalDb = true }; @@ -92,7 +102,7 @@ namespace Umbraco.Tests.Scoping [TestCase(true)] [TestCase(false)] - public void WipTest(bool complete) + public void TestScope(bool complete) { var umbracoContext = GetUmbracoContextNu("http://example.com/", setSingleton: true); @@ -105,9 +115,34 @@ namespace Umbraco.Tests.Scoping Current.Services.ContentTypeService.Save(contentType); var item = new Content("name", -1, contentType); + // event handler + var evented = 0; + _onPublishedAssertAction = () => + { + evented++; + + var e = umbracoContext.ContentCache.GetById(item.Id); + + // during events, due to LiveSnapshot, we see the changes + Assert.IsNotNull(e); + Assert.AreEqual("changed", e.Name); + }; + using (var scope = ScopeProvider.CreateScope()) { Current.Services.ContentService.SaveAndPublishWithStatus(item); + scope.Complete(); + } + + // been created + var x = umbracoContext.ContentCache.GetById(item.Id); + Assert.IsNotNull(x); + Assert.AreEqual("name", x.Name); + + ContentService.Published += OnPublishedAssert; + + using (var scope = ScopeProvider.CreateScope()) + { item.Name = "changed"; Current.Services.ContentService.SaveAndPublishWithStatus(item); @@ -115,22 +150,16 @@ namespace Umbraco.Tests.Scoping scope.Complete(); } - // fixme - some exceptions are badly swallowed by the scope 'robust exit'? - // fixme - the plumbing of 'other' content types is badly borked + // only 1 event occuring because we are publishing twice for the same event for + // the same object and the scope deduplicates the events (uses the latest) + Assert.AreEqual(complete ? 1 : 0, evented); - var x = umbracoContext.ContentCache.GetById(item.Id); - - if (complete) - { - Assert.IsNotNull(x); - Assert.AreEqual("changed", x.Name); - } - else - { - Assert.IsNull(x); - } - - // fixme - should do more tests & ensure it's all consistent even after rollback + // after the scope, + // if completed, we see the changes + // else changes have been rolled back + x = umbracoContext.ContentCache.GetById(item.Id); + Assert.IsNotNull(x); + Assert.AreEqual(complete ? "changed" : "name", x.Name); } } } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs index 46cc16e753..61ed0feb44 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs @@ -855,6 +855,12 @@ namespace Umbraco.Web.PublishedCache.NuCache } } + public Snapshot LiveSnapshot => new Snapshot(this, _liveGen +#if DEBUG + , _logger +#endif + ); + public Task CollectAsync() { lock (_rlocko) @@ -996,8 +1002,6 @@ namespace Umbraco.Web.PublishedCache.NuCache set => _store._collectAuto = value; } - public Snapshot LiveSnapshot => new Snapshot(_store, _store._liveGen); - public Tuple[] GetValues(int id) { _store._contentNodes.TryGetValue(id, out LinkedNode link); // else null @@ -1069,10 +1073,19 @@ namespace Umbraco.Web.PublishedCache.NuCache #endif } - internal Snapshot(ContentStore store, long gen) + internal Snapshot(ContentStore store, long gen +#if DEBUG + , ILogger logger +#endif + ) { _store = store; _gen = gen; + +#if DEBUG + _logger = logger; + _logger.Debug("Creating live."); +#endif } public ContentNode Get(int id) @@ -1146,7 +1159,7 @@ namespace Umbraco.Web.PublishedCache.NuCache { if (_gen < 0) return; #if DEBUG - _logger.Debug("Dispose snapshot (" + _genRef.GenRefRef.Count + ")."); + _logger.Debug("Dispose snapshot (" + (_genRef?.GenRefRef.Count.ToString() ?? "live") + ")."); #endif _gen = -1; if (_genRef != null) diff --git a/src/Umbraco.Web/PublishedCache/NuCache/FacadeService.cs b/src/Umbraco.Web/PublishedCache/NuCache/FacadeService.cs index 6fd98e04d1..ddf07fa230 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/FacadeService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/FacadeService.cs @@ -939,10 +939,28 @@ namespace Umbraco.Web.PublishedCache.NuCache ICacheProvider snapshotCache; lock (_storesLock) { - contentSnap = _contentStore.CreateSnapshot(); - mediaSnap = _mediaStore.CreateSnapshot(); - domainSnap = _domainStore.CreateSnapshot(); - snapshotCache = _snapshotCache; + var scopeContext = _scopeProvider.Context; + + if (scopeContext == null) + { + contentSnap = _contentStore.CreateSnapshot(); + mediaSnap = _mediaStore.CreateSnapshot(); + domainSnap = _domainStore.CreateSnapshot(); + snapshotCache = _snapshotCache; + } + else + { + // FIXME + contentSnap = _contentStore.LiveSnapshot; + mediaSnap = _mediaStore.LiveSnapshot; + domainSnap = _domainStore.Test.LiveSnapshot; + snapshotCache = _snapshotCache; + + scopeContext.Enlist("Umbraco.Web.PublishedCache.NuCache.FacadeService.FooDang", () => this, (completed, svc) => + { + ((Facade) svc.CurrentFacade).Resync(); + }); + } // create a new snapshot cache if snapshots are different gens if (contentSnap.Gen != _contentGen || mediaSnap.Gen != _mediaGen || domainSnap.Gen != _domainGen || _snapshotCache == null) @@ -954,9 +972,11 @@ namespace Umbraco.Web.PublishedCache.NuCache } } + // FIXME the facade cache is a problem here when it's the request cache?! var facadeCache = _options.FacadeCacheIsApplicationRequestCache ? Current.ApplicationCache.RequestCache : new StaticCacheProvider(); // assuming that's OK for tests, etc + var memberTypeCache = new PublishedContentTypeCache(null, null, _serviceContext.MemberTypeService, _logger); var domainCache = new DomainCache(domainSnap);