make directoryservice cache case sensitive

This commit is contained in:
cvium 2021-03-27 00:26:56 +01:00
parent 6946e58ca4
commit 7670189561
3 changed files with 204 additions and 3 deletions

View File

@ -12,11 +12,11 @@ namespace MediaBrowser.Controller.Providers
{
private readonly IFileSystem _fileSystem;
private readonly ConcurrentDictionary<string, FileSystemMetadata[]> _cache = new ConcurrentDictionary<string, FileSystemMetadata[]>(StringComparer.OrdinalIgnoreCase);
private readonly ConcurrentDictionary<string, FileSystemMetadata[]> _cache = new (StringComparer.Ordinal);
private readonly ConcurrentDictionary<string, FileSystemMetadata> _fileCache = new ConcurrentDictionary<string, FileSystemMetadata>(StringComparer.OrdinalIgnoreCase);
private readonly ConcurrentDictionary<string, FileSystemMetadata> _fileCache = new (StringComparer.Ordinal);
private readonly ConcurrentDictionary<string, List<string>> _filePathCache = new ConcurrentDictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
private readonly ConcurrentDictionary<string, List<string>> _filePathCache = new (StringComparer.Ordinal);
public DirectoryService(IFileSystem fileSystem)
{

View File

@ -0,0 +1,200 @@
using System.Linq;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
using Moq;
using Xunit;
namespace Jellyfin.Controller.Tests
{
public class DirectoryServiceTests
{
private const string LowerCasePath = "/music/someartist";
private const string UpperCasePath = "/music/SOMEARTIST";
private static readonly FileSystemMetadata[] _lowerCaseFileSystemMetadata =
{
new ()
{
FullName = LowerCasePath + "/Artwork",
IsDirectory = true
},
new ()
{
FullName = LowerCasePath + "/Some Other Folder",
IsDirectory = true
},
new ()
{
FullName = LowerCasePath + "/Song 2.mp3",
IsDirectory = false
},
new ()
{
FullName = LowerCasePath + "/Song 3.mp3",
IsDirectory = false
}
};
private static readonly FileSystemMetadata[] _upperCaseFileSystemMetadata =
{
new ()
{
FullName = UpperCasePath + "/Lyrics",
IsDirectory = true
},
new ()
{
FullName = UpperCasePath + "/Song 1.mp3",
IsDirectory = false
}
};
[Fact]
public void GetFileSystemEntries_GivenPathsWithDifferentCasing_CachesAll()
{
var fileSystemMock = new Mock<IFileSystem>();
fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is<string>(x => x == UpperCasePath), false)).Returns(_upperCaseFileSystemMetadata);
fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is<string>(x => x == LowerCasePath), false)).Returns(_lowerCaseFileSystemMetadata);
var directoryService = new DirectoryService(fileSystemMock.Object);
var upperCaseResult = directoryService.GetFileSystemEntries(UpperCasePath);
var lowerCaseResult = directoryService.GetFileSystemEntries(LowerCasePath);
Assert.Equal(_upperCaseFileSystemMetadata, upperCaseResult);
Assert.Equal(_lowerCaseFileSystemMetadata, lowerCaseResult);
}
[Fact]
public void GetFiles_GivenPathsWithDifferentCasing_ReturnsCorrectFiles()
{
var fileSystemMock = new Mock<IFileSystem>();
fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is<string>(x => x == UpperCasePath), false)).Returns(_upperCaseFileSystemMetadata);
fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is<string>(x => x == LowerCasePath), false)).Returns(_lowerCaseFileSystemMetadata);
var directoryService = new DirectoryService(fileSystemMock.Object);
var upperCaseResult = directoryService.GetFiles(UpperCasePath);
var lowerCaseResult = directoryService.GetFiles(LowerCasePath);
Assert.Equal(_upperCaseFileSystemMetadata.Where(f => !f.IsDirectory), upperCaseResult);
Assert.Equal(_lowerCaseFileSystemMetadata.Where(f => !f.IsDirectory), lowerCaseResult);
}
[Fact]
public void GetFile_GivenFilePathsWithDifferentCasing_ReturnsCorrectFile()
{
const string lowerCasePath = "/music/someartist/song 1.mp3";
var lowerCaseFileSystemMetadata = new FileSystemMetadata
{
FullName = lowerCasePath,
Exists = true
};
const string upperCasePath = "/music/SOMEARTIST/SONG 1.mp3";
var upperCaseFileSystemMetadata = new FileSystemMetadata
{
FullName = upperCasePath,
Exists = false
};
var fileSystemMock = new Mock<IFileSystem>();
fileSystemMock.Setup(f => f.GetFileInfo(It.Is<string>(x => x == upperCasePath))).Returns(upperCaseFileSystemMetadata);
fileSystemMock.Setup(f => f.GetFileInfo(It.Is<string>(x => x == lowerCasePath))).Returns(lowerCaseFileSystemMetadata);
var directoryService = new DirectoryService(fileSystemMock.Object);
var lowerCaseResult = directoryService.GetFile(lowerCasePath);
var upperCaseResult = directoryService.GetFile(upperCasePath);
Assert.Equal(lowerCaseFileSystemMetadata, lowerCaseResult);
Assert.Null(upperCaseResult);
}
[Fact]
public void GetFile_GivenCachedPath_ReturnsCachedFile()
{
const string path = "/music/someartist/song 1.mp3";
var cachedFileSystemMetadata = new FileSystemMetadata
{
FullName = path,
Exists = true
};
var newFileSystemMetadata = new FileSystemMetadata
{
FullName = "/music/SOMEARTIST/song 1.mp3",
Exists = true
};
var fileSystemMock = new Mock<IFileSystem>();
fileSystemMock.Setup(f => f.GetFileInfo(It.Is<string>(x => x == path))).Returns(cachedFileSystemMetadata);
var directoryService = new DirectoryService(fileSystemMock.Object);
var result = directoryService.GetFile(path);
fileSystemMock.Setup(f => f.GetFileInfo(It.Is<string>(x => x == path))).Returns(newFileSystemMetadata);
var secondResult = directoryService.GetFile(path);
Assert.Equal(cachedFileSystemMetadata, result);
Assert.Equal(cachedFileSystemMetadata, secondResult);
}
[Fact]
public void GetFilePaths_GivenCachedFilePathWithoutClear_ReturnsOnlyCachedPaths()
{
const string path = "/music/someartist";
var cachedPaths = new[]
{
"/music/someartist/song 1.mp3",
"/music/someartist/song 2.mp3",
"/music/someartist/song 3.mp3",
"/music/someartist/song 4.mp3",
};
var newPaths = new[]
{
"/music/someartist/song 5.mp3",
"/music/someartist/song 6.mp3",
"/music/someartist/song 7.mp3",
"/music/someartist/song 8.mp3",
};
var fileSystemMock = new Mock<IFileSystem>();
fileSystemMock.Setup(f => f.GetFilePaths(It.Is<string>(x => x == path), false)).Returns(cachedPaths);
var directoryService = new DirectoryService(fileSystemMock.Object);
var result = directoryService.GetFilePaths(path);
fileSystemMock.Setup(f => f.GetFilePaths(It.Is<string>(x => x == path), false)).Returns(newPaths);
var secondResult = directoryService.GetFilePaths(path);
Assert.Equal(cachedPaths, result);
Assert.Equal(cachedPaths, secondResult);
}
[Fact]
public void GetFilePaths_GivenCachedFilePathWithClear_ReturnsNewPaths()
{
const string path = "/music/someartist";
var cachedPaths = new[]
{
"/music/someartist/song 1.mp3",
"/music/someartist/song 2.mp3",
"/music/someartist/song 3.mp3",
"/music/someartist/song 4.mp3",
};
var newPaths = new[]
{
"/music/someartist/song 5.mp3",
"/music/someartist/song 6.mp3",
"/music/someartist/song 7.mp3",
"/music/someartist/song 8.mp3",
};
var fileSystemMock = new Mock<IFileSystem>();
fileSystemMock.Setup(f => f.GetFilePaths(It.Is<string>(x => x == path), false)).Returns(cachedPaths);
var directoryService = new DirectoryService(fileSystemMock.Object);
var result = directoryService.GetFilePaths(path);
fileSystemMock.Setup(f => f.GetFilePaths(It.Is<string>(x => x == path), false)).Returns(newPaths);
var secondResult = directoryService.GetFilePaths(path, true);
Assert.Equal(cachedPaths, result);
Assert.Equal(newPaths, secondResult);
}
}
}

View File

@ -16,6 +16,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
<PackageReference Include="coverlet.collector" Version="3.0.3" />