Directory lookup will not include some folders at base of drive

This commit is contained in:
Mark McDowall 2013-08-02 20:01:16 -07:00
parent 485f05d4b9
commit 1c5e30bbd0
8 changed files with 202 additions and 57 deletions

View File

@ -1,5 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq;
using Nancy; using Nancy;
using NzbDrone.Api.Extensions; using NzbDrone.Api.Extensions;
using NzbDrone.Common; using NzbDrone.Common;
@ -8,12 +10,12 @@ namespace NzbDrone.Api.Directories
{ {
public class DirectoryModule : NzbDroneApiModule public class DirectoryModule : NzbDroneApiModule
{ {
private readonly IDiskProvider _diskProvider; private readonly IDirectoryLookupService _directoryLookupService;
public DirectoryModule(IDiskProvider diskProvider) public DirectoryModule(IDirectoryLookupService directoryLookupService)
: base("/directories") : base("/directories")
{ {
_diskProvider = diskProvider; _directoryLookupService = directoryLookupService;
Get["/"] = x => GetDirectories(); Get["/"] = x => GetDirectories();
} }
@ -24,30 +26,7 @@ namespace NzbDrone.Api.Directories
string query = Request.Query.query.Value; string query = Request.Query.query.Value;
IEnumerable<String> dirs = null; var dirs = _directoryLookupService.LookupSubDirectories(query);
try
{
//Windows (Including UNC)
var windowsSep = query.LastIndexOf('\\');
if (windowsSep > -1)
{
dirs = _diskProvider.GetDirectories(query.Substring(0, windowsSep + 1));
}
//Unix
var index = query.LastIndexOf('/');
if (index > -1)
{
dirs = _diskProvider.GetDirectories(query.Substring(0, index + 1));
}
}
catch (Exception)
{
//Swallow the exceptions so proper JSON is returned to the client (Empty results)
return new List<string>().AsResponse();
}
if (dirs == null) if (dirs == null)
throw new Exception("A valid path was not provided"); throw new Exception("A valid path was not provided");

View File

@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Common.Test
{
[TestFixture]
public class DirectoryLookupServiceFixture :TestBase<DirectoryLookupService>
{
private const string RECYCLING_BIN = "$Recycle.Bin";
private const string SYSTEM_VOLUME_INFORMATION = "System Volume Information";
private List<String> _folders;
[SetUp]
public void Setup()
{
_folders = new List<String>
{
RECYCLING_BIN,
"Chocolatey",
"Documents and Settings",
"Dropbox",
"Intel",
"PerfLogs",
"Program Files",
"Program Files (x86)",
"ProgramData",
SYSTEM_VOLUME_INFORMATION,
"Test",
"Users",
"Windows"
};
}
private void SetupFolders(string root)
{
_folders.ForEach(e =>
{
e = Path.Combine(root, e);
});
}
[Test]
public void should_get_all_folder_for_none_root_path()
{
const string root = @"C:\Test\";
SetupFolders(root);
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetDirectories(It.IsAny<String>()))
.Returns(_folders.ToArray());
Subject.LookupSubDirectories(root).Should()
.HaveCount(_folders.Count);
}
[Test]
public void should_not_contain_recycling_bin_for_root_of_drive()
{
const string root = @"C:\";
SetupFolders(root);
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetDirectories(It.IsAny<String>()))
.Returns(_folders.ToArray());
Subject.LookupSubDirectories(root).Should().NotContain(Path.Combine(root, RECYCLING_BIN));
}
[Test]
public void should_not_contain_system_volume_information_for_root_of_drive()
{
const string root = @"C:\";
SetupFolders(root);
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetDirectories(It.IsAny<String>()))
.Returns(_folders.ToArray());
Subject.LookupSubDirectories(root).Should().NotContain(Path.Combine(root, SYSTEM_VOLUME_INFORMATION));
}
[Test]
public void should_not_contain_recycling_bin_or_system_volume_information_for_root_of_drive()
{
const string root = @"C:\";
SetupFolders(root);
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetDirectories(It.IsAny<String>()))
.Returns(_folders.ToArray());
Subject.LookupSubDirectories(root).Should().HaveCount(_folders.Count - 2);
}
}
}

View File

@ -62,6 +62,7 @@
<Compile Include="CacheTests\CachedManagerFixture.cs" /> <Compile Include="CacheTests\CachedManagerFixture.cs" />
<Compile Include="CacheTests\CachedFixture.cs" /> <Compile Include="CacheTests\CachedFixture.cs" />
<Compile Include="ConfigFileProviderTest.cs" /> <Compile Include="ConfigFileProviderTest.cs" />
<Compile Include="DirectoryLookupServiceFixture.cs" />
<Compile Include="EnsureTest\PathExtensionFixture.cs" /> <Compile Include="EnsureTest\PathExtensionFixture.cs" />
<Compile Include="EnvironmentTests\StartupArgumentsFixture.cs" /> <Compile Include="EnvironmentTests\StartupArgumentsFixture.cs" />
<Compile Include="EnvironmentTests\EnviromentProviderTest.cs" /> <Compile Include="EnvironmentTests\EnviromentProviderTest.cs" />

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace NzbDrone.Common
{
public interface IDirectoryLookupService
{
List<String> LookupSubDirectories(string query);
}
public class DirectoryLookupService : IDirectoryLookupService
{
private readonly IDiskProvider _diskProvider;
public DirectoryLookupService(IDiskProvider diskProvider)
{
_diskProvider = diskProvider;
}
public List<String> LookupSubDirectories(string query)
{
List<String> dirs = null;
try
{
//Windows (Including UNC)
var windowsSep = query.LastIndexOf('\\');
if (windowsSep > -1)
{
var path = query.Substring(0, windowsSep + 1);
var dirsList = _diskProvider.GetDirectories(path).ToList();
if (Path.GetPathRoot(path).Equals(path, StringComparison.InvariantCultureIgnoreCase))
{
var setToRemove = new HashSet<string> { "$Recycle.Bin", "System Volume Information" };
dirsList.RemoveAll(x => setToRemove.Contains(new DirectoryInfo(x).Name));
}
dirs = dirsList;
}
//Unix
var index = query.LastIndexOf('/');
if (index > -1)
{
dirs = _diskProvider.GetDirectories(query.Substring(0, index + 1)).ToList();
}
}
catch (Exception)
{
//Swallow the exceptions so proper JSON is returned to the client (Empty results)
return new List<string>();
}
return dirs;
}
}
}

View File

@ -58,7 +58,7 @@ namespace NzbDrone.Common
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public virtual DateTime GetLastFolderWrite(string path) public DateTime GetLastFolderWrite(string path)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();
@ -78,7 +78,7 @@ namespace NzbDrone.Common
.Max(c => c.LastWriteTimeUtc); .Max(c => c.LastWriteTimeUtc);
} }
public virtual DateTime GetLastFileWrite(string path) public DateTime GetLastFileWrite(string path)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();
@ -89,7 +89,7 @@ namespace NzbDrone.Common
return new FileInfo(path).LastWriteTimeUtc; return new FileInfo(path).LastWriteTimeUtc;
} }
public virtual void EnsureFolder(string path) public void EnsureFolder(string path)
{ {
if (!FolderExists(path)) if (!FolderExists(path))
{ {
@ -97,13 +97,13 @@ namespace NzbDrone.Common
} }
} }
public virtual bool FolderExists(string path) public bool FolderExists(string path)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();
return Directory.Exists(path); return Directory.Exists(path);
} }
public virtual bool FolderExists(string path, bool caseSensitive) public bool FolderExists(string path, bool caseSensitive)
{ {
if (caseSensitive) if (caseSensitive)
{ {
@ -113,13 +113,13 @@ namespace NzbDrone.Common
return FolderExists(path); return FolderExists(path);
} }
public virtual bool FileExists(string path) public bool FileExists(string path)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();
return File.Exists(path); return File.Exists(path);
} }
public virtual bool FileExists(string path, bool caseSensitive) public bool FileExists(string path, bool caseSensitive)
{ {
if (caseSensitive) if (caseSensitive)
{ {
@ -129,28 +129,28 @@ namespace NzbDrone.Common
return FileExists(path); return FileExists(path);
} }
public virtual string[] GetDirectories(string path) public string[] GetDirectories(string path)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();
return Directory.GetDirectories(path); return Directory.GetDirectories(path);
} }
public virtual string[] GetFiles(string path, SearchOption searchOption) public string[] GetFiles(string path, SearchOption searchOption)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();
return Directory.GetFiles(path, "*.*", searchOption); return Directory.GetFiles(path, "*.*", searchOption);
} }
public virtual long GetFolderSize(string path) public long GetFolderSize(string path)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();
return GetFiles(path, SearchOption.AllDirectories).Sum(e => new FileInfo(e).Length); return GetFiles(path, SearchOption.AllDirectories).Sum(e => new FileInfo(e).Length);
} }
public virtual long GetFileSize(string path) public long GetFileSize(string path)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();
@ -161,14 +161,14 @@ namespace NzbDrone.Common
return fi.Length; return fi.Length;
} }
public virtual String CreateFolder(string path) public String CreateFolder(string path)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();
return Directory.CreateDirectory(path).FullName; return Directory.CreateDirectory(path).FullName;
} }
public virtual void CopyFolder(string source, string target) public void CopyFolder(string source, string target)
{ {
Ensure.That(() => source).IsValidPath(); Ensure.That(() => source).IsValidPath();
Ensure.That(() => target).IsValidPath(); Ensure.That(() => target).IsValidPath();
@ -176,7 +176,7 @@ namespace NzbDrone.Common
TransferFolder(source, target, TransferAction.Copy); TransferFolder(source, target, TransferAction.Copy);
} }
public virtual void MoveFolder(string source, string destination) public void MoveFolder(string source, string destination)
{ {
Ensure.That(() => source).IsValidPath(); Ensure.That(() => source).IsValidPath();
Ensure.That(() => destination).IsValidPath(); Ensure.That(() => destination).IsValidPath();
@ -237,7 +237,7 @@ namespace NzbDrone.Common
} }
} }
public virtual void DeleteFile(string path) public void DeleteFile(string path)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();
@ -245,7 +245,7 @@ namespace NzbDrone.Common
File.Delete(path); File.Delete(path);
} }
public virtual void MoveFile(string source, string destination) public void MoveFile(string source, string destination)
{ {
Ensure.That(() => source).IsValidPath(); Ensure.That(() => source).IsValidPath();
Ensure.That(() => destination).IsValidPath(); Ensure.That(() => destination).IsValidPath();
@ -264,14 +264,14 @@ namespace NzbDrone.Common
File.Move(source, destination); File.Move(source, destination);
} }
public virtual void DeleteFolder(string path, bool recursive) public void DeleteFolder(string path, bool recursive)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();
Directory.Delete(path, recursive); Directory.Delete(path, recursive);
} }
public virtual void InheritFolderPermissions(string filename) public void InheritFolderPermissions(string filename)
{ {
Ensure.That(() => filename).IsValidPath(); Ensure.That(() => filename).IsValidPath();
@ -280,7 +280,7 @@ namespace NzbDrone.Common
File.SetAccessControl(filename, fs); File.SetAccessControl(filename, fs);
} }
public virtual long GetAvilableSpace(string path) public long GetAvilableSpace(string path)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();
@ -327,14 +327,14 @@ namespace NzbDrone.Common
return 0; return 0;
} }
public virtual string ReadAllText(string filePath) public string ReadAllText(string filePath)
{ {
Ensure.That(() => filePath).IsValidPath(); Ensure.That(() => filePath).IsValidPath();
return File.ReadAllText(filePath); return File.ReadAllText(filePath);
} }
public virtual void WriteAllText(string filename, string contents) public void WriteAllText(string filename, string contents)
{ {
Ensure.That(() => filename).IsValidPath(); Ensure.That(() => filename).IsValidPath();
@ -349,21 +349,21 @@ namespace NzbDrone.Common
return String.Equals(firstPath.CleanFilePath(), secondPath.CleanFilePath(), StringComparison.InvariantCultureIgnoreCase); return String.Equals(firstPath.CleanFilePath(), secondPath.CleanFilePath(), StringComparison.InvariantCultureIgnoreCase);
} }
public virtual void FileSetLastWriteTimeUtc(string path, DateTime dateTime) public void FileSetLastWriteTimeUtc(string path, DateTime dateTime)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();
File.SetLastWriteTimeUtc(path, dateTime); File.SetLastWriteTimeUtc(path, dateTime);
} }
public virtual void FolderSetLastWriteTimeUtc(string path, DateTime dateTime) public void FolderSetLastWriteTimeUtc(string path, DateTime dateTime)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();
Directory.SetLastWriteTimeUtc(path, dateTime); Directory.SetLastWriteTimeUtc(path, dateTime);
} }
public virtual bool IsFileLocked(FileInfo file) public bool IsFileLocked(FileInfo file)
{ {
FileStream stream = null; FileStream stream = null;
@ -385,7 +385,7 @@ namespace NzbDrone.Common
return false; return false;
} }
public virtual string GetPathRoot(string path) public string GetPathRoot(string path)
{ {
Ensure.That(() => path).IsValidPath(); Ensure.That(() => path).IsValidPath();

View File

@ -66,6 +66,7 @@
<Compile Include="Composition\Container.cs" /> <Compile Include="Composition\Container.cs" />
<Compile Include="Composition\IContainer.cs" /> <Compile Include="Composition\IContainer.cs" />
<Compile Include="Composition\ContainerBuilderBase.cs" /> <Compile Include="Composition\ContainerBuilderBase.cs" />
<Compile Include="DirectoryLookupService.cs" />
<Compile Include="EnsureThat\Ensure.cs" /> <Compile Include="EnsureThat\Ensure.cs" />
<Compile Include="EnsureThat\EnsureBoolExtensions.cs" /> <Compile Include="EnsureThat\EnsureBoolExtensions.cs" />
<Compile Include="EnsureThat\EnsureCollectionExtensions.cs" /> <Compile Include="EnsureThat\EnsureCollectionExtensions.cs" />

View File

@ -109,7 +109,7 @@ namespace NzbDrone.Core.Test.MediaFileTests
Subject.Execute(new DownloadedEpisodesScanCommand()); Subject.Execute(new DownloadedEpisodesScanCommand());
Mocker.GetMock<DiskProvider>() Mocker.GetMock<IDiskProvider>()
.Verify(v => v.GetFolderSize(It.IsAny<String>()), Times.Never()); .Verify(v => v.GetFolderSize(It.IsAny<String>()), Times.Never());
} }

View File

@ -85,13 +85,13 @@ namespace NzbDrone.Core.Datastore
public IEnumerable<TModel> Get(IEnumerable<int> ids) public IEnumerable<TModel> Get(IEnumerable<int> ids)
{ {
var query = String.Format("Id IN ({0})", String.Join(",", ids)); var idList = ids.ToList();
var query = String.Format("Id IN ({0})", String.Join(",", idList));
var result = Query.Where(query).ToList(); var result = Query.Where(query).ToList();
if (result.Count != ids.Count()) if (result.Count != idList.Count())
{ {
throw new ApplicationException("Expected query to return {0} rows but returned {1}".Inject(ids.Count(), result.Count)); throw new ApplicationException("Expected query to return {0} rows but returned {1}".Inject(idList.Count(), result.Count));
} }
return result; return result;