fix: Relax validation rules for custom format configuration

json-serializing-nullable-fields-issue
Robert Dailey 8 months ago
parent 08db62ee8c
commit 03a84e099c

@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Remove INF log that showed a total count of CFs without scores assigned. This log caused a lot of
confusion in support channels. You can still see a list of CFs without scores in the debug logs.
- Relaxed validation rules for `trash_ids` and `quality_profiles` under `custom_formats`. Both of
these nodes may now be empty. This is mostly to make commenting out parts of configuration
templates easier.
## [5.4.2] - 2023-09-14

@ -10,12 +10,16 @@
"required": ["trash_ids"],
"properties": {
"trash_ids": {
"$ref": "trash-ids.json"
"type": ["null", "array"],
"description": "A list of one or more Trash IDs taken from the Trash Guide JSON files.",
"uniqueItems": true,
"items": {
"type": "string"
}
},
"quality_profiles": {
"type": "array",
"type": ["null", "array"],
"description": "One or more quality profiles to update with the scores from the specified custom formats.",
"minItems": 1,
"items": {
"properties": {
"name": {

@ -2,14 +2,10 @@
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://raw.githubusercontent.com/recyclarr/recyclarr/master/schemas/config/trash-ids.json",
"type": "array",
"description": "A list of one or more Trash IDs taken from the Trash Guide Sonarr JSON files.",
"description": "A list of one or more Trash IDs taken from the Trash Guide JSON files.",
"minItems": 1,
"uniqueItems": true,
"items": {
"trash_id": {
"type": "string",
"minLength": 32,
"pattern": "^[0-9a-fA-F]+$"
}
"type": "string"
}
}

@ -32,10 +32,9 @@ public class QualityProfileConfigPhase
// 2. For each quality profile score config in that CF group
// 3. For each CF in the group above, match it to a Guide CF object and pair it with the quality profile config
var profileAndCfs = config.CustomFormats
.Where(x => x.QualityProfiles.IsNotEmpty())
.SelectMany(x => x.QualityProfiles
.Select(y => (Config: x, Profile: y)))
.SelectMany(x => x.Config.TrashIds
.Select(y => (Profile: y, x.TrashIds)))
.SelectMany(x => x.TrashIds
.Select(_cache.LookupByTrashId)
.NotNull()
.Select(y => (x.Profile, Cf: y)));

@ -40,14 +40,7 @@ public class CustomFormatConfigYamlValidator : AbstractValidator<CustomFormatCon
{
public CustomFormatConfigYamlValidator()
{
RuleFor(x => x.TrashIds).NotEmpty()
.When(x => x.TrashIds is not null)
.WithName("trash_ids")
.ForEach(x => x.Length(32).Matches(@"^[0-9a-fA-F]+$"));
RuleForEach(x => x.QualityProfiles).NotEmpty()
.When(x => x.QualityProfiles is not null)
.WithName("quality_profiles")
RuleForEach(x => x.QualityProfiles)
.SetValidator(new QualityScoreConfigYamlValidator());
}
}

@ -219,4 +219,49 @@ public class QualityProfileConfigPhaseTest
},
o => o.Excluding(x => x.ShouldCreate));
}
[Test, AutoMockData]
public void Empty_trash_ids_list_is_ignored(
[Frozen] ProcessedCustomFormatCache cache,
QualityProfileConfigPhase sut)
{
var config = SetupCfs(new CustomFormatConfig
{
TrashIds = Array.Empty<string>(),
QualityProfiles = new List<QualityProfileScoreConfig>
{
new()
{
Name = "test_profile",
Score = 100
}
}
});
var result = sut.Execute(config);
result.Should().BeEmpty();
}
[Test, AutoMockData]
public void Empty_quality_profiles_is_ignored(
[Frozen] ProcessedCustomFormatCache cache,
QualityProfileConfigPhase sut)
{
cache.AddCustomFormats(new[]
{
NewCf.DataWithScore("", "id1", 101, 1),
NewCf.DataWithScore("", "id2", 201, 2)
});
var config = SetupCfs(new CustomFormatConfig
{
TrashIds = new[] {"id1", "id2"},
QualityProfiles = Array.Empty<QualityProfileScoreConfig>()
});
var result = sut.Execute(config);
result.Should().BeEmpty();
}
}

@ -144,39 +144,6 @@ public class YamlConfigValidatorTest : ConfigIntegrationFixture
public static string FirstCf { get; } = $"{nameof(ServiceConfigYaml.CustomFormats)}[0].";
[Test]
public void Validation_failure_when_cf_trash_ids_empty()
{
var config = new ServiceConfigYaml
{
ApiKey = "valid",
BaseUrl = "http://valid",
CustomFormats = new List<CustomFormatConfigYaml>
{
new()
{
TrashIds = Array.Empty<string>(),
QualityProfiles = new List<QualityScoreConfigYaml>
{
new()
{
Name = "valid"
}
}
}
},
QualityDefinition = new QualitySizeConfigYaml
{
Type = "valid"
}
};
var validator = Resolve<ServiceConfigYamlValidator>();
var result = validator.TestValidate(config);
result.ShouldHaveValidationErrorFor(FirstCf + nameof(CustomFormatConfig.TrashIds));
}
[Test]
public void Validation_failure_when_quality_definition_type_empty()
{

Loading…
Cancel
Save