mirror of
https://github.com/Sonarr/Sonarr.git
synced 2026-03-05 13:20:20 -05:00
New: Return error if invalid indexer or download client provided for pushed releases
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download
|
||||
{
|
||||
[TestFixture]
|
||||
public class ResolveDownloadClientFixture : CoreTest<DownloadClientFactory>
|
||||
{
|
||||
private List<DownloadClientDefinition> _downloadClients;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_downloadClients = Builder<DownloadClientDefinition>.CreateListOfSize(3)
|
||||
.TheFirst(2)
|
||||
.With(v => v.Enable = true)
|
||||
.TheNext(1)
|
||||
.With(v => v.Enable = false)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Mocker.GetMock<IDownloadClientRepository>()
|
||||
.Setup(v => v.All())
|
||||
.Returns(_downloadClients);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_if_download_client_with_id_cannot_be_found()
|
||||
{
|
||||
Assert.Throws<ResolveDownloadClientException>(() => Subject.ResolveDownloadClient(10, null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_if_download_client_with_name_cannot_be_found()
|
||||
{
|
||||
Assert.Throws<ResolveDownloadClientException>(() => Subject.ResolveDownloadClient(null, "Not a Real Client"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_if_download_client_with_id_does_not_match_download_client_with_name()
|
||||
{
|
||||
Assert.Throws<ResolveDownloadClientException>(() => Subject.ResolveDownloadClient(_downloadClients[0].Id, _downloadClients[1].Name));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_if_download_client_is_not_enabled()
|
||||
{
|
||||
Assert.Throws<ResolveDownloadClientException>(() => Subject.ResolveDownloadClient(_downloadClients[2].Id, null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_download_client_when_only_id_is_provided()
|
||||
{
|
||||
var result = Subject.ResolveDownloadClient(_downloadClients[0].Id, null);
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Should().Be(_downloadClients[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_download_client_when_only_name_is_provided()
|
||||
{
|
||||
var result = Subject.ResolveDownloadClient(null, _downloadClients[0].Name);
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Should().Be(_downloadClients[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_download_client_when_id_and_name_provided_for_the_same_download_client()
|
||||
{
|
||||
var result = Subject.ResolveDownloadClient(_downloadClients[0].Id, _downloadClients[0].Name);
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Should().Be(_downloadClients[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_null_if_both_id_and_name_are_not_provided()
|
||||
{
|
||||
var result = Subject.ResolveDownloadClient(null, null);
|
||||
|
||||
result.Should().BeNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
@@ -13,7 +12,7 @@ using NzbDrone.Core.Test.Framework;
|
||||
namespace NzbDrone.Core.Test.Download
|
||||
{
|
||||
[TestFixture]
|
||||
public class DownloadClientProviderFixture : CoreTest<DownloadClientProvider>
|
||||
public class GetDownloadClientFixture : CoreTest<DownloadClientProvider>
|
||||
{
|
||||
private List<IDownloadClient> _downloadClients;
|
||||
private List<DownloadClientStatus> _blockedProviders;
|
||||
@@ -326,207 +325,5 @@ namespace NzbDrone.Core.Test.Download
|
||||
|
||||
Assert.Throws<DownloadClientUnavailableException>(() => Subject.GetDownloadClient(DownloadProtocol.Torrent, 1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_all_available_clients_for_protocol()
|
||||
{
|
||||
WithUsenetClient();
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent);
|
||||
|
||||
clients.Should().HaveCount(3);
|
||||
clients.Select(c => c.Definition.Id).Should().BeEquivalentTo(new[] { 2, 3, 4 });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_empty_when_no_clients_available_for_protocol()
|
||||
{
|
||||
WithUsenetClient();
|
||||
WithUsenetClient();
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent);
|
||||
|
||||
clients.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_clients_ordered_by_priority_then_by_last_used()
|
||||
{
|
||||
WithTorrentClient(priority: 1);
|
||||
WithTorrentClient(priority: 0);
|
||||
WithTorrentClient(priority: 0);
|
||||
WithTorrentClient(priority: 2);
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent);
|
||||
|
||||
clients.Should().HaveCount(4);
|
||||
var clientIds = clients.Select(c => c.Definition.Id).ToArray();
|
||||
clientIds[0].Should().Be(2);
|
||||
clientIds[1].Should().Be(3);
|
||||
clientIds[2].Should().Be(1);
|
||||
clientIds[3].Should().Be(4);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_rotate_clients_within_same_priority_based_on_last_used()
|
||||
{
|
||||
WithTorrentClient(priority: 0);
|
||||
WithTorrentClient(priority: 0);
|
||||
WithTorrentClient(priority: 0);
|
||||
|
||||
var clients1 = Subject.GetDownloadClients(DownloadProtocol.Torrent);
|
||||
clients1.First().Definition.Id.Should().Be(1);
|
||||
|
||||
Subject.ReportSuccessfulDownloadClient(DownloadProtocol.Torrent, 2);
|
||||
|
||||
var clients2 = Subject.GetDownloadClients(DownloadProtocol.Torrent);
|
||||
var clientIds = clients2.Select(c => c.Definition.Id).ToArray();
|
||||
clientIds[0].Should().Be(3);
|
||||
clientIds[1].Should().Be(1);
|
||||
clientIds[2].Should().Be(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_filter_clients_by_tags()
|
||||
{
|
||||
var seriesTags = new HashSet<int> { 1, 2 };
|
||||
|
||||
WithTorrentClient(tags: new HashSet<int> { 1 });
|
||||
WithTorrentClient(tags: new HashSet<int> { 3 });
|
||||
WithTorrentClient(tags: new HashSet<int> { 2 });
|
||||
WithTorrentClient();
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent, tags: seriesTags);
|
||||
|
||||
clients.Should().HaveCount(2);
|
||||
clients.Select(c => c.Definition.Id).Should().BeEquivalentTo(new[] { 1, 3 });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_non_tagged_clients_when_no_matching_tags()
|
||||
{
|
||||
var seriesTags = new HashSet<int> { 5 };
|
||||
|
||||
WithTorrentClient(tags: new HashSet<int> { 1 });
|
||||
WithTorrentClient(tags: new HashSet<int> { 2 });
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent, tags: seriesTags);
|
||||
|
||||
clients.Should().HaveCount(2);
|
||||
clients.Select(c => c.Definition.Id).Should().BeEquivalentTo(new[] { 3, 4 });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_when_all_clients_have_non_matching_tags()
|
||||
{
|
||||
var seriesTags = new HashSet<int> { 5 };
|
||||
|
||||
WithTorrentClient(tags: new HashSet<int> { 1 });
|
||||
WithTorrentClient(tags: new HashSet<int> { 2 });
|
||||
|
||||
Assert.Throws<DownloadClientUnavailableException>(() => Subject.GetDownloadClients(DownloadProtocol.Torrent, tags: seriesTags));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_indexer_specific_client_when_specified()
|
||||
{
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
WithTorrentIndexer(2);
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent, indexerId: 1);
|
||||
|
||||
clients.Should().HaveCount(1);
|
||||
clients.First().Definition.Id.Should().Be(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_when_indexer_client_does_not_exist()
|
||||
{
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
WithTorrentIndexer(5);
|
||||
|
||||
Assert.Throws<DownloadClientUnavailableException>(() => Subject.GetDownloadClients(DownloadProtocol.Torrent, indexerId: 1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_filter_blocked_clients_when_requested()
|
||||
{
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
|
||||
GivenBlockedClient(2);
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent, filterBlockedClients: true);
|
||||
|
||||
clients.Should().HaveCount(2);
|
||||
clients.Select(c => c.Definition.Id).Should().BeEquivalentTo(new[] { 1, 3 });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_when_all_clients_blocked_and_filter_enabled()
|
||||
{
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
|
||||
GivenBlockedClient(1);
|
||||
GivenBlockedClient(2);
|
||||
|
||||
Assert.Throws<DownloadClientUnavailableException>(() => Subject.GetDownloadClients(DownloadProtocol.Torrent, filterBlockedClients: true));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_blocked_clients_when_filter_disabled()
|
||||
{
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
|
||||
GivenBlockedClient(1);
|
||||
GivenBlockedClient(2);
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent, filterBlockedClients: false);
|
||||
|
||||
clients.Should().HaveCount(2);
|
||||
clients.Select(c => c.Definition.Id).Should().BeEquivalentTo(new[] { 1, 2 });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_when_indexer_client_is_blocked_and_filter_enabled()
|
||||
{
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
WithTorrentIndexer(2);
|
||||
|
||||
GivenBlockedClient(2);
|
||||
|
||||
Assert.Throws<DownloadClientUnavailableException>(() => Subject.GetDownloadClients(DownloadProtocol.Torrent, indexerId: 1, filterBlockedClients: true));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_combine_tags_and_priority_filtering()
|
||||
{
|
||||
var seriesTags = new HashSet<int> { 1 };
|
||||
|
||||
WithTorrentClient(priority: 1, tags: new HashSet<int> { 1 });
|
||||
WithTorrentClient(priority: 0, tags: new HashSet<int> { 1 });
|
||||
WithTorrentClient(priority: 0, tags: new HashSet<int> { 2 });
|
||||
WithTorrentClient(priority: 2);
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent, tags: seriesTags);
|
||||
|
||||
clients.Should().HaveCount(2);
|
||||
var clientIds = clients.Select(c => c.Definition.Id).ToArray();
|
||||
|
||||
clientIds[0].Should().Be(2);
|
||||
clientIds[1].Should().Be(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Clients;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download
|
||||
{
|
||||
[TestFixture]
|
||||
public class GetDownloadClientsFixture : CoreTest<DownloadClientProvider>
|
||||
{
|
||||
private List<IDownloadClient> _downloadClients;
|
||||
private List<DownloadClientStatus> _blockedProviders;
|
||||
private int _nextId;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_downloadClients = new List<IDownloadClient>();
|
||||
_blockedProviders = new List<DownloadClientStatus>();
|
||||
_nextId = 1;
|
||||
|
||||
Mocker.GetMock<IDownloadClientFactory>()
|
||||
.Setup(v => v.GetAvailableProviders())
|
||||
.Returns(_downloadClients);
|
||||
|
||||
Mocker.GetMock<IDownloadClientStatusService>()
|
||||
.Setup(v => v.GetBlockedProviders())
|
||||
.Returns(_blockedProviders);
|
||||
}
|
||||
|
||||
private Mock<IDownloadClient> WithUsenetClient(int priority = 0, HashSet<int> tags = null)
|
||||
{
|
||||
var mock = new Mock<IDownloadClient>(MockBehavior.Default);
|
||||
mock.SetupGet(s => s.Definition)
|
||||
.Returns(Builder<DownloadClientDefinition>
|
||||
.CreateNew()
|
||||
.With(v => v.Id = _nextId++)
|
||||
.With(v => v.Priority = priority)
|
||||
.With(v => v.Tags = tags ?? new HashSet<int>())
|
||||
.Build());
|
||||
|
||||
_downloadClients.Add(mock.Object);
|
||||
|
||||
mock.SetupGet(v => v.Protocol).Returns(DownloadProtocol.Usenet);
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
private Mock<IDownloadClient> WithTorrentClient(int priority = 0, HashSet<int> tags = null)
|
||||
{
|
||||
var mock = new Mock<IDownloadClient>(MockBehavior.Default);
|
||||
mock.SetupGet(s => s.Definition)
|
||||
.Returns(Builder<DownloadClientDefinition>
|
||||
.CreateNew()
|
||||
.With(v => v.Id = _nextId++)
|
||||
.With(v => v.Priority = priority)
|
||||
.With(v => v.Tags = tags ?? new HashSet<int>())
|
||||
.Build());
|
||||
|
||||
_downloadClients.Add(mock.Object);
|
||||
|
||||
mock.SetupGet(v => v.Protocol).Returns(DownloadProtocol.Torrent);
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
private void WithTorrentIndexer(int downloadClientId)
|
||||
{
|
||||
Mocker.GetMock<IIndexerFactory>()
|
||||
.Setup(v => v.Find(It.IsAny<int>()))
|
||||
.Returns(Builder<IndexerDefinition>
|
||||
.CreateNew()
|
||||
.With(v => v.Id = _nextId++)
|
||||
.With(v => v.DownloadClientId = downloadClientId)
|
||||
.Build());
|
||||
}
|
||||
|
||||
private void GivenBlockedClient(int id)
|
||||
{
|
||||
_blockedProviders.Add(new DownloadClientStatus
|
||||
{
|
||||
ProviderId = id,
|
||||
DisabledTill = DateTime.UtcNow.AddHours(3)
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_all_available_clients_for_protocol()
|
||||
{
|
||||
WithUsenetClient();
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent);
|
||||
|
||||
clients.Should().HaveCount(3);
|
||||
clients.Select(c => c.Definition.Id).Should().BeEquivalentTo(new[] { 2, 3, 4 });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_empty_when_no_clients_available_for_protocol()
|
||||
{
|
||||
WithUsenetClient();
|
||||
WithUsenetClient();
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent);
|
||||
|
||||
clients.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_clients_ordered_by_priority_then_by_last_used()
|
||||
{
|
||||
WithTorrentClient(priority: 1);
|
||||
WithTorrentClient(priority: 0);
|
||||
WithTorrentClient(priority: 0);
|
||||
WithTorrentClient(priority: 2);
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent);
|
||||
|
||||
clients.Should().HaveCount(4);
|
||||
var clientIds = clients.Select(c => c.Definition.Id).ToArray();
|
||||
clientIds[0].Should().Be(2);
|
||||
clientIds[1].Should().Be(3);
|
||||
clientIds[2].Should().Be(1);
|
||||
clientIds[3].Should().Be(4);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_rotate_clients_within_same_priority_based_on_last_used()
|
||||
{
|
||||
WithTorrentClient(priority: 0);
|
||||
WithTorrentClient(priority: 0);
|
||||
WithTorrentClient(priority: 0);
|
||||
|
||||
var clients1 = Subject.GetDownloadClients(DownloadProtocol.Torrent);
|
||||
clients1.First().Definition.Id.Should().Be(1);
|
||||
|
||||
Subject.ReportSuccessfulDownloadClient(DownloadProtocol.Torrent, 2);
|
||||
|
||||
var clients2 = Subject.GetDownloadClients(DownloadProtocol.Torrent);
|
||||
var clientIds = clients2.Select(c => c.Definition.Id).ToArray();
|
||||
clientIds[0].Should().Be(3);
|
||||
clientIds[1].Should().Be(1);
|
||||
clientIds[2].Should().Be(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_filter_clients_by_tags()
|
||||
{
|
||||
var seriesTags = new HashSet<int> { 1, 2 };
|
||||
|
||||
WithTorrentClient(tags: new HashSet<int> { 1 });
|
||||
WithTorrentClient(tags: new HashSet<int> { 3 });
|
||||
WithTorrentClient(tags: new HashSet<int> { 2 });
|
||||
WithTorrentClient();
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent, tags: seriesTags);
|
||||
|
||||
clients.Should().HaveCount(2);
|
||||
clients.Select(c => c.Definition.Id).Should().BeEquivalentTo(new[] { 1, 3 });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_non_tagged_clients_when_no_matching_tags()
|
||||
{
|
||||
var seriesTags = new HashSet<int> { 5 };
|
||||
|
||||
WithTorrentClient(tags: new HashSet<int> { 1 });
|
||||
WithTorrentClient(tags: new HashSet<int> { 2 });
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent, tags: seriesTags);
|
||||
|
||||
clients.Should().HaveCount(2);
|
||||
clients.Select(c => c.Definition.Id).Should().BeEquivalentTo(new[] { 3, 4 });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_when_all_clients_have_non_matching_tags()
|
||||
{
|
||||
var seriesTags = new HashSet<int> { 5 };
|
||||
|
||||
WithTorrentClient(tags: new HashSet<int> { 1 });
|
||||
WithTorrentClient(tags: new HashSet<int> { 2 });
|
||||
|
||||
Assert.Throws<DownloadClientUnavailableException>(() => Subject.GetDownloadClients(DownloadProtocol.Torrent, tags: seriesTags));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_indexer_specific_client_when_specified()
|
||||
{
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
WithTorrentIndexer(2);
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent, indexerId: 1);
|
||||
|
||||
clients.Should().HaveCount(1);
|
||||
clients.First().Definition.Id.Should().Be(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_when_indexer_client_does_not_exist()
|
||||
{
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
WithTorrentIndexer(5);
|
||||
|
||||
Assert.Throws<DownloadClientUnavailableException>(() => Subject.GetDownloadClients(DownloadProtocol.Torrent, indexerId: 1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_filter_blocked_clients_when_requested()
|
||||
{
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
|
||||
GivenBlockedClient(2);
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent, filterBlockedClients: true);
|
||||
|
||||
clients.Should().HaveCount(2);
|
||||
clients.Select(c => c.Definition.Id).Should().BeEquivalentTo(new[] { 1, 3 });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_when_all_clients_blocked_and_filter_enabled()
|
||||
{
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
|
||||
GivenBlockedClient(1);
|
||||
GivenBlockedClient(2);
|
||||
|
||||
Assert.Throws<DownloadClientUnavailableException>(() => Subject.GetDownloadClients(DownloadProtocol.Torrent, filterBlockedClients: true));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_blocked_clients_when_filter_disabled()
|
||||
{
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
|
||||
GivenBlockedClient(1);
|
||||
GivenBlockedClient(2);
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent, filterBlockedClients: false);
|
||||
|
||||
clients.Should().HaveCount(2);
|
||||
clients.Select(c => c.Definition.Id).Should().BeEquivalentTo(new[] { 1, 2 });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_when_indexer_client_is_blocked_and_filter_enabled()
|
||||
{
|
||||
WithTorrentClient();
|
||||
WithTorrentClient();
|
||||
WithTorrentIndexer(2);
|
||||
|
||||
GivenBlockedClient(2);
|
||||
|
||||
Assert.Throws<DownloadClientUnavailableException>(() => Subject.GetDownloadClients(DownloadProtocol.Torrent, indexerId: 1, filterBlockedClients: true));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_combine_tags_and_priority_filtering()
|
||||
{
|
||||
var seriesTags = new HashSet<int> { 1 };
|
||||
|
||||
WithTorrentClient(priority: 1, tags: new HashSet<int> { 1 });
|
||||
WithTorrentClient(priority: 0, tags: new HashSet<int> { 1 });
|
||||
WithTorrentClient(priority: 0, tags: new HashSet<int> { 2 });
|
||||
WithTorrentClient(priority: 2);
|
||||
|
||||
var clients = Subject.GetDownloadClients(DownloadProtocol.Torrent, tags: seriesTags);
|
||||
|
||||
clients.Should().HaveCount(2);
|
||||
var clientIds = clients.Select(c => c.Definition.Id).ToArray();
|
||||
|
||||
clientIds[0].Should().Be(2);
|
||||
clientIds[1].Should().Be(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Indexer
|
||||
{
|
||||
[TestFixture]
|
||||
public class ResolveIndexerFixture : CoreTest<IndexerFactory>
|
||||
{
|
||||
private List<IndexerDefinition> _indexers;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_indexers = Builder<IndexerDefinition>.CreateListOfSize(3)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Mocker.GetMock<IIndexerRepository>()
|
||||
.Setup(v => v.All())
|
||||
.Returns(_indexers);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_if_indexer_with_id_cannot_be_found()
|
||||
{
|
||||
Assert.Throws<ResolveIndexerException>(() => Subject.ResolveIndexer(10, null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_if_indexer_with_name_cannot_be_found()
|
||||
{
|
||||
Assert.Throws<ResolveIndexerException>(() => Subject.ResolveIndexer(null, "Not a Real Client"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_if_indexer_with_id_does_not_match_indexer_with_name()
|
||||
{
|
||||
Assert.Throws<ResolveIndexerException>(() => Subject.ResolveIndexer(_indexers[0].Id, _indexers[1].Name));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_indexer_when_only_id_is_provided()
|
||||
{
|
||||
var result = Subject.ResolveIndexer(_indexers[0].Id, null);
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Should().Be(_indexers[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_indexer_when_only_name_is_provided()
|
||||
{
|
||||
var result = Subject.ResolveIndexer(null, _indexers[0].Name);
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Should().Be(_indexers[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_indexer_when_id_and_name_provided_for_the_same_indexer()
|
||||
{
|
||||
var result = Subject.ResolveIndexer(_indexers[0].Id, _indexers[0].Name);
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Should().Be(_indexers[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_null_if_both_id_and_name_are_not_provided()
|
||||
{
|
||||
var result = Subject.ResolveIndexer(null, null);
|
||||
|
||||
result.Should().BeNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation.Results;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
||||
@@ -11,6 +12,7 @@ namespace NzbDrone.Core.Download
|
||||
public interface IDownloadClientFactory : IProviderFactory<IDownloadClient, DownloadClientDefinition>
|
||||
{
|
||||
List<IDownloadClient> DownloadHandlingEnabled(bool filterBlockedClients = true);
|
||||
DownloadClientDefinition ResolveDownloadClient(int? id, string name);
|
||||
}
|
||||
|
||||
public class DownloadClientFactory : ProviderFactory<IDownloadClient, DownloadClientDefinition>, IDownloadClientFactory
|
||||
@@ -54,6 +56,42 @@ namespace NzbDrone.Core.Download
|
||||
return enabledClients.ToList();
|
||||
}
|
||||
|
||||
public DownloadClientDefinition ResolveDownloadClient(int? id, string name)
|
||||
{
|
||||
var all = All();
|
||||
var clientByName = name.IsNullOrWhiteSpace() ? null : all.FirstOrDefault(c => c.Name.EqualsIgnoreCase(name));
|
||||
var clientById = id.HasValue ? all.FirstOrDefault(c => c.Id == id.Value) : null;
|
||||
|
||||
if (id.HasValue && clientById == null)
|
||||
{
|
||||
throw new ResolveDownloadClientException("Download client with ID '{0}' could not be found", id.Value);
|
||||
}
|
||||
|
||||
if (name.IsNotNullOrWhiteSpace() && clientByName == null)
|
||||
{
|
||||
throw new ResolveDownloadClientException("Download client with name '{0}' could not be found", name);
|
||||
}
|
||||
|
||||
if (clientByName == null && clientById == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (clientByName != null && clientById != null && clientByName.Id != clientById.Id)
|
||||
{
|
||||
throw new ResolveDownloadClientException("Download client with name '{0}' does not match download client with ID '{1}'", name, id.Value);
|
||||
}
|
||||
|
||||
var client = clientById ?? clientByName;
|
||||
|
||||
if (!client.Enable)
|
||||
{
|
||||
throw new ResolveDownloadClientException("Download client '{0}' ({1}) is not enabled", client.Name, id);
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
private IEnumerable<IDownloadClient> FilterBlockedClients(IEnumerable<IDownloadClient> clients)
|
||||
{
|
||||
var blockedClients = _downloadClientStatusService.GetBlockedProviders().ToDictionary(v => v.ProviderId, v => v);
|
||||
|
||||
@@ -121,6 +121,42 @@ namespace NzbDrone.Core.Download
|
||||
_lastUsedDownloadClient.Set(downloadProtocol.ToString(), downloadClientId);
|
||||
}
|
||||
|
||||
public DownloadClientDefinition ResolveDownloadClient(int? downloadClientId, string downloadClientName)
|
||||
{
|
||||
var all = _downloadClientFactory.All();
|
||||
var clientByName = downloadClientName.IsNullOrWhiteSpace() ? null : all.FirstOrDefault(c => c.Name.EqualsIgnoreCase(downloadClientName));
|
||||
var clientById = downloadClientId.HasValue ? all.FirstOrDefault(c => c.Id == downloadClientId.Value) : null;
|
||||
|
||||
if (downloadClientId.HasValue && clientById == null)
|
||||
{
|
||||
throw new ResolveDownloadClientException("Download client with ID '{0}' could not be found", downloadClientId.Value);
|
||||
}
|
||||
|
||||
if (downloadClientName.IsNotNullOrWhiteSpace() && clientByName == null)
|
||||
{
|
||||
throw new ResolveDownloadClientException("Download client with name '{0}' could not be found", downloadClientName);
|
||||
}
|
||||
|
||||
if (clientByName == null && clientById == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (clientByName != null && clientById != null && clientByName.Id != clientById.Id)
|
||||
{
|
||||
throw new ResolveDownloadClientException("Download client with name '{0}' does not match download client with ID '{1}'", downloadClientName, downloadClientId.Value);
|
||||
}
|
||||
|
||||
var client = clientById ?? clientByName;
|
||||
|
||||
if (!client.Enable)
|
||||
{
|
||||
throw new ResolveDownloadClientException("Download client '{0}' ({1}) is not enabled", client.Name, downloadClientId);
|
||||
}
|
||||
|
||||
return clientById ?? clientByName;
|
||||
}
|
||||
|
||||
private IEnumerable<IDownloadClient> FilterBlockedDownloadClients(IEnumerable<IDownloadClient> clients)
|
||||
{
|
||||
var blockedClients = _downloadClientStatusService.GetBlockedProviders().ToDictionary(v => v.ProviderId, v => v);
|
||||
|
||||
12
src/NzbDrone.Core/Download/ResolveDownloadClientException.cs
Normal file
12
src/NzbDrone.Core/Download/ResolveDownloadClientException.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.Net;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
|
||||
namespace NzbDrone.Core.Download;
|
||||
|
||||
public class ResolveDownloadClientException : NzbDroneClientException
|
||||
{
|
||||
public ResolveDownloadClientException(string message, params object[] args)
|
||||
: base(HttpStatusCode.BadRequest, message, args)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation.Results;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
||||
@@ -14,6 +15,7 @@ namespace NzbDrone.Core.Indexers
|
||||
List<IIndexer> AutomaticSearchEnabled(bool filterBlockedIndexers = true);
|
||||
List<IIndexer> InteractiveSearchEnabled(bool filterBlockedIndexers = true);
|
||||
IndexerDefinition FindByName(string name);
|
||||
IndexerDefinition ResolveIndexer(int? id, string name);
|
||||
}
|
||||
|
||||
public class IndexerFactory : ProviderFactory<IIndexer, IndexerDefinition>, IIndexerFactory
|
||||
@@ -90,6 +92,35 @@ namespace NzbDrone.Core.Indexers
|
||||
return _indexerRepository.FindByName(name);
|
||||
}
|
||||
|
||||
public IndexerDefinition ResolveIndexer(int? id, string name)
|
||||
{
|
||||
var all = All();
|
||||
var clientByName = name.IsNullOrWhiteSpace() ? null : all.FirstOrDefault(c => c.Name.EqualsIgnoreCase(name));
|
||||
var clientById = id.HasValue ? all.FirstOrDefault(c => c.Id == id.Value) : null;
|
||||
|
||||
if (id.HasValue && clientById == null)
|
||||
{
|
||||
throw new ResolveIndexerException("Indexer with ID '{0}' could not be found", id.Value);
|
||||
}
|
||||
|
||||
if (name.IsNotNullOrWhiteSpace() && clientByName == null)
|
||||
{
|
||||
throw new ResolveIndexerException("Indexer with name '{0}' could not be found", name);
|
||||
}
|
||||
|
||||
if (clientByName == null && clientById == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (clientByName != null && clientById != null && clientByName.Id != clientById.Id)
|
||||
{
|
||||
throw new ResolveIndexerException("Indexer with name '{0}' does not match Indexerwith ID '{1}'", name, id.Value);
|
||||
}
|
||||
|
||||
return clientById ?? clientByName;
|
||||
}
|
||||
|
||||
private IEnumerable<IIndexer> FilterBlockedIndexers(IEnumerable<IIndexer> indexers)
|
||||
{
|
||||
var blockedIndexers = _indexerStatusService.GetBlockedProviders().ToDictionary(v => v.ProviderId, v => v);
|
||||
|
||||
12
src/NzbDrone.Core/Indexers/ResolveDownloadClientException.cs
Normal file
12
src/NzbDrone.Core/Indexers/ResolveDownloadClientException.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System.Net;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
|
||||
namespace NzbDrone.Core.Indexers;
|
||||
|
||||
public class ResolveIndexerException : NzbDroneClientException
|
||||
{
|
||||
public ResolveIndexerException(string message, params object[] args)
|
||||
: base(HttpStatusCode.BadRequest, message, args)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ using FluentValidation.Results;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Indexers;
|
||||
@@ -84,59 +83,35 @@ namespace Sonarr.Api.V3.Indexers
|
||||
|
||||
private void ResolveIndexer(ReleaseInfo release)
|
||||
{
|
||||
if (release.IndexerId == 0 && release.Indexer.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var indexer = _indexerFactory.All().FirstOrDefault(v => v.Name.EqualsIgnoreCase(release.Indexer));
|
||||
var indexer = _indexerFactory.ResolveIndexer(release.IndexerId, release.Indexer);
|
||||
|
||||
if (indexer != null)
|
||||
{
|
||||
release.IndexerId = indexer.Id;
|
||||
_logger.Debug("Push Release {0} associated with indexer {1} - {2}.", release.Title, release.IndexerId, release.Indexer);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Push Release {0} not associated with known indexer {1}.", release.Title, release.Indexer);
|
||||
}
|
||||
}
|
||||
else if (release.IndexerId != 0 && release.Indexer.IsNullOrWhiteSpace())
|
||||
if (indexer == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var indexer = _indexerFactory.Get(release.IndexerId);
|
||||
release.Indexer = indexer.Name;
|
||||
_logger.Debug("Push Release {0} associated with indexer {1} - {2}.", release.Title, release.IndexerId, release.Indexer);
|
||||
}
|
||||
catch (ModelNotFoundException)
|
||||
{
|
||||
_logger.Debug("Push Release {0} not associated with known indexer {1}.", release.Title, release.IndexerId);
|
||||
release.IndexerId = 0;
|
||||
}
|
||||
_logger.Debug("Push Release {0} not associated with an indexer.", release.Title);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Push Release {0} not associated with an indexer.", release.Title);
|
||||
_logger.Debug("Push Release {0} associated with indexer '{1} ({2})", release.Title, indexer.Name, indexer.Id);
|
||||
|
||||
release.IndexerId = indexer.Id;
|
||||
release.Indexer = indexer.Name;
|
||||
}
|
||||
}
|
||||
|
||||
private int? ResolveDownloadClientId(ReleaseResource release)
|
||||
{
|
||||
var downloadClientId = release.DownloadClientId.GetValueOrDefault();
|
||||
var downloadClient = _downloadClientFactory.ResolveDownloadClient(release.DownloadClientId, release.DownloadClient);
|
||||
|
||||
if (downloadClientId == 0 && release.DownloadClient.IsNotNullOrWhiteSpace())
|
||||
if (downloadClient == null)
|
||||
{
|
||||
var downloadClient = _downloadClientFactory.All().FirstOrDefault(v => v.Name.EqualsIgnoreCase(release.DownloadClient));
|
||||
|
||||
if (downloadClient != null)
|
||||
{
|
||||
_logger.Debug("Push Release {0} associated with download client {1} - {2}.", release.Title, downloadClientId, release.DownloadClient);
|
||||
|
||||
return downloadClient.Id;
|
||||
}
|
||||
|
||||
_logger.Debug("Push Release {0} not associated with known download client {1}.", release.Title, release.DownloadClient);
|
||||
_logger.Debug("Push Release {0} not associated with a download client.", release.Title);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Push Release {0} associated with download client '{1} ({2})", release.Title, downloadClient.Name, downloadClient.Id);
|
||||
}
|
||||
|
||||
return release.DownloadClientId;
|
||||
return downloadClient?.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using FluentValidation.Results;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Indexers;
|
||||
@@ -86,58 +85,34 @@ public class ReleasePushController : RestController<ReleasePushResource>
|
||||
|
||||
private void ResolveIndexer(ReleaseInfo release)
|
||||
{
|
||||
if (release.IndexerId == 0 && release.Indexer.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var indexer = _indexerFactory.All().FirstOrDefault(v => v.Name.EqualsIgnoreCase(release.Indexer));
|
||||
var indexer = _indexerFactory.ResolveIndexer(release.IndexerId, release.Indexer);
|
||||
|
||||
if (indexer != null)
|
||||
{
|
||||
release.IndexerId = indexer.Id;
|
||||
_logger.Debug("Push Release {0} associated with indexer {1} - {2}.", release.Title, release.IndexerId, release.Indexer);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Push Release {0} not associated with known indexer {1}.", release.Title, release.Indexer);
|
||||
}
|
||||
}
|
||||
else if (release.IndexerId != 0 && release.Indexer.IsNullOrWhiteSpace())
|
||||
if (indexer == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var indexer = _indexerFactory.Get(release.IndexerId);
|
||||
release.Indexer = indexer.Name;
|
||||
_logger.Debug("Push Release {0} associated with indexer {1} - {2}.", release.Title, release.IndexerId, release.Indexer);
|
||||
}
|
||||
catch (ModelNotFoundException)
|
||||
{
|
||||
_logger.Debug("Push Release {0} not associated with known indexer {1}.", release.Title, release.IndexerId);
|
||||
release.IndexerId = 0;
|
||||
}
|
||||
_logger.Debug("Push Release {0} not associated with an indexer.", release.Title);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Push Release {0} not associated with an indexer.", release.Title);
|
||||
_logger.Debug("Push Release {0} associated with indexer '{1} ({2})", release.Title, indexer.Name, indexer.Id);
|
||||
|
||||
release.IndexerId = indexer.Id;
|
||||
release.Indexer = indexer.Name;
|
||||
}
|
||||
}
|
||||
|
||||
private int? ResolveDownloadClientId(ReleasePushResource release)
|
||||
{
|
||||
var downloadClientId = release.DownloadClientId.GetValueOrDefault();
|
||||
var downloadClient = _downloadClientFactory.ResolveDownloadClient(release.DownloadClientId, release.DownloadClientName);
|
||||
|
||||
if (downloadClientId == 0 && release.DownloadClientName.IsNotNullOrWhiteSpace())
|
||||
if (downloadClient == null)
|
||||
{
|
||||
var downloadClient = _downloadClientFactory.All().FirstOrDefault(v => v.Name.EqualsIgnoreCase(release.DownloadClientName));
|
||||
|
||||
if (downloadClient != null)
|
||||
{
|
||||
_logger.Debug("Push Release {0} associated with download client {1} - {2}.", release.Title, downloadClientId, release.DownloadClientName);
|
||||
|
||||
return downloadClient.Id;
|
||||
}
|
||||
|
||||
_logger.Debug("Push Release {0} not associated with known download client {1}.", release.Title, release.DownloadClientName);
|
||||
_logger.Debug("Push Release {0} not associated with a download client.", release.Title);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Push Release {0} associated with download client '{1} ({2})", release.Title, downloadClient.Name, downloadClient.Id);
|
||||
}
|
||||
|
||||
return release.DownloadClientId;
|
||||
return downloadClient?.Id;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user