If there is invalid / empty data in the Trash Guide JSON data, filter those out after they are loaded.pull/108/head
parent
bf61ab0fac
commit
1129f178a8
@ -0,0 +1,79 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using TestLibrary.AutoFixture;
|
||||||
|
using TrashLib.Sonarr.ReleaseProfile;
|
||||||
|
using TrashLib.Sonarr.ReleaseProfile.Filters;
|
||||||
|
|
||||||
|
namespace TrashLib.Tests.Sonarr.ReleaseProfile.Filters;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
[Parallelizable(ParallelScope.All)]
|
||||||
|
public class ReleaseProfileDataValidationFiltererTest
|
||||||
|
{
|
||||||
|
[Test, AutoMockData]
|
||||||
|
public void Valid_data_is_not_filtered_out(ReleaseProfileDataValidationFilterer sut)
|
||||||
|
{
|
||||||
|
var data = new[]
|
||||||
|
{
|
||||||
|
new ReleaseProfileData
|
||||||
|
{
|
||||||
|
TrashId = "trash_id",
|
||||||
|
Name = "name",
|
||||||
|
Required = new[] {new TermData {Term = "term1"}},
|
||||||
|
Ignored = new[] {new TermData {Term = "term2"}},
|
||||||
|
Preferred = new[] {new PreferredTermData {Terms = new[] {new TermData {Term = "term3"}}}}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = sut.FilterProfiles(data);
|
||||||
|
|
||||||
|
result.Should().BeEquivalentTo(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, AutoMockData]
|
||||||
|
public void Invalid_terms_are_filtered_out(ReleaseProfileDataValidationFilterer sut)
|
||||||
|
{
|
||||||
|
var data = new[]
|
||||||
|
{
|
||||||
|
new ReleaseProfileData
|
||||||
|
{
|
||||||
|
TrashId = "trash_id",
|
||||||
|
Name = "name",
|
||||||
|
Required = new[] {new TermData {Term = ""}},
|
||||||
|
Ignored = new[] {new TermData {Term = "term2"}},
|
||||||
|
Preferred = new[] {new PreferredTermData {Terms = new[] {new TermData {Term = "term3"}}}}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = sut.FilterProfiles(data);
|
||||||
|
|
||||||
|
result.Should().ContainSingle().Which.Should().BeEquivalentTo(new ReleaseProfileData
|
||||||
|
{
|
||||||
|
TrashId = "trash_id",
|
||||||
|
Name = "name",
|
||||||
|
Required = Array.Empty<TermData>(),
|
||||||
|
Ignored = new[] {new TermData {Term = "term2"}},
|
||||||
|
Preferred = new[] {new PreferredTermData {Terms = new[] {new TermData {Term = "term3"}}}}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, AutoMockData]
|
||||||
|
public void Whole_release_profile_filtered_out_if_all_terms_invalid(ReleaseProfileDataValidationFilterer sut)
|
||||||
|
{
|
||||||
|
var data = new[]
|
||||||
|
{
|
||||||
|
new ReleaseProfileData
|
||||||
|
{
|
||||||
|
TrashId = "trash_id",
|
||||||
|
Name = "name",
|
||||||
|
Required = new[] {new TermData {Term = ""}},
|
||||||
|
Ignored = new[] {new TermData {Term = ""}},
|
||||||
|
Preferred = new[] {new PreferredTermData {Terms = new[] {new TermData {Term = ""}}}}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = sut.FilterProfiles(data);
|
||||||
|
|
||||||
|
result.Should().BeEmpty();
|
||||||
|
}
|
||||||
|
}
|
@ -1,69 +1,58 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using Common.FluentValidation;
|
|
||||||
using FluentValidation.Results;
|
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using TrashLib.Sonarr.Config;
|
using TrashLib.Sonarr.Config;
|
||||||
|
|
||||||
namespace TrashLib.Sonarr.ReleaseProfile;
|
namespace TrashLib.Sonarr.ReleaseProfile.Filters;
|
||||||
|
|
||||||
public class ReleaseProfileDataFilterer
|
public class ReleaseProfileDataFilterer
|
||||||
{
|
{
|
||||||
private readonly ILogger _log;
|
private readonly ILogger _log;
|
||||||
|
private readonly ReleaseProfileDataValidationFilterer _validator;
|
||||||
|
|
||||||
public ReleaseProfileDataFilterer(ILogger log)
|
public ReleaseProfileDataFilterer(ILogger log)
|
||||||
{
|
{
|
||||||
_log = log;
|
_log = log;
|
||||||
}
|
_validator = new ReleaseProfileDataValidationFilterer(log);
|
||||||
|
|
||||||
private void LogInvalidTerm(List<ValidationFailure> failures, string filterDescription)
|
|
||||||
{
|
|
||||||
_log.Debug("Validation failed on term data ({Filter}): {Failures}", filterDescription, failures);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyCollection<TermData> ExcludeTerms(IEnumerable<TermData> terms,
|
public ReadOnlyCollection<TermData> ExcludeTerms(IEnumerable<TermData> terms,
|
||||||
IEnumerable<string> excludeFilter)
|
IEnumerable<string> excludeFilter)
|
||||||
{
|
{
|
||||||
return terms
|
var result = terms.Where(x => !excludeFilter.Contains(x.TrashId, StringComparer.InvariantCultureIgnoreCase));
|
||||||
.Where(x => !excludeFilter.Contains(x.TrashId, StringComparer.InvariantCultureIgnoreCase))
|
return _validator.FilterTerms(result).ToList().AsReadOnly();
|
||||||
.IsValid(new TermDataValidator(), (e, x) => LogInvalidTerm(e, $"Exclude: {x}"))
|
|
||||||
.ToList().AsReadOnly();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyCollection<PreferredTermData> ExcludeTerms(IEnumerable<PreferredTermData> terms,
|
public ReadOnlyCollection<PreferredTermData> ExcludeTerms(IEnumerable<PreferredTermData> terms,
|
||||||
IReadOnlyCollection<string> excludeFilter)
|
IReadOnlyCollection<string> excludeFilter)
|
||||||
{
|
{
|
||||||
return terms
|
var result = terms
|
||||||
.Select(x => new PreferredTermData
|
.Select(x => new PreferredTermData
|
||||||
{
|
{
|
||||||
Score = x.Score,
|
Score = x.Score,
|
||||||
Terms = ExcludeTerms(x.Terms, excludeFilter)
|
Terms = ExcludeTerms(x.Terms, excludeFilter)
|
||||||
})
|
});
|
||||||
.IsValid(new PreferredTermDataValidator(), (e, x) => LogInvalidTerm(e, $"Exclude Preferred: {x}"))
|
|
||||||
.ToList()
|
return _validator.FilterTerms(result).ToList().AsReadOnly();
|
||||||
.AsReadOnly();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyCollection<TermData> IncludeTerms(IEnumerable<TermData> terms,
|
public ReadOnlyCollection<TermData> IncludeTerms(IEnumerable<TermData> terms,
|
||||||
IEnumerable<string> includeFilter)
|
IEnumerable<string> includeFilter)
|
||||||
{
|
{
|
||||||
return terms
|
var result = terms.Where(x => includeFilter.Contains(x.TrashId, StringComparer.InvariantCultureIgnoreCase));
|
||||||
.Where(x => includeFilter.Contains(x.TrashId, StringComparer.InvariantCultureIgnoreCase))
|
return _validator.FilterTerms(result).ToList().AsReadOnly();
|
||||||
.IsValid(new TermDataValidator(), (e, x) => LogInvalidTerm(e, $"Include: {x}"))
|
|
||||||
.ToList().AsReadOnly();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyCollection<PreferredTermData> IncludeTerms(IEnumerable<PreferredTermData> terms,
|
public ReadOnlyCollection<PreferredTermData> IncludeTerms(IEnumerable<PreferredTermData> terms,
|
||||||
IReadOnlyCollection<string> includeFilter)
|
IReadOnlyCollection<string> includeFilter)
|
||||||
{
|
{
|
||||||
return terms
|
var result = terms
|
||||||
.Select(x => new PreferredTermData
|
.Select(x => new PreferredTermData
|
||||||
{
|
{
|
||||||
Score = x.Score,
|
Score = x.Score,
|
||||||
Terms = IncludeTerms(x.Terms, includeFilter)
|
Terms = IncludeTerms(x.Terms, includeFilter)
|
||||||
})
|
});
|
||||||
.IsValid(new PreferredTermDataValidator(), (e, x) => LogInvalidTerm(e, $"Include Preferred {x}"))
|
|
||||||
.ToList()
|
return _validator.FilterTerms(result).ToList().AsReadOnly();
|
||||||
.AsReadOnly();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReleaseProfileData? FilterProfile(ReleaseProfileData selectedProfile,
|
public ReleaseProfileData? FilterProfile(ReleaseProfileData selectedProfile,
|
@ -0,0 +1,51 @@
|
|||||||
|
using Common.FluentValidation;
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace TrashLib.Sonarr.ReleaseProfile.Filters;
|
||||||
|
|
||||||
|
public class ReleaseProfileDataValidationFilterer
|
||||||
|
{
|
||||||
|
private readonly ILogger _log;
|
||||||
|
|
||||||
|
public ReleaseProfileDataValidationFilterer(ILogger log)
|
||||||
|
{
|
||||||
|
_log = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LogInvalidTerm(List<ValidationFailure> failures, string filterDescription)
|
||||||
|
{
|
||||||
|
_log.Debug("Validation failed on term data ({Filter}): {Failures}", filterDescription, failures);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<TermData> FilterTerms(IEnumerable<TermData> terms)
|
||||||
|
{
|
||||||
|
return terms.IsValid(new TermDataValidator(), (e, x) => LogInvalidTerm(e, x.ToString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<PreferredTermData> FilterTerms(IEnumerable<PreferredTermData> terms)
|
||||||
|
{
|
||||||
|
return terms.IsValid(new PreferredTermDataValidator(), (e, x) => LogInvalidTerm(e, x.ToString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReleaseProfileData FilterProfile(ReleaseProfileData profile)
|
||||||
|
{
|
||||||
|
return profile with
|
||||||
|
{
|
||||||
|
Required = FilterTerms(profile.Required).ToList(),
|
||||||
|
Ignored = FilterTerms(profile.Ignored).ToList(),
|
||||||
|
Preferred = FilterTerms(profile.Preferred).ToList()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ReleaseProfileData> FilterProfiles(IEnumerable<ReleaseProfileData> data)
|
||||||
|
{
|
||||||
|
return data
|
||||||
|
.Select(FilterProfile)
|
||||||
|
.IsValid(new ReleaseProfileDataValidator(), (e, x) =>
|
||||||
|
{
|
||||||
|
_log.Warning("Excluding invalid release profile: {Profile}", x.ToString());
|
||||||
|
_log.Debug("Release profile excluded for these reasons: {Reasons}", e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue