U4-9588 - filesystems manager tlc

This commit is contained in:
Stephan
2017-03-08 11:02:30 +01:00
parent 5bbb44479f
commit bf2232258e
6 changed files with 97 additions and 19 deletions

View File

@@ -14,13 +14,16 @@ namespace Umbraco.Core.IO
private readonly FileSystemProvidersSection _config; private readonly FileSystemProvidersSection _config;
private readonly ConcurrentSet<ShadowWrapper> _wrappers = new ConcurrentSet<ShadowWrapper>(); private readonly ConcurrentSet<ShadowWrapper> _wrappers = new ConcurrentSet<ShadowWrapper>();
private readonly ShadowWrapper _macroPartialFileSystem; private readonly ConcurrentDictionary<string, ProviderConstructionInfo> _providerLookup = new ConcurrentDictionary<string, ProviderConstructionInfo>();
private readonly ShadowWrapper _partialViewsFileSystem; private readonly ConcurrentDictionary<string, IFileSystem2> _filesystems = new ConcurrentDictionary<string, IFileSystem2>();
private readonly ShadowWrapper _stylesheetsFileSystem;
private readonly ShadowWrapper _scriptsFileSystem; private ShadowWrapper _macroPartialFileSystem;
private readonly ShadowWrapper _xsltFileSystem; private ShadowWrapper _partialViewsFileSystem;
private readonly ShadowWrapper _masterPagesFileSystem; private ShadowWrapper _stylesheetsFileSystem;
private readonly ShadowWrapper _mvcViewsFileSystem; private ShadowWrapper _scriptsFileSystem;
private ShadowWrapper _xsltFileSystem;
private ShadowWrapper _masterPagesFileSystem;
private ShadowWrapper _mvcViewsFileSystem;
#region Singleton & Constructor #region Singleton & Constructor
@@ -31,16 +34,30 @@ namespace Umbraco.Core.IO
get { return Instance; } get { return Instance; }
} }
// for tests only, totally unsafe
internal void Reset()
{
_wrappers.Clear();
_providerLookup.Clear();
_filesystems.Clear();
CreateWellKnownFileSystems();
}
private IScopeProviderInternal ScopeProvider private IScopeProviderInternal ScopeProvider
{ {
// fixme - 'course this is bad, but enough for now // fixme - 'course this is bad, but enough for now
// beware: means that we capture the "current" scope provider - take care in tests!
get { return ApplicationContext.Current == null ? null : ApplicationContext.Current.ScopeProvider as IScopeProviderInternal; } get { return ApplicationContext.Current == null ? null : ApplicationContext.Current.ScopeProvider as IScopeProviderInternal; }
} }
internal FileSystemProviderManager() internal FileSystemProviderManager()
{ {
_config = (FileSystemProvidersSection) ConfigurationManager.GetSection("umbracoConfiguration/FileSystemProviders"); _config = (FileSystemProvidersSection) ConfigurationManager.GetSection("umbracoConfiguration/FileSystemProviders");
CreateWellKnownFileSystems();
}
private void CreateWellKnownFileSystems()
{
var macroPartialFileSystem = new PhysicalFileSystem(SystemDirectories.MacroPartials); var macroPartialFileSystem = new PhysicalFileSystem(SystemDirectories.MacroPartials);
var partialViewsFileSystem = new PhysicalFileSystem(SystemDirectories.PartialViews); var partialViewsFileSystem = new PhysicalFileSystem(SystemDirectories.PartialViews);
var stylesheetsFileSystem = new PhysicalFileSystem(SystemDirectories.Css); var stylesheetsFileSystem = new PhysicalFileSystem(SystemDirectories.Css);
@@ -88,9 +105,6 @@ namespace Umbraco.Core.IO
//public string ProviderAlias { get; set; } //public string ProviderAlias { get; set; }
} }
private readonly ConcurrentDictionary<string, ProviderConstructionInfo> _providerLookup = new ConcurrentDictionary<string, ProviderConstructionInfo>();
private readonly ConcurrentDictionary<string, IFileSystem2> _filesystems = new ConcurrentDictionary<string, IFileSystem2>();
/// <summary> /// <summary>
/// Gets an underlying (non-typed) filesystem supporting a strongly-typed filesystem. /// Gets an underlying (non-typed) filesystem supporting a strongly-typed filesystem.
/// </summary> /// </summary>
@@ -266,6 +280,14 @@ namespace Umbraco.Core.IO
} }
} }
public void Clear()
{
lock (_set)
{
_set.Clear();
}
}
public T[] ToArray() public T[] ToArray()
{ {
lock (_set) lock (_set)

View File

@@ -21,6 +21,17 @@ namespace Umbraco.Tests.IO
// media fs wants this // media fs wants this
ApplicationContext.Current = new ApplicationContext(CacheHelper.CreateDisabledCacheHelper(), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>())); ApplicationContext.Current = new ApplicationContext(CacheHelper.CreateDisabledCacheHelper(), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()));
// start clean
// because some tests will create corrupt or weird filesystems
FileSystemProviderManager.Current.Reset();
}
[TearDown]
public void TearDown()
{
// stay clean (see note in SetUp)
FileSystemProviderManager.Current.Reset();
} }
[Test] [Test]
@@ -39,22 +50,53 @@ namespace Umbraco.Tests.IO
Assert.NotNull(fs); Assert.NotNull(fs);
} }
[Test] [Test]
public void Singleton_Typed_File_System()
{
var fs1 = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
var fs2 = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
Assert.AreSame(fs1, fs2);
}
[Test]
public void Exception_Thrown_On_Invalid_Typed_File_System() public void Exception_Thrown_On_Invalid_Typed_File_System()
{ {
Assert.Throws<InvalidOperationException>(() => FileSystemProviderManager.Current.GetFileSystemProvider<InvalidTypedFileSystem>()); Assert.Throws<InvalidOperationException>(() => FileSystemProviderManager.Current.GetFileSystemProvider<InvalidTypedFileSystem>());
} }
/// <summary> [Test]
/// Used in unit tests, for a typed file system we need to inherit from FileSystemWrapper and they MUST have a ctor public void Exception_Thrown_On_NonConfigured_Typed_File_System()
/// that only accepts a base IFileSystem object {
/// </summary> // note: we need to reset the manager between tests else the Accept_Fallback test would corrupt that one
internal class InvalidTypedFileSystem : FileSystemWrapper Assert.Throws<ArgumentException>(() => FileSystemProviderManager.Current.GetFileSystemProvider<NonConfiguredTypeFileSystem>());
}
[Test]
public void Accept_Fallback_On_NonConfigured_Typed_File_System()
{
var fs = FileSystemProviderManager.Current.GetFileSystemProvider<NonConfiguredTypeFileSystem>(() => new PhysicalFileSystem("~/App_Data/foo"));
Assert.NotNull(fs);
}
/// <summary>
/// Used in unit tests, for a typed file system we need to inherit from FileSystemWrapper and they MUST have a ctor
/// that only accepts a base IFileSystem object
/// </summary>
internal class InvalidTypedFileSystem : FileSystemWrapper
{ {
public InvalidTypedFileSystem(IFileSystem wrapped, string invalidParam) : base(wrapped) public InvalidTypedFileSystem(IFileSystem wrapped, string invalidParam)
{ : base(wrapped)
} { }
} }
[FileSystemProvider("noconfig")]
internal class NonConfiguredTypeFileSystem : FileSystemWrapper
{
public NonConfiguredTypeFileSystem(IFileSystem wrapped)
: base(wrapped)
{ }
}
} }
} }

View File

@@ -806,6 +806,7 @@ namespace Umbraco.Tests.IO
} }
[Test] [Test]
[Ignore("Does not work on all environments, Directory.GetFiles is broken.")]
public void ShadowGetFilesUsingWildcardAndSingleCharacterFilter() public void ShadowGetFilesUsingWildcardAndSingleCharacterFilter()
{ {
// Arrange // Arrange
@@ -846,6 +847,7 @@ namespace Umbraco.Tests.IO
} }
[Test] [Test]
[Ignore("Does not work on all environments, Directory.GetFiles is broken.")]
public void ShadowFileSystemFilterIsAsBrokenAsRealFileSystemFilter() public void ShadowFileSystemFilterIsAsBrokenAsRealFileSystemFilter()
{ {
// Arrange // Arrange

View File

@@ -32,6 +32,7 @@ namespace Umbraco.Tests.Scoping
private static void ClearFiles() private static void ClearFiles()
{ {
TestHelper.DeleteDirectory(IOHelper.MapPath("media"));
TestHelper.DeleteDirectory(IOHelper.MapPath("FileSysTests")); TestHelper.DeleteDirectory(IOHelper.MapPath("FileSysTests"));
TestHelper.DeleteDirectory(IOHelper.MapPath("App_Data")); TestHelper.DeleteDirectory(IOHelper.MapPath("App_Data"));
} }
@@ -43,6 +44,8 @@ namespace Umbraco.Tests.Scoping
var physMediaFileSystem = new PhysicalFileSystem(IOHelper.MapPath("media"), "ignore"); var physMediaFileSystem = new PhysicalFileSystem(IOHelper.MapPath("media"), "ignore");
var mediaFileSystem = FileSystemProviderManager.Current.MediaFileSystem; var mediaFileSystem = FileSystemProviderManager.Current.MediaFileSystem;
Assert.IsFalse(physMediaFileSystem.FileExists("f1.txt"));
var scopeProvider = ApplicationContext.ScopeProvider; var scopeProvider = ApplicationContext.ScopeProvider;
using (var scope = scopeProvider.CreateScope(scopeFileSystems: true)) using (var scope = scopeProvider.CreateScope(scopeFileSystems: true))
{ {

View File

@@ -24,6 +24,7 @@ using Umbraco.Web.PublishedCache.XmlPublishedCache;
using Umbraco.Web.Security; using Umbraco.Web.Security;
using umbraco.BusinessLogic; using umbraco.BusinessLogic;
using Umbraco.Core.Events; using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Scoping; using Umbraco.Core.Scoping;
namespace Umbraco.Tests.TestHelpers namespace Umbraco.Tests.TestHelpers
@@ -110,6 +111,7 @@ namespace Umbraco.Tests.TestHelpers
{ {
IsReady = true IsReady = true
}; };
return _appContext; return _appContext;
} }

View File

@@ -18,6 +18,7 @@ using Umbraco.Web;
using Umbraco.Web.Models.Mapping; using Umbraco.Web.Models.Mapping;
using umbraco.BusinessLogic; using umbraco.BusinessLogic;
using Umbraco.Core.Events; using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Scoping; using Umbraco.Core.Scoping;
namespace Umbraco.Tests.TestHelpers namespace Umbraco.Tests.TestHelpers
@@ -150,6 +151,11 @@ namespace Umbraco.Tests.TestHelpers
{ {
var applicationContext = CreateApplicationContext(); var applicationContext = CreateApplicationContext();
ApplicationContext.Current = applicationContext; ApplicationContext.Current = applicationContext;
// FileSystemProviderManager captures the current ApplicationContext ScopeProvider
// in its current static instance (yea...) so we need to reset it here to ensure
// it is using the proper ScopeProvider
FileSystemProviderManager.Current.Reset();
} }
protected virtual ApplicationContext CreateApplicationContext() protected virtual ApplicationContext CreateApplicationContext()
@@ -170,6 +176,7 @@ namespace Umbraco.Tests.TestHelpers
{ {
IsReady = true IsReady = true
}; };
return applicationContext; return applicationContext;
} }