parent
b7d95d813d
commit
43226fe54d
|
|
@ -16,6 +16,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
||||||
public class FileVersionProvider
|
public class FileVersionProvider
|
||||||
{
|
{
|
||||||
private const string VersionKey = "v";
|
private const string VersionKey = "v";
|
||||||
|
private static readonly char[] QueryStringAndFragmentTokens = new [] { '?', '#' };
|
||||||
private readonly IFileProvider _fileProvider;
|
private readonly IFileProvider _fileProvider;
|
||||||
private readonly IMemoryCache _cache;
|
private readonly IMemoryCache _cache;
|
||||||
private readonly PathString _requestPathBase;
|
private readonly PathString _requestPathBase;
|
||||||
|
|
@ -24,8 +25,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
||||||
/// Creates a new instance of <see cref="FileVersionProvider"/>.
|
/// Creates a new instance of <see cref="FileVersionProvider"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fileProvider">The file provider to get and watch files.</param>
|
/// <param name="fileProvider">The file provider to get and watch files.</param>
|
||||||
/// <param name="applicationName">Name of the application.</param>
|
|
||||||
/// <param name="cache"><see cref="IMemoryCache"/> where versioned urls of files are cached.</param>
|
/// <param name="cache"><see cref="IMemoryCache"/> where versioned urls of files are cached.</param>
|
||||||
|
/// <param name="requestPathBase">The base path for the current HTTP request.</param>
|
||||||
public FileVersionProvider(
|
public FileVersionProvider(
|
||||||
IFileProvider fileProvider,
|
IFileProvider fileProvider,
|
||||||
IMemoryCache cache,
|
IMemoryCache cache,
|
||||||
|
|
@ -52,7 +53,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
||||||
/// <param name="path">The path of the file to which version should be added.</param>
|
/// <param name="path">The path of the file to which version should be added.</param>
|
||||||
/// <returns>Path containing the version query string.</returns>
|
/// <returns>Path containing the version query string.</returns>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// The version query string is appended as with the key "v".
|
/// The version query string is appended with the key "v".
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public string AddFileVersionToPath(string path)
|
public string AddFileVersionToPath(string path)
|
||||||
{
|
{
|
||||||
|
|
@ -63,7 +64,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
||||||
|
|
||||||
var resolvedPath = path;
|
var resolvedPath = path;
|
||||||
|
|
||||||
var queryStringOrFragmentStartIndex = path.IndexOfAny(new char[] { '?', '#' });
|
var queryStringOrFragmentStartIndex = path.IndexOfAny(QueryStringAndFragmentTokens);
|
||||||
if (queryStringOrFragmentStartIndex != -1)
|
if (queryStringOrFragmentStartIndex != -1)
|
||||||
{
|
{
|
||||||
resolvedPath = path.Substring(0, queryStringOrFragmentStartIndex);
|
resolvedPath = path.Substring(0, queryStringOrFragmentStartIndex);
|
||||||
|
|
@ -76,35 +77,39 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileInfo = _fileProvider.GetFileInfo(resolvedPath);
|
|
||||||
if (!fileInfo.Exists)
|
|
||||||
{
|
|
||||||
if (_requestPathBase.HasValue &&
|
|
||||||
resolvedPath.StartsWith(_requestPathBase.Value, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
resolvedPath = resolvedPath.Substring(_requestPathBase.Value.Length);
|
|
||||||
fileInfo = _fileProvider.GetFileInfo(resolvedPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fileInfo.Exists)
|
|
||||||
{
|
|
||||||
// if the file is not in the current server.
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string value;
|
string value;
|
||||||
if (!_cache.TryGetValue(path, out value))
|
if (!_cache.TryGetValue(path, out value))
|
||||||
{
|
{
|
||||||
value = QueryHelpers.AddQueryString(path, VersionKey, GetHashForFile(fileInfo));
|
var cacheEntryOptions = new MemoryCacheEntryOptions();
|
||||||
var cacheEntryOptions = new MemoryCacheEntryOptions().AddExpirationToken(_fileProvider.Watch(resolvedPath));
|
cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(resolvedPath));
|
||||||
_cache.Set(path, value, cacheEntryOptions);
|
var fileInfo = _fileProvider.GetFileInfo(resolvedPath);
|
||||||
|
|
||||||
|
if (!fileInfo.Exists &&
|
||||||
|
_requestPathBase.HasValue &&
|
||||||
|
resolvedPath.StartsWith(_requestPathBase.Value, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var requestPathBaseRelativePath = resolvedPath.Substring(_requestPathBase.Value.Length);
|
||||||
|
cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(requestPathBaseRelativePath));
|
||||||
|
fileInfo = _fileProvider.GetFileInfo(requestPathBaseRelativePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileInfo.Exists)
|
||||||
|
{
|
||||||
|
value = QueryHelpers.AddQueryString(path, VersionKey, GetHashForFile(fileInfo));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if the file is not in the current server.
|
||||||
|
value = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = _cache.Set<string>(path, value, cacheEntryOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetHashForFile(IFileInfo fileInfo)
|
private static string GetHashForFile(IFileInfo fileInfo)
|
||||||
{
|
{
|
||||||
using (var sha256 = SHA256.Create())
|
using (var sha256 = SHA256.Create())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -325,21 +325,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
return hostingEnvironment.Object;
|
return hostingEnvironment.Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IMemoryCache MakeCache()
|
private static IMemoryCache MakeCache() => new MemoryCache(new MemoryCacheOptions());
|
||||||
{
|
|
||||||
object result = null;
|
|
||||||
var cache = new Mock<IMemoryCache>();
|
|
||||||
cache.CallBase = true;
|
|
||||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out result))
|
|
||||||
.Returns(result != null);
|
|
||||||
cache.Setup(
|
|
||||||
c => c.Set(
|
|
||||||
/*key*/ It.IsAny<string>(),
|
|
||||||
/*value*/ It.IsAny<object>(),
|
|
||||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
|
|
||||||
.Returns(new object());
|
|
||||||
return cache.Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IUrlHelperFactory MakeUrlHelperFactory()
|
private static IUrlHelperFactory MakeUrlHelperFactory()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.AspNet.FileProviders;
|
using Microsoft.AspNet.FileProviders;
|
||||||
using Microsoft.AspNet.Hosting;
|
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
|
using Microsoft.AspNet.Mvc.Razor;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
|
@ -22,13 +21,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
||||||
[InlineData("/hello/world?q=foo&bar", "/hello/world?q=foo&bar&v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk")]
|
[InlineData("/hello/world?q=foo&bar", "/hello/world?q=foo&bar&v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk")]
|
||||||
[InlineData("/hello/world?q=foo&bar#abc", "/hello/world?q=foo&bar&v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk#abc")]
|
[InlineData("/hello/world?q=foo&bar#abc", "/hello/world?q=foo&bar&v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk#abc")]
|
||||||
[InlineData("/hello/world#somefragment", "/hello/world?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk#somefragment")]
|
[InlineData("/hello/world#somefragment", "/hello/world?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk#somefragment")]
|
||||||
public void AddsVersionToFiles_WhenCacheIsAbsent(string filePath, string expected)
|
public void AddFileVersionToPath_WhenCacheIsAbsent(string filePath, string expected)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var hostingEnvironment = GetMockHostingEnvironment(filePath);
|
var fileProvider = GetMockFileProvider(filePath);
|
||||||
var fileVersionProvider = new FileVersionProvider(
|
var fileVersionProvider = new FileVersionProvider(
|
||||||
hostingEnvironment.WebRootFileProvider,
|
fileProvider,
|
||||||
GetMockCache(),
|
new MemoryCache(new MemoryCacheOptions()),
|
||||||
GetRequestPathBase());
|
GetRequestPathBase());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -38,54 +37,188 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
||||||
Assert.Equal(expected, result);
|
Assert.Equal(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verifies if the stream is closed after reading.
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void AddsVersionToFiles_DoesNotLockFileAfterReading()
|
public void AddFileVersionToPath_CachesNotFoundResults()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var stream = new MemoryStream(Encoding.UTF8.GetBytes("Hello World!"));
|
var path = "/wwwroot/file.txt";
|
||||||
|
var fileProvider = GetMockFileProvider(
|
||||||
|
path,
|
||||||
|
pathStartsWithAppName: false,
|
||||||
|
fileDoesNotExist: true);
|
||||||
|
var fileVersionProvider = new FileVersionProvider(
|
||||||
|
fileProvider,
|
||||||
|
new MemoryCache(new MemoryCacheOptions()),
|
||||||
|
GetRequestPathBase());
|
||||||
|
var mockFileProvider = Mock.Get(fileProvider);
|
||||||
|
|
||||||
|
// Act 1
|
||||||
|
var result = fileVersionProvider.AddFileVersionToPath(path);
|
||||||
|
|
||||||
|
// Assert 1
|
||||||
|
Assert.Equal(path, result);
|
||||||
|
mockFileProvider.Verify(f => f.GetFileInfo(It.IsAny<string>()), Times.Once());
|
||||||
|
mockFileProvider.Verify(f => f.Watch(It.IsAny<string>()), Times.Once());
|
||||||
|
|
||||||
|
// Act 2
|
||||||
|
result = fileVersionProvider.AddFileVersionToPath(path);
|
||||||
|
|
||||||
|
// Assert 2
|
||||||
|
Assert.Equal(path, result);
|
||||||
|
mockFileProvider.Verify(f => f.GetFileInfo(It.IsAny<string>()), Times.Once());
|
||||||
|
mockFileProvider.Verify(f => f.Watch(It.IsAny<string>()), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("file.txt", false)]
|
||||||
|
[InlineData("/wwwroot/file.txt", true)]
|
||||||
|
public void AddFileVersionToPath_CachesFoundResults(string path, bool pathStartsWithAppName)
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var fileProvider = GetMockFileProvider(
|
||||||
|
"file.txt",
|
||||||
|
pathStartsWithAppName);
|
||||||
|
var fileVersionProvider = new FileVersionProvider(
|
||||||
|
fileProvider,
|
||||||
|
new MemoryCache(new MemoryCacheOptions()),
|
||||||
|
GetRequestPathBase());
|
||||||
|
var mockFileProvider = Mock.Get(fileProvider);
|
||||||
|
|
||||||
|
// Act 1
|
||||||
|
var result = fileVersionProvider.AddFileVersionToPath(path);
|
||||||
|
|
||||||
|
// Assert 1
|
||||||
|
Assert.Equal($"{path}?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result);
|
||||||
|
mockFileProvider.Verify(f => f.GetFileInfo(It.IsAny<string>()), Times.Once());
|
||||||
|
mockFileProvider.Verify(f => f.Watch(It.IsAny<string>()), Times.Once());
|
||||||
|
|
||||||
|
// Act 2
|
||||||
|
result = fileVersionProvider.AddFileVersionToPath(path);
|
||||||
|
|
||||||
|
// Assert 2
|
||||||
|
Assert.Equal($"{path}?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result);
|
||||||
|
mockFileProvider.Verify(f => f.GetFileInfo(It.IsAny<string>()), Times.Once());
|
||||||
|
mockFileProvider.Verify(f => f.Watch(It.IsAny<string>()), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AddFileVersionToPath_UpdatesEntryWhenCacheExpires_ForNonExistingFile()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var fileProvider = new TestFileProvider();
|
||||||
|
var fileVersionProvider = new FileVersionProvider(
|
||||||
|
fileProvider,
|
||||||
|
new MemoryCache(new MemoryCacheOptions()),
|
||||||
|
GetRequestPathBase());
|
||||||
|
|
||||||
|
// Act 1 - File does not exist
|
||||||
|
var result = fileVersionProvider.AddFileVersionToPath("file.txt");
|
||||||
|
|
||||||
|
// Assert 1
|
||||||
|
Assert.Equal("file.txt", result);
|
||||||
|
|
||||||
|
// Act 2 - File gets added
|
||||||
|
fileProvider.AddFile("file.txt", "Hello World!");
|
||||||
|
fileProvider.GetChangeToken("file.txt").HasChanged = true;
|
||||||
|
result = fileVersionProvider.AddFileVersionToPath("file.txt");
|
||||||
|
|
||||||
|
// Assert 2
|
||||||
|
Assert.Equal("file.txt?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AddFileVersionToPath_UpdatesEntryWhenCacheExpires_ForExistingFile()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var fileProvider = new TestFileProvider();
|
||||||
|
var fileVersionProvider = new FileVersionProvider(
|
||||||
|
fileProvider,
|
||||||
|
new MemoryCache(new MemoryCacheOptions()),
|
||||||
|
GetRequestPathBase());
|
||||||
|
fileProvider.AddFile("file.txt", "Hello World!");
|
||||||
|
|
||||||
|
// Act 1 - File exists
|
||||||
|
var result = fileVersionProvider.AddFileVersionToPath("file.txt");
|
||||||
|
|
||||||
|
// Assert 1
|
||||||
|
Assert.Equal("file.txt?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result);
|
||||||
|
|
||||||
|
// Act 2
|
||||||
|
fileProvider.DeleteFile("file.txt");
|
||||||
|
fileProvider.GetChangeToken("file.txt").HasChanged = true;
|
||||||
|
result = fileVersionProvider.AddFileVersionToPath("file.txt");
|
||||||
|
|
||||||
|
// Assert 2
|
||||||
|
Assert.Equal("file.txt", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AddFileVersionToPath_UpdatesEntryWhenCacheExpires_ForExistingFile_WithRequestPathBase()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var fileProvider = new TestFileProvider();
|
||||||
|
var fileVersionProvider = new FileVersionProvider(
|
||||||
|
fileProvider,
|
||||||
|
new MemoryCache(new MemoryCacheOptions()),
|
||||||
|
GetRequestPathBase("/wwwroot/"));
|
||||||
|
fileProvider.AddFile("file.txt", "Hello World!");
|
||||||
|
|
||||||
|
// Act 1 - File exists
|
||||||
|
var result = fileVersionProvider.AddFileVersionToPath("/wwwroot/file.txt");
|
||||||
|
|
||||||
|
// Assert 1
|
||||||
|
Assert.Equal("/wwwroot/file.txt?v=f4OxZX_x_FO5LcGBSKHWXfwtSx-j1ncoSt3SABJtkGk", result);
|
||||||
|
|
||||||
|
// Act 2
|
||||||
|
fileProvider.DeleteFile("file.txt");
|
||||||
|
fileProvider.GetChangeToken("file.txt").HasChanged = true;
|
||||||
|
result = fileVersionProvider.AddFileVersionToPath("/wwwroot/file.txt");
|
||||||
|
|
||||||
|
// Assert 2
|
||||||
|
Assert.Equal("/wwwroot/file.txt", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifies if the stream is closed after reading.
|
||||||
|
[Fact]
|
||||||
|
public void AddFileVersionToPath_DoesNotLockFileAfterReading()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var stream = new TestableMemoryStream(Encoding.UTF8.GetBytes("Hello World!"));
|
||||||
var mockFile = new Mock<IFileInfo>();
|
var mockFile = new Mock<IFileInfo>();
|
||||||
mockFile.SetupGet(f => f.Exists).Returns(true);
|
mockFile.SetupGet(f => f.Exists).Returns(true);
|
||||||
mockFile
|
mockFile
|
||||||
.Setup(m => m.CreateReadStream())
|
.Setup(m => m.CreateReadStream())
|
||||||
.Returns(stream);
|
.Returns(stream);
|
||||||
|
|
||||||
var mockFileProvider = new Mock<IFileProvider>();
|
var fileProvider = new TestFileProvider();
|
||||||
mockFileProvider.Setup(fp => fp.GetFileInfo(It.IsAny<string>()))
|
fileProvider.AddFile("/hello/world", mockFile.Object);
|
||||||
.Returns(mockFile.Object);
|
|
||||||
mockFileProvider.Setup(fp => fp.Watch(It.IsAny<string>()))
|
|
||||||
.Returns(new TestFileChangeToken());
|
|
||||||
|
|
||||||
var hostingEnvironment = new Mock<IHostingEnvironment>();
|
|
||||||
hostingEnvironment.Setup(h => h.WebRootFileProvider).Returns(mockFileProvider.Object);
|
|
||||||
|
|
||||||
var fileVersionProvider = new FileVersionProvider(
|
var fileVersionProvider = new FileVersionProvider(
|
||||||
hostingEnvironment.Object.WebRootFileProvider,
|
fileProvider,
|
||||||
GetMockCache(),
|
new MemoryCache(new MemoryCacheOptions()),
|
||||||
GetRequestPathBase());
|
GetRequestPathBase());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = fileVersionProvider.AddFileVersionToPath("/hello/world");
|
var result = fileVersionProvider.AddFileVersionToPath("/hello/world");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.False(stream.CanRead);
|
Assert.True(stream.Disposed);
|
||||||
Assert.Throws<ObjectDisposedException>(() => fileVersionProvider.AddFileVersionToPath("/hello/world"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("/testApp/hello/world", true, "/testApp")]
|
[InlineData("/testApp/hello/world", true, "/testApp")]
|
||||||
[InlineData("/testApp/foo/bar/hello/world", true, "/testApp/foo/bar")]
|
[InlineData("/testApp/foo/bar/hello/world", true, "/testApp/foo/bar")]
|
||||||
[InlineData("/test/testApp/hello/world", false, "/testApp")]
|
[InlineData("/test/testApp/hello/world", false, "/testApp")]
|
||||||
public void AddsVersionToFiles_PathContainingAppName(
|
public void AddFileVersionToPath_PathContainingAppName(
|
||||||
string filePath,
|
string filePath,
|
||||||
bool pathStartsWithAppBase,
|
bool pathStartsWithAppBase,
|
||||||
string requestPathBase)
|
string requestPathBase)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var hostingEnvironment = GetMockHostingEnvironment(filePath, pathStartsWithAppBase);
|
var fileProvider = GetMockFileProvider(filePath, pathStartsWithAppBase);
|
||||||
var fileVersionProvider = new FileVersionProvider(
|
var fileVersionProvider = new FileVersionProvider(
|
||||||
hostingEnvironment.WebRootFileProvider,
|
fileProvider,
|
||||||
GetMockCache(),
|
new MemoryCache(new MemoryCacheOptions()),
|
||||||
GetRequestPathBase(requestPathBase));
|
GetRequestPathBase(requestPathBase));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -100,10 +233,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var filePath = "http://contoso.com/hello/world";
|
var filePath = "http://contoso.com/hello/world";
|
||||||
var hostingEnvironment = GetMockHostingEnvironment(filePath, false, true);
|
var fileProvider = GetMockFileProvider(filePath, false, true);
|
||||||
var fileVersionProvider = new FileVersionProvider(
|
var fileVersionProvider = new FileVersionProvider(
|
||||||
hostingEnvironment.WebRootFileProvider,
|
fileProvider,
|
||||||
GetMockCache(),
|
new MemoryCache(new MemoryCacheOptions()),
|
||||||
GetRequestPathBase());
|
GetRequestPathBase());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -118,10 +251,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var filePath = "/hello/world";
|
var filePath = "/hello/world";
|
||||||
var hostingEnvironment = GetMockHostingEnvironment(filePath);
|
var fileProvider = GetMockFileProvider(filePath);
|
||||||
|
var memoryCache = new MemoryCache(new MemoryCacheOptions());
|
||||||
|
memoryCache.Set(filePath, "FromCache");
|
||||||
var fileVersionProvider = new FileVersionProvider(
|
var fileVersionProvider = new FileVersionProvider(
|
||||||
hostingEnvironment.WebRootFileProvider,
|
fileProvider,
|
||||||
GetMockCache("FromCache"),
|
memoryCache,
|
||||||
GetRequestPathBase());
|
GetRequestPathBase());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -138,8 +273,8 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var changeToken = new Mock<IChangeToken>();
|
var changeToken = new Mock<IChangeToken>();
|
||||||
var hostingEnvironment = GetMockHostingEnvironment(filePath, requestPathBase != null);
|
var fileProvider = GetMockFileProvider(filePath, requestPathBase != null);
|
||||||
Mock.Get(hostingEnvironment.WebRootFileProvider)
|
Mock.Get(fileProvider)
|
||||||
.Setup(f => f.Watch(watchPath)).Returns(changeToken.Object);
|
.Setup(f => f.Watch(watchPath)).Returns(changeToken.Object);
|
||||||
|
|
||||||
object cacheValue = null;
|
object cacheValue = null;
|
||||||
|
|
@ -151,10 +286,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
||||||
/*key*/ filePath,
|
/*key*/ filePath,
|
||||||
/*value*/ It.IsAny<object>(),
|
/*value*/ It.IsAny<object>(),
|
||||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
|
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
|
||||||
.Returns(new object())
|
.Returns((object key, object value, MemoryCacheEntryOptions options) => value)
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
var fileVersionProvider = new FileVersionProvider(
|
var fileVersionProvider = new FileVersionProvider(
|
||||||
hostingEnvironment.WebRootFileProvider,
|
fileProvider,
|
||||||
cache.Object,
|
cache.Object,
|
||||||
GetRequestPathBase(requestPathBase));
|
GetRequestPathBase(requestPathBase));
|
||||||
|
|
||||||
|
|
@ -166,7 +301,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
||||||
cache.VerifyAll();
|
cache.VerifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IHostingEnvironment GetMockHostingEnvironment(
|
private static IFileProvider GetMockFileProvider(
|
||||||
string filePath,
|
string filePath,
|
||||||
bool pathStartsWithAppName = false,
|
bool pathStartsWithAppName = false,
|
||||||
bool fileDoesNotExist = false)
|
bool fileDoesNotExist = false)
|
||||||
|
|
@ -177,54 +312,47 @@ namespace Microsoft.AspNet.Mvc.TagHelpers.Internal
|
||||||
.Setup(m => m.CreateReadStream())
|
.Setup(m => m.CreateReadStream())
|
||||||
.Returns(() => new MemoryStream(Encoding.UTF8.GetBytes("Hello World!")));
|
.Returns(() => new MemoryStream(Encoding.UTF8.GetBytes("Hello World!")));
|
||||||
|
|
||||||
var nonExistingMockFile = new Mock<IFileInfo>();
|
var doesNotExistMockFile = new Mock<IFileInfo>();
|
||||||
nonExistingMockFile.SetupGet(f => f.Exists).Returns(false);
|
doesNotExistMockFile.SetupGet(f => f.Exists).Returns(false);
|
||||||
nonExistingMockFile
|
|
||||||
.Setup(m => m.CreateReadStream())
|
|
||||||
.Returns(() => new MemoryStream(Encoding.UTF8.GetBytes("Hello World!")));
|
|
||||||
|
|
||||||
var mockFileProvider = new Mock<IFileProvider>();
|
var mockFileProvider = new Mock<IFileProvider>();
|
||||||
if (pathStartsWithAppName)
|
if (pathStartsWithAppName)
|
||||||
{
|
{
|
||||||
mockFileProvider.Setup(fp => fp.GetFileInfo(filePath)).Returns(nonExistingMockFile.Object);
|
mockFileProvider.Setup(fp => fp.GetFileInfo(filePath)).Returns(doesNotExistMockFile.Object);
|
||||||
mockFileProvider.Setup(fp => fp.GetFileInfo(It.Is<string>(str => str != filePath)))
|
mockFileProvider.Setup(fp => fp.GetFileInfo(It.Is<string>(str => str != filePath)))
|
||||||
.Returns(existingMockFile.Object);
|
.Returns(existingMockFile.Object);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mockFileProvider.Setup(fp => fp.GetFileInfo(It.IsAny<string>()))
|
mockFileProvider.Setup(fp => fp.GetFileInfo(It.IsAny<string>()))
|
||||||
.Returns(fileDoesNotExist? nonExistingMockFile.Object : existingMockFile.Object);
|
.Returns(fileDoesNotExist ? doesNotExistMockFile.Object : existingMockFile.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
mockFileProvider.Setup(fp => fp.Watch(It.IsAny<string>()))
|
mockFileProvider.Setup(fp => fp.Watch(It.IsAny<string>()))
|
||||||
.Returns(new TestFileChangeToken());
|
.Returns(new TestFileChangeToken());
|
||||||
|
|
||||||
var hostingEnvironment = new Mock<IHostingEnvironment>();
|
return mockFileProvider.Object;
|
||||||
hostingEnvironment.Setup(h => h.WebRootFileProvider).Returns(mockFileProvider.Object);
|
|
||||||
|
|
||||||
return hostingEnvironment.Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IMemoryCache GetMockCache(object result = null)
|
|
||||||
{
|
|
||||||
var cache = new Mock<IMemoryCache>();
|
|
||||||
cache.CallBase = true;
|
|
||||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out result))
|
|
||||||
.Returns(result != null);
|
|
||||||
|
|
||||||
cache
|
|
||||||
.Setup(
|
|
||||||
c => c.Set(
|
|
||||||
/*key*/ It.IsAny<string>(),
|
|
||||||
/*value*/ It.IsAny<object>(),
|
|
||||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
|
|
||||||
.Returns(new object());
|
|
||||||
return cache.Object;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PathString GetRequestPathBase(string requestPathBase = null)
|
private static PathString GetRequestPathBase(string requestPathBase = null)
|
||||||
{
|
{
|
||||||
return new PathString(requestPathBase);
|
return new PathString(requestPathBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TestableMemoryStream : MemoryStream
|
||||||
|
{
|
||||||
|
public TestableMemoryStream(byte[] buffer)
|
||||||
|
: base(buffer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Disposed { get; private set; }
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
base.Dispose(disposing);
|
||||||
|
Disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -885,22 +885,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
return applicationEnvironment.Object;
|
return applicationEnvironment.Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IMemoryCache MakeCache(object result = null)
|
private static IMemoryCache MakeCache() => new MemoryCache(new MemoryCacheOptions());
|
||||||
{
|
|
||||||
var cache = new Mock<IMemoryCache>();
|
|
||||||
cache.CallBase = true;
|
|
||||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out result))
|
|
||||||
.Returns(result != null);
|
|
||||||
|
|
||||||
cache
|
|
||||||
.Setup(
|
|
||||||
c => c.Set(
|
|
||||||
/*key*/ It.IsAny<string>(),
|
|
||||||
/*value*/ It.IsAny<object>(),
|
|
||||||
/*options*/ It.IsAny<MemoryCacheEntryOptions>()))
|
|
||||||
.Returns(result);
|
|
||||||
return cache.Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IUrlHelperFactory MakeUrlHelperFactory()
|
private static IUrlHelperFactory MakeUrlHelperFactory()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -980,24 +980,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
|
||||||
return applicationEnvironment.Object;
|
return applicationEnvironment.Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IMemoryCache MakeCache(object result = null)
|
private static IMemoryCache MakeCache() => new MemoryCache(new MemoryCacheOptions());
|
||||||
{
|
|
||||||
var cache = new Mock<IMemoryCache>();
|
|
||||||
cache.CallBase = true;
|
|
||||||
cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out result))
|
|
||||||
.Returns(result != null);
|
|
||||||
|
|
||||||
var cacheEntryOptions = new MemoryCacheEntryOptions();
|
|
||||||
cacheEntryOptions.AddExpirationToken(Mock.Of<IChangeToken>());
|
|
||||||
cache
|
|
||||||
.Setup(
|
|
||||||
c => c.Set(
|
|
||||||
/*key*/ It.IsAny<string>(),
|
|
||||||
/*value*/ It.IsAny<object>(),
|
|
||||||
/*options*/ cacheEntryOptions))
|
|
||||||
.Returns(result);
|
|
||||||
return cache.Object;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IUrlHelperFactory MakeUrlHelperFactory()
|
private static IUrlHelperFactory MakeUrlHelperFactory()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,14 @@ namespace Microsoft.Extensions.Primitives
|
||||||
|
|
||||||
public IDisposable RegisterChangeCallback(Action<object> callback, object state)
|
public IDisposable RegisterChangeCallback(Action<object> callback, object state)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
return new NullDisposable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class NullDisposable : IDisposable
|
||||||
|
{
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue