More autoupdate code.

pull/4/head
kay.one 13 years ago
parent 95460b2134
commit 1270e464b3

@ -2,12 +2,20 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using NLog; using NLog;
namespace NzbDrone.Common namespace NzbDrone.Common
{ {
public class DiskProvider public class DiskProvider
{ {
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetDiskFreeSpaceEx(string lpDirectoryName,
out ulong lpFreeBytesAvailable,
out ulong lpTotalNumberOfBytes,
out ulong lpTotalNumberOfFreeBytes);
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public virtual bool FolderExists(string path) public virtual bool FolderExists(string path)
@ -47,6 +55,25 @@ namespace NzbDrone.Common
return Directory.CreateDirectory(path).FullName; return Directory.CreateDirectory(path).FullName;
} }
public virtual void CopyDirectory(string source, string target)
{
Logger.Trace("Copying {0} -> {1}", source, target);
var sourceFolder = new DirectoryInfo(source);
var targetFolder = new DirectoryInfo(target);
if (!targetFolder.Exists)
{
targetFolder.Create();
}
foreach (var file in sourceFolder.GetFiles("*.*", SearchOption.AllDirectories))
{
var destFile = Path.Combine(target, file.Name);
file.CopyTo(destFile, true);
}
}
public virtual void DeleteFile(string path) public virtual void DeleteFile(string path)
{ {
File.Delete(path); File.Delete(path);
@ -77,30 +104,25 @@ namespace NzbDrone.Common
Directory.Move(source, destination); Directory.Move(source, destination);
} }
public virtual void CopyDirectory(string source, string target)
{
Logger.Trace("Copying {0} -> {1}", source, target);
var sourceFolder = new DirectoryInfo(source);
var targetFolder = new DirectoryInfo(target);
if (!targetFolder.Exists)
{
targetFolder.Create();
}
foreach (var file in sourceFolder.GetFiles("*.*", SearchOption.AllDirectories))
{
var destFile = Path.Combine(target, file.Name);
file.CopyTo(destFile, true);
}
}
public virtual void InheritFolderPermissions(string filename) public virtual void InheritFolderPermissions(string filename)
{ {
var fs = File.GetAccessControl(filename); var fs = File.GetAccessControl(filename);
fs.SetAccessRuleProtection(false, false); fs.SetAccessRuleProtection(false, false);
File.SetAccessControl(filename, fs); File.SetAccessControl(filename, fs);
} }
public virtual ulong FreeDiskSpace(DirectoryInfo directoryInfo)
{
ulong freeBytesAvailable;
ulong totalNumberOfBytes;
ulong totalNumberOfFreeBytes;
bool success = GetDiskFreeSpaceEx(directoryInfo.FullName, out freeBytesAvailable, out totalNumberOfBytes,
out totalNumberOfFreeBytes);
if (!success)
throw new System.ComponentModel.Win32Exception();
return freeBytesAvailable;
}
} }
} }

@ -17,7 +17,8 @@ namespace NzbDrone.Common
private const string NZBDRONE_DB_FILE = "nzbdrone.sdf"; private const string NZBDRONE_DB_FILE = "nzbdrone.sdf";
private const string LOG_DB_FILE = "log.sdf"; private const string LOG_DB_FILE = "log.sdf";
public const string UPDATE_SANDBOX_FOLDER_NAME = "nzbdrone_update"; private const string UPDATE_SANDBOX_FOLDER_NAME = "nzbdrone_update";
private const string UPDATE_BACKUP_FOLDER_NAME = "nzbdrone_backup";
private readonly string _applicationPath; private readonly string _applicationPath;
@ -103,9 +104,19 @@ namespace NzbDrone.Common
get { return Path.Combine(AppData, "Cache"); } get { return Path.Combine(AppData, "Cache"); }
} }
public string UpdateSandboxFolder public virtual string UpdateSandboxFolder
{ {
get { return Path.Combine(SystemTemp, UPDATE_SANDBOX_FOLDER_NAME); } get { return Path.Combine(SystemTemp, UPDATE_SANDBOX_FOLDER_NAME); }
} }
public virtual string UpdatePackageFolder
{
get { return Path.Combine(UPDATE_SANDBOX_FOLDER_NAME, "NzbDrone"); }
}
public virtual string UpdateBackUpFolder
{
get { return Path.Combine(UpdateSandboxFolder, UPDATE_BACKUP_FOLDER_NAME); }
}
} }
} }

@ -22,6 +22,16 @@ namespace NzbDrone.Common
s => String.Equals(s.ServiceName, name, StringComparison.InvariantCultureIgnoreCase)); s => String.Equals(s.ServiceName, name, StringComparison.InvariantCultureIgnoreCase));
} }
public virtual bool IsServiceRunning(string name)
{
Logger.Debug("Checking if '{0}' service is running", name);
var service = ServiceController.GetServices()
.SingleOrDefault(s => String.Equals(s.ServiceName, name, StringComparison.InvariantCultureIgnoreCase));
return service != null && service.Status == ServiceControllerStatus.Running;
}
public virtual void Install(string serviceName) public virtual void Install(string serviceName)
{ {

@ -11,7 +11,6 @@ using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Providers.Jobs; using NzbDrone.Core.Providers.Jobs;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using DiskProvider = NzbDrone.Core.Providers.Core.DiskProvider;
namespace NzbDrone.Core.Test.JobTests namespace NzbDrone.Core.Test.JobTests
{ {

@ -12,10 +12,10 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskProviderTests
[Test] [Test]
public void Should_extract_to_correct_folder() public void Should_extract_to_correct_folder()
{ {
var diskProvider = new DiskProvider(); var archiveProvider = new ArchiveProvider();
var destination = Path.Combine(TempFolder, "destination"); var destination = Path.Combine(TempFolder, "destination");
diskProvider.ExtractArchive(GetTestFilePath("TestArchive.zip"), destination); archiveProvider.ExtractArchive(GetTestFilePath("TestArchive.zip"), destination);
var destinationFolder = new DirectoryInfo(destination); var destinationFolder = new DirectoryInfo(destination);

@ -7,6 +7,7 @@ using AutoMoq;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;

@ -4,6 +4,7 @@ using AutoMoq;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;

@ -5,6 +5,7 @@ using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;

@ -6,6 +6,7 @@ using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;

@ -7,6 +7,7 @@ using AutoMoq;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;

@ -6,6 +6,7 @@ using AutoMoq;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;

@ -1,29 +1,34 @@
using System; using System;
using System.IO; using System.IO;
using AutoMoq;
using FluentAssertions; using FluentAssertions;
using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using DiskProvider = NzbDrone.Core.Providers.Core.DiskProvider;
namespace NzbDrone.Core.Test.ProviderTests.UpdateProviderTests namespace NzbDrone.Core.Test.ProviderTests.UpdateProviderTests
{ {
[TestFixture] [TestFixture]
internal class PreformUpdateFixture : TestBase internal class PreformUpdateFixture : TestBase
{ {
private AutoMoqer _mocker = null;
private string SandBoxPath;
[SetUp] [SetUp]
public void setup() public void setup()
{ {
_mocker = new AutoMoqer(MockBehavior.Strict); WithStrictMocker();
_mocker.GetMock<PathProvider>() Mocker.GetMock<PathProvider>()
.SetupGet(c => c.SystemTemp).Returns(TempFolder); .SetupGet(c => c.UpdateSandboxFolder).Returns(Path.Combine(TempFolder, "NzbDrone_update"));
SandBoxPath = Mocker.GetMock<PathProvider>().Object.UpdateSandboxFolder;
Mocker.GetMock<PathProvider>()
.SetupGet(c => c.UpdatePackageFolder).Returns(Path.Combine(SandBoxPath, "NzbDrone"));
} }
@ -38,21 +43,20 @@ namespace NzbDrone.Core.Test.ProviderTests.UpdateProviderTests
Version = new Version("0.6.0.2031") Version = new Version("0.6.0.2031")
}; };
_mocker.GetMock<HttpProvider>().Setup( Mocker.GetMock<HttpProvider>().Setup(
c => c.DownloadFile(updatePackage.Url, Path.Combine(TempFolder, PathProvider.UPDATE_SANDBOX_FOLDER_NAME, updatePackage.FileName))); c => c.DownloadFile(updatePackage.Url, Path.Combine(SandBoxPath, updatePackage.FileName)));
_mocker.GetMock<DiskProvider>().Setup( Mocker.GetMock<ArchiveProvider>().Setup(
c => c.ExtractArchive(Path.Combine(TempFolder, PathProvider.UPDATE_SANDBOX_FOLDER_NAME, updatePackage.FileName), c => c.ExtractArchive(Path.Combine(SandBoxPath, updatePackage.FileName), SandBoxPath));
Path.Combine(TempFolder, PathProvider.UPDATE_SANDBOX_FOLDER_NAME)));
_mocker.Resolve<UpdateProvider>().PreformUpdate(updatePackage); Mocker.Resolve<UpdateProvider>().StartUpgrade(updatePackage);
} }
[Test] [Test]
public void Should_download_and_extract_to_temp_folder() public void Should_download_and_extract_to_temp_folder()
{ {
var updateSubFolder = new DirectoryInfo(Path.Combine(TempFolder, PathProvider.UPDATE_SANDBOX_FOLDER_NAME)); var updateSubFolder = new DirectoryInfo(SandBoxPath);
var updatePackage = new UpdatePackage var updatePackage = new UpdatePackage
{ {
@ -65,9 +69,10 @@ namespace NzbDrone.Core.Test.ProviderTests.UpdateProviderTests
//Act //Act
updateSubFolder.Exists.Should().BeFalse(); updateSubFolder.Exists.Should().BeFalse();
_mocker.Resolve<HttpProvider>(); Mocker.Resolve<HttpProvider>();
_mocker.Resolve<DiskProvider>(); Mocker.Resolve<DiskProvider>();
_mocker.Resolve<UpdateProvider>().PreformUpdate(updatePackage); Mocker.Resolve<ArchiveProvider>();
Mocker.Resolve<UpdateProvider>().StartUpgrade(updatePackage);
updateSubFolder.Refresh(); updateSubFolder.Refresh();
//Assert //Assert

@ -1,122 +1,25 @@
using System; using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Ionic.Zip; using Ionic.Zip;
using NLog; using NLog;
namespace NzbDrone.Core.Providers.Core namespace NzbDrone.Core.Providers.Core
{ {
public class DiskProvider public class ArchiveProvider
{ {
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static readonly Logger logger = LogManager.GetCurrentClassLogger();
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetDiskFreeSpaceEx(string lpDirectoryName,
out ulong lpFreeBytesAvailable,
out ulong lpTotalNumberOfBytes,
out ulong lpTotalNumberOfFreeBytes);
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public virtual bool FolderExists(string path)
{
return Directory.Exists(path);
}
public virtual bool FileExists(string path)
{
return File.Exists(path);
}
public virtual string[] GetDirectories(string path)
{
return Directory.GetDirectories(path);
}
public virtual string[] GetFiles(string path, SearchOption searchOption)
{
return Directory.GetFiles(path, "*.*", searchOption);
}
public virtual long GetDirectorySize(string path)
{
return GetFiles(path, SearchOption.AllDirectories).Sum(e => new FileInfo(e).Length);
}
public virtual long GetSize(string path)
{
var fi = new FileInfo(path);
return fi.Length;
//return new FileInfo(path).Length;
}
public virtual String CreateDirectory(string path)
{
return Directory.CreateDirectory(path).FullName;
}
public virtual void DeleteFile(string path)
{
File.Delete(path);
}
public virtual void MoveFile(string sourcePath, string destinationPath)
{
File.Move(sourcePath, destinationPath);
}
public virtual void DeleteFolder(string path, bool recursive)
{
Directory.Delete(path, recursive);
}
public virtual DateTime DirectoryDateCreated(string path)
{
return Directory.GetCreationTime(path);
}
public virtual IEnumerable<FileInfo> GetFileInfos(string path, string pattern, SearchOption searchOption)
{
return new DirectoryInfo(path).GetFiles(pattern, searchOption);
}
public virtual void MoveDirectory(string source, string destination)
{
Directory.Move(source, destination);
}
public virtual void ExtractArchive(string compressedFile, string destination) public virtual void ExtractArchive(string compressedFile, string destination)
{ {
Logger.Trace("Extracting archive [{0}] to [{1}]", compressedFile, destination); logger.Trace("Extracting archive [{0}] to [{1}]", compressedFile, destination);
using (ZipFile zipFile = ZipFile.Read(compressedFile)) using (ZipFile zipFile = ZipFile.Read(compressedFile))
{ {
zipFile.ExtractAll(destination); zipFile.ExtractAll(destination);
} }
Logger.Trace("Extraction complete."); logger.Trace("Extraction complete.");
} }
public virtual void InheritFolderPermissions(string filename)
{
var fs = File.GetAccessControl(filename);
fs.SetAccessRuleProtection(false, false);
File.SetAccessControl(filename, fs);
}
public virtual ulong FreeDiskSpace(DirectoryInfo directoryInfo)
{
ulong freeBytesAvailable;
ulong totalNumberOfBytes;
ulong totalNumberOfFreeBytes;
bool success = GetDiskFreeSpaceEx(directoryInfo.FullName, out freeBytesAvailable, out totalNumberOfBytes,
out totalNumberOfFreeBytes);
if (!success)
throw new System.ComponentModel.Win32Exception();
return freeBytesAvailable;
}
} }
} }

@ -4,6 +4,7 @@ using System.IO;
using System.Linq; using System.Linq;
using Ninject; using Ninject;
using NLog; using NLog;
using NzbDrone.Common;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;

@ -8,7 +8,6 @@ using NzbDrone.Common;
using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using DiskProvider = NzbDrone.Core.Providers.Core.DiskProvider;
namespace NzbDrone.Core.Providers.Jobs namespace NzbDrone.Core.Providers.Jobs
{ {

@ -1,6 +1,7 @@
using System; using System;
using NLog; using NLog;
using Ninject; using Ninject;
using NzbDrone.Common;
using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;

@ -3,6 +3,7 @@ using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using NLog; using NLog;
using Ninject; using Ninject;
using NzbDrone.Common;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using Ninject; using Ninject;
using NLog; using NLog;
using NzbDrone.Common;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using PetaPoco; using PetaPoco;

@ -2,14 +2,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using NLog; using NLog;
using Ninject; using Ninject;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using DiskProvider = NzbDrone.Core.Providers.Core.DiskProvider;
namespace NzbDrone.Core.Providers namespace NzbDrone.Core.Providers
{ {
@ -20,6 +19,7 @@ namespace NzbDrone.Core.Providers
private readonly EnviromentProvider _enviromentProvider; private readonly EnviromentProvider _enviromentProvider;
private readonly PathProvider _pathProvider; private readonly PathProvider _pathProvider;
private readonly DiskProvider _diskProvider; private readonly DiskProvider _diskProvider;
private readonly ArchiveProvider _archiveProvider;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static readonly Regex ParseRegex = new Regex(@"(?:\>)(?<filename>NzbDrone.+?(?<version>\d+\.\d+\.\d+\.\d+).+?)(?:\<\/A\>)", RegexOptions.IgnoreCase); private static readonly Regex ParseRegex = new Regex(@"(?:\>)(?<filename>NzbDrone.+?(?<version>\d+\.\d+\.\d+\.\d+).+?)(?:\<\/A\>)", RegexOptions.IgnoreCase);
@ -28,13 +28,14 @@ namespace NzbDrone.Core.Providers
[Inject] [Inject]
public UpdateProvider(HttpProvider httpProvider, ConfigProvider configProvider, EnviromentProvider enviromentProvider, public UpdateProvider(HttpProvider httpProvider, ConfigProvider configProvider, EnviromentProvider enviromentProvider,
PathProvider pathProvider, DiskProvider diskProvider) PathProvider pathProvider, DiskProvider diskProvider, ArchiveProvider archiveProvider)
{ {
_httpProvider = httpProvider; _httpProvider = httpProvider;
_configProvider = configProvider; _configProvider = configProvider;
_enviromentProvider = enviromentProvider; _enviromentProvider = enviromentProvider;
_pathProvider = pathProvider; _pathProvider = pathProvider;
_diskProvider = diskProvider; _diskProvider = diskProvider;
_archiveProvider = archiveProvider;
} }
public UpdateProvider() public UpdateProvider()
@ -74,7 +75,7 @@ namespace NzbDrone.Core.Providers
return null; return null;
} }
public virtual void PreformUpdate(UpdatePackage updatePackage) public virtual void StartUpgrade(UpdatePackage updatePackage)
{ {
var packageDestination = Path.Combine(_pathProvider.UpdateSandboxFolder, updatePackage.FileName); var packageDestination = Path.Combine(_pathProvider.UpdateSandboxFolder, updatePackage.FileName);
@ -83,7 +84,7 @@ namespace NzbDrone.Core.Providers
Logger.Info("Download completed for update package from [{0}]", updatePackage.FileName); Logger.Info("Download completed for update package from [{0}]", updatePackage.FileName);
Logger.Info("Extracting Update package"); Logger.Info("Extracting Update package");
_diskProvider.ExtractArchive(packageDestination, _pathProvider.UpdateSandboxFolder); _archiveProvider.ExtractArchive(packageDestination, _pathProvider.UpdateSandboxFolder);
Logger.Info("Update package extracted successfully"); Logger.Info("Update package extracted successfully");
} }

@ -1,4 +1,5 @@
using AutoMoq; using System.IO;
using AutoMoq;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
@ -13,21 +14,47 @@ namespace NzbDrone.Update.Test
{ {
AutoMoqer mocker = new AutoMoqer(); AutoMoqer mocker = new AutoMoqer();
private const string UPDATE_FOLDER = @"C:\Temp\NzbDrone_update\NzbDrone";
private const string BACKUP_FOLDER = @"C:\Temp\NzbDrone_update\NzbDrone_Backup";
private const string TARGET_FOLDER = @"C:\NzbDrone\";
Mock<PathProvider> _pathProvider = null;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
mocker = new AutoMoqer(); mocker = new AutoMoqer();
_pathProvider = mocker.GetMock<PathProvider>();
_pathProvider.SetupGet(c => c.UpdateBackUpFolder).Returns(BACKUP_FOLDER);
_pathProvider.SetupGet(c => c.UpdatePackageFolder).Returns(UPDATE_FOLDER);
mocker.GetMock<DiskProvider>()
.Setup(c => c.FolderExists(UPDATE_FOLDER))
.Returns(true);
mocker.GetMock<DiskProvider>()
.Setup(c => c.FolderExists(TARGET_FOLDER))
.Returns(true);
} }
[Test] public void WithInstalledService()
public void should_stop_nzbdrone_service_if_installed()
{ {
mocker.GetMock<ServiceProvider>() mocker.GetMock<ServiceProvider>()
.Setup(c => c.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME)) .Setup(c => c.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME))
.Returns(true); .Returns(true);
}
[Test]
public void should_stop_nzbdrone_service_if_installed()
{
WithInstalledService();
//Act //Act
mocker.Resolve<UpdateProvider>().Start(null); mocker.Resolve<UpdateProvider>().Start(TARGET_FOLDER);
//Assert //Assert
mocker.GetMock<ServiceProvider>().Verify(c => c.Stop(ServiceProvider.NZBDRONE_SERVICE_NAME), Times.Once()); mocker.GetMock<ServiceProvider>().Verify(c => c.Stop(ServiceProvider.NZBDRONE_SERVICE_NAME), Times.Once());
@ -44,12 +71,89 @@ namespace NzbDrone.Update.Test
.Returns(proccesses); .Returns(proccesses);
//Act //Act
mocker.Resolve<UpdateProvider>().Start(null); mocker.Resolve<UpdateProvider>().Start(TARGET_FOLDER);
//Assert //Assert
mocker.GetMock<ProcessProvider>().Verify(c => c.Kill(proccesses[0].Id), Times.Once()); mocker.GetMock<ProcessProvider>().Verify(c => c.Kill(proccesses[0].Id), Times.Once());
mocker.GetMock<ProcessProvider>().Verify(c => c.Kill(proccesses[1].Id), Times.Once()); mocker.GetMock<ProcessProvider>().Verify(c => c.Kill(proccesses[1].Id), Times.Once());
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
} }
[Test]
public void should_create_backup_of_current_installation()
{
var diskprovider = mocker.GetMock<DiskProvider>()
.Setup(c => c.CopyDirectory(TARGET_FOLDER, BACKUP_FOLDER));
mocker.Resolve<UpdateProvider>().Start(TARGET_FOLDER);
mocker.VerifyAllMocks();
}
[Test]
public void should_copy_update_package_to_target()
{
var diskprovider = mocker.GetMock<DiskProvider>()
.Setup(c => c.CopyDirectory(UPDATE_FOLDER, TARGET_FOLDER));
mocker.Resolve<UpdateProvider>().Start(TARGET_FOLDER);
mocker.VerifyAllMocks();
}
[Test]
public void should_restore_if_update_fails()
{
var diskprovider = mocker.GetMock<DiskProvider>();
diskprovider.Setup(c => c.CopyDirectory(BACKUP_FOLDER, TARGET_FOLDER));
diskprovider.Setup(c => c.CopyDirectory(UPDATE_FOLDER, TARGET_FOLDER)).Throws(new IOException());
mocker.Resolve<UpdateProvider>().Start(TARGET_FOLDER);
mocker.VerifyAllMocks();
}
[Test]
public void should_restart_service_if_service_was_running()
{
WithInstalledService();
var serviceProvider = mocker.GetMock<ServiceProvider>();
serviceProvider.Setup(c => c.IsServiceRunning(ServiceProvider.NZBDRONE_SERVICE_NAME)).Returns(true);
//Act
mocker.Resolve<UpdateProvider>().Start(TARGET_FOLDER);
//Assert
serviceProvider
.Verify(c => c.Start(ServiceProvider.NZBDRONE_SERVICE_NAME), Times.Once());
mocker.VerifyAllMocks();
}
[Test]
public void should_not_restart_service_if_service_was_not_running()
{
WithInstalledService();
var serviceProvider = mocker.GetMock<ServiceProvider>();
serviceProvider.Setup(c => c.IsServiceRunning(ServiceProvider.NZBDRONE_SERVICE_NAME))
.Returns(false);
//Act
mocker.Resolve<UpdateProvider>().Start(TARGET_FOLDER);
//Assert
mocker.GetMock<ProcessProvider>()
.Verify(c => c.Start(TARGET_FOLDER + "nzbdrone.exe"), Times.Once());
serviceProvider
.Verify(c => c.Start(It.IsAny<string>()), Times.Never());
mocker.VerifyAllMocks();
}
} }
} }

@ -28,25 +28,25 @@ namespace NzbDrone.Update.Test
[TestCase(null)] [TestCase(null)]
[TestCase("")] [TestCase("")]
[TestCase(" ")] [TestCase(" ")]
public void verify_should_throw_target_folder_is_blank(string target) public void update_should_throw_target_folder_is_blank(string target)
{ {
Assert.Throws<ArgumentException>(() => mocker.Resolve<UpdateProvider>().Verify(target)) Assert.Throws<ArgumentException>(() => mocker.Resolve<UpdateProvider>().Start(target))
.Message.Should().StartWith("Target folder can not be null or empty"); .Message.Should().StartWith("Target folder can not be null or empty");
} }
[Test] [Test]
public void verify_should_throw_if_target_folder_doesnt_exist() public void update_should_throw_if_target_folder_doesnt_exist()
{ {
string targetFolder = "c:\\NzbDrone\\"; string targetFolder = "c:\\NzbDrone\\";
Assert.Throws<DirectoryNotFoundException>(() => mocker.Resolve<UpdateProvider>().Verify(targetFolder)) Assert.Throws<DirectoryNotFoundException>(() => mocker.Resolve<UpdateProvider>().Start(targetFolder))
.Message.Should().StartWith("Target folder doesn't exist"); .Message.Should().StartWith("Target folder doesn't exist");
} }
[Test] [Test]
public void verify_should_throw_if_update_folder_doesnt_exist() public void update_should_throw_if_update_folder_doesnt_exist()
{ {
const string sandboxFolder = @"C:\Temp\NzbDrone_update\nzbdrone_update"; const string sandboxFolder = @"C:\Temp\NzbDrone_update\nzbdrone";
const string targetFolder = "c:\\NzbDrone\\"; const string targetFolder = "c:\\NzbDrone\\";
mocker.GetMock<DiskProvider>() mocker.GetMock<DiskProvider>()
@ -57,22 +57,8 @@ namespace NzbDrone.Update.Test
.Setup(c => c.FolderExists(sandboxFolder)) .Setup(c => c.FolderExists(sandboxFolder))
.Returns(false); .Returns(false);
Assert.Throws<DirectoryNotFoundException>(() => mocker.Resolve<UpdateProvider>().Verify(targetFolder)) Assert.Throws<DirectoryNotFoundException>(() => mocker.Resolve<UpdateProvider>().Start(targetFolder))
.Message.Should().StartWith("Update folder doesn't exist"); .Message.Should().StartWith("Update folder doesn't exist");
} }
[Test]
public void verify_should_pass_if_update_folder_and_target_folder_both_exist()
{
const string targetFolder = "c:\\NzbDrone\\";
mocker.GetMock<DiskProvider>()
.Setup(c => c.FolderExists(It.IsAny<string>()))
.Returns(true);
mocker.Resolve<UpdateProvider>().Verify(targetFolder);
mocker.VerifyAllMocks();
}
} }
} }

@ -12,40 +12,47 @@ namespace NzbDrone.Update.Providers
private readonly EnviromentProvider _enviromentProvider; private readonly EnviromentProvider _enviromentProvider;
private readonly ServiceProvider _serviceProvider; private readonly ServiceProvider _serviceProvider;
private readonly ProcessProvider _processProvider; private readonly ProcessProvider _processProvider;
private readonly PathProvider _pathProvider;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public UpdateProvider(DiskProvider diskProvider, EnviromentProvider enviromentProvider, public UpdateProvider(DiskProvider diskProvider, EnviromentProvider enviromentProvider,
ServiceProvider serviceProvider, ProcessProvider processProvider) ServiceProvider serviceProvider, ProcessProvider processProvider, PathProvider pathProvider)
{ {
_diskProvider = diskProvider; _diskProvider = diskProvider;
_enviromentProvider = enviromentProvider; _enviromentProvider = enviromentProvider;
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_processProvider = processProvider; _processProvider = processProvider;
_pathProvider = pathProvider;
} }
public void Verify(string targetFolder) private void Verify(string installationFolder)
{ {
Logger.Info("Verifying requirements before update..."); Logger.Info("Verifying requirements before update...");
if (String.IsNullOrWhiteSpace(targetFolder)) if (String.IsNullOrWhiteSpace(installationFolder))
throw new ArgumentException("Target folder can not be null or empty"); throw new ArgumentException("Target folder can not be null or empty");
if (!_diskProvider.FolderExists(targetFolder)) if (!_diskProvider.FolderExists(installationFolder))
throw new DirectoryNotFoundException("Target folder doesn't exist" + targetFolder); throw new DirectoryNotFoundException("Target folder doesn't exist" + installationFolder);
var sandboxFolder = Path.Combine(_enviromentProvider.StartUpPath, "nzbdrone_update");
Logger.Info("Verifying Update Folder"); Logger.Info("Verifying Update Folder");
if (!_diskProvider.FolderExists(sandboxFolder)) if (!_diskProvider.FolderExists(_pathProvider.UpdatePackageFolder))
throw new DirectoryNotFoundException("Update folder doesn't exist" + sandboxFolder); throw new DirectoryNotFoundException("Update folder doesn't exist" + _pathProvider.UpdateSandboxFolder);
} }
public void Start(string installationFolder) public void Start(string targetFolder)
{ {
Verify(targetFolder);
bool isService = false;
Logger.Info("Stopping all running services"); Logger.Info("Stopping all running services");
if (_serviceProvider.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME)) if (_serviceProvider.ServiceExist(ServiceProvider.NZBDRONE_SERVICE_NAME))
{ {
if (_serviceProvider.IsServiceRunning(ServiceProvider.NZBDRONE_SERVICE_NAME))
{
isService = true;
}
_serviceProvider.Stop(ServiceProvider.NZBDRONE_SERVICE_NAME); _serviceProvider.Stop(ServiceProvider.NZBDRONE_SERVICE_NAME);
} }
@ -56,17 +63,44 @@ namespace NzbDrone.Update.Providers
_processProvider.Kill(processInfo.Id); _processProvider.Kill(processInfo.Id);
} }
Logger.Info("Creating backup of existing installation");
_diskProvider.CopyDirectory(targetFolder, _pathProvider.UpdateBackUpFolder);
//Create backup of current folder Logger.Info("Copying update package to target");
try
{
_diskProvider.CopyDirectory(_pathProvider.UpdatePackageFolder, targetFolder);
}
catch (Exception e)
{
RollBack(targetFolder);
Logger.Fatal("Failed to copy upgrade package to target folder.", e);
}
finally
{
StartNzbDrone(isService, targetFolder);
}
}
//Copy update folder on top of the existing folder private void RollBack(string targetFolder)
{
Logger.Info("Attempting to rollback upgrade");
_diskProvider.CopyDirectory(_pathProvider.UpdateBackUpFolder, targetFolder);
}
//Happy: Cleanup
//Happy: Start Service, Process?
//Sad: delete fucked up folder private void StartNzbDrone(bool isService, string targetFolder)
//Sad: restore backup {
//Sad: start service, process if (isService)
{
_serviceProvider.Start(ServiceProvider.NZBDRONE_SERVICE_NAME);
}
else
{
_processProvider.Start(Path.Combine(targetFolder, "nzbdrone.exe"));
}
} }
} }
} }

@ -4,6 +4,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Web.Mvc; using System.Web.Mvc;
using NLog; using NLog;
using NzbDrone.Common;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Providers.Jobs; using NzbDrone.Core.Providers.Jobs;

@ -1,9 +1,5 @@
using System; using System.Web.Mvc;
using System.Collections.Generic; using NzbDrone.Common;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
using NzbDrone.Core.Providers.Core;
namespace NzbDrone.Web.Controllers namespace NzbDrone.Web.Controllers
{ {

@ -3,8 +3,8 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Web.Mvc; using System.Web.Mvc;
using NzbDrone.Common;
using NzbDrone.Core.Helpers; using NzbDrone.Core.Helpers;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Providers.Jobs; using NzbDrone.Core.Providers.Jobs;

Loading…
Cancel
Save