diff --git a/src/Umbraco.Core/Cache/NullCacheProvider.cs b/src/Umbraco.Core/Cache/NullCacheProvider.cs index f4e449499b..6b797307ac 100644 --- a/src/Umbraco.Core/Cache/NullCacheProvider.cs +++ b/src/Umbraco.Core/Cache/NullCacheProvider.cs @@ -5,38 +5,31 @@ using System.Web.Caching; namespace Umbraco.Core.Cache { - internal class NullCacheProvider : IRuntimeCacheProvider + /// + /// Represents a cache provider that does not cache anything. + /// + public class NullCacheProvider : IRuntimeCacheProvider { public virtual void ClearAllCache() - { - } + { } public virtual void ClearCacheItem(string key) - { - } + { } public virtual void ClearCacheObjectTypes(string typeName) - { - } + { } public virtual void ClearCacheObjectTypes() - { - } + { } public virtual void ClearCacheObjectTypes(Func predicate) - { - } - - - + { } public virtual void ClearCacheByKeySearch(string keyStartsWith) - { - } + { } public virtual void ClearCacheByKeyExpression(string regexString) - { - } + { } public virtual IEnumerable GetCacheItemsByKeySearch(string keyStartsWith) { @@ -64,8 +57,6 @@ namespace Umbraco.Core.Cache } public void InsertCacheItem(string cacheKey, Func getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null) - { - - } + { } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs index 8afa5639f1..feccba03b4 100644 --- a/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs +++ b/src/Umbraco.Core/Cache/ObjectCacheRuntimeCacheProvider.cs @@ -1,23 +1,23 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Linq; -using System.Reflection; using System.Runtime.Caching; using System.Text.RegularExpressions; using System.Threading; using System.Web.Caching; -using Umbraco.Core.Logging; using CacheItemPriority = System.Web.Caching.CacheItemPriority; namespace Umbraco.Core.Cache { /// + /// Represents a cache provider that caches item in a . /// A cache provider that wraps the logic of a System.Runtime.Caching.ObjectCache /// - internal class ObjectCacheRuntimeCacheProvider : IRuntimeCacheProvider + /// The is created with name "in-memory". That name is + /// used to retrieve configuration options. It does not identify the memory cache, i.e. + /// each instance of this class has its own, independent, memory cache. + public class ObjectCacheRuntimeCacheProvider : IRuntimeCacheProvider { - private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); internal ObjectCache MemoryCache; diff --git a/src/Umbraco.Core/Cache/StaticCacheProvider.cs b/src/Umbraco.Core/Cache/StaticCacheProvider.cs index 9c448efa6a..c7fd00d39a 100644 --- a/src/Umbraco.Core/Cache/StaticCacheProvider.cs +++ b/src/Umbraco.Core/Cache/StaticCacheProvider.cs @@ -3,14 +3,13 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; -using System.Web.Caching; namespace Umbraco.Core.Cache { /// - /// A cache provider that statically caches everything in an in memory dictionary + /// Represents a cache provider that statically caches item in a concurrent dictionary. /// - internal class StaticCacheProvider : ICacheProvider + public class StaticCacheProvider : ICacheProvider { internal readonly ConcurrentDictionary StaticCache = new ConcurrentDictionary(); @@ -75,7 +74,6 @@ namespace Umbraco.Core.Cache public virtual object GetCacheItem(string cacheKey, Func getCacheItem) { return StaticCache.GetOrAdd(cacheKey, key => getCacheItem()); - } - + } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/DefaultDatabaseFactory.cs b/src/Umbraco.Core/Persistence/DefaultDatabaseFactory.cs index 72c4275541..658b8ebabe 100644 --- a/src/Umbraco.Core/Persistence/DefaultDatabaseFactory.cs +++ b/src/Umbraco.Core/Persistence/DefaultDatabaseFactory.cs @@ -102,5 +102,14 @@ namespace Umbraco.Core.Persistence } } } + + // during tests, the thread static var can leak between tests + // this method provides a way to force-reset the variable + internal void ResetForTests() + { + if (_nonHttpInstance == null) return; + _nonHttpInstance.Dispose(); + _nonHttpInstance = null; + } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Persistence/Repositories/RedirectUrlRepositoryTests.cs b/src/Umbraco.Tests/Persistence/Repositories/RedirectUrlRepositoryTests.cs index c511ed21da..86278e5b66 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/RedirectUrlRepositoryTests.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/RedirectUrlRepositoryTests.cs @@ -62,6 +62,8 @@ namespace Umbraco.Tests.Persistence.Repositories { var provider = new PetaPocoUnitOfWorkProvider(Logger); + Assert.AreNotEqual(_textpage.Id, _otherpage.Id); + using (var uow = provider.GetUnitOfWork()) using (var repo = CreateRepository(uow)) { diff --git a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs index 996b7e2fff..222e86f3d4 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs @@ -1,22 +1,16 @@ using System; -using System.Collections.Generic; -using System.ComponentModel; using System.Configuration; using System.Data.SqlServerCe; using System.IO; -using System.Linq; using System.Web.Routing; using System.Xml; -using Moq; using NUnit.Framework; using SQLCE4Umbraco; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Core.ObjectResolution; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Persistence.SqlSyntax; @@ -27,7 +21,6 @@ using Umbraco.Core.Services; using Umbraco.Web; using Umbraco.Web.PublishedCache; using Umbraco.Web.PublishedCache.XmlPublishedCache; -using Umbraco.Web.Routing; using Umbraco.Web.Security; using umbraco.BusinessLogic; using Umbraco.Core.Events; @@ -35,9 +28,10 @@ using Umbraco.Core.Events; namespace Umbraco.Tests.TestHelpers { /// - /// Use this abstract class for tests that requires a Sql Ce database populated with the umbraco db schema. - /// The PetaPoco Database class should be used through the . + /// Provides a base class for Umbraco application tests that require a database. /// + /// Can provide a SqlCE database populated with the Umbraco schema. The database should be accessed + /// through the . [TestFixture, RequiresSTA] public abstract class BaseDatabaseFactoryTest : BaseUmbracoApplicationTest { @@ -48,15 +42,15 @@ namespace Umbraco.Tests.TestHelpers private bool _firstTestInFixture = true; //Used to flag if its the first test in the current session - private bool _isFirstRunInTestSession = false; + private bool _isFirstRunInTestSession; //Used to flag if its the first test in the current fixture - private bool _isFirstTestInFixture = false; + private bool _isFirstTestInFixture; private ApplicationContext _appContext; private string _dbPath; //used to store (globally) the pre-built db with schema and initial data - private static Byte[] _dbBytes; + private static byte[] _dbBytes; private DefaultDatabaseFactory _dbFactory; [SetUp] @@ -71,7 +65,7 @@ namespace Umbraco.Tests.TestHelpers GetDbConnectionString(), GetDbProviderName(), Logger); - + _dbFactory.ResetForTests(); base.Initialize(); @@ -90,18 +84,15 @@ namespace Umbraco.Tests.TestHelpers protected override ApplicationContext CreateApplicationContext() { - //disable cache - var cacheHelper = CacheHelper.CreateDisabledCacheHelper(); - - var repositoryFactory = new RepositoryFactory(cacheHelper, Logger, SqlSyntax, SettingsForTests.GenerateMockSettings()); + var repositoryFactory = new RepositoryFactory(CacheHelper, Logger, SqlSyntax, SettingsForTests.GenerateMockSettings()); var evtMsgs = new TransientMessagesFactory(); _appContext = new ApplicationContext( //assign the db context - new DatabaseContext(_dbFactory, Logger, SqlSyntax, "System.Data.SqlServerCe.4.0"), + new DatabaseContext(_dbFactory, Logger, SqlSyntax, GetDbProviderName()), //assign the service context - new ServiceContext(repositoryFactory, new PetaPocoUnitOfWorkProvider(_dbFactory), new FileUnitOfWorkProvider(), new PublishingStrategy(evtMsgs, Logger), cacheHelper, Logger, evtMsgs), - cacheHelper, + new ServiceContext(repositoryFactory, new PetaPocoUnitOfWorkProvider(_dbFactory), new FileUnitOfWorkProvider(), new PublishingStrategy(evtMsgs, Logger), CacheHelper, Logger, evtMsgs), + CacheHelper, ProfilingLogger) { IsReady = true @@ -109,10 +100,7 @@ namespace Umbraco.Tests.TestHelpers return _appContext; } - protected virtual ISqlSyntaxProvider SqlSyntax - { - get { return new SqlCeSyntaxProvider(); } - } + protected virtual ISqlSyntaxProvider SqlSyntax => GetSyntaxProvider(); /// /// The database behavior to use for the test/fixture @@ -121,11 +109,16 @@ namespace Umbraco.Tests.TestHelpers { get { - var att = this.GetType().GetCustomAttribute(false); - return att != null ? att.Behavior : DatabaseBehavior.NoDatabasePerFixture; + var att = GetType().GetCustomAttribute(false); + return att?.Behavior ?? DatabaseBehavior.NoDatabasePerFixture; } } + protected virtual ISqlSyntaxProvider GetSyntaxProvider() + { + return new SqlCeSyntaxProvider(); + } + protected virtual string GetDbProviderName() { return "System.Data.SqlServerCe.4.0"; @@ -168,7 +161,7 @@ namespace Umbraco.Tests.TestHelpers || (DatabaseTestBehavior == DatabaseBehavior.NewDbFileAndSchemaPerTest || DatabaseTestBehavior == DatabaseBehavior.EmptyDbFilePerTest) || (_isFirstTestInFixture && DatabaseTestBehavior == DatabaseBehavior.NewDbFileAndSchemaPerFixture)) { - + using (ProfilingLogger.TraceDuration("Remove database file")) { RemoveDatabaseFile(ex => @@ -248,7 +241,7 @@ namespace Umbraco.Tests.TestHelpers //Create the umbraco database and its base data schemaHelper.CreateDatabaseSchema(false, ApplicationContext); - //close the connections, we're gonna read this baby in as a byte array so we don't have to re-initialize the + //close the connections, we're gonna read this baby in as a byte array so we don't have to re-initialize the // damn db for each test CloseDbConnections(); @@ -284,7 +277,7 @@ namespace Umbraco.Tests.TestHelpers private void CloseDbConnections() { - //Ensure that any database connections from a previous test is disposed. + //Ensure that any database connections from a previous test is disposed. //This is really just double safety as its also done in the TearDown. if (ApplicationContext != null && DatabaseContext != null && DatabaseContext.Database != null) DatabaseContext.Database.Dispose(); @@ -306,23 +299,21 @@ namespace Umbraco.Tests.TestHelpers } } } - if (_firstTestInFixture) + if (_firstTestInFixture == false) return; + + lock (Locker) { - lock (Locker) - { - if (_firstTestInFixture) - { - _isFirstTestInFixture = true; //set the flag - _firstTestInFixture = false; - } - } + if (_firstTestInFixture == false) return; + + _isFirstTestInFixture = true; //set the flag + _firstTestInFixture = false; } } private void RemoveDatabaseFile(Action onFail = null) { CloseDbConnections(); - string path = TestHelper.CurrentAssemblyDirectory; + var path = TestHelper.CurrentAssemblyDirectory; try { string filePath = string.Concat(path, "\\UmbracoPetaPocoTests.sdf"); @@ -336,22 +327,13 @@ namespace Umbraco.Tests.TestHelpers LogHelper.Error("Could not remove the old database file", ex); //We will swallow this exception! That's because a sub class might require further teardown logic. - if (onFail != null) - { - onFail(ex); - } + onFail?.Invoke(ex); } } - protected ServiceContext ServiceContext - { - get { return ApplicationContext.Services; } - } + protected ServiceContext ServiceContext => ApplicationContext.Services; - protected DatabaseContext DatabaseContext - { - get { return ApplicationContext.DatabaseContext; } - } + protected DatabaseContext DatabaseContext => ApplicationContext.DatabaseContext; protected UmbracoContext GetUmbracoContext(string url, int templateId, RouteData routeData = null, bool setSingleton = false) { @@ -397,7 +379,7 @@ namespace Umbraco.Tests.TestHelpers protected virtual string GetXmlContent(int templateId) { return @" - @@ -410,7 +392,7 @@ namespace Umbraco.Tests.TestHelpers 1 This is some content]]> - + diff --git a/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs b/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs index 84b109a66a..60125bafa0 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs @@ -1,5 +1,4 @@ -using System.Collections; -using System.Collections.Generic; +using System; using System.IO; using System.Reflection; using AutoMapper; @@ -9,7 +8,6 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models.Mapping; using Umbraco.Core.ObjectResolution; using Umbraco.Core.Persistence; -using Umbraco.Core.Persistence.Factories; using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Persistence.UnitOfWork; using Umbraco.Core.Profiling; @@ -20,18 +18,16 @@ using Umbraco.Web; using Umbraco.Web.Models.Mapping; using umbraco.BusinessLogic; using Umbraco.Core.Events; -using ObjectExtensions = Umbraco.Core.ObjectExtensions; namespace Umbraco.Tests.TestHelpers { /// - /// A base test class used for umbraco tests whcih sets up the logging, plugin manager any base resolvers, etc... and - /// ensures everything is torn down properly. + /// Provides a base class for Umbraco application tests. /// + /// Sets logging, pluging manager, application context, base resolvers... [TestFixture] public abstract class BaseUmbracoApplicationTest : BaseUmbracoConfigurationTest { - [TestFixtureSetUp] public void InitializeFixture() { @@ -65,16 +61,18 @@ namespace Umbraco.Tests.TestHelpers { base.TearDown(); - //reset settings + // reset settings SettingsForTests.Reset(); UmbracoContext.Current = null; TestHelper.CleanContentDirectories(); TestHelper.CleanUmbracoSettingsConfig(); - //reset the app context, this should reset most things that require resetting like ALL resolvers + + // reset the app context, this should reset most things that require resetting like ALL resolvers ApplicationContext.Current.DisposeIfDisposable(); ApplicationContext.Current = null; - ResetPluginManager(); + // reset plugin manager + ResetPluginManager(); } private static readonly object Locker = new object(); @@ -85,7 +83,7 @@ namespace Umbraco.Tests.TestHelpers { if (LegacyPropertyEditorIdToAliasConverter.Count() == 0) { - //Create the legacy prop-eds mapping + // create the legacy prop-eds mapping LegacyPropertyEditorIdToAliasConverter.CreateMappingsForCoreEditors(); } } @@ -100,7 +98,7 @@ namespace Umbraco.Tests.TestHelpers /// private void InitializeMappers() { - if (this.GetType().GetCustomAttribute(false) != null) + if (GetType().GetCustomAttribute(false) != null) { Mapper.Initialize(configuration => { @@ -121,12 +119,9 @@ namespace Umbraco.Tests.TestHelpers /// /// By default this returns false which means the plugin manager will not be reset so it doesn't need to re-scan /// all of the assemblies. Inheritors can override this if plugin manager resetting is required, generally needs - /// to be set to true if the SetupPluginManager has been overridden. + /// to be set to true if the SetupPluginManager has been overridden. /// - protected virtual bool PluginManagerResetRequired - { - get { return false; } - } + protected virtual bool PluginManagerResetRequired => false; /// /// Inheritors can resset the plugin manager if they choose to on teardown @@ -141,7 +136,12 @@ namespace Umbraco.Tests.TestHelpers protected virtual void SetupCacheHelper() { - CacheHelper = CacheHelper.CreateDisabledCacheHelper(); + CacheHelper = CreateCacheHelper(); + } + + protected virtual CacheHelper CreateCacheHelper() + { + return CacheHelper.CreateDisabledCacheHelper(); } /// @@ -156,7 +156,7 @@ namespace Umbraco.Tests.TestHelpers protected virtual ApplicationContext CreateApplicationContext() { var sqlSyntax = new SqlCeSyntaxProvider(); - var repoFactory = new RepositoryFactory(CacheHelper.CreateDisabledCacheHelper(), Logger, sqlSyntax, SettingsForTests.GenerateMockSettings()); + var repoFactory = new RepositoryFactory(CacheHelper, Logger, sqlSyntax, SettingsForTests.GenerateMockSettings()); var evtMsgs = new TransientMessagesFactory(); var applicationContext = new ApplicationContext( @@ -207,16 +207,12 @@ namespace Umbraco.Tests.TestHelpers Resolution.Freeze(); } - protected ApplicationContext ApplicationContext - { - get { return ApplicationContext.Current; } - } + protected ApplicationContext ApplicationContext => ApplicationContext.Current; + + protected ILogger Logger => ProfilingLogger.Logger; - protected ILogger Logger - { - get { return ProfilingLogger.Logger; } - } protected ProfilingLogger ProfilingLogger { get; private set; } + protected CacheHelper CacheHelper { get; private set; } } } \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 8514378b53..f05e44e509 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -178,6 +178,7 @@ +