diff --git a/src/NzbDrone.Core.Test/Blacklisting/BlacklistRepositoryFixture.cs b/src/NzbDrone.Core.Test/Blacklisting/BlacklistRepositoryFixture.cs index d6a58930d..2f87fa27e 100644 --- a/src/NzbDrone.Core.Test/Blacklisting/BlacklistRepositoryFixture.cs +++ b/src/NzbDrone.Core.Test/Blacklisting/BlacklistRepositoryFixture.cs @@ -4,6 +4,7 @@ using System.Linq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Blacklisting; +using NzbDrone.Core.Languages; using NzbDrone.Core.Qualities; using NzbDrone.Core.Test.Framework; @@ -21,7 +22,8 @@ namespace NzbDrone.Core.Test.Blacklisting { MovieId = 1234, Quality = new QualityModel(), - SourceTitle = "series.title.s01e01", + Languages = new List(), + SourceTitle = "movie.title.1998", Date = DateTime.UtcNow }; } @@ -34,7 +36,7 @@ namespace NzbDrone.Core.Test.Blacklisting } [Test] - public void should_should_have_episode_ids() + public void should_should_have_movie_id() { Subject.Insert(_blacklist); diff --git a/src/NzbDrone.Core.Test/Datastore/Converters/BooleanIntConverterFixture.cs b/src/NzbDrone.Core.Test/Datastore/Converters/BooleanIntConverterFixture.cs new file mode 100644 index 000000000..649a7303e --- /dev/null +++ b/src/NzbDrone.Core.Test/Datastore/Converters/BooleanIntConverterFixture.cs @@ -0,0 +1,59 @@ +using System; +using FluentAssertions; +using Marr.Data.Converters; +using NUnit.Framework; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Datastore.Converters +{ + [TestFixture] + public class BooleanIntConverterFixture : CoreTest + { + [TestCase(true, 1)] + [TestCase(false, 0)] + public void should_return_int_when_saving_boolean_to_db(bool input, int expected) + { + Subject.ToDB(input).Should().Be(expected); + } + + [Test] + public void should_return_db_null_for_null_value_when_saving_to_db() + { + Subject.ToDB(null).Should().Be(DBNull.Value); + } + + [TestCase(1, true)] + [TestCase(0, false)] + public void should_return_bool_when_getting_int_from_db(int input, bool expected) + { + var context = new ConverterContext + { + DbValue = (long)input + }; + + Subject.FromDB(context).Should().Be(expected); + } + + [Test] + public void should_return_db_null_for_null_value_when_getting_from_db() + { + var context = new ConverterContext + { + DbValue = DBNull.Value + }; + + Subject.FromDB(context).Should().Be(DBNull.Value); + } + + [Test] + public void should_throw_for_non_boolean_equivalent_number_value_when_getting_from_db() + { + var context = new ConverterContext + { + DbValue = (long)2 + }; + + Assert.Throws(() => Subject.FromDB(context)); + } + } +} diff --git a/src/NzbDrone.Core.Test/Datastore/Converters/CommandConverterFixture.cs b/src/NzbDrone.Core.Test/Datastore/Converters/CommandConverterFixture.cs new file mode 100644 index 000000000..17ce66cfb --- /dev/null +++ b/src/NzbDrone.Core.Test/Datastore/Converters/CommandConverterFixture.cs @@ -0,0 +1,64 @@ +using System; +using System.Data; +using FluentAssertions; +using Marr.Data.Converters; +using Moq; +using NUnit.Framework; +using NzbDrone.Common.Serializer; +using NzbDrone.Core.Datastore.Converters; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Movies.Commands; + +namespace NzbDrone.Core.Test.Datastore.Converters +{ + [TestFixture] + public class CommandConverterFixture : CoreTest + { + [Test] + public void should_return_json_string_when_saving_boolean_to_db() + { + var command = new RefreshMovieCommand(); + + Subject.ToDB(command).Should().BeOfType(); + } + + [Test] + public void should_return_null_for_null_value_when_saving_to_db() + { + Subject.ToDB(null).Should().Be(null); + } + + [Test] + public void should_return_db_null_for_db_null_value_when_saving_to_db() + { + Subject.ToDB(DBNull.Value).Should().Be(DBNull.Value); + } + + [Test] + public void should_return_command_when_getting_json_from_db() + { + var dataRecordMock = new Mock(); + dataRecordMock.Setup(s => s.GetOrdinal("Name")).Returns(0); + dataRecordMock.Setup(s => s.GetString(0)).Returns("RefreshMovie"); + + var context = new ConverterContext + { + DataRecord = dataRecordMock.Object, + DbValue = new RefreshMovieCommand().ToJson() + }; + + Subject.FromDB(context).Should().BeOfType(); + } + + [Test] + public void should_return_null_for_null_value_when_getting_from_db() + { + var context = new ConverterContext + { + DbValue = DBNull.Value + }; + + Subject.FromDB(context).Should().Be(null); + } + } +} diff --git a/src/NzbDrone.Core.Test/Datastore/Converters/DoubleConverterFixture.cs b/src/NzbDrone.Core.Test/Datastore/Converters/DoubleConverterFixture.cs new file mode 100644 index 000000000..bf4974124 --- /dev/null +++ b/src/NzbDrone.Core.Test/Datastore/Converters/DoubleConverterFixture.cs @@ -0,0 +1,70 @@ +using System; +using FluentAssertions; +using Marr.Data.Converters; +using NUnit.Framework; +using NzbDrone.Core.Datastore.Converters; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Datastore.Converters +{ + [TestFixture] + public class DoubleConverterFixture : CoreTest + { + [Test] + public void should_return_double_when_saving_double_to_db() + { + var input = 10.5D; + + Subject.ToDB(input).Should().Be(input); + } + + [Test] + public void should_return_null_for_null_value_when_saving_to_db() + { + Subject.ToDB(null).Should().Be(null); + } + + [Test] + public void should_return_db_null_for_db_null_value_when_saving_to_db() + { + Subject.ToDB(DBNull.Value).Should().Be(DBNull.Value); + } + + [Test] + public void should_return_double_when_getting_double_from_db() + { + var expected = 10.5D; + + var context = new ConverterContext + { + DbValue = expected + }; + + Subject.FromDB(context).Should().Be(expected); + } + + [Test] + public void should_return_double_when_getting_string_from_db() + { + var expected = 10.5D; + + var context = new ConverterContext + { + DbValue = $"{expected}" + }; + + Subject.FromDB(context).Should().Be(expected); + } + + [Test] + public void should_return_null_for_null_value_when_getting_from_db() + { + var context = new ConverterContext + { + DbValue = DBNull.Value + }; + + Subject.FromDB(context).Should().Be(DBNull.Value); + } + } +} diff --git a/src/NzbDrone.Core.Test/Datastore/Converters/EnumIntConverterFixture.cs b/src/NzbDrone.Core.Test/Datastore/Converters/EnumIntConverterFixture.cs new file mode 100644 index 000000000..a54296855 --- /dev/null +++ b/src/NzbDrone.Core.Test/Datastore/Converters/EnumIntConverterFixture.cs @@ -0,0 +1,58 @@ +using System; +using System.Reflection; +using FluentAssertions; +using Marr.Data.Converters; +using Marr.Data.Mapping; +using Moq; +using NUnit.Framework; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Movies; +using NzbDrone.Core.Download.Pending; + +namespace NzbDrone.Core.Test.Datastore.Converters +{ + [TestFixture] + public class EnumIntConverterFixture : CoreTest + { + [Test] + public void should_return_int_when_saving_enum_to_db() + { + Subject.ToDB(PendingReleaseReason.Delay).Should().Be((int)PendingReleaseReason.Delay); + } + + [Test] + public void should_return_db_null_for_null_value_when_saving_to_db() + { + Subject.ToDB(null).Should().Be(DBNull.Value); + } + + [Test] + public void should_return_enum_when_getting_int_from_db() + { + var mockMemberInfo = new Mock(); + mockMemberInfo.SetupGet(s => s.DeclaringType).Returns(typeof(PendingRelease)); + mockMemberInfo.SetupGet(s => s.Name).Returns("Reason"); + + var expected = PendingReleaseReason.Delay; + + var context = new ConverterContext + { + ColumnMap = new ColumnMap(mockMemberInfo.Object) { FieldType = typeof(PendingReleaseReason) }, + DbValue = (long)expected + }; + + Subject.FromDB(context).Should().Be(expected); + } + + [Test] + public void should_return_null_for_null_value_when_getting_from_db() + { + var context = new ConverterContext + { + DbValue = DBNull.Value + }; + + Subject.FromDB(context).Should().Be(null); + } + } +} diff --git a/src/NzbDrone.Core.Test/Datastore/Converters/GuidConverterFixture.cs b/src/NzbDrone.Core.Test/Datastore/Converters/GuidConverterFixture.cs new file mode 100644 index 000000000..8444fa053 --- /dev/null +++ b/src/NzbDrone.Core.Test/Datastore/Converters/GuidConverterFixture.cs @@ -0,0 +1,51 @@ +using System; +using FluentAssertions; +using Marr.Data.Converters; +using NUnit.Framework; +using NzbDrone.Core.Datastore.Converters; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Datastore.Converters +{ + [TestFixture] + public class GuidConverterFixture : CoreTest + { + [Test] + public void should_return_string_when_saving_guid_to_db() + { + var guid = Guid.NewGuid(); + + Subject.ToDB(guid).Should().Be(guid.ToString()); + } + + [Test] + public void should_return_db_null_for_null_value_when_saving_to_db() + { + Subject.ToDB(null).Should().Be(DBNull.Value); + } + + [Test] + public void should_return_guid_when_getting_string_from_db() + { + var guid = Guid.NewGuid(); + + var context = new ConverterContext + { + DbValue = guid.ToString() + }; + + Subject.FromDB(context).Should().Be(guid); + } + + [Test] + public void should_return_empty_guid_for_db_null_value_when_getting_from_db() + { + var context = new ConverterContext + { + DbValue = DBNull.Value + }; + + Subject.FromDB(context).Should().Be(Guid.Empty); + } + } +} diff --git a/src/NzbDrone.Core.Test/Datastore/Converters/Int32ConverterFixture.cs b/src/NzbDrone.Core.Test/Datastore/Converters/Int32ConverterFixture.cs new file mode 100644 index 000000000..2c10a0aaf --- /dev/null +++ b/src/NzbDrone.Core.Test/Datastore/Converters/Int32ConverterFixture.cs @@ -0,0 +1,58 @@ +using System; +using FluentAssertions; +using Marr.Data.Converters; +using NUnit.Framework; +using NzbDrone.Core.Datastore.Converters; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Datastore.Converters +{ + [TestFixture] + public class Int32ConverterFixture : CoreTest + { + [Test] + public void should_return_int_when_saving_int_to_db() + { + var i = 5; + + Subject.ToDB(5).Should().Be(5); + } + + [Test] + public void should_return_int_when_getting_int_from_db() + { + var i = 5; + + var context = new ConverterContext + { + DbValue = i + }; + + Subject.FromDB(context).Should().Be(i); + } + + [Test] + public void should_return_int_when_getting_string_from_db() + { + var i = 5; + + var context = new ConverterContext + { + DbValue = i.ToString() + }; + + Subject.FromDB(context).Should().Be(i); + } + + [Test] + public void should_return_db_null_for_db_null_value_when_getting_from_db() + { + var context = new ConverterContext + { + DbValue = DBNull.Value + }; + + Subject.FromDB(context).Should().Be(DBNull.Value); + } + } +} diff --git a/src/NzbDrone.Core.Test/Datastore/Converters/OsPathConverterFixture.cs b/src/NzbDrone.Core.Test/Datastore/Converters/OsPathConverterFixture.cs new file mode 100644 index 000000000..f7f3da0d8 --- /dev/null +++ b/src/NzbDrone.Core.Test/Datastore/Converters/OsPathConverterFixture.cs @@ -0,0 +1,49 @@ +using System; +using FluentAssertions; +using Marr.Data.Converters; +using NUnit.Framework; +using NzbDrone.Common.Disk; +using NzbDrone.Core.Datastore.Converters; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Test.Common; + +namespace NzbDrone.Core.Test.Datastore.Converters +{ + [TestFixture] + public class OsPathConverterFixture : CoreTest + { + [Test] + public void should_return_string_when_saving_os_path_to_db() + { + var path = @"C:\Test\TV".AsOsAgnostic(); + var osPath = new OsPath(path); + + Subject.ToDB(osPath).Should().Be(path); + } + + [Test] + public void should_return_os_path_when_getting_string_from_db() + { + var path = @"C:\Test\TV".AsOsAgnostic(); + var osPath = new OsPath(path); + + var context = new ConverterContext + { + DbValue = path + }; + + Subject.FromDB(context).Should().Be(osPath); + } + + [Test] + public void should_return_db_null_for_db_null_value_when_getting_from_db() + { + var context = new ConverterContext + { + DbValue = DBNull.Value + }; + + Subject.FromDB(context).Should().Be(DBNull.Value); + } + } +} diff --git a/src/NzbDrone.Core.Test/Datastore/Converters/QualityIntConverterFixture.cs b/src/NzbDrone.Core.Test/Datastore/Converters/QualityIntConverterFixture.cs new file mode 100644 index 000000000..31ae8b6b3 --- /dev/null +++ b/src/NzbDrone.Core.Test/Datastore/Converters/QualityIntConverterFixture.cs @@ -0,0 +1,58 @@ +using System; +using FluentAssertions; +using Marr.Data.Converters; +using NUnit.Framework; +using NzbDrone.Core.Datastore.Converters; +using NzbDrone.Core.Qualities; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Datastore.Converters +{ + [TestFixture] + public class QualityIntConverterFixture : CoreTest + { + [Test] + public void should_return_int_when_saving_quality_to_db() + { + var quality = Quality.Bluray1080p; + + Subject.ToDB(quality).Should().Be(quality.Id); + } + + [Test] + public void should_return_0_when_saving_db_null_to_db() + { + Subject.ToDB(DBNull.Value).Should().Be(0); + } + + [Test] + public void should_throw_when_saving_another_object_to_db() + { + Assert.Throws(() => Subject.ToDB("Not a quality")); + } + + [Test] + public void should_return_quality_when_getting_string_from_db() + { + var quality = Quality.Bluray1080p; + + var context = new ConverterContext + { + DbValue = quality.Id + }; + + Subject.FromDB(context).Should().Be(quality); + } + + [Test] + public void should_return_db_null_for_db_null_value_when_getting_from_db() + { + var context = new ConverterContext + { + DbValue = DBNull.Value + }; + + Subject.FromDB(context).Should().Be(Quality.Unknown); + } + } +} diff --git a/src/NzbDrone.Core.Test/Datastore/Converters/TimeSpanConverterFixture.cs b/src/NzbDrone.Core.Test/Datastore/Converters/TimeSpanConverterFixture.cs new file mode 100644 index 000000000..c96848179 --- /dev/null +++ b/src/NzbDrone.Core.Test/Datastore/Converters/TimeSpanConverterFixture.cs @@ -0,0 +1,65 @@ +using System; +using System.Globalization; +using FluentAssertions; +using Marr.Data.Converters; +using NUnit.Framework; +using NzbDrone.Core.Datastore.Converters; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Datastore.Converters +{ + [TestFixture] + public class TimeSpanConverterFixture : CoreTest + { + [Test] + public void should_return_string_when_saving_timespan_to_db() + { + var timeSpan = TimeSpan.FromMinutes(5); + + Subject.ToDB(timeSpan).Should().Be(timeSpan.ToString("c", CultureInfo.InvariantCulture)); + } + + [Test] + public void should_return_null_when_saving_empty_string_to_db() + { + Subject.ToDB("").Should().Be(null); + } + + [Test] + public void should_return_time_span_when_getting_time_span_from_db() + { + var timeSpan = TimeSpan.FromMinutes(5); + + var context = new ConverterContext + { + DbValue = timeSpan + }; + + Subject.FromDB(context).Should().Be(timeSpan); + } + + [Test] + public void should_return_time_span_when_getting_string_from_db() + { + var timeSpan = TimeSpan.FromMinutes(5); + + var context = new ConverterContext + { + DbValue = timeSpan.ToString("c", CultureInfo.InvariantCulture) + }; + + Subject.FromDB(context).Should().Be(timeSpan); + } + + [Test] + public void should_return_time_span_zero_for_db_null_value_when_getting_from_db() + { + var context = new ConverterContext + { + DbValue = DBNull.Value + }; + + Subject.FromDB(context).Should().Be(TimeSpan.Zero); + } + } +} diff --git a/src/NzbDrone.Core.Test/Datastore/Converters/UtcConverterFixture.cs b/src/NzbDrone.Core.Test/Datastore/Converters/UtcConverterFixture.cs new file mode 100644 index 000000000..904f653d3 --- /dev/null +++ b/src/NzbDrone.Core.Test/Datastore/Converters/UtcConverterFixture.cs @@ -0,0 +1,51 @@ +using System; +using FluentAssertions; +using Marr.Data.Converters; +using NUnit.Framework; +using NzbDrone.Core.Datastore.Converters; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Datastore.Converters +{ + [TestFixture] + public class UtcConverterFixture : CoreTest + { + [Test] + public void should_return_date_time_when_saving_date_time_to_db() + { + var dateTime = DateTime.Now; + + Subject.ToDB(dateTime).Should().Be(dateTime.ToUniversalTime()); + } + + [Test] + public void should_return_db_null_when_saving_db_null_to_db() + { + Subject.ToDB(DBNull.Value).Should().Be(DBNull.Value); + } + + [Test] + public void should_return_time_span_when_getting_time_span_from_db() + { + var dateTime = DateTime.Now.ToUniversalTime(); + + var context = new ConverterContext + { + DbValue = dateTime + }; + + Subject.FromDB(context).Should().Be(dateTime); + } + + [Test] + public void should_return_db_null_for_db_null_value_when_getting_from_db() + { + var context = new ConverterContext + { + DbValue = DBNull.Value + }; + + Subject.FromDB(context).Should().Be(DBNull.Value); + } + } +} diff --git a/src/NzbDrone.Core.Test/Download/DownloadClientStatusServiceFixture.cs b/src/NzbDrone.Core.Test/Download/DownloadClientStatusServiceFixture.cs new file mode 100644 index 000000000..a608321d9 --- /dev/null +++ b/src/NzbDrone.Core.Test/Download/DownloadClientStatusServiceFixture.cs @@ -0,0 +1,161 @@ +using System; +using System.Linq; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Core.Download; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Download +{ + public class DownloadClientStatusServiceFixture : CoreTest + { + private DateTime _epoch; + + [SetUp] + public void SetUp() + { + _epoch = DateTime.UtcNow; + + Mocker.GetMock() + .SetupGet(v => v.StartTime) + .Returns(_epoch - TimeSpan.FromHours(1)); + } + + private DownloadClientStatus WithStatus(DownloadClientStatus status) + { + Mocker.GetMock() + .Setup(v => v.FindByProviderId(1)) + .Returns(status); + + Mocker.GetMock() + .Setup(v => v.All()) + .Returns(new[] { status }); + + return status; + } + + private void VerifyUpdate() + { + Mocker.GetMock() + .Verify(v => v.Upsert(It.IsAny()), Times.Once()); + } + + private void VerifyNoUpdate() + { + Mocker.GetMock() + .Verify(v => v.Upsert(It.IsAny()), Times.Never()); + } + + [Test] + public void should_not_consider_blocked_within_5_minutes_since_initial_failure() + { + WithStatus(new DownloadClientStatus + { + InitialFailure = _epoch - TimeSpan.FromMinutes(4), + MostRecentFailure = _epoch - TimeSpan.FromSeconds(4), + EscalationLevel = 3 + }); + + Subject.RecordFailure(1); + + VerifyUpdate(); + + var status = Subject.GetBlockedProviders().FirstOrDefault(); + status.Should().BeNull(); + } + + [Test] + public void should_consider_blocked_after_5_minutes_since_initial_failure() + { + WithStatus(new DownloadClientStatus + { + InitialFailure = _epoch - TimeSpan.FromMinutes(6), + MostRecentFailure = _epoch - TimeSpan.FromSeconds(120), + EscalationLevel = 3 + }); + + Subject.RecordFailure(1); + + VerifyUpdate(); + + var status = Subject.GetBlockedProviders().FirstOrDefault(); + status.Should().NotBeNull(); + } + + [Test] + public void should_not_escalate_further_till_after_5_minutes_since_initial_failure() + { + var origStatus = WithStatus(new DownloadClientStatus + { + InitialFailure = _epoch - TimeSpan.FromMinutes(4), + MostRecentFailure = _epoch - TimeSpan.FromSeconds(4), + EscalationLevel = 3 + }); + + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + + var status = Subject.GetBlockedProviders().FirstOrDefault(); + status.Should().BeNull(); + + origStatus.EscalationLevel.Should().Be(3); + } + + [Test] + public void should_escalate_further_after_5_minutes_since_initial_failure() + { + WithStatus(new DownloadClientStatus + { + InitialFailure = _epoch - TimeSpan.FromMinutes(6), + MostRecentFailure = _epoch - TimeSpan.FromSeconds(120), + EscalationLevel = 3 + }); + + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + + var status = Subject.GetBlockedProviders().FirstOrDefault(); + status.Should().NotBeNull(); + + status.EscalationLevel.Should().BeGreaterThan(3); + } + + [Test] + public void should_not_escalate_beyond_3_hours() + { + WithStatus(new DownloadClientStatus + { + InitialFailure = _epoch - TimeSpan.FromMinutes(6), + MostRecentFailure = _epoch - TimeSpan.FromSeconds(120), + EscalationLevel = 3 + }); + + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + + var status = Subject.GetBlockedProviders().FirstOrDefault(); + status.Should().NotBeNull(); + status.DisabledTill.Should().HaveValue(); + status.DisabledTill.Should().NotBeAfter(_epoch + TimeSpan.FromHours(3.1)); + } + } +} diff --git a/src/NzbDrone.Core.Test/Download/DownloadClientTests/Blackhole/TorrentBlackholeFixture.cs b/src/NzbDrone.Core.Test/Download/DownloadClientTests/Blackhole/TorrentBlackholeFixture.cs index 47544ab34..554f09e85 100644 --- a/src/NzbDrone.Core.Test/Download/DownloadClientTests/Blackhole/TorrentBlackholeFixture.cs +++ b/src/NzbDrone.Core.Test/Download/DownloadClientTests/Blackhole/TorrentBlackholeFixture.cs @@ -74,6 +74,11 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole .Returns(1000000); } + protected void GivenMagnetFilePath(string extension = ".magnet") + { + _magnetFilePath = Path.ChangeExtension(_filePath, extension); + } + protected override RemoteMovie CreateRemoteMovie() { var remoteMovie = base.CreateRemoteMovie(); @@ -99,6 +104,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole var result = Subject.GetItems().Single(); VerifyCompleted(result); + + result.CanBeRemoved.Should().BeFalse(); + result.CanMoveFiles.Should().BeFalse(); } [Test] @@ -137,7 +145,27 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole [Test] public void Download_should_save_magnet_if_enabled() { + GivenMagnetFilePath(); + Subject.Definition.Settings.As().SaveMagnetFiles = true; + + var remoteMovie = CreateRemoteMovie(); + remoteMovie.Release.DownloadUrl = null; + + Subject.Download(remoteMovie); + + Mocker.GetMock().Verify(c => c.Get(It.Is(v => v.Url.FullUri == _downloadUrl)), Times.Never()); + Mocker.GetMock().Verify(c => c.OpenWriteStream(_filePath), Times.Never()); + Mocker.GetMock().Verify(c => c.OpenWriteStream(_magnetFilePath), Times.Once()); + Mocker.GetMock().Verify(c => c.DownloadFile(It.IsAny(), It.IsAny()), Times.Never()); + } + + [Test] + public void Download_should_save_magnet_using_specified_extension() + { + var magnetFileExtension = ".url"; + GivenMagnetFilePath(magnetFileExtension); Subject.Definition.Settings.As().SaveMagnetFiles = true; + Subject.Definition.Settings.As().MagnetFileExtension = magnetFileExtension; var remoteMovie = CreateRemoteMovie(); remoteMovie.Release.DownloadUrl = null; diff --git a/src/NzbDrone.Core.Test/Download/DownloadClientTests/DelugeTests/DelugeFixture.cs b/src/NzbDrone.Core.Test/Download/DownloadClientTests/DelugeTests/DelugeFixture.cs index 39577835e..e25a7cc6b 100644 --- a/src/NzbDrone.Core.Test/Download/DownloadClientTests/DelugeTests/DelugeFixture.cs +++ b/src/NzbDrone.Core.Test/Download/DownloadClientTests/DelugeTests/DelugeFixture.cs @@ -290,6 +290,24 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DelugeTests item.CanBeRemoved.Should().Be(canBeRemoved); } + [Test] + public void GetItems_should_ignore_items_without_hash() + { + _downloading.Hash = null; + + GivenTorrents(new List + { + _downloading, + _queued + }); + + var items = Subject.GetItems(); + + items.Should().HaveCount(1); + + items.First().Status.Should().Be(DownloadItemStatus.Queued); + } + [Test] public void should_return_status_with_outputdirs() { diff --git a/src/NzbDrone.Core.Test/Download/DownloadClientTests/DownloadStationTests/TorrentDownloadStationFixture.cs b/src/NzbDrone.Core.Test/Download/DownloadClientTests/DownloadStationTests/TorrentDownloadStationFixture.cs index c4e396965..cd9896d99 100644 --- a/src/NzbDrone.Core.Test/Download/DownloadClientTests/DownloadStationTests/TorrentDownloadStationFixture.cs +++ b/src/NzbDrone.Core.Test/Download/DownloadClientTests/DownloadStationTests/TorrentDownloadStationFixture.cs @@ -73,6 +73,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests Transfer = new Dictionary { { "size_downloaded", "0"}, + { "size_uploaded", "0"}, { "speed_download", "0" } } } @@ -96,6 +97,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests Transfer = new Dictionary { { "size_downloaded", "1000"}, + { "size_uploaded", "100"}, { "speed_download", "0" } }, } @@ -119,6 +121,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests Transfer = new Dictionary { { "size_downloaded", "1000"}, + { "size_uploaded", "100"}, { "speed_download", "0" } } } @@ -142,6 +145,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests Transfer = new Dictionary { { "size_downloaded", "100"}, + { "size_uploaded", "10"}, { "speed_download", "50" } } } @@ -165,6 +169,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests Transfer = new Dictionary { { "size_downloaded", "10"}, + { "size_uploaded", "1"}, { "speed_download", "0" } } } @@ -188,6 +193,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests Transfer = new Dictionary { { "size_downloaded", "1000"}, + { "size_uploaded", "100"}, { "speed_download", "0" } } } @@ -211,6 +217,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests Transfer = new Dictionary { { "size_downloaded", "1000"}, + { "size_uploaded", "100"}, { "speed_download", "0" } } } @@ -234,6 +241,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests Transfer = new Dictionary { { "size_downloaded", "1000"}, + { "size_uploaded", "100"}, { "speed_download", "0" } } } @@ -257,6 +265,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DownloadStationTests Transfer = new Dictionary { { "size_downloaded", "1000"}, + { "size_uploaded", "100"}, { "speed_download", "0" } } } diff --git a/src/NzbDrone.Core.Test/Download/DownloadClientTests/NzbgetTests/NzbgetFixture.cs b/src/NzbDrone.Core.Test/Download/DownloadClientTests/NzbgetTests/NzbgetFixture.cs index 4be3a54a6..756098a6e 100644 --- a/src/NzbDrone.Core.Test/Download/DownloadClientTests/NzbgetTests/NzbgetFixture.cs +++ b/src/NzbDrone.Core.Test/Download/DownloadClientTests/NzbgetTests/NzbgetFixture.cs @@ -168,10 +168,13 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests GivenQueue(_queued); GivenHistory(null); - + var result = Subject.GetItems().Single(); VerifyQueued(result); + + result.CanBeRemoved.Should().BeTrue(); + result.CanMoveFiles.Should().BeTrue(); } [Test] @@ -185,6 +188,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests var result = Subject.GetItems().Single(); VerifyPaused(result); + + result.CanBeRemoved.Should().BeTrue(); + result.CanMoveFiles.Should().BeTrue(); } [Test] @@ -198,6 +204,25 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests var result = Subject.GetItems().Single(); VerifyDownloading(result); + + result.CanBeRemoved.Should().BeTrue(); + result.CanMoveFiles.Should().BeTrue(); + } + + [Test] + public void post_processing_item_should_have_required_properties() + { + _queued.ActiveDownloads = 1; + + GivenQueue(_queued); + GivenHistory(null); + + _queued.RemainingSizeLo = 0; + + var result = Subject.GetItems().Single(); + + result.CanBeRemoved.Should().BeTrue(); + result.CanMoveFiles.Should().BeTrue(); } [Test] @@ -209,6 +234,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests var result = Subject.GetItems().Single(); VerifyCompleted(result); + + result.CanBeRemoved.Should().BeTrue(); + result.CanMoveFiles.Should().BeTrue(); } [Test] @@ -377,6 +405,37 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests result.OutputPath.Should().Be(@"O:\mymount\Droned.1998.1080p.WEB-DL-DRONE".AsOsAgnostic()); } + [Test] + public void should_use_dest_dir_if_final_dir_is_null() + { + GivenQueue(null); + GivenHistory(_completed); + + Subject.GetItems().First().OutputPath.Should().Be(_completed.DestDir); + } + + [Test] + public void should_use_dest_dir_if_final_dir_is_not_set() + { + _completed.FinalDir = string.Empty; + + GivenQueue(null); + GivenHistory(_completed); + + Subject.GetItems().First().OutputPath.Should().Be(_completed.DestDir); + } + + [Test] + public void should_use_final_dir_when_set_instead_of_dest_dir() + { + _completed.FinalDir = "/remote/mount/tv2/Droned.S01E01.Pilot.1080p.WEB-DL-DRONE"; + + GivenQueue(null); + GivenHistory(_completed); + + Subject.GetItems().First().OutputPath.Should().Be(_completed.FinalDir); + } + [TestCase("11.0", false)] [TestCase("12.0", true)] [TestCase("11.0-b30ef0134", false)] diff --git a/src/NzbDrone.Core.Test/Download/DownloadClientTests/QBittorrentTests/QBittorrentFixture.cs b/src/NzbDrone.Core.Test/Download/DownloadClientTests/QBittorrentTests/QBittorrentFixture.cs index 245dbb4c7..b3d05e7f6 100644 --- a/src/NzbDrone.Core.Test/Download/DownloadClientTests/QBittorrentTests/QBittorrentFixture.cs +++ b/src/NzbDrone.Core.Test/Download/DownloadClientTests/QBittorrentTests/QBittorrentFixture.cs @@ -9,6 +9,7 @@ using NzbDrone.Core.MediaFiles.TorrentInfo; using NzbDrone.Core.Download; using NzbDrone.Core.Download.Clients.QBittorrent; using NzbDrone.Test.Common; +using NzbDrone.Core.Exceptions; namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests { @@ -37,8 +38,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests .Returns(r => new HttpResponse(r, new HttpHeader(), new Byte[0])); Mocker.GetMock() - .Setup(s => s.GetConfig(It.IsAny())) - .Returns(new QBittorrentPreferences()); + .Setup(s => s.GetConfig(It.IsAny())) + .Returns(new QBittorrentPreferences() { DhtEnabled = true }); + + Mocker.GetMock() + .Setup(s => s.GetProxy(It.IsAny(), It.IsAny())) + .Returns(Mocker.GetMock().Object); } protected void GivenRedirectToMagnet() @@ -95,15 +100,18 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests Subject.Definition.Settings.As().RecentMoviePriority = (int) QBittorrentPriority.First; } - protected void GivenMaxRatio(float maxRatio, bool removeOnMaxRatio = true) + protected void GivenGlobalSeedLimits(float maxRatio, int maxSeedingTime = -1, bool removeOnMaxRatio = false) { Mocker.GetMock() - .Setup(s => s.GetConfig(It.IsAny())) - .Returns(new QBittorrentPreferences - { - RemoveOnMaxRatio = removeOnMaxRatio, - MaxRatio = maxRatio - }); + .Setup(s => s.GetConfig(It.IsAny())) + .Returns(new QBittorrentPreferences + { + RemoveOnMaxRatio = removeOnMaxRatio, + MaxRatio = maxRatio, + MaxRatioEnabled = maxRatio >= 0, + MaxSeedingTime = maxSeedingTime, + MaxSeedingTimeEnabled = maxSeedingTime >= 0 + }); } protected virtual void GivenTorrents(List torrents) @@ -154,7 +162,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests var item = Subject.GetItems().Single(); VerifyPaused(item); - item.RemainingTime.Should().NotBe(TimeSpan.Zero); + item.RemainingTime.Should().NotHaveValue(); } [TestCase("pausedUP")] @@ -162,6 +170,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests [TestCase("uploading")] [TestCase("stalledUP")] [TestCase("checkingUP")] + [TestCase("forcedUP")] public void completed_item_should_have_required_properties(string state) { var torrent = new QBittorrentTorrent @@ -184,6 +193,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests [TestCase("queuedDL")] [TestCase("checkingDL")] + [TestCase("metaDL")] public void queued_item_should_have_required_properties(string state) { var torrent = new QBittorrentTorrent @@ -201,7 +211,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests var item = Subject.GetItems().Single(); VerifyQueued(item); - item.RemainingTime.Should().NotBe(TimeSpan.Zero); + item.RemainingTime.Should().NotHaveValue(); } [Test] @@ -243,7 +253,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests var item = Subject.GetItems().Single(); VerifyWarning(item); - item.RemainingTime.Should().NotBe(TimeSpan.Zero); + item.RemainingTime.Should().NotHaveValue(); } [Test] @@ -271,6 +281,35 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests id.Should().Be(expectedHash); } + [Test] + public void Download_should_refuse_magnet_if_no_trackers_provided_and_dht_is_disabled() + { + Mocker.GetMock() + .Setup(s => s.GetConfig(It.IsAny())) + .Returns(new QBittorrentPreferences() { DhtEnabled = false }); + + var remoteMovie = CreateRemoteMovie(); + remoteMovie.Release.DownloadUrl = "magnet:?xt=urn:btih:ZPBPA2P6ROZPKRHK44D5OW6NHXU5Z6KR"; + + Assert.Throws(() => Subject.Download(remoteMovie)); + } + + [Test] + public void Download_should_accept_magnet_if_trackers_provided_and_dht_is_disabled() + { + Mocker.GetMock() + .Setup(s => s.GetConfig(It.IsAny())) + .Returns(new QBittorrentPreferences() { DhtEnabled = false }); + + var remoteMovie = CreateRemoteMovie(); + remoteMovie.Release.DownloadUrl = "magnet:?xt=urn:btih:ZPBPA2P6ROZPKRHK44D5OW6NHXU5Z6KR&tr=udp://abc"; + + Assert.DoesNotThrow(() => Subject.Download(remoteMovie)); + + Mocker.GetMock() + .Verify(s => s.AddTorrentFromUrl(It.IsAny(), It.IsAny()), Times.Once()); + } + [Test] public void Download_should_set_top_priority() { @@ -352,7 +391,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests [Test] public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_not_reached() { - GivenMaxRatio(1.0f); + GivenGlobalSeedLimits(1.0f); var torrent = new QBittorrentTorrent { @@ -373,11 +412,11 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests item.CanMoveFiles.Should().BeFalse(); } - [Test] - public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_reached_and_not_paused() + protected virtual QBittorrentTorrent GivenCompletedTorrent( + string state = "pausedUP", + float ratio = 0.1f, float ratioLimit = -2, + int seedingTime = 1, int seedingTimeLimit = -2) { - GivenMaxRatio(1.0f); - var torrent = new QBittorrentTorrent { Hash = "HASH", @@ -385,12 +424,32 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests Size = 1000, Progress = 1.0, Eta = 8640000, - State = "uploading", + State = state, Label = "", SavePath = "", - Ratio = 1.0f + Ratio = ratio, + RatioLimit = ratioLimit, + SeedingTimeLimit = seedingTimeLimit }; - GivenTorrents(new List { torrent }); + + GivenTorrents(new List() { torrent }); + + Mocker.GetMock() + .Setup(s => s.GetTorrentProperties("HASH", It.IsAny())) + .Returns(new QBittorrentTorrentProperties + { + Hash = "HASH", + SeedingTime = seedingTime + }); + + return torrent; + } + + [Test] + public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_reached_and_not_paused() + { + GivenGlobalSeedLimits(1.0f); + GivenCompletedTorrent("uploading", ratio: 1.0f); var item = Subject.GetItems().Single(); item.CanBeRemoved.Should().BeFalse(); @@ -400,21 +459,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests [Test] public void should_not_be_removable_and_should_not_allow_move_files_if_max_ratio_is_not_set() { - GivenMaxRatio(1.0f, false); - - var torrent = new QBittorrentTorrent - { - Hash = "HASH", - Name = _title, - Size = 1000, - Progress = 1.0, - Eta = 8640000, - State = "uploading", - Label = "", - SavePath = "", - Ratio = 1.0f - }; - GivenTorrents(new List { torrent }); + GivenGlobalSeedLimits(-1); + GivenCompletedTorrent("pausedUP", ratio: 1.0f); var item = Subject.GetItems().Single(); item.CanBeRemoved.Should().BeFalse(); @@ -424,21 +470,86 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests [Test] public void should_be_removable_and_should_allow_move_files_if_max_ratio_reached_and_paused() { - GivenMaxRatio(1.0f); + GivenGlobalSeedLimits(1.0f); + GivenCompletedTorrent("pausedUP", ratio: 1.0f); - var torrent = new QBittorrentTorrent - { - Hash = "HASH", - Name = _title, - Size = 1000, - Progress = 1.0, - Eta = 8640000, - State = "pausedUP", - Label = "", - SavePath = "", - Ratio = 1.0f - }; - GivenTorrents(new List { torrent }); + 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.0f); + GivenCompletedTorrent("pausedUP", ratio: 1.0f, ratioLimit: 0.8f); + + 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.2f); + GivenCompletedTorrent("pausedUP", ratio: 0.5f, ratioLimit: 0.8f); + + 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_seedingtime_reached_and_not_paused() + { + GivenGlobalSeedLimits(-1, 20); + GivenCompletedTorrent("uploading", ratio: 2.0f, 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_seedingtime_reached_and_paused() + { + GivenGlobalSeedLimits(-1, 20); + GivenCompletedTorrent("pausedUP", ratio: 2.0f, 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_seedingtime_reached_and_paused() + { + GivenGlobalSeedLimits(-1, 40); + GivenCompletedTorrent("pausedUP", ratio: 2.0f, seedingTime: 20, seedingTimeLimit: 10); + + var item = Subject.GetItems().Single(); + item.CanBeRemoved.Should().BeTrue(); + item.CanMoveFiles.Should().BeTrue(); + } + + [Test] + public void should_not_be_removable_if_overridden_max_seedingtime_not_reached_and_paused() + { + GivenGlobalSeedLimits(-1, 20); + GivenCompletedTorrent("pausedUP", ratio: 2.0f, seedingTime: 30, seedingTimeLimit: 40); + + 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_seedingtime_reached_but_ratio_not_and_paused() + { + GivenGlobalSeedLimits(2.0f, 20); + GivenCompletedTorrent("pausedUP", ratio: 1.0f, seedingTime: 30); var item = Subject.GetItems().Single(); item.CanBeRemoved.Should().BeTrue(); @@ -449,7 +560,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests public void should_get_category_from_the_category_if_set() { const string category = "movies-radarr"; - GivenMaxRatio(1.0f); + GivenGlobalSeedLimits(1.0f); var torrent = new QBittorrentTorrent { @@ -474,7 +585,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests public void should_get_category_from_the_label_if_the_category_is_not_available() { const string category = "movies-radarr"; - GivenMaxRatio(1.0f); + GivenGlobalSeedLimits(1.0f); var torrent = new QBittorrentTorrent { @@ -494,5 +605,32 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests var item = Subject.GetItems().Single(); item.Category.Should().Be(category); } + + [Test] + public void should_handle_eta_biginteger() + { + // Let this stand as a lesson to never write temporary unit tests on your dev machine and claim it works. + // Commit the tests and let it run with the official build on the official build agents. + // (Also don't replace library versions in your build script) + + var json = "{ \"eta\": 18446744073709335000 }"; + var torrent = Newtonsoft.Json.JsonConvert.DeserializeObject(json); + torrent.Eta.ToString().Should().Be("18446744073709335000"); + + } + + [Test] + public void Test_should_force_api_version_check() + { + // Set TestConnection up to fail quick + Mocker.GetMock() + .Setup(v => v.GetApiVersion(It.IsAny())) + .Returns(new Version(1, 0)); + + Subject.Test(); + + Mocker.GetMock() + .Verify(v => v.GetProxy(It.IsAny(), true), Times.Once()); + } } } diff --git a/src/NzbDrone.Core.Test/Download/DownloadServiceFixture.cs b/src/NzbDrone.Core.Test/Download/DownloadServiceFixture.cs index 77811aa8f..30a4b0f32 100644 --- a/src/NzbDrone.Core.Test/Download/DownloadServiceFixture.cs +++ b/src/NzbDrone.Core.Test/Download/DownloadServiceFixture.cs @@ -173,14 +173,50 @@ namespace NzbDrone.Core.Test.Download } [Test] - public void should_not_attempt_download_if_client_isnt_configure() + public void Download_report_should_not_trigger_indexer_backoff_on_indexer_404_error() { - Subject.DownloadReport(_parseResult); + var mock = WithUsenetClient(); + mock.Setup(s => s.Download(It.IsAny())) + .Callback(v => { + throw new ReleaseUnavailableException(v.Release, "Error", new WebException()); + }); + + Assert.Throws(() => Subject.DownloadReport(_parseResult)); + + Mocker.GetMock() + .Verify(v => v.RecordFailure(It.IsAny(), It.IsAny()), Times.Never()); + } + + [Test] + public void should_not_attempt_download_if_client_isnt_configured() + { + Assert.Throws(() => Subject.DownloadReport(_parseResult)); Mocker.GetMock().Verify(c => c.Download(It.IsAny()), Times.Never()); VerifyEventNotPublished(); + } + + [Test] + public void should_attempt_download_even_if_client_is_disabled() + { + var mockUsenet = WithUsenetClient(); - ExceptionVerification.ExpectedWarns(1); + Mocker.GetMock() + .Setup(v => v.GetBlockedProviders()) + .Returns(new List + { + new DownloadClientStatus + { + ProviderId = _downloadClients.First().Definition.Id, + DisabledTill = DateTime.UtcNow.AddHours(3) + } + }); + + Subject.DownloadReport(_parseResult); + + Mocker.GetMock().Verify(c => c.GetBlockedProviders(), Times.Never()); + mockUsenet.Verify(c => c.Download(It.IsAny()), Times.Once()); + VerifyEventPublished(); } [Test] diff --git a/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/AddFixture.cs b/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/AddFixture.cs index d0ffe1a39..39d526e2c 100644 --- a/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/AddFixture.cs +++ b/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/AddFixture.cs @@ -13,6 +13,7 @@ using NzbDrone.Core.Profiles; using NzbDrone.Core.Qualities; using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Movies; +using System.Linq; namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests { @@ -63,7 +64,11 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests Mocker.GetMock() .Setup(s => s.All()) - .Returns(new List()); + .Returns(_heldReleases); + + Mocker.GetMock() + .Setup(s => s.AllByMovieId(It.IsAny())) + .Returns(i => _heldReleases.Where(v => v.MovieId == i).ToList()); Mocker.GetMock() .Setup(s => s.GetMovie(It.IsAny())) diff --git a/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveGrabbedFixture.cs b/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveGrabbedFixture.cs index c0a9f9a56..670865e40 100644 --- a/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveGrabbedFixture.cs +++ b/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveGrabbedFixture.cs @@ -13,6 +13,7 @@ using NzbDrone.Core.Profiles; using NzbDrone.Core.Qualities; using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Movies; +using System.Linq; namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests { @@ -23,8 +24,9 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests private Movie _movie; private Profile _profile; private ReleaseInfo _release; - private ParsedMovieInfo _parsedEpisodeInfo; - private RemoteMovie _remoteEpisode; + private ParsedMovieInfo _parsedMovieInfo; + private RemoteMovie _remoteMovie; + private List _heldReleases; [SetUp] public void Setup() @@ -48,28 +50,34 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests _release = Builder.CreateNew().Build(); - _parsedEpisodeInfo = Builder.CreateNew().Build(); - _parsedEpisodeInfo.Quality = new QualityModel(Quality.HDTV720p); + _parsedMovieInfo = Builder.CreateNew().Build(); + _parsedMovieInfo.Quality = new QualityModel(Quality.HDTV720p); - _remoteEpisode = new RemoteMovie(); - //_remoteEpisode.Episodes = new List{ _episode }; - _remoteEpisode.Movie = _movie; - _remoteEpisode.ParsedMovieInfo = _parsedEpisodeInfo; - _remoteEpisode.Release = _release; + _remoteMovie = new RemoteMovie(); + _remoteMovie.Movie = _movie; + _remoteMovie.ParsedMovieInfo = _parsedMovieInfo; + _remoteMovie.Release = _release; - _temporarilyRejected = new DownloadDecision(_remoteEpisode, new Rejection("Temp Rejected", RejectionType.Temporary)); + _temporarilyRejected = new DownloadDecision(_remoteMovie, new Rejection("Temp Rejected", RejectionType.Temporary)); + + _heldReleases = new List(); Mocker.GetMock() .Setup(s => s.All()) - .Returns(new List()); + .Returns(_heldReleases); + + Mocker.GetMock() + .Setup(s => s.AllByMovieId(It.IsAny())) + .Returns(i => _heldReleases.Where(v => v.MovieId == i).ToList()); Mocker.GetMock() .Setup(s => s.GetMovie(It.IsAny())) .Returns(_movie); - //Mocker.GetMock() - // .Setup(s => s.GetMovie(It.IsAny(), _series.Title)) - // .Returns(_episode); + Mocker.GetMock() + .Setup(s => s.GetMovies(It.IsAny>())) + .Returns(new List { _movie }); + Mocker.GetMock() .Setup(s => s.PrioritizeDecisionsForMovies(It.IsAny>())) @@ -78,27 +86,25 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests private void GivenHeldRelease(QualityModel quality) { - var parsedEpisodeInfo = _parsedEpisodeInfo.JsonClone(); - parsedEpisodeInfo.Quality = quality; + var parsedMovieInfo = _parsedMovieInfo.JsonClone(); + parsedMovieInfo.Quality = quality; var heldReleases = Builder.CreateListOfSize(1) .All() .With(h => h.MovieId = _movie.Id) .With(h => h.Release = _release.JsonClone()) - .With(h => h.ParsedMovieInfo = parsedEpisodeInfo) + .With(h => h.ParsedMovieInfo = parsedMovieInfo) .Build(); - Mocker.GetMock() - .Setup(s => s.All()) - .Returns(heldReleases); + _heldReleases.AddRange(heldReleases); } [Test] public void should_delete_if_the_grabbed_quality_is_the_same() { - GivenHeldRelease(_parsedEpisodeInfo.Quality); + GivenHeldRelease(_parsedMovieInfo.Quality); - Subject.Handle(new MovieGrabbedEvent(_remoteEpisode)); + Subject.Handle(new MovieGrabbedEvent(_remoteMovie)); VerifyDelete(); } @@ -108,7 +114,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests { GivenHeldRelease(new QualityModel(Quality.SDTV)); - Subject.Handle(new MovieGrabbedEvent(_remoteEpisode)); + Subject.Handle(new MovieGrabbedEvent(_remoteMovie)); VerifyDelete(); } @@ -118,7 +124,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests { GivenHeldRelease(new QualityModel(Quality.Bluray720p)); - Subject.Handle(new MovieGrabbedEvent(_remoteEpisode)); + Subject.Handle(new MovieGrabbedEvent(_remoteMovie)); VerifyNoDelete(); } diff --git a/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemovePendingFixture.cs b/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemovePendingFixture.cs index 6e1ebdb51..fb638f4de 100644 --- a/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemovePendingFixture.cs +++ b/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemovePendingFixture.cs @@ -38,6 +38,10 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests .Setup(s => s.GetMovie(It.IsAny())) .Returns(_movie); + Mocker.GetMock() + .Setup(s => s.GetMovies(It.IsAny>())) + .Returns(new List { _movie }); + Mocker.GetMock() .Setup(s => s.GetMovie(It.IsAny())) .Returns(_movie); @@ -49,7 +53,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests { Id = id, ParsedMovieInfo = new ParsedMovieInfo { MovieTitle = title, Year = year }, - MovieId = _movie.Id, + MovieId = _movie.Id }); } @@ -65,90 +69,6 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests AssertRemoved(1); } - [Test] - public void should_not_remove_different_release() - { - AddPending(id: 1, title: "Movie", year: 2001); - AddPending(2, "Movie 2", 2001); - - var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-movie{1}", 1, _movie.Id)); - - Subject.RemovePendingQueueItems(queueId); - - AssertRemoved(1); - } - - /*[Test] - public void should_remove_multiple_releases_release() - { - AddPending(id: 1, title: "Movie", year: 2001); - AddPending(id: 2, title: "Movie", year: 2002); - AddPending(id: 3, title: "Movie", year: 2003); - AddPending(id: 4, title: "Movie", year: 2003); - - var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-movie{1}", 3, _movie.Id)); - - Subject.RemovePendingQueueItems(queueId); - - AssertRemoved(3, 4); - } - - [Test] - public void should_not_remove_diffrent_season() - { - AddPending(id: 1, title: "Movie", year: 2001); - AddPending(id: 2, title: "Movie", year: 2001); - AddPending(id: 3, title: "Movie", year: 2001); - AddPending(id: 4, title: "Movie", year: 2001); - - var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-movie{1}", 1, _movie.Id)); - - Subject.RemovePendingQueueItems(queueId); - - AssertRemoved(1, 2); - } - - [Test] - public void should_not_remove_diffrent_episodes() - { - AddPending(id: 1, title: "Movie", year: 2001); - AddPending(id: 2, title: "Movie", year: 2001); - AddPending(id: 3, title: "Movie", year: 2001); - AddPending(id: 4, title: "Movie", year: 2001); - - var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-movie{1}", 1, _movie.Id)); - - Subject.RemovePendingQueueItems(queueId); - - AssertRemoved(1, 2); - } - - [Test] - public void should_not_remove_multiepisodes() - { - AddPending(id: 1, title: "Movie", year: 2001); - AddPending(id: 2, title: "Movie", year: 2001); - - var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-movie{1}", 1, _movie.Id)); - - Subject.RemovePendingQueueItems(queueId); - - AssertRemoved(1); - } - - [Test] - public void should_not_remove_singleepisodes() - { - AddPending(id: 1, title: "Movie", year: 2001); - AddPending(id: 2, title: "Movie", year: 2001); - - var queueId = HashConverter.GetHashInt31(string.Format("pending-{0}-movie{1}", 2, _movie.Id)); - - Subject.RemovePendingQueueItems(queueId); - - AssertRemoved(2); - }*/ - private void AssertRemoved(params int[] ids) { Mocker.GetMock().Verify(c => c.DeleteMany(It.Is>(s => s.SequenceEqual(ids)))); diff --git a/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveRejectedFixture.cs b/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveRejectedFixture.cs index 0a91cdc7d..3c0cc0ef9 100644 --- a/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveRejectedFixture.cs +++ b/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveRejectedFixture.cs @@ -69,6 +69,10 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests Mocker.GetMock() .Setup(s => s.GetMovie(It.IsAny())) .Returns(_movie); + + Mocker.GetMock() + .Setup(s => s.GetMovies(It.IsAny>())) + .Returns(new List { _movie }); Mocker.GetMock() .Setup(s => s.GetMovie(It.IsAny())) diff --git a/src/NzbDrone.Core.Test/Files/Indexers/TorrentRss/EvolutionWorld.xml b/src/NzbDrone.Core.Test/Files/Indexers/TorrentRss/EvolutionWorld.xml new file mode 100644 index 000000000..48c5b651b --- /dev/null +++ b/src/NzbDrone.Core.Test/Files/Indexers/TorrentRss/EvolutionWorld.xml @@ -0,0 +1,30 @@ + + + + Evolution World + Advanced RSS Feed for xbtitFM by Petr1fied + http://ew.pw + Tue, 15 Aug 2017 00:00:00 +0000 + (c) 2017 Evolution World + + + + <![CDATA[[TVShow --> TVShow Bluray 720p] Fargo S01 Complete Season 1 720p BRRip DD5.1 x264-PSYPHER [SEEDERS (3)/LEECHERS (0)]]]> + Fargo S01 Complete Season 1 720p BRRip DD5.1 x264-PSYPHER



Plot:

Various chronicles of deception, intrigue and murder in and around frozen Minnesota.

Note::-
Encode is tested and its perfect, no sync issue there in any episode.
All episodes comes with AC3 Audio for better audio and video plaback and English Subs are muxed in video .

TECHNiCAL Information:


RUNTIME..................: 1 hr x 10
Total SIZE...............: 9.75 GiB
Total Episodes...........: 10
VIDEO CODEC..............: x264 2nd Pass (High,L4.1)
RESOLUTION...............: 1280x720
BITRATE (Video)..........: 2100 Kbps - 2400 kbps
Aspect Ratio.............: 16:9
Video Container..........: MKV
FRAMERATE................: 23.967 fps
AUDIO....................: English AC3 6 Channel 384 kbps
SUBTITLES................: English, English (SDH)
CHAPTERS.................: Yes
SOURCE...................: DON (Thanks !)


GENRE...................: Crime | Drama | Thriller
RATING..................: 9.1/10 from 140,765 users
IMDB link...............: http://www.imdb.com/title/tt2802850/]]>
+ http://ew.pw/index.php?page=torrent-details&id=dea071a7a62a0d662538d46402fb112f30b8c9fa + http://ew.pw/index.php?page=torrent-details&id=dea071a7a62a0d662538d46402fb112f30b8c9fa + + Sun, 13 Aug 2017 22:21:43 +0000 +
+ + + <![CDATA[[TVShow --> TVShow Bluray 720p] American Horror Story S04 Complete Season 4 720p BRRip DD5.1 x264 - PSYPHER [SEEDERS (2)/LEECHERS (0)]]]> + + http://ew.pw/index.php?page=torrent-details&id=2725fe19ea2addf5aafbd523d134191b8abbb2ee + http://ew.pw/index.php?page=torrent-details&id=2725fe19ea2addf5aafbd523d134191b8abbb2ee + + Fri, 28 Jul 2017 16:29:51 +0000 + +
+
+ \ No newline at end of file diff --git a/src/NzbDrone.Core.Test/Files/Indexers/TorrentRss/LimeTorrents.xml b/src/NzbDrone.Core.Test/Files/Indexers/TorrentRss/LimeTorrents.xml new file mode 100644 index 000000000..8c136e7f1 --- /dev/null +++ b/src/NzbDrone.Core.Test/Files/Indexers/TorrentRss/LimeTorrents.xml @@ -0,0 +1,98 @@ + + + + limetorrents.cc - RSS Feed + http://www.limetorrents.cc/ + Latest Torrents RSS. + en-us + Thu, 16 Feb 2017 05:48:36 +0200 + Thu, 16 Feb 2017 05:48:36 +0200 + http://blogs.law.harvard.edu/tech/rss + limetorrents.cc RSS Generator 1.1 + + The Expanse 2x04 (720p-HDTV-x264-SVA)[VTV] + http://www.limetorrents.cc/The-Expanse-2x04-(720p-HDTV-x264-SVA)[VTV]-torrent-8643587.html + 16 Feb 2017 05:24:26 +0300 + TV shows + http://www.limetorrents.cc/The-Expanse-2x04-(720p-HDTV-x264-SVA)[VTV]-torrent-8643587.html + 880496711 + + TV shows
+ Seeds: 0
Leechers: 0
Size: 839.71 MB

More @ limetorrents.cc
]]> +
+ + http://www.limetorrents.cc/The-Expanse-2x04-(720p-HDTV-x264-SVA)[VTV]-torrent-8643587.html + TV shows + +
+ + Criminal Minds S12E13 720p HDTV x264-FLEET[PRiME] + http://www.limetorrents.cc/Criminal-Minds-S12E13-720p-HDTV-x264-FLEET[PRiME]-torrent-8643586.html + 16 Feb 2017 05:20:49 +0300 + TV shows + http://www.limetorrents.cc/Criminal-Minds-S12E13-720p-HDTV-x264-FLEET[PRiME]-torrent-8643586.html + 940818158 + + TV shows
+ Seeds: 0
Leechers: 0
Size: 897.23 MB

More @ limetorrents.cc
]]> +
+ + http://www.limetorrents.cc/Criminal-Minds-S12E13-720p-HDTV-x264-FLEET[PRiME]-torrent-8643586.html + TV shows + +
+ + Legion S01E02 720p HDTV x264-AVS[PRiME] + http://www.limetorrents.cc/Legion-S01E02-720p-HDTV-x264-AVS[PRiME]-torrent-8643585.html + 16 Feb 2017 05:20:48 +0300 + TV shows + http://www.limetorrents.cc/Legion-S01E02-720p-HDTV-x264-AVS[PRiME]-torrent-8643585.html + 1320654292 + + TV shows
+ Seeds: 0
Leechers: 0
Size: 1.23 GB

More @ limetorrents.cc
]]> +
+ + http://www.limetorrents.cc/Legion-S01E02-720p-HDTV-x264-AVS[PRiME]-torrent-8643585.html + TV shows + +
+ + Suits S06E14 HDTV x264-SVA[PRiME] + http://www.limetorrents.cc/Suits-S06E14-HDTV-x264-SVA[PRiME]-torrent-8643579.html + 16 Feb 2017 05:11:58 +0300 + TV shows + http://www.limetorrents.cc/Suits-S06E14-HDTV-x264-SVA[PRiME]-torrent-8643579.html + 212274667 + + TV shows
+ Seeds: 0
Leechers: 0
Size: 202.44 MB

More @ limetorrents.cc
]]> +
+ + http://www.limetorrents.cc/Suits-S06E14-HDTV-x264-SVA[PRiME]-torrent-8643579.html + TV shows + +
+ + The Expanse S02E04 HDTV x264-SVA[PRiME] + http://www.limetorrents.cc/The-Expanse-S02E04-HDTV-x264-SVA[PRiME]-torrent-8643578.html + 16 Feb 2017 05:11:57 +0300 + TV shows + http://www.limetorrents.cc/The-Expanse-S02E04-HDTV-x264-SVA[PRiME]-torrent-8643578.html + 269445781 + + TV shows
+ Seeds: 0
Leechers: 0
Size: 256.96 MB

More @ limetorrents.cc
]]> +
+ + http://www.limetorrents.cc/The-Expanse-S02E04-HDTV-x264-SVA[PRiME]-torrent-8643578.html + TV shows + +
+
+
\ No newline at end of file diff --git a/src/NzbDrone.Core.Test/Files/Indexers/Torznab/torznab_animetosho.xml b/src/NzbDrone.Core.Test/Files/Indexers/Torznab/torznab_animetosho.xml new file mode 100644 index 000000000..94505a443 --- /dev/null +++ b/src/NzbDrone.Core.Test/Files/Indexers/Torznab/torznab_animetosho.xml @@ -0,0 +1,60 @@ + + + + + Anime Tosho + https://localhost/ + Latest releases feed + en-gb + 30 + Wed, 17 May 2017 20:36:06 +0000 + + + [finFAGs]_Frame_Arms_Girl_07_(1280x720_TV_AAC)_[1262B6F7].mkv + Wed, 17 May 2017 20:36:06 +0000 + https://localhost/view/123451 + Anime + Total Size: 301.8 MB
]]>
+ https://localhost/view/finfags-_frame_arms_girl_07_-1280x720_tv_aac-_-1262b6f7-mkv.123451 + https://localhost/view/finfags-_frame_arms_girl_07_-1280x720_tv_aac-_-1262b6f7-mkv.123451 + + TokyoTosho + + + + + + + + + + + + +
+ + [HorribleSubs] Frame Arms Girl - 07 [720p].mkv + Mon, 15 May 2017 19:15:56 +0000 + https://localhost/view/123452 + Anime + Total Size: 452.0 MB
]]>
+ https://localhost/view/horriblesubs-frame-arms-girl-07-720p-mkv.123452 + https://localhost/view/horriblesubs-frame-arms-girl-07-720p-mkv.123452 + + + TokyoTosho + + + + + + + + + + + + +
+
+
diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/DownloadClientCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/DownloadClientCheckFixture.cs index dc6986d79..665038e32 100644 --- a/src/NzbDrone.Core.Test/HealthCheck/Checks/DownloadClientCheckFixture.cs +++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/DownloadClientCheckFixture.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using NUnit.Framework; using NzbDrone.Core.Download; using NzbDrone.Core.HealthCheck.Checks; -using NzbDrone.Core.Indexers; using NzbDrone.Core.Test.Framework; using NzbDrone.Test.Common; @@ -26,7 +25,7 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks public void should_return_error_when_download_client_throws() { var downloadClient = Mocker.GetMock(); - downloadClient.Setup(s => s.Definition).Returns(new IndexerDefinition{Name = "Test"}); + downloadClient.Setup(s => s.Definition).Returns(new DownloadClientDefinition{Name = "Test"}); downloadClient.Setup(s => s.GetItems()) .Throws(); @@ -36,8 +35,6 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks .Returns(new IDownloadClient[] { downloadClient.Object }); Subject.Check().ShouldBeError(); - - ExceptionVerification.ExpectedErrors(1); } [Test] diff --git a/src/NzbDrone.Core.Test/HealthCheck/Checks/IndexerStatusCheckFixture.cs b/src/NzbDrone.Core.Test/HealthCheck/Checks/IndexerStatusCheckFixture.cs index 7fd6eb8ee..1d71d3a80 100644 --- a/src/NzbDrone.Core.Test/HealthCheck/Checks/IndexerStatusCheckFixture.cs +++ b/src/NzbDrone.Core.Test/HealthCheck/Checks/IndexerStatusCheckFixture.cs @@ -57,13 +57,6 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks { Subject.Check().ShouldBeOk(); } - [Test] - public void should_not_return_error_when_indexer_failed_less_than_an_hour() - { - GivenIndexer(1, 0.1, 0.5); - - Subject.Check().ShouldBeOk(); - } [Test] public void should_return_warning_if_indexer_unavailable() diff --git a/src/NzbDrone.Core.Test/HistoryTests/HistoryRepositoryFixture.cs b/src/NzbDrone.Core.Test/HistoryTests/HistoryRepositoryFixture.cs index 6115d729d..bd6a581d7 100644 --- a/src/NzbDrone.Core.Test/HistoryTests/HistoryRepositoryFixture.cs +++ b/src/NzbDrone.Core.Test/HistoryTests/HistoryRepositoryFixture.cs @@ -4,6 +4,8 @@ using NUnit.Framework; using NzbDrone.Core.History; using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Qualities; +using NzbDrone.Core.Languages; +using System.Collections.Generic; namespace NzbDrone.Core.Test.HistoryTests { @@ -20,6 +22,7 @@ namespace NzbDrone.Core.Test.HistoryTests { var history = Builder.CreateNew() .With(c => c.Quality = new QualityModel()) + .With(c => c.Languages = new List()) .BuildNew(); history.Data.Add("key1", "value1"); @@ -36,12 +39,14 @@ namespace NzbDrone.Core.Test.HistoryTests { var historyBluray = Builder.CreateNew() .With(c => c.Quality = new QualityModel(Quality.Bluray1080p)) + .With(c => c.Languages = new List { Language.English }) .With(c => c.MovieId = 12) .With(c => c.EventType = HistoryEventType.Grabbed) .BuildNew(); var historyDvd = Builder.CreateNew() .With(c => c.Quality = new QualityModel(Quality.DVD)) + .With(c => c.Languages = new List { Language.English }) .With(c => c.MovieId = 12) .With(c => c.EventType = HistoryEventType.Grabbed) .BuildNew(); diff --git a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedBlacklistFixture.cs b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedBlacklistFixture.cs index 3e0208545..ba4ed976e 100644 --- a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedBlacklistFixture.cs +++ b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedBlacklistFixture.cs @@ -7,6 +7,7 @@ using NzbDrone.Core.Qualities; using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Movies; using System.Collections.Generic; +using NzbDrone.Core.Languages; namespace NzbDrone.Core.Test.Housekeeping.Housekeepers { @@ -19,6 +20,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers var blacklist = Builder.CreateNew() .With(h => h.MovieId = new int()) .With(h => h.Quality = new QualityModel()) + .With(h => h.Languages = new List()) .BuildNew(); Db.Insert(blacklist); @@ -36,6 +38,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers var blacklist = Builder.CreateNew() .With(h => h.MovieId = new int()) .With(h => h.Quality = new QualityModel()) + .With(h => h.Languages = new List()) .With(b => b.MovieId = movie.Id) .BuildNew(); diff --git a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedHistoryItemsFixture.cs b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedHistoryItemsFixture.cs index fb1b257c3..adba4307d 100644 --- a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedHistoryItemsFixture.cs +++ b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedHistoryItemsFixture.cs @@ -1,10 +1,12 @@ -using FizzWare.NBuilder; +using FizzWare.NBuilder; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Housekeeping.Housekeepers; 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 { @@ -31,6 +33,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers var history = Builder.CreateNew() .With(h => h.Quality = new QualityModel()) + .With(h => h.Languages = new List()) .BuildNew(); Db.Insert(history); @@ -45,6 +48,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers var history = Builder.CreateNew() .With(h => h.Quality = new QualityModel()) + .With(h => h.Languages = new List()) .With(h => h.MovieId = _movie.Id) .BuildNew(); Db.Insert(history); @@ -53,4 +57,4 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers AllStoredModels.Should().HaveCount(1); } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatusFixture.cs b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatusFixture.cs index 459a3180a..94c88be49 100644 --- a/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatusFixture.cs +++ b/src/NzbDrone.Core.Test/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatusFixture.cs @@ -51,4 +51,4 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers AllStoredModels.Should().Contain(h => h.ProviderId == _indexer.Id); } } -} +} \ No newline at end of file diff --git a/src/NzbDrone.Core.Test/IndexerTests/IndexerStatusServiceFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/IndexerStatusServiceFixture.cs index 5f41a3020..55ed8abfb 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/IndexerStatusServiceFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/IndexerStatusServiceFixture.cs @@ -3,6 +3,7 @@ using System.Linq; using FluentAssertions; using Moq; using NUnit.Framework; +using NzbDrone.Common.EnvironmentInfo; using NzbDrone.Core.Indexers; using NzbDrone.Core.Test.Framework; @@ -11,11 +12,15 @@ namespace NzbDrone.Core.Test.IndexerTests public class IndexerStatusServiceFixture : CoreTest { private DateTime _epoch; - + [SetUp] public void SetUp() { _epoch = DateTime.UtcNow; + + Mocker.GetMock() + .SetupGet(v => v.StartTime) + .Returns(_epoch - TimeSpan.FromHours(1)); } private void WithStatus(IndexerStatus status) @@ -29,25 +34,16 @@ namespace NzbDrone.Core.Test.IndexerTests .Returns(new[] { status }); } - private void VerifyUpdate(bool updated = true) + private void VerifyUpdate() { Mocker.GetMock() - .Verify(v => v.Upsert(It.IsAny()), Times.Exactly(updated ? 1 : 0)); + .Verify(v => v.Upsert(It.IsAny()), Times.Once()); } - [Test] - public void should_start_backoff_on_first_failure() + private void VerifyNoUpdate() { - WithStatus(new IndexerStatus()); - - Subject.RecordFailure(1); - - VerifyUpdate(); - - var status = Subject.GetBlockedProviders().FirstOrDefault(); - status.Should().NotBeNull(); - status.DisabledTill.Should().HaveValue(); - status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(5), 500); + Mocker.GetMock() + .Verify(v => v.Upsert(It.IsAny()), Times.Never()); } [Test] @@ -70,22 +66,7 @@ namespace NzbDrone.Core.Test.IndexerTests Subject.RecordSuccess(1); - VerifyUpdate(false); - } - - [Test] - public void should_preserve_escalation_on_intermittent_success() - { - WithStatus(new IndexerStatus { MostRecentFailure = _epoch - TimeSpan.FromSeconds(4), EscalationLevel = 3 }); - - Subject.RecordSuccess(1); - Subject.RecordSuccess(1); - Subject.RecordFailure(1); - - var status = Subject.GetBlockedProviders().FirstOrDefault(); - status.Should().NotBeNull(); - status.DisabledTill.Should().HaveValue(); - status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(15), 500); + VerifyNoUpdate(); } } } diff --git a/src/NzbDrone.Core.Test/IndexerTests/TorrentRssIndexerTests/TorrentRssIndexerFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/TorrentRssIndexerTests/TorrentRssIndexerFixture.cs index e253e24c1..0a384c099 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/TorrentRssIndexerTests/TorrentRssIndexerFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/TorrentRssIndexerTests/TorrentRssIndexerFixture.cs @@ -5,9 +5,11 @@ using Moq; using NUnit.Framework; using NzbDrone.Common.Http; using NzbDrone.Core.Indexers; +using NzbDrone.Core.Indexers.Exceptions; using NzbDrone.Core.Indexers.TorrentRss; using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Test.Framework; +using NzbDrone.Test.Common; namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests { @@ -48,7 +50,7 @@ namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests releases.Should().HaveCount(50); releases.First().Should().BeOfType(); - + var torrentInfo = (TorrentInfo)releases.First(); torrentInfo.Title.Should().Be("Conan.2015.02.05.Jeff.Bridges.720p.HDTV.X264-CROOKS"); @@ -173,6 +175,32 @@ namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests torrentInfo.Seeders.Should().NotHaveValue(); } + [Test] + public void should_parse_recent_feed_from_LimeTorrents() + { + GivenRecentFeedResponse("TorrentRss/LimeTorrents.xml"); + + var releases = Subject.FetchRecent(); + + releases.Should().HaveCount(5); + releases.First().Should().BeOfType(); + + var torrentInfo = releases.First() as TorrentInfo; + + torrentInfo.Title.Should().Be("The Expanse 2x04 (720p-HDTV-x264-SVA)[VTV]"); + torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); + torrentInfo.DownloadUrl.Should().Be("http://itorrents.org/torrent/51C578C9823DD58F6EEA287C368ED935843D63AB.torrent?title=The-Expanse-2x04-(720p-HDTV-x264-SVA)[VTV]"); + torrentInfo.InfoUrl.Should().BeNullOrEmpty(); + torrentInfo.CommentUrl.Should().Be("http://www.limetorrents.cc/The-Expanse-2x04-(720p-HDTV-x264-SVA)[VTV]-torrent-8643587.html"); + torrentInfo.Indexer.Should().Be(Subject.Definition.Name); + torrentInfo.PublishDate.Should().Be(DateTime.Parse("16 Feb 2017 05:24:26 +0300").ToUniversalTime()); + torrentInfo.Size.Should().Be(880496711); + torrentInfo.InfoHash.Should().BeNull(); + torrentInfo.MagnetUrl.Should().BeNull(); + torrentInfo.Peers.Should().NotHaveValue(); + torrentInfo.Seeders.Should().NotHaveValue(); + } + [Test] public void should_parse_recent_feed_from_AnimeTosho_without_size() { @@ -213,7 +241,7 @@ namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests torrentInfo.Title.Should().Be("DAYS - 05 (1280x720 HEVC2 AAC).mkv"); torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); - torrentInfo.DownloadUrl.Should().Be("http://storage.animetosho.org/torrents/4b58360143d59a55cbd922397a3eaa378165f3ff/DAYS%20-%2005%20%281280x720%20HEVC2%20AAC%29.torrent"); + torrentInfo.DownloadUrl.Should().Be("http://storage.animetosho.org/torrents/4b58360143d59a55cbd922397a3eaa378165f3ff/DAYS%20-%2005%20%281280x720%20HEVC2%20AAC%29.torrent"); } [Test] @@ -234,20 +262,43 @@ namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests } [Test] - public void should_parse_recent_feed_from_DanishBits_without_description() + public void should_parse_recent_feed_from_EveolutionWorld_without_size() { - GivenRecentFeedResponse("TorrentRss/DanishBits.xml"); - - var oldSettings = Subject.Definition.Settings as TorrentRssIndexerSettings; - oldSettings.AllowZeroSize = true; - Subject.Definition.Settings = oldSettings; + Subject.Definition.Settings.As().AllowZeroSize = true; + GivenRecentFeedResponse("TorrentRss/EvolutionWorld.xml"); var releases = Subject.FetchRecent(); - oldSettings.AllowZeroSize = false; - Subject.Definition.Settings = oldSettings; + releases.Should().HaveCount(2); + releases.First().Should().BeOfType(); + + var torrentInfo = releases.First() as TorrentInfo; + + torrentInfo.Title.Should().Be("[TVShow --> TVShow Bluray 720p] Fargo S01 Complete Season 1 720p BRRip DD5.1 x264-PSYPHER [SEEDERS (3)/LEECHERS (0)]"); + torrentInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); + torrentInfo.DownloadUrl.Should().Be("http://ew.pw/download.php?id=dea071a7a62a0d662538d46402fb112f30b8c9fa&f=Fargo%20S01%20Complete%20Season%201%20720p%20BRRip%20DD5.1%20x264-PSYPHER.torrent&auth=secret"); + torrentInfo.InfoUrl.Should().BeNullOrEmpty(); + torrentInfo.CommentUrl.Should().BeNullOrEmpty(); + torrentInfo.Indexer.Should().Be(Subject.Definition.Name); + torrentInfo.PublishDate.Should().Be(DateTime.Parse("2017-08-13T22:21:43Z").ToUniversalTime()); + torrentInfo.Size.Should().Be(0); + torrentInfo.InfoHash.Should().BeNull(); + torrentInfo.MagnetUrl.Should().BeNull(); + torrentInfo.Peers.Should().NotHaveValue(); + torrentInfo.Seeders.Should().NotHaveValue(); + } + + [Test] + public void should_record_indexer_failure_if_unsupported_feed() + { + GivenRecentFeedResponse("TorrentRss/invalid/TorrentDay_NoPubDate.xml"); + + Subject.FetchRecent().Should().BeEmpty(); + + Mocker.GetMock() + .Verify(v => v.RecordFailure(It.IsAny(), TimeSpan.Zero), Times.Once()); - releases.Should().HaveCount(30); + ExceptionVerification.ExpectedErrors(1); } } } diff --git a/src/NzbDrone.Core.Test/IndexerTests/TorrentRssIndexerTests/TorrentRssSettingsDetectorFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/TorrentRssIndexerTests/TorrentRssSettingsDetectorFixture.cs index a85ac91e6..9a3aac3ef 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/TorrentRssIndexerTests/TorrentRssSettingsDetectorFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/TorrentRssIndexerTests/TorrentRssSettingsDetectorFixture.cs @@ -180,6 +180,26 @@ namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests }); } + [Test] + public void should_detect_rss_settings_for_LimeTorrents() + { + _indexerSettings.AllowZeroSize = true; + + GivenRecentFeedResponse("TorrentRss/LimeTorrents.xml"); + + var settings = Subject.Detect(_indexerSettings); + + settings.ShouldBeEquivalentTo(new TorrentRssIndexerParserSettings + { + UseEZTVFormat = false, + UseEnclosureUrl = true, + UseEnclosureLength = true, + ParseSizeInDescription = false, + ParseSeedersInDescription = false, + SizeElementName = null + }); + } + [Test] public void should_detect_rss_settings_for_AlphaRatio() { @@ -234,14 +254,11 @@ namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests } [TestCase("BitMeTv/BitMeTv.xml")] - [TestCase("Fanzub/fanzub.xml")] - [TestCase("KickassTorrents/KickassTorrents.xml")] [TestCase("IPTorrents/IPTorrents.xml")] - [TestCase("Newznab/newznab_nzb_su.xml")] [TestCase("Nyaa/Nyaa.xml")] - [TestCase("Omgwtfnzbs/Omgwtfnzbs.xml")] [TestCase("Torznab/torznab_hdaccess_net.xml")] [TestCase("Torznab/torznab_tpb.xml")] + [TestCase("Torznab/torznab_animetosho.xml")] public void should_detect_recent_feed(string rssXmlFile) { GivenRecentFeedResponse(rssXmlFile); @@ -268,9 +285,7 @@ namespace NzbDrone.Core.Test.IndexerTests.TorrentRssIndexerTests var ex = Assert.Throws(() => Subject.Detect(_indexerSettings)); - ex.Message.Should().Contain("Empty feed"); - - ExceptionVerification.ExpectedErrors(1); + ex.Message.Should().Contain("Rss feed must have a pubDate"); } [TestCase("Torrentleech/Torrentleech.xml")] diff --git a/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs b/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs index f303cbfaa..72982a55b 100644 --- a/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerTests/TorznabTests/TorznabFixture.cs @@ -44,7 +44,7 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests Mocker.GetMock() .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.GET))) .Returns(r => new HttpResponse(r, new HttpHeader(), recentFeed)); - + var releases = Subject.FetchRecent(); releases.Should().HaveCount(5); @@ -95,6 +95,37 @@ namespace NzbDrone.Core.Test.IndexerTests.TorznabTests releaseInfo.Peers.Should().Be(36724); } + [Test] + public void should_parse_recent_feed_from_torznab_animetosho() + { + var recentFeed = ReadAllText(@"Files/Indexers/Torznab/torznab_animetosho.xml"); + + Mocker.GetMock() + .Setup(o => o.Execute(It.Is(v => v.Method == HttpMethod.GET))) + .Returns(r => new HttpResponse(r, new HttpHeader(), recentFeed)); + + var releases = Subject.FetchRecent(); + + releases.Should().HaveCount(2); + + releases.First().Should().BeOfType(); + var releaseInfo = releases.First() as TorrentInfo; + + releaseInfo.Title.Should().Be("[finFAGs]_Frame_Arms_Girl_07_(1280x720_TV_AAC)_[1262B6F7].mkv"); + releaseInfo.DownloadProtocol.Should().Be(DownloadProtocol.Torrent); + releaseInfo.DownloadUrl.Should().Be("http://storage.localhost/torrents/123451.torrent"); + releaseInfo.InfoUrl.Should().Be("https://localhost/view/finfags-_frame_arms_girl_07_-1280x720_tv_aac-_-1262b6f7-mkv.123451"); + releaseInfo.CommentUrl.Should().Be("https://localhost/view/finfags-_frame_arms_girl_07_-1280x720_tv_aac-_-1262b6f7-mkv.123451"); + releaseInfo.Indexer.Should().Be(Subject.Definition.Name); + releaseInfo.PublishDate.Should().Be(DateTime.Parse("Wed, 17 May 2017 20:36:06 +0000").ToUniversalTime()); + releaseInfo.Size.Should().Be(316477946); + releaseInfo.TvdbId.Should().Be(0); + releaseInfo.TvRageId.Should().Be(0); + releaseInfo.InfoHash.Should().Be("2d69a861bef5a9f2cdf791b7328e37b7953205e1"); + releaseInfo.Seeders.Should().BeNull(); + releaseInfo.Peers.Should().BeNull(); + } + [Test] public void should_use_pagesize_reported_by_caps() { diff --git a/src/NzbDrone.Core.Test/Languages/LanguageFixture.cs b/src/NzbDrone.Core.Test/Languages/LanguageFixture.cs new file mode 100644 index 000000000..203693c08 --- /dev/null +++ b/src/NzbDrone.Core.Test/Languages/LanguageFixture.cs @@ -0,0 +1,79 @@ +using System.Linq; +using System.Collections.Generic; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Languages; + +namespace NzbDrone.Core.Test.Languages +{ + [TestFixture] + public class LanguageFixture : CoreTest + { + public static object[] FromIntCases = + { + new object[] {1, Language.English}, + new object[] {2, Language.French}, + new object[] {3, Language.Spanish}, + new object[] {4, Language.German}, + new object[] {5, Language.Italian}, + new object[] {6, Language.Danish}, + new object[] {7, Language.Dutch}, + new object[] {8, Language.Japanese}, + new object[] {9, Language.Icelandic}, + new object[] {10, Language.Chinese}, + new object[] {11, Language.Russian}, + new object[] {12, Language.Polish}, + new object[] {13, Language.Vietnamese}, + new object[] {14, Language.Swedish}, + new object[] {15, Language.Norwegian}, + new object[] {16, Language.Finnish}, + new object[] {17, Language.Turkish}, + new object[] {18, Language.Portuguese}, + new object[] {19, Language.Flemish}, + new object[] {20, Language.Greek}, + new object[] {21, Language.Korean}, + new object[] {22, Language.Hungarian} + }; + + public static object[] ToIntCases = + { + new object[] {Language.English, 1}, + new object[] {Language.French, 2}, + new object[] {Language.Spanish, 3}, + new object[] {Language.German, 4}, + new object[] {Language.Italian, 5}, + new object[] {Language.Danish, 6}, + new object[] {Language.Dutch, 7}, + new object[] {Language.Japanese, 8}, + new object[] {Language.Icelandic, 9}, + new object[] {Language.Chinese, 10}, + new object[] {Language.Russian, 11}, + new object[] {Language.Polish, 12}, + new object[] {Language.Vietnamese, 13}, + new object[] {Language.Swedish, 14}, + new object[] {Language.Norwegian, 15}, + new object[] {Language.Finnish, 16}, + new object[] {Language.Turkish, 17}, + new object[] {Language.Portuguese, 18}, + new object[] {Language.Flemish, 19}, + new object[] {Language.Greek, 20}, + new object[] {Language.Korean, 21}, + new object[] {Language.Hungarian, 22} + }; + + [Test, TestCaseSource("FromIntCases")] + public void should_be_able_to_convert_int_to_languageTypes(int source, Language expected) + { + var language = (Language)source; + language.Should().Be(expected); + } + + [Test, TestCaseSource("ToIntCases")] + public void should_be_able_to_convert_languageTypes_to_int(Language source, int expected) + { + var i = (int)source; + i.Should().Be(expected); + } + } +} diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index 6ccf62969..016db40c4 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -115,7 +115,17 @@ + + + + + + + + + + @@ -167,6 +177,7 @@ + @@ -270,6 +281,7 @@ + @@ -307,6 +319,7 @@ + @@ -419,6 +432,15 @@ PreserveNewest + + Always + + + Always + + + Always + Always diff --git a/src/NzbDrone.Core.Test/Profiles/Delay/DelayProfileServiceFixture.cs b/src/NzbDrone.Core.Test/Profiles/Delay/DelayProfileServiceFixture.cs new file mode 100644 index 000000000..ff2df10f4 --- /dev/null +++ b/src/NzbDrone.Core.Test/Profiles/Delay/DelayProfileServiceFixture.cs @@ -0,0 +1,112 @@ +using System.Collections.Generic; +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Profiles.Delay; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.Profiles.Delay +{ + [TestFixture] + public class DelayProfileServiceFixture : CoreTest + { + private List _delayProfiles; + private DelayProfile _first; + private DelayProfile _last; + + [SetUp] + public void Setup() + { + _delayProfiles = Builder.CreateListOfSize(4) + .TheFirst(1) + .With(d => d.Order = int.MaxValue) + .TheNext(1) + .With(d => d.Order = 1) + .TheNext(1) + .With(d => d.Order = 2) + .TheNext(1) + .With(d => d.Order = 3) + .Build() + .ToList(); + + _first = _delayProfiles[1]; + _last = _delayProfiles.Last(); + + Mocker.GetMock() + .Setup(s => s.All()) + .Returns(_delayProfiles); + } + + [Test] + public void should_move_to_first_if_afterId_is_null() + { + var moving = _last; + var result = Subject.Reorder(moving.Id, null).OrderBy(d => d.Order).ToList(); + var moved = result.First(); + + moved.Id.Should().Be(moving.Id); + moved.Order.Should().Be(1); + } + + [Test] + public void should_move_after_if_afterId_is_not_null() + { + var after = _first; + var moving = _last; + var result = Subject.Reorder(moving.Id, _first.Id).OrderBy(d => d.Order).ToList(); + var moved = result[1]; + + moved.Id.Should().Be(moving.Id); + moved.Order.Should().Be(after.Order + 1); + } + + [Test] + public void should_reorder_delay_profiles_that_are_after_moved() + { + var moving = _last; + var result = Subject.Reorder(moving.Id, null).OrderBy(d => d.Order).ToList(); + + for (int i = 1; i < result.Count; i++) + { + var delayProfile = result[i]; + + if (delayProfile.Id == 1) + { + delayProfile.Order.Should().Be(int.MaxValue); + } + + else + { + delayProfile.Order.Should().Be(i + 1); + } + } + } + + [Test] + public void should_not_change_afters_order_if_moving_was_after() + { + var after = _first; + var afterOrder = after.Order; + var moving = _last; + var result = Subject.Reorder(moving.Id, _first.Id).OrderBy(d => d.Order).ToList(); + var afterMove = result.First(); + + afterMove.Id.Should().Be(after.Id); + afterMove.Order.Should().Be(afterOrder); + } + + [Test] + public void should_change_afters_order_if_moving_was_before() + { + var after = _last; + var afterOrder = after.Order; + var moving = _first; + + var result = Subject.Reorder(moving.Id, after.Id).OrderBy(d => d.Order).ToList(); + var afterMove = result.Single(d => d.Id == after.Id); + + afterMove.Order.Should().BeLessThan(afterOrder); + } + } +} diff --git a/src/NzbDrone.Core.Test/ThingiProviderTests/ProviderBaseFixture.cs b/src/NzbDrone.Core.Test/ThingiProviderTests/ProviderBaseFixture.cs new file mode 100644 index 000000000..a3a5a0c51 --- /dev/null +++ b/src/NzbDrone.Core.Test/ThingiProviderTests/ProviderBaseFixture.cs @@ -0,0 +1,29 @@ +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Indexers.Newznab; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.ThingiProviderTests +{ + public class ProviderRepositoryFixture : DbTest + { + [Test] + public void should_read_write_download_provider() + { + var model = Builder.CreateNew().BuildNew(); + var newznabSettings = Builder.CreateNew().Build(); + model.Settings = newznabSettings; + Subject.Insert(model); + + var storedProvider = Subject.Single(); + + storedProvider.Settings.Should().BeOfType(); + + var storedSetting = (NewznabSettings)storedProvider.Settings; + + storedSetting.ShouldBeEquivalentTo(newznabSettings, o=>o.IncludingAllRuntimeProperties()); + } + } +} diff --git a/src/NzbDrone.Core.Test/ThingiProviderTests/ProviderStatusServiceFixture.cs b/src/NzbDrone.Core.Test/ThingiProviderTests/ProviderStatusServiceFixture.cs new file mode 100644 index 000000000..80d533ed2 --- /dev/null +++ b/src/NzbDrone.Core.Test/ThingiProviderTests/ProviderStatusServiceFixture.cs @@ -0,0 +1,167 @@ +using System; +using System.Linq; +using FluentAssertions; +using Moq; +using NLog; +using NUnit.Framework; +using NzbDrone.Common.EnvironmentInfo; +using NzbDrone.Core.Messaging.Events; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.ThingiProvider; +using NzbDrone.Core.ThingiProvider.Status; + +namespace NzbDrone.Core.Test.ThingiProviderTests +{ + public class MockProviderStatus : ProviderStatusBase + { + } + + public interface IMockProvider : IProvider + { + } + + public interface IMockProviderStatusRepository : IProviderStatusRepository + { + } + + public class MockProviderStatusService : ProviderStatusServiceBase + { + public MockProviderStatusService(IMockProviderStatusRepository providerStatusRepository, IEventAggregator eventAggregator, IRuntimeInfo runtimeInfo, Logger logger) + : base(providerStatusRepository, eventAggregator, runtimeInfo, logger) + { + + } + } + + public class ProviderStatusServiceFixture : CoreTest + { + private DateTime _epoch; + + [SetUp] + public void SetUp() + { + _epoch = DateTime.UtcNow; + + Mocker.GetMock() + .SetupGet(v => v.StartTime) + .Returns(_epoch - TimeSpan.FromHours(1)); + } + + private void GivenRecentStartup() + { + Mocker.GetMock() + .SetupGet(v => v.StartTime) + .Returns(_epoch - TimeSpan.FromMinutes(12)); + } + + private MockProviderStatus WithStatus(MockProviderStatus status) + { + Mocker.GetMock() + .Setup(v => v.FindByProviderId(1)) + .Returns(status); + + Mocker.GetMock() + .Setup(v => v.All()) + .Returns(new[] { status }); + + return status; + } + + private void VerifyUpdate() + { + Mocker.GetMock() + .Verify(v => v.Upsert(It.IsAny()), Times.Once()); + } + + private void VerifyNoUpdate() + { + Mocker.GetMock() + .Verify(v => v.Upsert(It.IsAny()), Times.Never()); + } + + [Test] + public void should_start_backoff_on_first_failure() + { + WithStatus(new MockProviderStatus()); + + Subject.RecordFailure(1); + + VerifyUpdate(); + + var status = Subject.GetBlockedProviders().FirstOrDefault(); + status.Should().NotBeNull(); + status.DisabledTill.Should().HaveValue(); + status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(5), 500); + } + + [Test] + public void should_cancel_backoff_on_success() + { + WithStatus(new MockProviderStatus { EscalationLevel = 2 }); + + Subject.RecordSuccess(1); + + VerifyUpdate(); + + var status = Subject.GetBlockedProviders().FirstOrDefault(); + status.Should().BeNull(); + } + + [Test] + public void should_not_store_update_if_already_okay() + { + WithStatus(new MockProviderStatus { EscalationLevel = 0 }); + + Subject.RecordSuccess(1); + + VerifyNoUpdate(); + } + + [Test] + public void should_preserve_escalation_on_intermittent_success() + { + WithStatus(new MockProviderStatus + { + InitialFailure = _epoch - TimeSpan.FromSeconds(20), + MostRecentFailure = _epoch - TimeSpan.FromSeconds(4), + EscalationLevel = 3 + }); + + Subject.RecordSuccess(1); + Subject.RecordSuccess(1); + Subject.RecordFailure(1); + + var status = Subject.GetBlockedProviders().FirstOrDefault(); + status.Should().NotBeNull(); + status.DisabledTill.Should().HaveValue(); + status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(15), 500); + } + + [Test] + public void should_not_escalate_further_till_after_5_minutes_since_startup() + { + GivenRecentStartup(); + + var origStatus = WithStatus(new MockProviderStatus + { + InitialFailure = _epoch - TimeSpan.FromMinutes(6), + MostRecentFailure = _epoch - TimeSpan.FromSeconds(120), + EscalationLevel = 3 + }); + + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + Subject.RecordFailure(1); + + var status = Subject.GetBlockedProviders().FirstOrDefault(); + status.Should().NotBeNull(); + + origStatus.EscalationLevel.Should().Be(3); + status.DisabledTill.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(5), 500); + } + } +} diff --git a/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs b/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs index 16298c329..915cf79e1 100644 --- a/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs +++ b/src/NzbDrone.Core/Download/Clients/Blackhole/TorrentBlackhole.cs @@ -50,7 +50,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole title = FileNameBuilder.CleanFileName(title); - var filepath = Path.Combine(Settings.TorrentFolder, string.Format("{0}.magnet", title)); + var filepath = Path.Combine(Settings.TorrentFolder, $"{title}.{Settings.MagnetFileExtension.Trim('.')}"); var fileContent = Encoding.UTF8.GetBytes(magnetLink); using (var stream = _diskProvider.OpenWriteStream(filepath)) diff --git a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatus.cs b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatus.cs index ac021bb3c..60c956b99 100644 --- a/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatus.cs +++ b/src/NzbDrone.Core/Housekeeping/Housekeepers/CleanupOrphanedIndexerStatus.cs @@ -1,4 +1,4 @@ -using NzbDrone.Core.Datastore; +using NzbDrone.Core.Datastore; namespace NzbDrone.Core.Housekeeping.Housekeepers { @@ -20,7 +20,7 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers WHERE Id IN ( SELECT IndexerStatus.Id FROM IndexerStatus LEFT OUTER JOIN Indexers - ON IndexerStatus.IndexerId = Indexers.Id + ON IndexerStatus.ProviderId = Indexers.Id WHERE Indexers.Id IS NULL)"); } } diff --git a/src/NzbDrone.Core/Profiles/Delay/DelayProfileService.cs b/src/NzbDrone.Core/Profiles/Delay/DelayProfileService.cs index 7f9a1159d..da7f3fa93 100644 --- a/src/NzbDrone.Core/Profiles/Delay/DelayProfileService.cs +++ b/src/NzbDrone.Core/Profiles/Delay/DelayProfileService.cs @@ -1,5 +1,7 @@ +using System; using System.Collections.Generic; using System.Linq; +using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; namespace NzbDrone.Core.Profiles.Delay @@ -14,25 +16,35 @@ namespace NzbDrone.Core.Profiles.Delay List AllForTag(int tagId); List AllForTags(HashSet tagIds); DelayProfile BestForTags(HashSet tagIds); + List Reorder(int id, int? afterId); } public class DelayProfileService : IDelayProfileService { private readonly IDelayProfileRepository _repo; + private readonly ICached _bestForTagsCache; - public DelayProfileService(IDelayProfileRepository repo) + public DelayProfileService(IDelayProfileRepository repo, ICacheManager cacheManager) { _repo = repo; + _bestForTagsCache = cacheManager.GetCache(GetType(), "best"); } public DelayProfile Add(DelayProfile profile) - { - return _repo.Insert(profile); + { + profile.Order = _repo.Count(); + + var result = _repo.Insert(profile); + _bestForTagsCache.Clear(); + + return result; } public DelayProfile Update(DelayProfile profile) { - return _repo.Update(profile); + var result = _repo.Update(profile); + _bestForTagsCache.Clear(); + return result; } public void Delete(int id) @@ -49,6 +61,7 @@ namespace NzbDrone.Core.Profiles.Delay } _repo.UpdateMany(all); + _bestForTagsCache.Clear(); } public List All() @@ -69,13 +82,87 @@ namespace NzbDrone.Core.Profiles.Delay public List AllForTags(HashSet tagIds) { - return _repo.All().Where(r => r.Tags.Intersect(tagIds).Any() || r.Tags.Empty()).ToList(); + return All().Where(r => r.Tags.Intersect(tagIds).Any() || r.Tags.Empty()).ToList(); } public DelayProfile BestForTags(HashSet tagIds) { - return _repo.All().Where(r => r.Tags.Intersect(tagIds).Any() || r.Tags.Empty()) + var key = "-" + tagIds.Select(v => v.ToString()).Join(","); + return _bestForTagsCache.Get(key, () => FetchBestForTags(tagIds), TimeSpan.FromSeconds(30)); + } + + private DelayProfile FetchBestForTags(HashSet tagIds) + { + return _repo.All() + .Where(r => r.Tags.Intersect(tagIds).Any() || r.Tags.Empty()) .OrderBy(d => d.Order).First(); } + + public List Reorder(int id, int? afterId) + { + var all = All().OrderBy(d => d.Order) + .ToList(); + + var moving = all.SingleOrDefault(d => d.Id == id); + var after = afterId.HasValue ? all.SingleOrDefault(d => d.Id == afterId) : null; + + if (moving == null) + { + // TODO: This should throw + return all; + } + + var afterOrder = GetAfterOrder(moving, after); + var afterCount = afterOrder + 2; + var movingOrder = moving.Order; + + foreach (var delayProfile in all) + { + if (delayProfile.Id == 1) + { + continue; + } + + if (delayProfile.Id == id) + { + delayProfile.Order = afterOrder + 1; + } + + else if (delayProfile.Id == after?.Id) + { + delayProfile.Order = afterOrder; + } + + else if (delayProfile.Order > afterOrder) + { + delayProfile.Order = afterCount; + afterCount++; + } + + else if (delayProfile.Order > movingOrder) + { + delayProfile.Order--; + } + } + + _repo.UpdateMany(all); + + return All(); + } + + private int GetAfterOrder(DelayProfile moving, DelayProfile after) + { + if (after == null) + { + return 0; + } + + if (moving.Order < after.Order) + { + return after.Order - 1; + } + + return after.Order; + } } }