Fixed: Some Tests and Added New Ones

This commit is contained in:
Qstick 2019-07-09 22:05:32 -04:00
parent a3f72bd4a0
commit 612d948eba
22 changed files with 604 additions and 84 deletions

View File

@ -52,15 +52,6 @@ CleanFolder()
find $path -depth -empty -type d -exec rm -r "{}" \;
}
AddJsonNet()
{
rm $outputFolder/Newtonsoft.Json.*
cp $sourceFolder/packages/Newtonsoft.Json.*/lib/net35/*.dll $outputFolder
cp $sourceFolder/packages/Newtonsoft.Json.*/lib/net35/*.dll $outputFolder/NzbDrone.Update
}
BuildWithMSBuild()
{
export PATH=$msBuild:$PATH
@ -115,8 +106,6 @@ Build()
CleanFolder $outputFolder false
AddJsonNet
echo "Removing Mono.Posix.dll"
rm $outputFolder/Mono.Posix.dll

View File

@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Test.Common;
using FluentAssertions;
namespace NzbDrone.Common.Test.DiskTests
{
@ -16,6 +18,7 @@ namespace NzbDrone.Common.Test.DiskTests
private readonly string _targetPath = @"C:\target\my.video.mkv".AsOsAgnostic();
private readonly string _backupPath = @"C:\source\my.video.mkv.backup~".AsOsAgnostic();
private readonly string _tempTargetPath = @"C:\target\my.video.mkv.partial~".AsOsAgnostic();
private readonly string _nfsFile = ".nfs01231232";
[SetUp]
public void SetUp()
@ -237,7 +240,7 @@ namespace NzbDrone.Common.Test.DiskTests
WithExistingFile(_targetPath);
Assert.Throws<IOException>(() => Subject.TransferFile(_sourcePath, _targetPath, TransferMode.Move, false));
Assert.Throws<DestinationAlreadyExistsException>(() => Subject.TransferFile(_sourcePath, _targetPath, TransferMode.Move, false));
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.DeleteFile(_targetPath), Times.Never());
@ -642,6 +645,21 @@ namespace NzbDrone.Common.Test.DiskTests
VerifyCopyFolder(source.FullName, destination.FullName);
}
[Test]
public void CopyFolder_should_ignore_nfs_temp_file()
{
WithRealDiskProvider();
var source = GetFilledTempFolder();
File.WriteAllText(Path.Combine(source.FullName, _nfsFile), "SubFile1");
var destination = new DirectoryInfo(GetTempFilePath());
Subject.TransferFolder(source.FullName, destination.FullName, TransferMode.Copy);
File.Exists(Path.Combine(destination.FullName, _nfsFile)).Should().BeFalse();
}
[Test]
public void MoveFolder_should_move_folder()
@ -704,6 +722,26 @@ namespace NzbDrone.Common.Test.DiskTests
destination.GetFileSystemInfos().Should().BeEmpty();
}
[Test]
public void MirrorFolder_should_not_remove_nfs_files()
{
WithRealDiskProvider();
var original = GetFilledTempFolder();
var source = new DirectoryInfo(GetTempFilePath());
var destination = new DirectoryInfo(GetTempFilePath());
source.Create();
Subject.TransferFolder(original.FullName, destination.FullName, TransferMode.Copy);
File.WriteAllText(Path.Combine(destination.FullName, _nfsFile), "SubFile1");
var count = Subject.MirrorFolder(source.FullName, destination.FullName);
count.Should().Equals(0);
destination.GetFileSystemInfos().Should().HaveCount(1);
}
[Test]
public void MirrorFolder_should_add_new_files()
{
@ -721,6 +759,24 @@ namespace NzbDrone.Common.Test.DiskTests
VerifyCopyFolder(original.FullName, destination.FullName);
}
[Test]
public void MirrorFolder_should_ignore_nfs_temp_file()
{
WithRealDiskProvider();
var source = GetFilledTempFolder();
File.WriteAllText(Path.Combine(source.FullName, _nfsFile), "SubFile1");
var destination = new DirectoryInfo(GetTempFilePath());
var count = Subject.MirrorFolder(source.FullName, destination.FullName);
count.Should().Equals(3);
File.Exists(Path.Combine(destination.FullName, _nfsFile)).Should().BeFalse();
}
[Test]
public void MirrorFolder_should_not_touch_equivalent_files()
{
@ -740,6 +796,75 @@ namespace NzbDrone.Common.Test.DiskTests
VerifyCopyFolder(original.FullName, destination.FullName);
}
[Test]
public void TransferFolder_should_use_movefolder_if_on_same_mount()
{
WithEmulatedDiskProvider();
var src = @"C:\Base1\TestDir1".AsOsAgnostic();
var dst = @"C:\Base1\TestDir2".AsOsAgnostic();
WithMockMount(@"C:\Base1".AsOsAgnostic());
WithExistingFile(@"C:\Base1\TestDir1\test.file.txt".AsOsAgnostic());
Subject.TransferFolder(src, dst, TransferMode.Move);
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.MoveFolder(src, dst, false), Times.Once());
}
[Test]
public void TransferFolder_should_not_use_movefolder_if_on_same_mount_but_target_already_exists()
{
WithEmulatedDiskProvider();
var src = @"C:\Base1\TestDir1".AsOsAgnostic();
var dst = @"C:\Base1\TestDir2".AsOsAgnostic();
WithMockMount(@"C:\Base1".AsOsAgnostic());
WithExistingFile(@"C:\Base1\TestDir1\test.file.txt".AsOsAgnostic());
WithExistingFolder(dst);
Subject.TransferFolder(src, dst, TransferMode.Move);
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.MoveFolder(src, dst, false), Times.Never());
}
[Test]
public void TransferFolder_should_not_use_movefolder_if_on_same_mount_but_transactional()
{
WithEmulatedDiskProvider();
var src = @"C:\Base1\TestDir1".AsOsAgnostic();
var dst = @"C:\Base1\TestDir2".AsOsAgnostic();
WithMockMount(@"C:\Base1".AsOsAgnostic());
WithExistingFile(@"C:\Base1\TestDir1\test.file.txt".AsOsAgnostic());
Subject.TransferFolder(src, dst, TransferMode.Move, DiskTransferVerificationMode.Transactional);
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.MoveFolder(src, dst, false), Times.Never());
}
[Test]
public void TransferFolder_should_not_use_movefolder_if_on_different_mount()
{
WithEmulatedDiskProvider();
var src = @"C:\Base1\TestDir1".AsOsAgnostic();
var dst = @"C:\Base2\TestDir2".AsOsAgnostic();
WithMockMount(@"C:\Base1".AsOsAgnostic());
WithMockMount(@"C:\Base2".AsOsAgnostic());
Subject.TransferFolder(src, dst, TransferMode.Move);
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.MoveFolder(src, dst, false), Times.Never());
}
public DirectoryInfo GetFilledTempFolder()
{
var tempFolder = GetTempFilePath();
@ -756,8 +881,23 @@ namespace NzbDrone.Common.Test.DiskTests
return new DirectoryInfo(tempFolder);
}
private void WithExistingFolder(string path, bool exists = true)
{
var dir = Path.GetDirectoryName(path);
if (exists && dir.IsNotNullOrWhiteSpace())
WithExistingFolder(dir);
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.FolderExists(path))
.Returns(exists);
}
private void WithExistingFile(string path, bool exists = true, int size = 1000)
{
var dir = Path.GetDirectoryName(path);
if (exists && dir.IsNotNullOrWhiteSpace())
WithExistingFolder(dir);
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.FileExists(path))
.Returns(exists);
@ -809,6 +949,45 @@ namespace NzbDrone.Common.Test.DiskTests
{
WithExistingFile(v, false);
});
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.FolderExists(It.IsAny<string>()))
.Returns(false);
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.CreateFolder(It.IsAny<string>()))
.Callback<string>((f) =>
{
WithExistingFolder(f);
});
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.MoveFolder(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
.Callback<string, string, bool>((s, d, b) =>
{
WithExistingFolder(s, false);
WithExistingFolder(d);
// Note: Should also deal with the files.
});
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.DeleteFolder(It.IsAny<string>(), It.IsAny<bool>()))
.Callback<string, bool>((f, r) =>
{
WithExistingFolder(f, false);
// Note: Should also deal with the files.
});
// Note: never returns anything.
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.GetDirectoryInfos(It.IsAny<string>()))
.Returns(new List<DirectoryInfo>());
// Note: never returns anything.
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.GetFileInfos(It.IsAny<string>()))
.Returns(new List<FileInfo>());
}
private void WithRealDiskProvider()
@ -865,6 +1044,18 @@ namespace NzbDrone.Common.Test.DiskTests
.Returns<string>(s => new FileStream(s, FileMode.Open, FileAccess.Read));
}
private void WithMockMount(string root)
{
var rootDir = root;
var mock = new Mock<IMount>();
mock.SetupGet(v => v.RootDirectory)
.Returns(rootDir);
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.GetMount(It.Is<string>(s => s.StartsWith(rootDir))))
.Returns(mock.Object);
}
private void VerifyCopyFolder(string source, string destination)
{
var sourceFiles = Directory.GetFileSystemEntries(source, "*", SearchOption.AllDirectories).Select(v => v.Substring(source.Length + 1)).ToArray();

View File

@ -32,7 +32,7 @@ namespace NzbDrone.Common.Test.DiskTests
public void should_be_able_to_check_space_on_ramdrive()
{
MonoOnly();
Subject.GetAvailableSpace("/").Should().NotBe(0);
Subject.GetAvailableSpace("/run/").Should().NotBe(0);
}
[Ignore("Docker")]
@ -62,7 +62,7 @@ namespace NzbDrone.Common.Test.DiskTests
{
if (new DriveInfo(driveletter.ToString()).IsReady)
continue;
Assert.Throws<DirectoryNotFoundException>(() => Subject.GetAvailableSpace(driveletter + @":\NOT_A_REAL_PATH\DOES_NOT_EXIST".AsOsAgnostic()));
return;
}

View File

@ -10,8 +10,9 @@ namespace NzbDrone.Common.Test.EnvironmentInfo
[Test]
public void should_return_version()
{
BuildInfo.Version.Major.Should().BeOneOf(0, 10);
BuildInfo.Version.Major.Should().BeOneOf(2, 10);
}
[Test]
public void should_get_branch()
{

View File

@ -7,6 +7,13 @@ namespace NzbDrone.Common.Test.Http
{
public class HttpUriFixture : TestBase
{
[TestCase("abc://my_host.com:8080/root/api/")]
public void should_parse(string uri)
{
var newUri = new HttpUri(uri);
newUri.FullUri.Should().Be(uri);
}
[TestCase("", "", "")]
[TestCase("/", "", "/")]
[TestCase("base", "", "base")]
@ -77,7 +84,7 @@ namespace NzbDrone.Common.Test.Http
public void should_combine_relative_path(string basePath, string relativePath, string expected)
{
var newUri = new HttpUri(basePath).CombinePath(relativePath);
newUri.FullUri.Should().Be(expected);
}
}

View File

@ -20,6 +20,7 @@ namespace NzbDrone.Common.Test
}
[TestCase("")]
[TestCase("http://")]
public void DownloadString_should_throw_on_error(string url)
{
Assert.Throws<ArgumentException>(() => Subject.DownloadString(url));

View File

@ -16,7 +16,6 @@ namespace NzbDrone.Common.Extensions
private const string LOG_DB = "logs.db";
private const string NLOG_CONFIG_FILE = "nlog.config";
private const string UPDATE_CLIENT_EXE = "Radarr.Update.exe";
private const string BACKUP_FOLDER = "Backups";
private static readonly string UPDATE_SANDBOX_FOLDER_NAME = "radarr_update" + Path.DirectorySeparatorChar;
private static readonly string UPDATE_PACKAGE_FOLDER_NAME = "Radarr" + Path.DirectorySeparatorChar;

View File

@ -7,7 +7,7 @@ namespace NzbDrone.Common.Extensions
{
public static int? ParseInt32(this string source)
{
int result = 0;
int result;
if (int.TryParse(source, out result))
{
@ -17,9 +17,9 @@ namespace NzbDrone.Common.Extensions
return null;
}
public static Nullable<long> ParseInt64(this string source)
public static long? ParseInt64(this string source)
{
long result = 0;
long result;
if (long.TryParse(source, out result))
{

View File

@ -13,6 +13,9 @@ using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Movies;
using NzbDrone.Test.Common;
using NzbDrone.Core.Exceptions;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Download.Clients;
namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
{
@ -36,7 +39,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
.Build();
}
private RemoteMovie GetRemoteMovie(QualityModel quality, Movie movie = null)
private RemoteMovie GetRemoteMovie(QualityModel quality, Movie movie = null, DownloadProtocol downloadProtocol = DownloadProtocol.Usenet)
{
if (movie == null)
{
@ -54,12 +57,13 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
MovieTitle = "A Movie",
},
Movie = movie,
Release = new ReleaseInfo()
{
PublishDate = DateTime.UtcNow,
Title = "A.Movie.1998",
Size = 200
Size = 200,
DownloadProtocol = downloadProtocol
}
};
@ -91,6 +95,25 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>()), Times.Once());
}
[Test]
public void should_not_download_if_any_movie_was_already_downloaded()
{
var remoteMovie1 = GetRemoteMovie(
new QualityModel(Quality.HDTV720p)
);
var remoteMovie2 = GetRemoteMovie(
new QualityModel(Quality.HDTV720p)
);
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteMovie1));
decisions.Add(new DownloadDecision(remoteMovie2));
Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>()), Times.Once());
}
[Test]
public void should_return_downloaded_reports()
{
@ -179,7 +202,6 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteMovie, new Rejection("Failure!", RejectionType.Temporary)));
decisions.Add(new DownloadDecision(remoteMovie));
Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>()), Times.Never());
@ -201,15 +223,68 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
[Test]
public void should_add_to_pending_even_if_already_added_to_pending()
{
var remoteEpisode = GetRemoteMovie(new QualityModel(Quality.HDTV720p));
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteEpisode, new Rejection("Failure!", RejectionType.Temporary)));
decisions.Add(new DownloadDecision(remoteEpisode, new Rejection("Failure!", RejectionType.Temporary)));
Subject.ProcessDecisions(decisions);
Mocker.GetMock<IPendingReleaseService>().Verify(v => v.AddMany(It.IsAny<List<Tuple<DownloadDecision, PendingReleaseReason>>>()), Times.Once());
}
[Test]
public void should_add_to_failed_if_already_failed_for_that_protocol()
{
var remoteMovie = GetRemoteMovie(new QualityModel(Quality.HDTV720p));
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteMovie, new Rejection("Failure!", RejectionType.Temporary)));
decisions.Add(new DownloadDecision(remoteMovie, new Rejection("Failure!", RejectionType.Temporary)));
decisions.Add(new DownloadDecision(remoteMovie));
decisions.Add(new DownloadDecision(remoteMovie));
Mocker.GetMock<IDownloadService>().Setup(s => s.DownloadReport(It.IsAny<RemoteMovie>()))
.Throws(new DownloadClientUnavailableException("Download client failed"));
Subject.ProcessDecisions(decisions);
Mocker.GetMock<IPendingReleaseService>().Verify(v => v.AddMany(It.IsAny<List<Tuple<DownloadDecision, PendingReleaseReason>>>()), Times.Exactly(2));
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteMovie>()), Times.Once());
}
[Test]
public void should_not_add_to_failed_if_failed_for_a_different_protocol()
{
var remoteMovie = GetRemoteMovie(new QualityModel(Quality.HDTV720p), null, DownloadProtocol.Usenet);
var remoteMovie2 = GetRemoteMovie(new QualityModel(Quality.HDTV720p), null, DownloadProtocol.Torrent);
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteMovie));
decisions.Add(new DownloadDecision(remoteMovie2));
Mocker.GetMock<IDownloadService>().Setup(s => s.DownloadReport(It.Is<RemoteMovie>(r => r.Release.DownloadProtocol == DownloadProtocol.Usenet)))
.Throws(new DownloadClientUnavailableException("Download client failed"));
Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.Is<RemoteMovie>(r => r.Release.DownloadProtocol == DownloadProtocol.Usenet)), Times.Once());
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.Is<RemoteMovie>(r => r.Release.DownloadProtocol == DownloadProtocol.Torrent)), Times.Once());
}
[Test]
public void should_add_to_rejected_if_release_unavailable_on_indexer()
{
var remoteMovie = GetRemoteMovie(new QualityModel(Quality.HDTV720p));
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteMovie));
Mocker.GetMock<IDownloadService>()
.Setup(s => s.DownloadReport(It.IsAny<RemoteMovie>()))
.Throws(new ReleaseUnavailableException(remoteMovie.Release, "That 404 Error is not just a Quirk"));
var result = Subject.ProcessDecisions(decisions);
result.Grabbed.Should().BeEmpty();
result.Rejected.Should().NotBeEmpty();
ExceptionVerification.ExpectedWarns(1);
}
}
}

View File

@ -42,8 +42,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
var item = Subject.GetItems().Single();
VerifyCompleted(item);
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
item.CanBeRemoved.Should().BeFalse();
item.CanMoveFiles.Should().BeFalse();
}
[Test]
@ -66,9 +66,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
}
[Test]
public void Download_with_TvDirectory_should_force_directory()
public void Download_with_MovieDirectory_should_force_directory()
{
GivenTvDirectory();
GivenMovieDirectory();
GivenSuccessfulDownload();
var remoteMovie = CreateRemoteMovie();
@ -84,7 +84,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
[Test]
public void Download_with_category_should_force_directory()
{
GivenTvCategory();
GivenMovieCategory();
GivenSuccessfulDownload();
var remoteMovie = CreateRemoteMovie();
@ -100,7 +100,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
[Test]
public void Download_with_category_should_not_have_double_slashes()
{
GivenTvCategory();
GivenMovieCategory();
GivenSuccessfulDownload();
_transmissionConfigItems["download-dir"] += "/";
@ -175,7 +175,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
item.Status.Should().Be(expectedItemStatus);
}
[TestCase(TransmissionTorrentStatus.Stopped, DownloadItemStatus.Completed, true)]
[TestCase(TransmissionTorrentStatus.Stopped, DownloadItemStatus.Completed, false)]
[TestCase(TransmissionTorrentStatus.CheckWait, DownloadItemStatus.Downloading, false)]
[TestCase(TransmissionTorrentStatus.Check, DownloadItemStatus.Downloading, false)]
[TestCase(TransmissionTorrentStatus.Queued, DownloadItemStatus.Completed, false)]
@ -207,7 +207,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
[Test]
public void should_exclude_items_not_in_category()
{
GivenTvCategory();
GivenMovieCategory();
_downloading.DownloadDir = @"C:/Downloads/Finished/transmission/radarr";
@ -226,7 +226,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
[Test]
public void should_exclude_items_not_in_TvDirectory()
{
GivenTvDirectory();
GivenMovieDirectory();
_downloading.DownloadDir = @"C:/Downloads/Finished/radarr/subdir";
@ -283,5 +283,139 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
var item = Subject.GetItems().Single();
item.RemainingTime.Should().NotHaveValue();
}
[Test]
public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_reached_and_not_stopped()
{
GivenGlobalSeedLimits(1.0);
PrepareClientToReturnCompletedItem(false, ratio: 1.0);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeFalse();
item.CanMoveFiles.Should().BeFalse();
}
[Test]
public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_is_not_set()
{
GivenGlobalSeedLimits();
PrepareClientToReturnCompletedItem(true, ratio: 1.0);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeFalse();
item.CanMoveFiles.Should().BeFalse();
}
[Test]
public void should_be_removable_and_should_allow_move_files_if_max_ratio_reached_and_paused()
{
GivenGlobalSeedLimits(1.0);
PrepareClientToReturnCompletedItem(true, ratio: 1.0);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[Test]
public void should_be_removable_and_should_allow_move_files_if_overridden_max_ratio_reached_and_paused()
{
GivenGlobalSeedLimits(2.0);
PrepareClientToReturnCompletedItem(true, ratio: 1.0, ratioLimit: 0.8);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[Test]
public void should_not_be_removable_if_overridden_max_ratio_not_reached_and_paused()
{
GivenGlobalSeedLimits(0.2);
PrepareClientToReturnCompletedItem(true, ratio: 0.5, ratioLimit: 0.8);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeFalse();
item.CanMoveFiles.Should().BeFalse();
}
[Test]
public void should_not_be_removable_and_should_not_allow_move_files_if_max_idletime_reached_and_not_paused()
{
GivenGlobalSeedLimits(null, 20);
PrepareClientToReturnCompletedItem(false, ratio: 2.0, seedingTime: 30);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeFalse();
item.CanMoveFiles.Should().BeFalse();
}
[Test]
public void should_be_removable_and_should_allow_move_files_if_max_idletime_reached_and_paused()
{
GivenGlobalSeedLimits(null, 20);
PrepareClientToReturnCompletedItem(true, ratio: 2.0, seedingTime: 20);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[Test]
public void should_be_removable_and_should_allow_move_files_if_overridden_max_idletime_reached_and_paused()
{
GivenGlobalSeedLimits(null, 40);
PrepareClientToReturnCompletedItem(true, ratio: 2.0, seedingTime: 20, idleLimit: 10);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
[Test]
public void should_be_removable_and_should_not_allow_move_files_if_overridden_max_idletime_reached_and_not_paused()
{
GivenGlobalSeedLimits(null, 40);
PrepareClientToReturnCompletedItem(false, ratio: 2.0, seedingTime: 20, idleLimit: 10);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeFalse();
}
[Test]
public void should_not_be_removable_if_overridden_max_idletime_not_reached_and_paused()
{
GivenGlobalSeedLimits(null, 20);
PrepareClientToReturnCompletedItem(true, ratio: 2.0, seedingTime: 30, idleLimit: 40);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeFalse();
item.CanMoveFiles.Should().BeFalse();
}
[Test]
public void should_not_be_removable_if_max_idletime_reached_but_ratio_not_and_not_paused()
{
GivenGlobalSeedLimits(2.0, 20);
PrepareClientToReturnCompletedItem(false, ratio: 1.0, seedingTime: 30);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeFalse();
item.CanMoveFiles.Should().BeFalse();
}
[Test]
public void should_be_removable_and_should_allow_move_files_if_max_idletime_configured_and_paused()
{
GivenGlobalSeedLimits(2.0, 20);
PrepareClientToReturnCompletedItem(true, ratio: 1.0, seedingTime: 30);
var item = Subject.GetItems().Single();
item.CanBeRemoved.Should().BeTrue();
item.CanMoveFiles.Should().BeTrue();
}
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using Moq;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients.Transmission;
using NzbDrone.Core.MediaFiles.TorrentInfo;
@ -72,11 +73,13 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
{
HashString = "HASH",
IsFinished = true,
Status = TransmissionTorrentStatus.Stopped,
Status = TransmissionTorrentStatus.Seeding,
Name = _title,
TotalSize = 1000,
LeftUntilDone = 0,
DownloadDir = "somepath"
DownloadDir = "somepath",
DownloadedEver = 1000,
UploadedEver = 900
};
_magnet = new TransmissionTorrent
@ -106,16 +109,16 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
Mocker.GetMock<ITransmissionProxy>()
.Setup(v => v.GetConfig(It.IsAny<TransmissionSettings>()))
.Returns(_transmissionConfigItems);
.Returns(() => Json.Deserialize<TransmissionConfig>(_transmissionConfigItems.ToJson()));
}
protected void GivenTvCategory()
protected void GivenMovieCategory()
{
_settings.MovieCategory = "radarr";
}
protected void GivenTvDirectory()
protected void GivenMovieDirectory()
{
_settings.MovieDirectory = @"C:/Downloads/Finished/radarr";
}
@ -178,8 +181,40 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
});
}
protected void PrepareClientToReturnCompletedItem()
protected void PrepareClientToReturnCompletedItem(bool stopped = false, double ratio = 0.9, int seedingTime = 60, double? ratioLimit = null, int? idleLimit = null)
{
if (stopped)
_completed.Status = TransmissionTorrentStatus.Stopped;
_completed.UploadedEver = (int)(_completed.DownloadedEver * ratio);
_completed.SecondsSeeding = seedingTime * 60;
if (ratioLimit.HasValue)
{
if (double.IsPositiveInfinity(ratioLimit.Value))
{
_completed.SeedRatioMode = 2;
}
else
{
_completed.SeedRatioMode = 1;
_completed.SeedRatioLimit = ratioLimit.Value;
}
}
if (idleLimit.HasValue)
{
if (double.IsPositiveInfinity(idleLimit.Value))
{
_completed.SeedIdleMode = 2;
}
else
{
_completed.SeedIdleMode = 1;
_completed.SeedIdleLimit = idleLimit.Value;
}
}
GivenTorrents(new List<TransmissionTorrent>
{
_completed
@ -193,5 +228,20 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
_magnet
});
}
protected void GivenGlobalSeedLimits(double? ratioLimit = null, int? idleLimit = null)
{
_transmissionConfigItems["seedRatioLimited"] = ratioLimit.HasValue;
if (ratioLimit.HasValue)
{
_transmissionConfigItems["seedRatioLimit"] = ratioLimit.Value;
}
_transmissionConfigItems["idle-seeding-limit-enabled"] = idleLimit.HasValue;
if (idleLimit.HasValue)
{
_transmissionConfigItems["idle-seeding-limit"] = idleLimit.Value;
}
}
}
}

View File

@ -74,7 +74,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
[Test]
public void Download_with_TvDirectory_should_force_directory()
{
GivenTvDirectory();
GivenMovieDirectory();
GivenSuccessfulDownload();
var remoteMovie = CreateRemoteMovie();
@ -90,7 +90,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
[Test]
public void Download_with_category_should_force_directory()
{
GivenTvCategory();
GivenMovieCategory();
GivenSuccessfulDownload();
var remoteMovie = CreateRemoteMovie();
@ -106,7 +106,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
[Test]
public void Download_with_category_should_not_have_double_slashes()
{
GivenTvCategory();
GivenMovieCategory();
GivenSuccessfulDownload();
_transmissionConfigItems["download-dir"] += "/";
@ -213,7 +213,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
[Test]
public void should_exclude_items_not_in_category()
{
GivenTvCategory();
GivenMovieCategory();
_downloading.DownloadDir = @"C:/Downloads/Finished/transmission/radarr";
@ -232,7 +232,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.VuzeTests
[Test]
public void should_exclude_items_not_in_TvDirectory()
{
GivenTvDirectory();
GivenMovieDirectory();
_downloading.DownloadDir = @"C:/Downloads/Finished/radarr/subdir";

View File

@ -8,6 +8,8 @@ using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Movies;
using NzbDrone.Core.Languages;
using System.Collections.Generic;
namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
{
@ -70,6 +72,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
var movieFile = Builder<MovieFile>.CreateNew()
.With(h => h.Quality = new QualityModel())
.With(h => h.Languages = new List<Language>())
.BuildNew();
Db.Insert(movie);

View File

@ -22,7 +22,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("The Colbert Report - 2014-06-02 - Thomas Piketty.mkv", null)]
[TestCase("Real Time with Bill Maher S12E17 May 23, 2014.mp4", null)]
[TestCase("Reizen Waes - S01E08 - Transistri\u00EB, Zuid-Osseti\u00EB en Abchazi\u00EB SDTV.avi", null)]
[TestCase("Simpsons 10x11 - Wild Barts Cant Be Broken [rl].avi", null)]
[TestCase("Simpsons 10x11 - Wild Barts Cant Be Broken [rl].avi", "rl")]
[TestCase("[ www.Torrenting.com ] - Revenge.S03E14.720p.HDTV.X264-DIMENSION", "DIMENSION")]
[TestCase("Seed S02E09 HDTV x264-2HD [eztv]-[rarbg.com]", "2HD")]
[TestCase("7s-atlantis-s02e01-720p.mkv", null)]
@ -32,6 +32,11 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Who.is.America.S01E01.INTERNAL.720p.HDTV.x264-aAF-RakuvUS-Obfuscated", "aAF")]
[TestCase("Haunted.Hayride.2018.720p.WEBRip.DDP5.1.x264-NTb-postbot", "NTb")]
[TestCase("Haunted.Hayride.2018.720p.WEBRip.DDP5.1.x264-NTb-xpost", "NTb")]
[TestCase("2.Broke.Girls.S02E24.1080p.AMZN.WEBRip.DD5.1.x264-CasStudio-AsRequested", "CasStudio")]
[TestCase("Billions.S04E11.Lamster.1080p.AMZN.WEB-DL.DDP5.1.H.264-NTb-AlternativeToRequested", "NTb")]
[TestCase("NCIS.S16E04.Third.Wheel.1080p.AMZN.WEB-DL.DDP5.1.H.264-NTb-GEROV", "NTb")]
[TestCase("Will.and.Grace.S10E06.Kid.n.Play.1080p.AMZN.WEB-DL.DDP5.1.H.264-NTb-Z0iDS3N", "NTb")]
[TestCase("Absolute.Power.S02E06.The.House.of.Lords.DVDRip.x264-MaG-Chamele0n", "MaG")]
//[TestCase("", "")]
public void should_parse_release_group(string title, string expected)
{

View File

@ -36,11 +36,13 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
}
var qualityDefinition = _qualityDefinitionService.Get(quality);
if (subject.Movie.Runtime == 0)
{
_logger.Warn("{0} has no runtime information using median movie runtime of 110 minutes.", subject.Movie);
subject.Movie.Runtime = 110;
}
if (subject.Movie.Runtime == 0)
{
_logger.Warn("{0} has no runtime information using median movie runtime of 110 minutes.", subject.Movie);
subject.Movie.Runtime = 110;
}
if (qualityDefinition.MinSize.HasValue)
{
var minSize = qualityDefinition.MinSize.Value.Megabytes();

View File

@ -7,4 +7,4 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
public string Name { get; set; }
public string SavePath { get; set; }
}
}
}

View File

@ -35,17 +35,8 @@ namespace NzbDrone.Core.Download.Clients.Transmission
public override IEnumerable<DownloadClientItem> GetItems()
{
List<TransmissionTorrent> torrents;
try
{
torrents = _proxy.GetTorrents(Settings);
}
catch (DownloadClientException ex)
{
_logger.Error(ex, ex.Message);
return Enumerable.Empty<DownloadClientItem>();
}
var configFunc = new Lazy<TransmissionConfig>(() => _proxy.GetConfig(Settings));
var torrents = _proxy.GetTorrents(Settings);
var items = new List<DownloadClientItem>();
@ -111,9 +102,8 @@ namespace NzbDrone.Core.Download.Clients.Transmission
item.Status = DownloadItemStatus.Downloading;
}
item.CanMoveFiles = item.CanBeRemoved =
torrent.Status == TransmissionTorrentStatus.Stopped &&
item.SeedRatio >= torrent.SeedRatioLimit;
item.CanBeRemoved = HasReachedSeedLimit(torrent, item.SeedRatio, configFunc);
item.CanMoveFiles = item.CanBeRemoved && torrent.Status == TransmissionTorrentStatus.Stopped;
items.Add(item);
}
@ -121,6 +111,46 @@ namespace NzbDrone.Core.Download.Clients.Transmission
return items;
}
protected bool HasReachedSeedLimit(TransmissionTorrent torrent, double? ratio, Lazy<TransmissionConfig> config)
{
var isStopped = torrent.Status == TransmissionTorrentStatus.Stopped;
var isSeeding = torrent.Status == TransmissionTorrentStatus.Seeding;
if (torrent.SeedRatioMode == 1)
{
if (isStopped && ratio.HasValue && ratio >= torrent.SeedRatioLimit)
{
return true;
}
}
else if (torrent.SeedRatioMode == 0)
{
if (isStopped && config.Value.SeedRatioLimited && ratio >= config.Value.SeedRatioLimit)
{
return true;
}
}
// Transmission doesn't support SeedTimeLimit, use/abuse seed idle limit, but only if it was set per-torrent.
if (torrent.SeedIdleMode == 1)
{
if ((isStopped || isSeeding) && torrent.SecondsSeeding > torrent.SeedIdleLimit * 60)
{
return true;
}
}
else if (torrent.SeedIdleMode == 0)
{
// The global idle limit is a real idle limit, if it's configured then 'Stopped' is enough.
if (isStopped && config.Value.IdleSeedingLimitEnabled)
{
return true;
}
}
return false;
}
public override void RemoveItem(string downloadId, bool deleteData)
{
_proxy.RemoveTorrent(downloadId.ToLower(), deleteData, Settings);
@ -129,8 +159,8 @@ namespace NzbDrone.Core.Download.Clients.Transmission
public override DownloadClientInfo GetStatus()
{
var config = _proxy.GetConfig(Settings);
var destDir = config.GetValueOrDefault("download-dir") as string;
var destDir = config.DownloadDir;
if (Settings.MovieCategory.IsNotNullOrWhiteSpace())
{
destDir = string.Format("{0}/.{1}", destDir, Settings.MovieCategory);
@ -197,7 +227,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission
if (!Settings.MovieCategory.IsNotNullOrWhiteSpace()) return null;
var config = _proxy.GetConfig(Settings);
var destDir = (string)config.GetValueOrDefault("download-dir");
var destDir = config.DownloadDir;
return $"{destDir.TrimEnd('/')}/{Settings.MovieCategory}";
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace NzbDrone.Core.Download.Clients.Transmission
{
public class TransmissionConfig
{
[JsonProperty("rpc-version")]
public string RpcVersion { get; set; }
public string Version { get; set; }
[JsonProperty("download-dir")]
public string DownloadDir { get; set; }
public double SeedRatioLimit { get; set; }
public bool SeedRatioLimited { get; set; }
[JsonProperty("idle-seeding-limit")]
public long IdleSeedingLimit { get; set; }
[JsonProperty("idle-seeding-limit-enabled")]
public bool IdleSeedingLimitEnabled { get; set; }
}
}

View File

@ -16,7 +16,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission
void AddTorrentFromUrl(string torrentUrl, string downloadDirectory, TransmissionSettings settings);
void AddTorrentFromData(byte[] torrentData, string downloadDirectory, TransmissionSettings settings);
void SetTorrentSeedingConfiguration(string hash, TorrentSeedConfiguration seedConfiguration, TransmissionSettings settings);
Dictionary<string, object> GetConfig(TransmissionSettings settings);
TransmissionConfig GetConfig(TransmissionSettings settings);
string GetProtocolVersion(TransmissionSettings settings);
string GetClientVersion(TransmissionSettings settings);
void RemoveTorrent(string hash, bool removeData, TransmissionSettings settings);
@ -101,26 +101,22 @@ namespace NzbDrone.Core.Download.Clients.Transmission
{
var config = GetConfig(settings);
var version = config["rpc-version"];
return version.ToString();
return config.RpcVersion;
}
public string GetClientVersion(TransmissionSettings settings)
{
var config = GetConfig(settings);
var version = config["version"];
return version.ToString();
return config.Version;
}
public Dictionary<string, object> GetConfig(TransmissionSettings settings)
public TransmissionConfig GetConfig(TransmissionSettings settings)
{
// Gets the transmission version.
var result = GetSessionVariables(settings);
return result.Arguments;
return Json.Deserialize<TransmissionConfig>(result.Arguments.ToJson());
}
public void RemoveTorrent(string hashString, bool removeData, TransmissionSettings settings)
@ -164,15 +160,20 @@ namespace NzbDrone.Core.Download.Clients.Transmission
"hashString", // Unique torrent ID. Use this instead of the client id?
"name",
"downloadDir",
"status",
"totalSize",
"leftUntilDone",
"isFinished",
"eta",
"status",
"secondsDownloading",
"secondsSeeding",
"errorString",
"uploadedEver",
"downloadedEver",
"seedRatioLimit",
"seedRatioMode",
"seedIdleLimit",
"seedIdleMode",
"fileCount"
};

View File

@ -12,10 +12,14 @@
public int Eta { get; set; }
public TransmissionTorrentStatus Status { get; set; }
public int SecondsDownloading { get; set; }
public int SecondsSeeding { get; set; }
public string ErrorString { get; set; }
public long DownloadedEver { get; set; }
public long UploadedEver { get; set; }
public long SeedRatioLimit { get; set; }
public double SeedRatioLimit { get; set; }
public int SeedRatioMode { get; set; }
public long SeedIdleLimit { get; set; }
public int SeedIdleMode { get; set; }
public int FileCount { get; set; }
}
}

View File

@ -171,6 +171,7 @@
<Compile Include="Download\Clients\QBittorrent\QBittorrentProxySelector.cs" />
<Compile Include="Download\Clients\QBittorrent\QBittorrentProxyV1.cs" />
<Compile Include="Download\Clients\QBittorrent\QBittorrentProxyV2.cs" />
<Compile Include="Download\Clients\Transmission\TransmissionConfig.cs" />
<Compile Include="Download\DownloadClientInfo.cs" />
<Compile Include="Download\DownloadClientStatusRepository.cs" />
<Compile Include="Download\DownloadClientStatusService.cs" />

View File

@ -113,7 +113,7 @@ namespace NzbDrone.Core.Parser
private static readonly Regex SixDigitAirDateRegex = new Regex(@"(?<=[_.-])(?<airdate>(?<!\d)(?<airyear>[1-9]\d{1})(?<airmonth>[0-1][0-9])(?<airday>[0-3][0-9]))(?=[_.-])",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex CleanReleaseGroupRegex = new Regex(@"^(.*?[-._ ](S\d+E\d+)[-._ ])|(-(RP|1|NZBGeek|Obfuscated|sample|Pre|postbot|xpost|Rakuv[a-z]*|WhiteRev|BUYMORE|AsRequested))+$",
private static readonly Regex CleanReleaseGroupRegex = new Regex(@"^(.*?[-._ ](S\d+E\d+)[-._ ])|(-(RP|1|NZBGeek|Obfuscated|sample|Pre|postbot|xpost|Rakuv[a-z]*|WhiteRev|BUYMORE|AsRequested|AlternativeToRequested|GEROV|Z0iDS3N|Chamele0n))+$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex CleanTorrentSuffixRegex = new Regex(@"\[(?:ettv|rartv|rarbg|cttv)\]$",