diff --git a/src/NzbDrone.Core.Test/DiskSpace/DiskSpaceServiceFixture.cs b/src/NzbDrone.Core.Test/DiskSpace/DiskSpaceServiceFixture.cs new file mode 100644 index 000000000..3e43fbe0c --- /dev/null +++ b/src/NzbDrone.Core.Test/DiskSpace/DiskSpaceServiceFixture.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common.Disk; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.DiskSpace; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Movies; +using NzbDrone.Test.Common; + +namespace NzbDrone.Core.Test.DiskSpace +{ + [TestFixture] + public class DiskSpaceServiceFixture : CoreTest + { + private string _moviesFolder; + private string _moviesFolder2; + private string _droneFactoryFolder; + + [SetUp] + public void SetUp() + { + _moviesFolder = @"G:\fasdlfsdf\movies".AsOsAgnostic(); + _moviesFolder2 = @"G:\fasdlfsdf\movies2".AsOsAgnostic(); + _droneFactoryFolder = @"G:\dronefactory".AsOsAgnostic(); + + Mocker.GetMock() + .Setup(v => v.GetMounts()) + .Returns(new List()); + + Mocker.GetMock() + .Setup(v => v.GetPathRoot(It.IsAny())) + .Returns(@"G:\".AsOsAgnostic()); + + Mocker.GetMock() + .Setup(v => v.GetAvailableSpace(It.IsAny())) + .Returns(0); + + Mocker.GetMock() + .Setup(v => v.GetTotalSize(It.IsAny())) + .Returns(0); + + GivenMovies(); + } + + private void GivenMovies(params Movie[] movies) + { + Mocker.GetMock() + .Setup(v => v.GetAllMovies()) + .Returns(movies.ToList()); + } + + private void GivenExistingFolder(string folder) + { + Mocker.GetMock() + .Setup(v => v.FolderExists(folder)) + .Returns(true); + } + + [Test] + public void should_check_diskspace_for_movies_folders() + { + GivenMovies(new Movie { Path = _moviesFolder }); + + GivenExistingFolder(_moviesFolder); + + var freeSpace = Subject.GetFreeSpace(); + + freeSpace.Should().NotBeEmpty(); + } + + [Test] + public void should_check_diskspace_for_same_root_folder_only_once() + { + GivenMovies(new Movie { Path = _moviesFolder }, new Movie { Path = _moviesFolder2 }); + + GivenExistingFolder(_moviesFolder); + GivenExistingFolder(_moviesFolder2); + + var freeSpace = Subject.GetFreeSpace(); + + freeSpace.Should().HaveCount(1); + + Mocker.GetMock() + .Verify(v => v.GetAvailableSpace(It.IsAny()), Times.Once()); + } + + [Test] + [Ignore("Unknown failure")] + public void should_not_check_diskspace_for_missing_movies_folders() + { + GivenMovies(new Movie { Path = _moviesFolder }); + + var freeSpace = Subject.GetFreeSpace(); + + freeSpace.Should().BeEmpty(); + + Mocker.GetMock() + .Verify(v => v.GetAvailableSpace(It.IsAny()), Times.Never()); + } + + [Test] + public void should_check_diskspace_for_dronefactory_folder() + { + Mocker.GetMock() + .SetupGet(v => v.DownloadedMoviesFolder) + .Returns(_droneFactoryFolder); + + GivenExistingFolder(_droneFactoryFolder); + + var freeSpace = Subject.GetFreeSpace(); + + freeSpace.Should().NotBeEmpty(); + } + + [Test] + [Ignore("Unknown failure")] + public void should_not_check_diskspace_for_missing_dronefactory_folder() + { + Mocker.GetMock() + .SetupGet(v => v.DownloadedMoviesFolder) + .Returns(_droneFactoryFolder); + + var freeSpace = Subject.GetFreeSpace(); + + freeSpace.Should().BeEmpty(); + + Mocker.GetMock() + .Verify(v => v.GetAvailableSpace(It.IsAny()), Times.Never()); + } + + [TestCase("/boot")] + [TestCase("/var/lib/rancher")] + [TestCase("/var/lib/rancher/volumes")] + [TestCase("/var/lib/kubelet")] + [TestCase("/var/lib/docker")] + [TestCase("/some/place/docker/aufs")] + [TestCase("/etc/network")] + [TestCase("/snap/filebot/9")] + [TestCase("/snap/core/5145")] + public void should_not_check_diskspace_for_irrelevant_mounts(string path) + { + var mount = new Mock(); + mount.SetupGet(v => v.RootDirectory).Returns(path); + mount.SetupGet(v => v.DriveType).Returns(System.IO.DriveType.Fixed); + + Mocker.GetMock() + .Setup(v => v.GetMounts()) + .Returns(new List { mount.Object }); + + var freeSpace = Subject.GetFreeSpace(); + + freeSpace.Should().BeEmpty(); + } + } +} diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index a7172a0a7..695786ddb 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -168,6 +168,7 @@ + diff --git a/src/NzbDrone.Core/DiskSpace/DiskSpaceService.cs b/src/NzbDrone.Core/DiskSpace/DiskSpaceService.cs index ee5065f81..9a603b7da 100644 --- a/src/NzbDrone.Core/DiskSpace/DiskSpaceService.cs +++ b/src/NzbDrone.Core/DiskSpace/DiskSpaceService.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; @@ -22,6 +23,8 @@ namespace NzbDrone.Core.DiskSpace private readonly IDiskProvider _diskProvider; private readonly Logger _logger; + private static readonly Regex _regexSpecialDrive = new Regex("^/var/lib/(docker|rancher|kubelet)(/|$)|^/(boot|etc|snap)(/|$)|/docker(/var)?/aufs(/|$)", RegexOptions.Compiled); + public DiskSpaceService(IMovieService movieService, IConfigService configService, IDiskProvider diskProvider, Logger logger) { _movieService = movieService; @@ -59,7 +62,10 @@ namespace NzbDrone.Core.DiskSpace private IEnumerable GetFixedDisksFreeSpace() { - return GetDiskSpace(_diskProvider.GetMounts().Where(d => d.DriveType == DriveType.Fixed).Select(d => d.RootDirectory), true); + return GetDiskSpace(_diskProvider.GetMounts() + .Where(d => d.DriveType == DriveType.Fixed) + .Where(d => !_regexSpecialDrive.IsMatch(d.RootDirectory)) + .Select(d => d.RootDirectory), true); } private IEnumerable GetDiskSpace(IEnumerable paths, bool suppressWarnings = false) diff --git a/src/NzbDrone.Mono/Disk/DiskProvider.cs b/src/NzbDrone.Mono/Disk/DiskProvider.cs index 2f1b4c93a..6be2ee4a3 100644 --- a/src/NzbDrone.Mono/Disk/DiskProvider.cs +++ b/src/NzbDrone.Mono/Disk/DiskProvider.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -189,8 +189,6 @@ namespace NzbDrone.Mono.Disk } return g.gr_gid; - - } } } diff --git a/src/NzbDrone.Mono/Disk/ProcMountProvider.cs b/src/NzbDrone.Mono/Disk/ProcMountProvider.cs index 48dc9f0a9..f810fd89f 100644 --- a/src/NzbDrone.Mono/Disk/ProcMountProvider.cs +++ b/src/NzbDrone.Mono/Disk/ProcMountProvider.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -111,6 +111,18 @@ namespace NzbDrone.Mono.Disk return null; } + if (mount.StartsWith("/var/lib/")) + { + // Could be /var/lib/docker when docker uses zfs. Very unlikely that a useful mount is located in /var/lib. + return null; + } + + if (mount.StartsWith("/snap/")) + { + // Mount point for snap packages + return null; + } + var driveType = FindDriveType.Find(type); if (name.StartsWith("/dev/") || GetFileSystems().GetValueOrDefault(type, false))