Fixed: Correct rejection message when profile does not allow upgrades

Fixes #2958
pull/2984/head
Mark McDowall 6 years ago
parent ee59f91ba2
commit 05e7b90aab

@ -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();
}
}
}

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

@ -24,7 +24,8 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) 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)) 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); _logger.Debug("Comparing file quality and language with report. Existing file is {0} - {1}", file.Quality, file.Language);
if (!_upgradableSpecification.CutoffNotMet(profile, if (!_upgradableSpecification.CutoffNotMet(qualityProfile,
subject.Series.LanguageProfile, languageProfile,
file.Quality, file.Quality,
file.Language, file.Language,
_preferredWordServiceCalculator.Calculate(subject.Series, file.GetSceneOrFileName()), _preferredWordServiceCalculator.Calculate(subject.Series, file.GetSceneOrFileName()),
@ -46,10 +47,10 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
{ {
_logger.Debug("Cutoff already met, rejecting."); _logger.Debug("Cutoff already met, rejecting.");
var qualityCutoffIndex = profile.GetIndex(profile.Cutoff); var qualityCutoffIndex = qualityProfile.GetIndex(qualityProfile.Cutoff);
var qualityCutoff = profile.Items[qualityCutoffIndex.Index]; 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);
} }
} }

@ -40,25 +40,27 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
foreach (var queueItem in matchingEpisode) foreach (var queueItem in matchingEpisode)
{ {
var remoteEpisode = queueItem.RemoteEpisode; 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); var queuedItemPreferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Series, queueItem.Title);
if (!_upgradableSpecification.CutoffNotMet(subject.Series.QualityProfile, if (!_upgradableSpecification.CutoffNotMet(qualityProfile,
subject.Series.LanguageProfile, languageProfile,
remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Quality,
remoteEpisode.ParsedEpisodeInfo.Language, remoteEpisode.ParsedEpisodeInfo.Language,
queuedItemPreferredWordScore, queuedItemPreferredWordScore,
subject.ParsedEpisodeInfo.Quality, subject.ParsedEpisodeInfo.Quality,
subject.PreferredWordScore)) 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, if (!_upgradableSpecification.IsUpgradable(qualityProfile,
subject.Series.LanguageProfile, languageProfile,
remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Quality,
remoteEpisode.ParsedEpisodeInfo.Language, remoteEpisode.ParsedEpisodeInfo.Language,
queuedItemPreferredWordScore, queuedItemPreferredWordScore,
@ -66,7 +68,19 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
subject.ParsedEpisodeInfo.Language, subject.ParsedEpisodeInfo.Language,
subject.PreferredWordScore)) 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");
} }
} }

@ -13,6 +13,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
bool LanguageCutoffNotMet(LanguageProfile languageProfile, Language currentLanguage); 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 CutoffNotMet(QualityProfile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality = null, int newScore = 0);
bool IsRevisionUpgrade(QualityModel currentQuality, QualityModel newQuality); bool IsRevisionUpgrade(QualityModel currentQuality, QualityModel newQuality);
bool IsUpgradeAllowed(QualityProfile qualityProfile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, QualityModel newQuality, Language newLanguage);
} }
public class UpgradableSpecification : IUpgradableSpecification 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) 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; return true;
} }
@ -70,7 +71,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
return false; return false;
} }
if (IsLanguageUpgradable(languageProfile, currentLanguage, newLanguage) && languageProfile.UpgradeAllowed) if (IsLanguageUpgradable(languageProfile, currentLanguage, newLanguage))
{ {
return true; return true;
} }
@ -151,5 +152,32 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
return false; 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;
}
} }
} }

@ -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();
}
}
}

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

Loading…
Cancel
Save