Fixed: Install Update UI should now report an error if the application folder is not writable instead of failing silently.

This commit is contained in:
Taloth Saldono 2015-01-21 23:57:35 +01:00
parent 11803afc39
commit 3a938e18fa
6 changed files with 74 additions and 25 deletions

View File

@ -13,7 +13,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
{
private const string DRONE_FACTORY_FOLDER = @"C:\Test\Unsorted";
private void GivenDroneFactoryFolder(bool exists = false)
private void GivenDroneFactoryFolder(bool exists = false, bool writable = true)
{
Mocker.GetMock<IConfigService>()
.SetupGet(s => s.DownloadedEpisodesFolder)
@ -22,6 +22,10 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.FolderExists(DRONE_FACTORY_FOLDER))
.Returns(exists);
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.FolderWritable(It.IsAny<String>()))
.Returns(exists && writable);
}
[Test]
@ -35,11 +39,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
[Test]
public void should_return_error_when_unable_to_write_to_drone_factory_folder()
{
GivenDroneFactoryFolder(true);
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.WriteAllText(It.IsAny<String>(), It.IsAny<String>()))
.Throws<Exception>();
GivenDroneFactoryFolder(true, false);
Subject.Check().ShouldBeError();
}

View File

@ -21,9 +21,9 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
.Setup(s => s.StartUpFolder)
.Returns(@"C:\NzbDrone");
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.WriteAllText(It.IsAny<String>(), It.IsAny<String>()))
.Throws<Exception>();
Mocker.GetMock<NzbDrone.Common.Disk.IDiskProvider>()
.Setup(c => c.FolderWritable(Moq.It.IsAny<string>()))
.Returns(false);
Subject.Check().ShouldBeError();
}
@ -41,9 +41,9 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
.Setup(s => s.StartUpFolder)
.Returns(@"/opt/nzbdrone");
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.WriteAllText(It.IsAny<String>(), It.IsAny<String>()))
.Throws<Exception>();
Mocker.GetMock<NzbDrone.Common.Disk.IDiskProvider>()
.Setup(c => c.FolderWritable(Moq.It.IsAny<string>()))
.Returns(false);
Subject.Check().ShouldBeError();
}

View File

@ -11,6 +11,7 @@ using NzbDrone.Common.Http;
using NzbDrone.Common.Model;
using NzbDrone.Common.Processes;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Update;
using NzbDrone.Core.Update.Commands;
@ -59,6 +60,10 @@ namespace NzbDrone.Core.Test.UpdateTests
Mocker.GetMock<IProcessProvider>().Setup(c => c.GetCurrentProcess()).Returns(new ProcessInfo { Id = 12 });
Mocker.GetMock<IRuntimeInfo>().Setup(c => c.ExecutingApplication).Returns(@"C:\Test\NzbDrone.exe");
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.FolderWritable(It.IsAny<string>()))
.Returns(true);
_sandboxFolder = Mocker.GetMock<IAppFolderInfo>().Object.GetUpdateSandboxFolder();
}
@ -259,6 +264,36 @@ namespace NzbDrone.Core.Test.UpdateTests
ExceptionVerification.ExpectedErrors(1);
}
[Test]
public void should_log_error_when_startup_folder_is_not_writable()
{
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.FolderWritable(It.IsAny<string>()))
.Returns(false);
var updateArchive = Path.Combine(_sandboxFolder, _updatePackage.FileName);
Subject.Execute(new ApplicationUpdateCommand());
Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(_updatePackage.Url, updateArchive), Times.Never());
ExceptionVerification.ExpectedErrors(1);
}
[Test]
public void should_throw_when_install_cannot_be_started()
{
Mocker.GetMock<IDiskProvider>()
.Setup(c => c.FolderWritable(It.IsAny<string>()))
.Returns(false);
var updateArchive = Path.Combine(_sandboxFolder, _updatePackage.FileName);
Assert.Throws<NzbDroneClientException>(() => Subject.Execute(new InstallUpdateCommand() { UpdatePackage = _updatePackage }));
Mocker.GetMock<IHttpClient>().Verify(c => c.DownloadFile(_updatePackage.Url, updateArchive), Times.Never());
ExceptionVerification.ExpectedErrors(1);
}
[TearDown]
public void TearDown()
{

View File

@ -98,20 +98,17 @@ namespace NzbDrone.Core.Download
{
return new NzbDroneValidationFailure(propertyName, "Folder does not exist")
{
DetailedDescription = "The folder you specified does not exist or is inaccessible. Please verify the folder permissions for the user account that is used to execute NzbDrone."
DetailedDescription = string.Format("The folder you specified does not exist or is inaccessible. Please verify the folder permissions for the user account '{0}', which is used to execute Sonarr.", Environment.UserName)
};
}
if (mustBeWritable)
if (mustBeWritable && !_diskProvider.FolderWritable(folder))
{
if (!_diskProvider.FolderWritable(folder))
_logger.Error("Folder '{0}' is not writable.", folder);
return new NzbDroneValidationFailure(propertyName, "Unable to write to folder")
{
_logger.Error("Folder '{0}' is not writable.", folder);
return new NzbDroneValidationFailure(propertyName, "Unable to write to folder")
{
DetailedDescription = "The folder you specified is not writable. Please verify the folder permissions for the user account that is used to execute NzbDrone."
};
}
DetailedDescription = string.Format("The folder you specified is not writable. Please verify the folder permissions for the user account '{0}', which is used to execute Sonarr.", Environment.UserName)
};
}
return null;

View File

@ -31,7 +31,7 @@ namespace NzbDrone.Core.HealthCheck.Checks
{
if (!_diskProvider.FolderWritable(_appFolderInfo.StartUpFolder))
{
return new HealthCheck(GetType(), HealthCheckResult.Error, "Unable to update, running from write-protected folder");
return new HealthCheck(GetType(), HealthCheckResult.Error, string.Format("Cannot install update because startup folder '{0}' is not writable by the user '{1}'.", _appFolderInfo.StartUpFolder, Environment.UserName));
}
}

View File

@ -10,6 +10,7 @@ using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Common.Processes;
using NzbDrone.Core.Backup;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Update.Commands;
@ -61,12 +62,20 @@ namespace NzbDrone.Core.Update
_logger = logger;
}
private void InstallUpdate(UpdatePackage updatePackage)
private bool InstallUpdate(UpdatePackage updatePackage)
{
try
{
EnsureAppDataSafety();
if (OsInfo.IsWindows || _configFileProvider.UpdateMechanism != UpdateMechanism.Script)
{
if (!_diskProvider.FolderWritable(_appFolderInfo.StartUpFolder))
{
throw new ApplicationException(string.Format("Cannot install update because startup folder '{0}' is not writable by the user '{1}'.", _appFolderInfo.StartUpFolder, Environment.UserName));
}
}
var updateSandboxFolder = _appFolderInfo.GetUpdateSandboxFolder();
var packageDestination = Path.Combine(updateSandboxFolder, updatePackage.FileName);
@ -100,7 +109,7 @@ namespace NzbDrone.Core.Update
if (OsInfo.IsNotWindows && _configFileProvider.UpdateMechanism == UpdateMechanism.Script)
{
InstallUpdateWithScript(updateSandboxFolder);
return;
return true;
}
_logger.Info("Preparing client");
@ -111,10 +120,13 @@ namespace NzbDrone.Core.Update
_logger.ProgressInfo("NzbDrone will restart shortly.");
_processProvider.Start(_appFolderInfo.GetUpdateClientExePath(), GetUpdaterArgs(updateSandboxFolder));
return true;
}
catch (Exception ex)
{
_logger.ErrorException("Update process failed", ex);
return false;
}
}
@ -170,7 +182,12 @@ namespace NzbDrone.Core.Update
public void Execute(InstallUpdateCommand message)
{
InstallUpdate(message.UpdatePackage);
var success = InstallUpdate(message.UpdatePackage);
if (!success)
{
throw new NzbDroneClientException(System.Net.HttpStatusCode.Conflict, "Failed to install update");
}
}
}
}