U4-10118 Umbraco.Core.IO.FileSystemProviderManager is simply not testable and cannot be properly used or setup in tests

This commit is contained in:
Shannon
2017-09-12 13:18:34 +10:00
parent b884bed7cf
commit 68f1120b4f
7 changed files with 122 additions and 14 deletions

View File

@@ -6,7 +6,7 @@ using System.Text;
namespace Umbraco.Core.Configuration
{
public class FileSystemProviderElement : ConfigurationElement
public class FileSystemProviderElement : ConfigurationElement, IFileSystemProviderElement
{
private const string ALIAS_KEY = "alias";
private const string TYPE_KEY = "type";
@@ -38,5 +38,30 @@ namespace Umbraco.Core.Configuration
return ((KeyValueConfigurationCollection)(base[PARAMETERS_KEY]));
}
}
string IFileSystemProviderElement.Alias
{
get { return Alias; }
}
string IFileSystemProviderElement.Type
{
get { return Type; }
}
private IDictionary<string, string> _params;
IDictionary<string, string> IFileSystemProviderElement.Parameters
{
get
{
if (_params != null) return _params;
_params = new Dictionary<string, string>();
foreach (KeyValueConfigurationElement element in Parameters)
{
_params.Add(element.Key, element.Value);
}
return _params;
}
}
}
}

View File

@@ -7,7 +7,7 @@ using System.Text;
namespace Umbraco.Core.Configuration
{
[ConfigurationCollection(typeof(FileSystemProviderElement), AddItemName = "Provider")]
public class FileSystemProviderElementCollection : ConfigurationElementCollection
public class FileSystemProviderElementCollection : ConfigurationElementCollection, IEnumerable<IFileSystemProviderElement>
{
protected override ConfigurationElement CreateNewElement()
{
@@ -19,12 +19,25 @@ namespace Umbraco.Core.Configuration
return ((FileSystemProviderElement)(element)).Alias;
}
new public FileSystemProviderElement this[string key]
public new FileSystemProviderElement this[string key]
{
get
{
return (FileSystemProviderElement)BaseGet(key);
}
}
IEnumerator<IFileSystemProviderElement> IEnumerable<IFileSystemProviderElement>.GetEnumerator()
{
for (var i = 0; i < Count; i++)
{
yield return BaseGet(i) as IFileSystemProviderElement;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

View File

@@ -6,7 +6,7 @@ using System.Text;
namespace Umbraco.Core.Configuration
{
public class FileSystemProvidersSection : ConfigurationSection
public class FileSystemProvidersSection : ConfigurationSection, IFileSystemProvidersSection
{
[ConfigurationProperty("", IsDefaultCollection = true, IsRequired = true)]
@@ -14,5 +14,17 @@ namespace Umbraco.Core.Configuration
{
get { return ((FileSystemProviderElementCollection)(base[""])); }
}
private IDictionary<string, IFileSystemProviderElement> _providers;
IDictionary<string, IFileSystemProviderElement> IFileSystemProvidersSection.Providers
{
get
{
if (_providers != null) return _providers;
_providers = Providers.ToDictionary(x => x.Alias, x => x);
return _providers;
}
}
}
}

View File

@@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace Umbraco.Core.Configuration
{
public interface IFileSystemProviderElement
{
string Alias { get; }
string Type { get; }
IDictionary<string, string> Parameters { get; }
}
}

View File

@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Umbraco.Core.Configuration
{
public interface IFileSystemProvidersSection
{
IDictionary<string, IFileSystemProviderElement> Providers { get; }
}
}

View File

@@ -11,7 +11,7 @@ namespace Umbraco.Core.IO
{
public class FileSystemProviderManager
{
private readonly FileSystemProvidersSection _config;
private readonly IFileSystemProvidersSection _config;
private readonly ConcurrentSet<ShadowWrapper> _wrappers = new ConcurrentSet<ShadowWrapper>();
private readonly ConcurrentDictionary<string, ProviderConstructionInfo> _providerLookup = new ConcurrentDictionary<string, ProviderConstructionInfo>();
@@ -28,13 +28,31 @@ namespace Umbraco.Core.IO
private ShadowWrapper _mvcViewsFileSystem;
#region Singleton & Constructor
//ensures that the construction of the singleton only happens when Current is accessed, otherwise any reference to this class would cause
//the ctor to be invoked which can lead to problems outside of a web app.
private static readonly Lazy<FileSystemProviderManager> Instance = new Lazy<FileSystemProviderManager>(() => new FileSystemProviderManager());
private static readonly FileSystemProviderManager Instance = new FileSystemProviderManager();
private static FileSystemProviderManager _current;
public static FileSystemProviderManager Current
{
get { return Instance; }
get
{
if (_current != null) return _current;
_current = Instance.Value;
return _current;
}
}
/// <summary>
/// For tests only, allows setting the value of the singleton "Current" property
/// </summary>
/// <param name="instance"></param>
public static void SetCurrent(FileSystemProviderManager instance)
{
_current = instance;
}
// for tests only, totally unsafe
internal void Reset()
@@ -52,10 +70,24 @@ namespace Umbraco.Core.IO
// beware: means that we capture the "current" scope provider - take care in tests!
get { return ApplicationContext.Current == null ? null : ApplicationContext.Current.ScopeProvider as IScopeProviderInternal; }
}
internal FileSystemProviderManager()
/// <summary>
/// Constructor that can be used for tests
/// </summary>
/// <param name="configSection"></param>
public FileSystemProviderManager(IFileSystemProvidersSection configSection)
{
_config = (FileSystemProvidersSection) ConfigurationManager.GetSection("umbracoConfiguration/FileSystemProviders");
if (configSection == null) throw new ArgumentNullException("configSection");
_config = configSection;
CreateWellKnownFileSystems();
}
/// <summary>
/// Default constructor that will read the config from the locally found config section
/// </summary>
public FileSystemProviderManager()
{
_config = (FileSystemProvidersSection)ConfigurationManager.GetSection("umbracoConfiguration/FileSystemProviders");
CreateWellKnownFileSystems();
}
@@ -166,17 +198,21 @@ namespace Umbraco.Core.IO
if (providerType.IsAssignableFrom(typeof(IFileSystem)))
throw new InvalidOperationException(string.Format("Type {0} does not implement IFileSystem.", providerType.FullName));
// find a ctor matching the config parameters
// find a ctor matching the config parameters
var paramCount = providerConfig.Parameters != null ? providerConfig.Parameters.Count : 0;
var constructor = providerType.GetConstructors().SingleOrDefault(x
=> x.GetParameters().Length == paramCount && x.GetParameters().All(y => providerConfig.Parameters.AllKeys.Contains(y.Name)));
=> x.GetParameters().Length == paramCount && x.GetParameters().All(y => providerConfig.Parameters.Keys.Contains(y.Name)));
if (constructor == null)
throw new InvalidOperationException(string.Format("Type {0} has no ctor matching the {1} configuration parameter(s).", providerType.FullName, paramCount));
var parameters = new object[paramCount];
if (providerConfig.Parameters != null) // keeps ReSharper happy
if (providerConfig.Parameters != null)
{
var allKeys = providerConfig.Parameters.Keys.ToArray();
for (var i = 0; i < paramCount; i++)
parameters[i] = providerConfig.Parameters[providerConfig.Parameters.AllKeys[i]].Value;
parameters[i] = providerConfig.Parameters[allKeys[i]];
}
return new ProviderConstructionInfo
{

View File

@@ -238,6 +238,8 @@
<Compile Include="Configuration\Grid\IGridConfig.cs" />
<Compile Include="Configuration\Grid\IGridEditorConfig.cs" />
<Compile Include="Configuration\Grid\IGridEditorsConfig.cs" />
<Compile Include="Configuration\IFileSystemProviderElement.cs" />
<Compile Include="Configuration\IFileSystemProvidersSection.cs" />
<Compile Include="Configuration\UmbracoConfig.cs" />
<Compile Include="Configuration\UmbracoConfigurationSection.cs" />
<Compile Include="Configuration\UmbracoSettings\AppCodeFileExtensionsCollection.cs" />