From cad8b37df8389a7eac568cf23fb8425554c137da Mon Sep 17 00:00:00 2001 From: Robin Dadswell <19610103+RobinDadswell@users.noreply.github.com> Date: Mon, 12 Apr 2021 16:38:01 +0100 Subject: [PATCH] New: Health Check for Downloads to Root Folder already implemented within Radarr (cherry picked from commit 88780f33a4c5032aaa151aaae7090371beb42f33) --- .../DownloadClientRootFolderCheckFixture.cs | 96 +++++++++++++++++++ .../Checks/HealthCheckFixtureExtensions.cs | 7 +- .../Checks/DownloadClientRootFolderCheck.cs | 67 +++++++++++++ 3 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 src/NzbDrone.Core.Test/HealthCheck/Checks/DownloadClientRootFolderCheckFixture.cs create mode 100644 src/NzbDrone.Core/HealthCheck/Checks/DownloadClientRootFolderCheck.cs diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/DownloadClientRootFolderCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/DownloadClientRootFolderCheckFixture.cs new file mode 100644 index 000000000..cc4dd431c --- /dev/null +++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/DownloadClientRootFolderCheckFixture.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using Moq; +using NUnit.Framework; +using NzbDrone.Common.Disk; +using NzbDrone.Core.Download; +using NzbDrone.Core.Download.Clients; +using NzbDrone.Core.HealthCheck.Checks; +using NzbDrone.Core.RootFolders; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Test.Common; + +namespace NzbDrone.Core.Test.HealthCheck.Checks +{ + [TestFixture] + public class DownloadClientRootFolderCheckFixture : CoreTest + { + private readonly string _downloadRootPath = @"c:\Test".AsOsAgnostic(); + + private DownloadClientInfo _clientStatus; + private Mock _downloadClient; + + private static Exception[] DownloadClientExceptions = + { + new DownloadClientUnavailableException("error"), + new DownloadClientAuthenticationException("error"), + new DownloadClientException("error") + }; + + [SetUp] + public void Setup() + { + _clientStatus = new DownloadClientInfo + { + IsLocalhost = true, + OutputRootFolders = new List { new OsPath(_downloadRootPath) } + }; + + _downloadClient = Mocker.GetMock(); + _downloadClient.Setup(s => s.Definition) + .Returns(new DownloadClientDefinition { Name = "Test" }); + + _downloadClient.Setup(s => s.GetStatus()) + .Returns(_clientStatus); + + Mocker.GetMock() + .Setup(s => s.GetDownloadClients()) + .Returns(new IDownloadClient[] { _downloadClient.Object }); + + Mocker.GetMock() + .Setup(x => x.FolderExists(It.IsAny())) + .Returns(true); + + Mocker.GetMock() + .Setup(x => x.FolderWritable(It.IsAny())) + .Returns(true); + } + + private void GivenRootFolder(string folder) + { + Mocker.GetMock() + .Setup(s => s.All()) + .Returns(new List { new RootFolder { Path = folder.AsOsAgnostic() } }); + } + + [Test] + public void should_return_downloads_in_root_folder_if_downloading_to_root_folder() + { + GivenRootFolder(_downloadRootPath); + + Subject.Check().ShouldBeWarning(wikiFragment: "downloads_in_root_folder"); + } + + [Test] + public void should_return_ok_if_not_downloading_to_root_folder() + { + string rootFolderPath = "c:\\Test2".AsOsAgnostic(); + + GivenRootFolder(rootFolderPath); + + Subject.Check().ShouldBeOk(); + } + + [Test] + [TestCaseSource("DownloadClientExceptions")] + public void should_return_ok_if_client_throws_downloadclientexception(Exception ex) + { + _downloadClient.Setup(s => s.GetStatus()) + .Throws(ex); + + Subject.Check().ShouldBeOk(); + + ExceptionVerification.ExpectedErrors(0); + } + } +} diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/HealthCheckFixtureExtensions.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/HealthCheckFixtureExtensions.cs index 7488ff08a..5b0400354 100644 --- a/src/NzbDrone.Core.Test/HealthCheck/Checks/HealthCheckFixtureExtensions.cs +++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/HealthCheckFixtureExtensions.cs @@ -21,7 +21,7 @@ public static void ShouldBeNotice(this Core.HealthCheck.HealthCheck result, stri } } - public static void ShouldBeWarning(this Core.HealthCheck.HealthCheck result, string message = null) + public static void ShouldBeWarning(this Core.HealthCheck.HealthCheck result, string message = null, string wikiFragment = null) { result.Type.Should().Be(HealthCheckResult.Warning); @@ -29,6 +29,11 @@ public static void ShouldBeWarning(this Core.HealthCheck.HealthCheck result, str { result.Message.Should().Contain(message); } + + if (wikiFragment.IsNotNullOrWhiteSpace()) + { + result.WikiUrl.Fragment.Should().Be(wikiFragment); + } } public static void ShouldBeError(this Core.HealthCheck.HealthCheck result, string message = null) diff --git a/src/NzbDrone.Core/HealthCheck/Checks/DownloadClientRootFolderCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/DownloadClientRootFolderCheck.cs new file mode 100644 index 000000000..5c802f042 --- /dev/null +++ b/src/NzbDrone.Core/HealthCheck/Checks/DownloadClientRootFolderCheck.cs @@ -0,0 +1,67 @@ +using System; +using System.Linq; +using NLog; +using NzbDrone.Common.Extensions; +using NzbDrone.Core.Datastore.Events; +using NzbDrone.Core.Download; +using NzbDrone.Core.Download.Clients; +using NzbDrone.Core.RemotePathMappings; +using NzbDrone.Core.RootFolders; +using NzbDrone.Core.ThingiProvider.Events; + +namespace NzbDrone.Core.HealthCheck.Checks +{ + [CheckOn(typeof(ProviderUpdatedEvent))] + [CheckOn(typeof(ProviderDeletedEvent))] + [CheckOn(typeof(ModelEvent))] + [CheckOn(typeof(ModelEvent))] + + public class DownloadClientRootFolderCheck : HealthCheckBase, IProvideHealthCheck + { + private readonly IProvideDownloadClient _downloadClientProvider; + private readonly IRootFolderService _rootFolderService; + private readonly Logger _logger; + + public DownloadClientRootFolderCheck(IProvideDownloadClient downloadClientProvider, + IRootFolderService rootFolderService, + Logger logger) + { + _downloadClientProvider = downloadClientProvider; + _rootFolderService = rootFolderService; + _logger = logger; + } + + public override HealthCheck Check() + { + var clients = _downloadClientProvider.GetDownloadClients(); + var rootFolders = _rootFolderService.All(); + + foreach (var client in clients) + { + try + { + var status = client.GetStatus(); + var folders = status.OutputRootFolders; + + foreach (var folder in folders) + { + if (rootFolders.Any(r => r.Path.PathEquals(folder.FullPath))) + { + return new HealthCheck(GetType(), HealthCheckResult.Warning, string.Format("Download client {0} places downloads in the root folder {1}. You should not download to a root folder.", client.Definition.Name, folder.FullPath), "#downloads_in_root_folder"); + } + } + } + catch (DownloadClientException ex) + { + _logger.Debug(ex, "Unable to communicate with {0}", client.Definition.Name); + } + catch (Exception ex) + { + _logger.Error(ex, "Unknown error occured in DownloadClientRootFolderCheck HealthCheck"); + } + } + + return new HealthCheck(GetType()); + } + } +}