diff --git a/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigRegistryTest.cs b/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigRegistryTest.cs deleted file mode 100644 index 7304a6a2..00000000 --- a/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigRegistryTest.cs +++ /dev/null @@ -1,110 +0,0 @@ -// using Recyclarr.TrashLib.Config; -// using Recyclarr.TrashLib.Config.Parsing; -// using Recyclarr.TrashLib.Config.Services; -// using Recyclarr.TrashLib.Processors; -// using Recyclarr.TrashLib.TestLibrary; -// -// namespace Recyclarr.TrashLib.Tests.Config.Parsing; -// -// [TestFixture] -// [Parallelizable(ParallelScope.All)] -// public class ConfigRegistryTest -// { -// [Test] -// public void Get_configs_by_type() -// { -// var configs = new IServiceConfiguration[] -// { -// new SonarrConfiguration {InstanceName = "one"}, -// new SonarrConfiguration {InstanceName = "two"}, -// new RadarrConfiguration {InstanceName = "three"} -// }; -// -// var sut = new ConfigExtensions(); -// foreach (var c in configs) -// { -// sut.Add(c); -// } -// -// var result = sut.GetConfigsBasedOnSettings(MockSyncSettings.Sonarr()); -// -// result.Should().Equal(configs.Take(2)); -// } -// -// [Test] -// public void Null_service_type_returns_configs_of_all_types() -// { -// var configs = new IServiceConfiguration[] -// { -// new SonarrConfiguration {InstanceName = "one"}, -// new SonarrConfiguration {InstanceName = "two"}, -// new RadarrConfiguration {InstanceName = "three"} -// }; -// -// var sut = new ConfigExtensions(); -// foreach (var c in configs) -// { -// sut.Add(c); -// } -// -// var result = sut.GetConfigsBasedOnSettings(MockSyncSettings.AnyService()); -// -// result.Should().Equal(configs); -// } -// -// [Test] -// public void Get_empty_collection_when_no_configs_of_type() -// { -// var sut = new ConfigExtensions(); -// sut.Add(new SonarrConfiguration()); -// -// var settings = Substitute.For(); -// settings.Service.Returns(SupportedServices.Radarr); -// -// var result = sut.GetConfigsBasedOnSettings(settings); -// -// result.Should().BeEmpty(); -// } -// -// [Test] -// public void Get_configs_by_type_and_instance_name() -// { -// var configs = new IServiceConfiguration[] -// { -// new SonarrConfiguration {InstanceName = "one"}, -// new SonarrConfiguration {InstanceName = "two"}, -// new RadarrConfiguration {InstanceName = "three"} -// }; -// -// var sut = new ConfigExtensions(); -// foreach (var c in configs) -// { -// sut.Add(c); -// } -// -// var result = sut.GetConfigsBasedOnSettings(MockSyncSettings.Sonarr("one")); -// -// result.Should().Equal(configs.Take(1)); -// } -// -// [Test] -// public void Instance_matching_should_be_case_insensitive() -// { -// var configs = new IServiceConfiguration[] -// { -// new SonarrConfiguration {InstanceName = "one"} -// }; -// -// var sut = new ConfigExtensions(); -// foreach (var c in configs) -// { -// sut.Add(c); -// } -// -// var result = sut.GetConfigsBasedOnSettings(MockSyncSettings.AnyService("ONE")); -// -// result.Should().Equal(configs); -// } -// } - - diff --git a/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigValidationExecutorTest.cs b/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigValidationExecutorTest.cs index 1d67f2b1..77b78c78 100644 --- a/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigValidationExecutorTest.cs +++ b/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigValidationExecutorTest.cs @@ -1,60 +1,54 @@ -// using System.Diagnostics.CodeAnalysis; -// using Autofac; -// using FluentValidation; -// using Recyclarr.Cli.TestLibrary; -// using Recyclarr.TrashLib.Config.Parsing; -// using Recyclarr.TrashLib.Config.Services; -// -// namespace Recyclarr.TrashLib.Tests.Config.Parsing; -// -// [TestFixture] -// [Parallelizable(ParallelScope.All)] -// public class ConfigValidationExecutorTest : IntegrationFixture -// { -// [SuppressMessage("Design", "CA1812", Justification = "Instantiated via reflection in unit test")] -// private sealed class TestValidator : AbstractValidator -// { -// public bool ShouldSucceed { get; set; } -// -// public TestValidator() -// { -// RuleFor(x => x).Must(_ => ShouldSucceed); -// } -// } -// -// protected override void RegisterExtraTypes(ContainerBuilder builder) -// { -// builder.RegisterType() -// .AsSelf() -// .As>() -// .SingleInstance(); -// } -// -// [Test] -// public void Return_false_on_validation_failure() -// { -// var validator = Resolve(); -// validator.ShouldSucceed = false; -// -// var sut = Resolve(); -// -// var result = sut.Validate(new RadarrConfiguration()); -// -// result.Should().BeFalse(); -// } -// -// [Test] -// public void Valid_returns_true() -// { -// var validator = Resolve(); -// validator.ShouldSucceed = true; -// -// var sut = Resolve(); -// -// var result = sut.Validate(new RadarrConfiguration()); -// -// result.Should().BeTrue(); -// } -// } +using FluentValidation; +using FluentValidation.Results; +using Recyclarr.Common.FluentValidation; +using Recyclarr.TrashLib.Config.Parsing; +using Recyclarr.TrashLib.Config.Services; +namespace Recyclarr.TrashLib.Tests.Config.Parsing; +[TestFixture] +[Parallelizable(ParallelScope.All)] +public class ConfigValidationExecutorTest +{ + [Test, AutoMockData] + public void Return_false_on_validation_failure( + [Frozen] IRuntimeValidationService validationService, + ConfigValidationExecutor sut) + { + validationService.Validate(default!).ReturnsForAnyArgs(new ValidationResult(new[] + { + new ValidationFailure("property", "message") + })); + + var result = sut.Validate(new RadarrConfiguration()); + + result.Should().BeFalse(); + } + + [Test, AutoMockData] + public void Return_true_when_severity_is_warning( + [Frozen] IRuntimeValidationService validationService, + ConfigValidationExecutor sut) + { + validationService.Validate(default!).ReturnsForAnyArgs(new ValidationResult(new[] + { + new ValidationFailure("property", "message") {Severity = Severity.Warning} + })); + + var result = sut.Validate(new RadarrConfiguration()); + + result.Should().BeTrue(); + } + + [Test, AutoMockData] + public void Valid_returns_true( + [Frozen] IRuntimeValidationService validationService, + ConfigValidationExecutor sut) + { + validationService.Validate(default!).ReturnsForAnyArgs(new ValidationResult()); + + var result = sut.Validate(new RadarrConfiguration()); + + result.Should().BeTrue(); + } +} diff --git a/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderEnvVarTest.cs b/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderEnvVarTest.cs index c3643bb1..c422219b 100644 --- a/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderEnvVarTest.cs +++ b/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderEnvVarTest.cs @@ -1,189 +1,171 @@ -// using Recyclarr.Cli.TestLibrary; -// using Recyclarr.Common; -// using Recyclarr.TrashLib.Config.EnvironmentVariables; -// using Recyclarr.TrashLib.Config.Parsing; -// using Recyclarr.TrashLib.TestLibrary; -// using YamlDotNet.Core; -// -// namespace Recyclarr.TrashLib.Tests.Config.Parsing; -// -// [TestFixture] -// [Parallelizable(ParallelScope.All)] -// public class ConfigurationLoaderEnvVarTest : IntegrationFixture -// { -// [Test] -// public void Test_successful_environment_variable_loading() -// { -// var env = Resolve(); -// env.GetEnvironmentVariable("SONARR_API_KEY").Returns("the_api_key"); -// env.GetEnvironmentVariable("SONARR_URL").Returns("http://the_url"); -// -// var sut = Resolve(); -// -// const string testYml = @" -// sonarr: -// instance: -// api_key: !env_var SONARR_API_KEY -// base_url: !env_var SONARR_URL http://sonarr:1233 -// "; -// -// var configCollection = sut.Load(new StringReader(testYml)); -// -// var config = configCollection.GetConfigsBasedOnSettings(MockSyncSettings.Sonarr()); -// config.Should().BeEquivalentTo(new[] -// { -// new -// { -// BaseUrl = new Uri("http://the_url"), -// ApiKey = "the_api_key" -// } -// }); -// } -// -// [Test] -// public void Use_default_value_if_env_var_not_defined() -// { -// var sut = Resolve(); -// -// const string testYml = @" -// sonarr: -// instance: -// base_url: !env_var SONARR_URL http://sonarr:1233 -// api_key: value -// "; -// -// var configCollection = sut.Load(new StringReader(testYml)); -// -// var config = configCollection.GetConfigsBasedOnSettings(MockSyncSettings.Sonarr()); -// config.Should().BeEquivalentTo(new[] -// { -// new -// { -// BaseUrl = new Uri("http://sonarr:1233") -// } -// }); -// } -// -// [Test] -// public void Default_value_with_spaces_is_allowed() -// { -// var env = Resolve(); -// env.GetEnvironmentVariable("SONARR_URL").Returns(""); -// -// var sut = Resolve(); -// -// const string testYml = @" -// sonarr: -// instance: -// base_url: !env_var SONARR_URL http://somevalue -// api_key: value -// "; -// -// var configCollection = sut.Load(new StringReader(testYml)); -// -// var config = configCollection.GetConfigsBasedOnSettings(MockSyncSettings.Sonarr()); -// config.Should().BeEquivalentTo(new[] -// { -// new -// { -// BaseUrl = new Uri("http://somevalue") -// } -// }); -// } -// -// [Test] -// public void Quotation_characters_are_stripped_from_default_value() -// { -// var env = Resolve(); -// env.GetEnvironmentVariable("SONARR_URL").Returns(""); -// -// var sut = Resolve(); -// -// const string testYml = @" -// sonarr: -// instance: -// base_url: !env_var SONARR_URL ""http://theurl"" -// api_key: !env_var SONARR_API 'the key' -// "; -// -// var configCollection = sut.Load(new StringReader(testYml)); -// -// var config = configCollection.GetConfigsBasedOnSettings(MockSyncSettings.Sonarr()); -// config.Should().BeEquivalentTo(new[] -// { -// new -// { -// BaseUrl = new Uri("http://theurl"), -// ApiKey = "the key" -// } -// }); -// } -// -// [Test] -// public void Multiple_spaces_between_default_and_env_var_work() -// { -// var sut = Resolve(); -// -// const string testYml = @" -// sonarr: -// instance: -// base_url: !env_var SONARR_URL http://somevalue -// api_key: value -// "; -// -// var configCollection = sut.Load(new StringReader(testYml)); -// -// var config = configCollection.GetConfigsBasedOnSettings(MockSyncSettings.Sonarr()); -// config.Should().BeEquivalentTo(new[] -// { -// new -// { -// BaseUrl = new Uri("http://somevalue") -// } -// }); -// } -// -// [Test] -// public void Tab_characters_are_stripped() -// { -// var sut = Resolve(); -// -// const string testYml = $@" -// sonarr: -// instance: -// base_url: !env_var SONARR_URL {"\t"}http://somevalue -// api_key: value -// "; -// -// var configCollection = sut.Load(new StringReader(testYml)); -// -// var config = configCollection.GetConfigsBasedOnSettings(MockSyncSettings.Sonarr()); -// config.Should().BeEquivalentTo(new[] -// { -// new -// { -// BaseUrl = new Uri("http://somevalue") -// } -// }); -// } -// -// [Test] -// public void Throw_when_no_env_var_and_no_default() -// { -// var sut = Resolve(); -// -// const string testYml = @" -// sonarr: -// instance: -// base_url: !env_var SONARR_URL -// api_key: value -// "; -// -// var act = () => sut.Load(new StringReader(testYml)); -// -// act.Should().Throw() -// .WithInnerException(); -// } -// } +using Recyclarr.Common; +using Recyclarr.TrashLib.Config.Parsing; +using Recyclarr.TrashLib.TestLibrary; +namespace Recyclarr.TrashLib.Tests.Config.Parsing; +[TestFixture] +[Parallelizable(ParallelScope.All)] +public class ConfigurationLoaderEnvVarTest : TrashLibIntegrationFixture +{ + [Test] + public void Test_successful_environment_variable_loading() + { + var env = Resolve(); + env.GetEnvironmentVariable("SONARR_API_KEY").Returns("the_api_key"); + env.GetEnvironmentVariable("SONARR_URL").Returns("http://the_url"); + + var sut = Resolve(); + + const string testYml = @" +sonarr: + instance: + api_key: !env_var SONARR_API_KEY + base_url: !env_var SONARR_URL http://sonarr:1233 +"; + + var config = sut.Load(testYml); + + config.Should().BeEquivalentTo(new[] + { + new + { + BaseUrl = new Uri("http://the_url"), + ApiKey = "the_api_key" + } + }); + } + + [Test] + public void Use_default_value_if_env_var_not_defined() + { + var sut = Resolve(); + + const string testYml = @" +sonarr: + instance: + base_url: !env_var SONARR_URL http://sonarr:1233 + api_key: value +"; + + var config = sut.Load(testYml); + config.Should().BeEquivalentTo(new[] + { + new + { + BaseUrl = new Uri("http://sonarr:1233") + } + }); + } + + [Test] + public void Default_value_with_spaces_is_allowed() + { + var env = Resolve(); + env.GetEnvironmentVariable("SONARR_URL").Returns(""); + + var sut = Resolve(); + + const string testYml = @" +sonarr: + instance: + base_url: !env_var SONARR_URL http://somevalue + api_key: value +"; + + var config = sut.Load(testYml); + config.Should().BeEquivalentTo(new[] + { + new + { + BaseUrl = new Uri("http://somevalue") + } + }); + } + + [Test] + public void Quotation_characters_are_stripped_from_default_value() + { + var env = Resolve(); + env.GetEnvironmentVariable("SONARR_URL").Returns(""); + + var sut = Resolve(); + + const string testYml = @" +sonarr: + instance: + base_url: !env_var SONARR_URL ""http://theurl"" + api_key: !env_var SONARR_API 'the key' +"; + + var config = sut.Load(testYml); + config.Should().BeEquivalentTo(new[] + { + new + { + BaseUrl = new Uri("http://theurl"), + ApiKey = "the key" + } + }); + } + + [Test] + public void Multiple_spaces_between_default_and_env_var_work() + { + var sut = Resolve(); + + const string testYml = @" +sonarr: + instance: + base_url: !env_var SONARR_URL http://somevalue + api_key: value +"; + + var config = sut.Load(testYml); + config.Should().BeEquivalentTo(new[] + { + new + { + BaseUrl = new Uri("http://somevalue") + } + }); + } + + [Test] + public void Tab_characters_are_stripped() + { + var sut = Resolve(); + + const string testYml = $@" +sonarr: + instance: + base_url: !env_var SONARR_URL {"\t"}http://somevalue + api_key: value +"; + + var config = sut.Load(testYml); + config.Should().BeEquivalentTo(new[] + { + new + { + BaseUrl = new Uri("http://somevalue") + } + }); + } + + [Test] + public void No_configs_returned_when_no_env_var_and_no_default() + { + var sut = Resolve(); + + const string testYml = @" +sonarr: + instance: + base_url: !env_var SONARR_URL + api_key: value +"; + + var result = sut.Load(testYml); + result.Should().BeEmpty(); + } +} diff --git a/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderSecretsTest.cs b/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderSecretsTest.cs index 1b67dcda..9dc2a752 100644 --- a/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderSecretsTest.cs +++ b/src/Recyclarr.TrashLib.Tests/Config/Parsing/ConfigurationLoaderSecretsTest.cs @@ -1,138 +1,127 @@ -// using Recyclarr.Cli.TestLibrary; -// using Recyclarr.TrashLib.Config.Parsing; -// using Recyclarr.TrashLib.Config.Secrets; -// using Recyclarr.TrashLib.Config.Services; -// using Recyclarr.TrashLib.TestLibrary; -// using Serilog.Sinks.TestCorrelator; -// using YamlDotNet.Core; -// -// namespace Recyclarr.TrashLib.Tests.Config.Parsing; -// -// [TestFixture] -// [Parallelizable(ParallelScope.All)] -// public class ConfigurationLoaderSecretsTest : IntegrationFixture -// { -// [Test] -// public void Test_secret_loading() -// { -// var configLoader = Resolve(); -// -// const string testYml = @" -// sonarr: -// instance1: -// api_key: !secret api_key -// base_url: !secret 123GARBAGE_ -// release_profiles: -// - trash_ids: -// - !secret secret_rp -// "; -// -// const string secretsYml = @" -// api_key: 95283e6b156c42f3af8a9b16173f876b -// 123GARBAGE_: 'https://radarr:7878' -// secret_rp: 1234567 -// "; -// -// Fs.AddFile(Paths.SecretsPath.FullName, new MockFileData(secretsYml)); -// var expected = new List -// { -// new() -// { -// InstanceName = "instance1", -// ApiKey = "95283e6b156c42f3af8a9b16173f876b", -// BaseUrl = new Uri("https://radarr:7878"), -// ReleaseProfiles = new List -// { -// new() -// { -// TrashIds = new[] {"1234567"} -// } -// } -// } -// }; -// -// var parsedSecret = configLoader.Load(new StringReader(testYml), "sonarr"); -// parsedSecret.GetConfigsBasedOnSettings(MockSyncSettings.Sonarr()) -// .Should().BeEquivalentTo(expected); -// } -// -// [Test] -// public void Throw_when_referencing_invalid_secret() -// { -// using var logContext = TestCorrelator.CreateContext(); -// var configLoader = Resolve(); -// -// const string testYml = @" -// sonarr: -// instance2: -// api_key: !secret api_key -// base_url: fake_url -// "; -// -// const string secretsYml = "no_api_key: 95283e6b156c42f3af8a9b16173f876b"; -// -// Fs.AddFile(Paths.SecretsPath.FullName, new MockFileData(secretsYml)); -// -// var act = () => configLoader.Load(new StringReader(testYml), "sonarr"); -// -// act.Should().Throw() -// .WithInnerException() -// .WithMessage("*api_key is not defined in secrets.yml"); -// } -// -// [Test] -// public void Throw_when_referencing_secret_without_secrets_file() -// { -// var configLoader = Resolve(); -// -// const string testYml = @" -// sonarr: -// instance3: -// api_key: !secret api_key -// base_url: fake_url -// "; -// -// Action act = () => configLoader.Load(new StringReader(testYml), "sonarr"); -// act.Should().Throw() -// .WithInnerException() -// .WithMessage("*api_key is not defined in secrets.yml"); -// } -// -// [Test] -// public void Throw_when_secret_value_is_not_scalar() -// { -// var configLoader = Resolve(); -// -// const string testYml = @" -// sonarr: -// instance4: -// api_key: !secret { property: value } -// base_url: fake_url -// "; -// -// Action act = () => configLoader.Load(new StringReader(testYml), "sonarr"); -// act.Should().Throw().WithMessage("Expected 'Scalar'*"); -// } -// -// [Test] -// public void Throw_when_expected_value_is_not_scalar() -// { -// var configLoader = Resolve(); -// -// const string testYml = @" -// sonarr: -// instance5: -// api_key: fake_key -// base_url: fake_url -// release_profiles: !secret bogus_profile -// "; -// -// const string secretsYml = @"bogus_profile: 95283e6b156c42f3af8a9b16173f876b"; -// -// Fs.AddFile(Paths.SecretsPath.FullName, new MockFileData(secretsYml)); -// Action act = () => configLoader.Load(new StringReader(testYml), "sonarr"); -// act.Should().Throw().WithMessage("Exception during deserialization"); -// } -// } +using Recyclarr.TrashLib.Config; +using Recyclarr.TrashLib.Config.Parsing; +using Recyclarr.TrashLib.TestLibrary; +using Serilog.Sinks.TestCorrelator; +namespace Recyclarr.TrashLib.Tests.Config.Parsing; +[TestFixture] +[Parallelizable(ParallelScope.All)] +public class ConfigurationLoaderSecretsTest : TrashLibIntegrationFixture +{ + [Test] + public void Test_secret_loading() + { + var configLoader = Resolve(); + + const string testYml = @" +sonarr: + instance1: + api_key: !secret api_key + base_url: !secret 123GARBAGE_ + release_profiles: + - trash_ids: + - !secret secret_rp +"; + + const string secretsYml = @" +api_key: 95283e6b156c42f3af8a9b16173f876b +123GARBAGE_: 'https://radarr:7878' +secret_rp: 1234567 +"; + + Fs.AddFile(Paths.SecretsPath.FullName, new MockFileData(secretsYml)); + var expected = new[] + { + new + { + InstanceName = "instance1", + ApiKey = "95283e6b156c42f3af8a9b16173f876b", + BaseUrl = new Uri("https://radarr:7878"), + ReleaseProfiles = new[] + { + new + { + TrashIds = new[] {"1234567"} + } + } + } + }; + + var parsedSecret = configLoader.Load(() => new StringReader(testYml), SupportedServices.Sonarr); + parsedSecret.Should().BeEquivalentTo(expected); + } + + [Test] + public void Throw_when_referencing_invalid_secret() + { + using var logContext = TestCorrelator.CreateContext(); + var configLoader = Resolve(); + + const string testYml = @" +sonarr: + instance2: + api_key: !secret api_key + base_url: fake_url +"; + + const string secretsYml = "no_api_key: 95283e6b156c42f3af8a9b16173f876b"; + + Fs.AddFile(Paths.SecretsPath.FullName, new MockFileData(secretsYml)); + + var result = configLoader.Load(() => new StringReader(testYml), SupportedServices.Sonarr); + result.Should().BeEmpty(); + } + + [Test] + public void Throw_when_referencing_secret_without_secrets_file() + { + var configLoader = Resolve(); + + const string testYml = @" +sonarr: + instance3: + api_key: !secret api_key + base_url: fake_url +"; + + var result = configLoader.Load(() => new StringReader(testYml), SupportedServices.Sonarr); + result.Should().BeEmpty(); + } + + [Test] + public void No_config_loaded_when_secret_value_is_not_scalar() + { + var configLoader = Resolve(); + + const string testYml = @" +sonarr: + instance4: + api_key: !secret { property: value } + base_url: fake_url +"; + + var result = configLoader.Load(() => new StringReader(testYml), SupportedServices.Sonarr); + result.Should().BeEmpty(); + } + + [Test] + public void No_config_loaded_when_resolved_value_is_not_correct() + { + var configLoader = Resolve(); + + const string testYml = @" +sonarr: + instance5: + api_key: fake_key + base_url: fake_url + release_profiles: !secret bogus_profile +"; + + const string secretsYml = @"bogus_profile: 95283e6b156c42f3af8a9b16173f876b"; + + Fs.AddFile(Paths.SecretsPath.FullName, new MockFileData(secretsYml)); + var result = configLoader.Load(() => new StringReader(testYml), SupportedServices.Sonarr); + result.Should().BeEmpty(); + } +}