Fixed: Correct rejection message when profile does not allow upgrades

Fixes #2958
This commit is contained in:
Mark McDowall 2019-02-19 18:30:57 -08:00
parent ee59f91ba2
commit 05e7b90aab
7 changed files with 406 additions and 16 deletions

View File

@ -0,0 +1,292 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Profiles.Qualities;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Profiles.Languages;
using NzbDrone.Core.Test.Languages;
namespace NzbDrone.Core.Test.DecisionEngineTests
{
[TestFixture]
public class UpgradeAllowedSpecificationFixture : CoreTest<UpgradableSpecification>
{
[Test]
public void should_return_false_when_quality_are_the_same_language_is_better_and_upgrade_allowed_is_false_for_language_profile()
{
Subject.IsUpgradeAllowed(
new QualityProfile
{
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
UpgradeAllowed = true
},
new LanguageProfile
{
Languages = LanguageFixture.GetDefaultLanguages(Language.English, Language.French),
Cutoff = Language.French,
UpgradeAllowed = false
},
new QualityModel(Quality.DVD),
Language.English,
new QualityModel(Quality.DVD),
Language.French
).Should().BeFalse();
}
[Test]
public void should_return_false_when_quality_is_better_languages_are_the_same_and_upgrade_allowed_is_false_for_quality_profile()
{
Subject.IsUpgradeAllowed(
new QualityProfile
{
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
UpgradeAllowed = false
},
new LanguageProfile
{
Languages = LanguageFixture.GetDefaultLanguages(Language.English),
Cutoff = Language.English,
UpgradeAllowed = true
},
new QualityModel(Quality.DVD),
Language.English,
new QualityModel(Quality.Bluray1080p),
Language.English
).Should().BeFalse();
}
[Test]
public void should_return_true_for_language_upgrade_when_upgrading_is_allowed()
{
Subject.IsUpgradeAllowed(
new QualityProfile
{
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
UpgradeAllowed = true
},
new LanguageProfile
{
Languages = LanguageFixture.GetDefaultLanguages(Language.English, Language.French),
Cutoff = Language.French,
UpgradeAllowed = true
},
new QualityModel(Quality.DVD),
Language.English,
new QualityModel(Quality.DVD),
Language.French
).Should().BeTrue();
}
[Test]
public void should_return_true_for_same_language_when_upgrading_is_allowed()
{
Subject.IsUpgradeAllowed(
new QualityProfile
{
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
UpgradeAllowed = true
},
new LanguageProfile
{
Languages = LanguageFixture.GetDefaultLanguages(Language.English, Language.French),
Cutoff = Language.French,
UpgradeAllowed = true
},
new QualityModel(Quality.DVD),
Language.English,
new QualityModel(Quality.DVD),
Language.English
).Should().BeTrue();
}
[Test]
public void should_return_true_for_same_language_when_upgrading_is_not_allowed()
{
Subject.IsUpgradeAllowed(
new QualityProfile
{
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
UpgradeAllowed = true
},
new LanguageProfile
{
Languages = LanguageFixture.GetDefaultLanguages(Language.English, Language.French),
Cutoff = Language.French,
UpgradeAllowed = false
},
new QualityModel(Quality.DVD),
Language.English,
new QualityModel(Quality.DVD),
Language.English
).Should().BeTrue();
}
[Test]
public void should_return_true_for_lower_language_when_upgrading_is_allowed()
{
Subject.IsUpgradeAllowed(
new QualityProfile
{
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
UpgradeAllowed = true
},
new LanguageProfile
{
Languages = LanguageFixture.GetDefaultLanguages(Language.English, Language.French),
Cutoff = Language.French,
UpgradeAllowed = true
},
new QualityModel(Quality.DVD),
Language.French,
new QualityModel(Quality.DVD),
Language.English
).Should().BeTrue();
}
[Test]
public void should_return_true_for_lower_language_when_upgrading_is_not_allowed()
{
Subject.IsUpgradeAllowed(
new QualityProfile
{
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
UpgradeAllowed = true
},
new LanguageProfile
{
Languages = LanguageFixture.GetDefaultLanguages(Language.English, Language.French),
Cutoff = Language.French,
UpgradeAllowed = false
},
new QualityModel(Quality.DVD),
Language.French,
new QualityModel(Quality.DVD),
Language.English
).Should().BeTrue();
}
[Test]
public void should_return_true_for_quality_upgrade_when_upgrading_is_allowed()
{
Subject.IsUpgradeAllowed(
new QualityProfile
{
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
UpgradeAllowed = true
},
new LanguageProfile
{
Languages = LanguageFixture.GetDefaultLanguages(Language.English),
Cutoff = Language.English,
UpgradeAllowed = true
},
new QualityModel(Quality.DVD),
Language.English,
new QualityModel(Quality.Bluray1080p),
Language.English
).Should().BeTrue();
}
[Test]
public void should_return_true_for_same_quality_when_upgrading_is_allowed()
{
Subject.IsUpgradeAllowed(
new QualityProfile
{
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
UpgradeAllowed = true
},
new LanguageProfile
{
Languages = LanguageFixture.GetDefaultLanguages(Language.English),
Cutoff = Language.English,
UpgradeAllowed = true
},
new QualityModel(Quality.DVD),
Language.English,
new QualityModel(Quality.DVD),
Language.English
).Should().BeTrue();
}
[Test]
public void should_return_true_for_same_quality_when_upgrading_is_not_allowed()
{
Subject.IsUpgradeAllowed(
new QualityProfile
{
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
UpgradeAllowed = false
},
new LanguageProfile
{
Languages = LanguageFixture.GetDefaultLanguages(Language.English),
Cutoff = Language.English,
UpgradeAllowed = true
},
new QualityModel(Quality.DVD),
Language.English,
new QualityModel(Quality.DVD),
Language.English
).Should().BeTrue();
}
[Test]
public void should_return_true_for_lower_quality_when_upgrading_is_allowed()
{
Subject.IsUpgradeAllowed(
new QualityProfile
{
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
UpgradeAllowed = true
},
new LanguageProfile
{
Languages = LanguageFixture.GetDefaultLanguages(Language.English),
Cutoff = Language.English,
UpgradeAllowed = true
},
new QualityModel(Quality.DVD),
Language.English,
new QualityModel(Quality.SDTV),
Language.English
).Should().BeTrue();
}
[Test]
public void should_return_true_for_lower_quality_when_upgrading_is_not_allowed()
{
Subject.IsUpgradeAllowed(
new QualityProfile
{
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(),
UpgradeAllowed = false
},
new LanguageProfile
{
Languages = LanguageFixture.GetDefaultLanguages(Language.English),
Cutoff = Language.English,
UpgradeAllowed = true
},
new QualityModel(Quality.DVD),
Language.English,
new QualityModel(Quality.SDTV),
Language.English
).Should().BeTrue();
}
}
}

View File

@ -159,6 +159,7 @@
<Compile Include="Datastore\SqliteSchemaDumperTests\SqliteSchemaDumperFixture.cs" />
<Compile Include="DecisionEngineTests\AcceptableSizeSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\AnimeVersionUpgradeSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\UpgradeAllowedSpecificationFixture .cs" />
<Compile Include="DecisionEngineTests\FullSeasonSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\MaximumSizeSpecificationFixture.cs" />
<Compile Include="DecisionEngineTests\ProtocolSpecificationFixture.cs" />

View File

@ -24,7 +24,8 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
{
var profile = subject.Series.QualityProfile.Value;
var qualityProfile = subject.Series.QualityProfile.Value;
var languageProfile = subject.Series.LanguageProfile.Value;
foreach (var file in subject.Episodes.Where(c => c.EpisodeFileId != 0).Select(c => c.EpisodeFile.Value))
{
@ -36,8 +37,8 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
_logger.Debug("Comparing file quality and language with report. Existing file is {0} - {1}", file.Quality, file.Language);
if (!_upgradableSpecification.CutoffNotMet(profile,
subject.Series.LanguageProfile,
if (!_upgradableSpecification.CutoffNotMet(qualityProfile,
languageProfile,
file.Quality,
file.Language,
_preferredWordServiceCalculator.Calculate(subject.Series, file.GetSceneOrFileName()),
@ -46,10 +47,10 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
{
_logger.Debug("Cutoff already met, rejecting.");
var qualityCutoffIndex = profile.GetIndex(profile.Cutoff);
var qualityCutoff = profile.Items[qualityCutoffIndex.Index];
var qualityCutoffIndex = qualityProfile.GetIndex(qualityProfile.Cutoff);
var qualityCutoff = qualityProfile.Items[qualityCutoffIndex.Index];
return Decision.Reject("Existing file meets cutoff: {0} - {1}", qualityCutoff, subject.Series.LanguageProfile.Value.Cutoff);
return Decision.Reject("Existing file meets cutoff: {0} - {1}", qualityCutoff, languageProfile.Cutoff);
}
}

View File

@ -40,25 +40,27 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
foreach (var queueItem in matchingEpisode)
{
var remoteEpisode = queueItem.RemoteEpisode;
var qualityProfile = subject.Series.QualityProfile.Value;
var languageProfile = subject.Series.LanguageProfile.Value;
_logger.Debug("Checking if existing release in queue meets cutoff. Queued quality is: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
_logger.Debug("Checking if existing release in queue meets cutoff. Queued: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
var queuedItemPreferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Series, queueItem.Title);
if (!_upgradableSpecification.CutoffNotMet(subject.Series.QualityProfile,
subject.Series.LanguageProfile,
if (!_upgradableSpecification.CutoffNotMet(qualityProfile,
languageProfile,
remoteEpisode.ParsedEpisodeInfo.Quality,
remoteEpisode.ParsedEpisodeInfo.Language,
queuedItemPreferredWordScore,
subject.ParsedEpisodeInfo.Quality,
subject.PreferredWordScore))
{
return Decision.Reject("Quality for release in queue already meets cutoff: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
return Decision.Reject("Release in queue already meets cutoff: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
}
_logger.Debug("Checking if release is higher quality than queued release. Queued quality is: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
_logger.Debug("Checking if release is higher quality than queued release. Queued: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
if (!_upgradableSpecification.IsUpgradable(subject.Series.QualityProfile,
subject.Series.LanguageProfile,
if (!_upgradableSpecification.IsUpgradable(qualityProfile,
languageProfile,
remoteEpisode.ParsedEpisodeInfo.Quality,
remoteEpisode.ParsedEpisodeInfo.Language,
queuedItemPreferredWordScore,
@ -66,7 +68,19 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
subject.ParsedEpisodeInfo.Language,
subject.PreferredWordScore))
{
return Decision.Reject("Quality for release in queue is of equal or higher preference: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
return Decision.Reject("Release in queue is of equal or higher preference: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
}
_logger.Debug("Checking if profiles allow upgrading. Queued: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
if (!_upgradableSpecification.IsUpgradeAllowed(subject.Series.QualityProfile,
subject.Series.LanguageProfile,
remoteEpisode.ParsedEpisodeInfo.Quality,
remoteEpisode.ParsedEpisodeInfo.Language,
subject.ParsedEpisodeInfo.Quality,
subject.ParsedEpisodeInfo.Language))
{
return Decision.Reject("Another release is queued and the Quality or Language profile does not allow upgrades");
}
}

View File

@ -13,6 +13,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
bool LanguageCutoffNotMet(LanguageProfile languageProfile, Language currentLanguage);
bool CutoffNotMet(QualityProfile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality = null, int newScore = 0);
bool IsRevisionUpgrade(QualityModel currentQuality, QualityModel newQuality);
bool IsUpgradeAllowed(QualityProfile qualityProfile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, QualityModel newQuality, Language newLanguage);
}
public class UpgradableSpecification : IUpgradableSpecification
@ -59,7 +60,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public bool IsUpgradable(QualityProfile qualityProfile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality, Language newLanguage, int newScore)
{
if (IsQualityUpgradable(qualityProfile, currentQuality, newQuality) && qualityProfile.UpgradeAllowed)
if (IsQualityUpgradable(qualityProfile, currentQuality, newQuality))
{
return true;
}
@ -70,7 +71,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
return false;
}
if (IsLanguageUpgradable(languageProfile, currentLanguage, newLanguage) && languageProfile.UpgradeAllowed)
if (IsLanguageUpgradable(languageProfile, currentLanguage, newLanguage))
{
return true;
}
@ -151,5 +152,32 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
return false;
}
public bool IsUpgradeAllowed(QualityProfile qualityProfile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, QualityModel newQuality, Language newLanguage)
{
var isQualityUpgrade = new QualityModelComparer(qualityProfile).Compare(newQuality, currentQuality) > 0;
var isLanguageUpgrade = new LanguageComparer(languageProfile).Compare(newLanguage, currentLanguage) > 0;
if (isQualityUpgrade && qualityProfile.UpgradeAllowed ||
isLanguageUpgrade && languageProfile.UpgradeAllowed)
{
_logger.Debug("At least one profile allows upgrading");
return true;
}
if (isQualityUpgrade && !qualityProfile.UpgradeAllowed)
{
_logger.Debug("Quality profile allows upgrades, skipping");
return false;
}
if (isLanguageUpgrade && !languageProfile.UpgradeAllowed)
{
_logger.Debug("Language profile does not allow upgrades, skipping");
return false;
}
return true;
}
}
}

View File

@ -0,0 +1,53 @@
using System.Linq;
using NLog;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.DecisionEngine.Specifications
{
public class UpgradeAllowedSpecification : IDecisionEngineSpecification
{
private readonly UpgradableSpecification _upgradableSpecification;
private readonly Logger _logger;
public UpgradeAllowedSpecification(UpgradableSpecification upgradableSpecification, Logger logger)
{
_upgradableSpecification = upgradableSpecification;
_logger = logger;
}
public SpecificationPriority Priority => SpecificationPriority.Default;
public RejectionType Type => RejectionType.Permanent;
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
{
var qualityProfile = subject.Series.QualityProfile.Value;
var languageProfile = subject.Series.LanguageProfile.Value;
foreach (var file in subject.Episodes.Where(c => c.EpisodeFileId != 0).Select(c => c.EpisodeFile.Value))
{
if (file == null)
{
_logger.Debug("File is no longer available, skipping this file.");
continue;
}
_logger.Debug("Comparing file quality and language with report. Existing file is {0} - {1}", file.Quality, file.Language);
if (!_upgradableSpecification.IsUpgradeAllowed(qualityProfile,
languageProfile,
file.Quality,
file.Language,
subject.ParsedEpisodeInfo.Quality,
subject.ParsedEpisodeInfo.Language))
{
_logger.Debug("Upgrading is not allowed by the quality or language profile");
return Decision.Reject("Existing file and the Quality or Language profile does not allow upgrades");
}
}
return Decision.Accept();
}
}
}

View File

@ -145,6 +145,7 @@
<Compile Include="CustomFilters\CustomFilterService.cs" />
<Compile Include="Datastore\Migration\127_rename_release_profiles.cs" />
<Compile Include="Datastore\Migration\126_add_custom_filters.cs" />
<Compile Include="DecisionEngine\Specifications\UpgradeAllowedSpecification.cs" />
<Compile Include="Extras\Metadata\MetadataSectionType.cs" />
<Compile Include="Download\Aggregation\RemoteEpisodeAggregationService.cs" />
<Compile Include="Download\Aggregation\Aggregators\AggregatePreferredWordScore.cs" />