Files
jdescopingtool/NEW/tests/JdeScoping.Infrastructure.Tests/Validation/ConnectionStringValidatorTests.cs
T
Joseph Doherty 6642c83cdb feat(configmanager): add runtime config validation using Infrastructure validators
Enable ConfigManager to validate runtime configuration (SecureStore secrets,
connection strings, LDAP) using the same validators as the Host application.
Adds AddInfrastructureValidators() extension for shared validator registration.
2026-01-21 18:31:42 -05:00

318 lines
9.7 KiB
C#

using JdeScoping.Infrastructure.Tests.Helpers;
using JdeScoping.Infrastructure.Validation;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging.Abstractions;
using Shouldly;
namespace JdeScoping.Infrastructure.Tests.Validation;
public class ConnectionStringValidatorTests : IDisposable
{
private readonly InMemorySecureStore _secureStore;
public ConnectionStringValidatorTests()
{
_secureStore = new InMemorySecureStore();
}
public void Dispose()
{
_secureStore.Dispose();
}
private ConnectionStringValidator CreateValidator(Dictionary<string, string?> configValues)
{
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(configValues)
.Build();
return new ConnectionStringValidator(
configuration,
_secureStore,
NullLogger<ConnectionStringValidator>.Instance);
}
[Fact]
public void Order_Returns150()
{
// Arrange
var validator = CreateValidator(new Dictionary<string, string?>());
// Assert
validator.Order.ShouldBe(150);
}
[Fact]
public void Name_ReturnsConnectionStrings()
{
// Arrange
var validator = CreateValidator(new Dictionary<string, string?>());
// Assert
validator.Name.ShouldBe("ConnectionStrings");
}
[Fact]
public void Validate_NoConnectionStrings_ReturnsValid()
{
// Arrange
var validator = CreateValidator(new Dictionary<string, string?>());
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeTrue();
result.Errors.ShouldBeEmpty();
result.Warnings.ShouldBeEmpty();
}
[Fact]
public void Validate_ConnectionStringWithNoPlaceholders_ValidatesFormat()
{
// Arrange
var validator = CreateValidator(new Dictionary<string, string?>
{
["ConnectionStrings:SqlServer"] = "Server=localhost;Database=TestDb;Trusted_Connection=true;"
});
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeTrue();
result.Errors.ShouldBeEmpty();
}
[Fact]
public void Validate_EmptyConnectionString_ReturnsError()
{
// Arrange
var validator = CreateValidator(new Dictionary<string, string?>
{
["ConnectionStrings:SqlServer"] = ""
});
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeFalse();
result.Errors.ShouldContain("Connection string 'SqlServer' is empty");
}
[Fact]
public void Validate_PlaceholderKeyNotInSecureStore_ReturnsError()
{
// Arrange
var validator = CreateValidator(new Dictionary<string, string?>
{
["ConnectionStrings:SqlServer"] = "Server=localhost;Database=TestDb;Password=${DB_PASSWORD};"
});
// Note: Not adding DB_PASSWORD to SecureStore
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeFalse();
result.Errors.ShouldContain(e => e.Contains("'${DB_PASSWORD}'") && e.Contains("not found in SecureStore"));
}
[Fact]
public void Validate_PlaceholderKeyHasEmptyValue_ReturnsError()
{
// Arrange
_secureStore.Set("DB_PASSWORD", "");
var validator = CreateValidator(new Dictionary<string, string?>
{
["ConnectionStrings:SqlServer"] = "Server=localhost;Database=TestDb;Password=${DB_PASSWORD};"
});
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeFalse();
result.Errors.ShouldContain(e => e.Contains("'${DB_PASSWORD}'") && e.Contains("empty value"));
}
[Fact]
public void Validate_AllPlaceholdersResolved_ValidatesFormat()
{
// Arrange
_secureStore.Set("DB_PASSWORD", "secretpassword");
var validator = CreateValidator(new Dictionary<string, string?>
{
["ConnectionStrings:SqlServer"] = "Server=localhost;Database=TestDb;Password=${DB_PASSWORD};"
});
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeTrue();
result.Errors.ShouldBeEmpty();
}
[Fact]
public void Validate_MultiplePlaceholders_ResolvesAll()
{
// Arrange
_secureStore.Set("DB_SERVER", "prodserver.local");
_secureStore.Set("DB_USER", "app_user");
_secureStore.Set("DB_PASSWORD", "secretpassword");
var validator = CreateValidator(new Dictionary<string, string?>
{
["ConnectionStrings:SqlServer"] = "Server=${DB_SERVER};Database=TestDb;User Id=${DB_USER};Password=${DB_PASSWORD};"
});
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeTrue();
result.Errors.ShouldBeEmpty();
}
[Fact]
public void Validate_MultiplePlaceholders_ReportsAllMissing()
{
// Arrange - only set one of three required placeholders
_secureStore.Set("DB_SERVER", "prodserver.local");
var validator = CreateValidator(new Dictionary<string, string?>
{
["ConnectionStrings:SqlServer"] = "Server=${DB_SERVER};Database=TestDb;User Id=${DB_USER};Password=${DB_PASSWORD};"
});
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeFalse();
result.Errors.Count.ShouldBe(2); // DB_USER and DB_PASSWORD missing
result.Errors.ShouldContain(e => e.Contains("'${DB_USER}'"));
result.Errors.ShouldContain(e => e.Contains("'${DB_PASSWORD}'"));
}
[Fact]
public void Validate_MissingServerOrDataSource_ReturnsError()
{
// Arrange - connection string with no Server= or Data Source=
var validator = CreateValidator(new Dictionary<string, string?>
{
["ConnectionStrings:Invalid"] = "Database=TestDb;Trusted_Connection=true;"
});
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeFalse();
result.Errors.ShouldContain(e => e.Contains("'Invalid'") && e.Contains("missing required"));
}
[Fact]
public void Validate_DataSourceFormat_ValidatesSuccessfully()
{
// Arrange - Oracle-style connection string
var validator = CreateValidator(new Dictionary<string, string?>
{
["ConnectionStrings:Oracle"] = "Data Source=//localhost:1521/ORCL;User Id=test;Password=test;"
});
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeTrue();
}
[Fact]
public void Validate_HostFormat_ValidatesSuccessfully()
{
// Arrange - PostgreSQL-style connection string
var validator = CreateValidator(new Dictionary<string, string?>
{
["ConnectionStrings:Postgres"] = "Host=localhost;Port=5432;Database=testdb;Username=test;Password=test;"
});
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeTrue();
}
[Fact]
public void Validate_MultipleConnectionStrings_ValidatesAll()
{
// Arrange
_secureStore.Set("SQL_PASSWORD", "sqlpass");
var validator = CreateValidator(new Dictionary<string, string?>
{
["ConnectionStrings:SqlServer"] = "Server=localhost;Database=TestDb;Password=${SQL_PASSWORD};",
["ConnectionStrings:Oracle"] = "Data Source=//localhost:1521/ORCL;User Id=test;Password=test;",
["ConnectionStrings:InvalidEmpty"] = ""
});
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeFalse();
result.Errors.Count.ShouldBe(1); // Only the empty one should fail
result.Errors.ShouldContain("Connection string 'InvalidEmpty' is empty");
}
[Fact]
public void Validate_UnknownConnectionFormat_AddsWarning()
{
// Arrange - connection string with Server= but no Database=
var validator = CreateValidator(new Dictionary<string, string?>
{
["ConnectionStrings:Custom"] = "Server=localhost;CustomProperty=value;"
});
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeTrue(); // Still valid, just a warning
result.Warnings.ShouldContain(w => w.Contains("'Custom'") && w.Contains("unknown format"));
}
[Fact]
public void Validate_WhitespaceOnlyConnectionString_ReturnsError()
{
// Arrange
var validator = CreateValidator(new Dictionary<string, string?>
{
["ConnectionStrings:SqlServer"] = " "
});
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeFalse();
result.Errors.ShouldContain("Connection string 'SqlServer' is empty");
}
[Fact]
public void Validate_CaseInsensitiveServerCheck_ValidatesSuccessfully()
{
// Arrange - mixed case Server
var validator = CreateValidator(new Dictionary<string, string?>
{
["ConnectionStrings:SqlServer"] = "server=localhost;Database=TestDb;"
});
// Act
var result = validator.Validate();
// Assert
result.IsValid.ShouldBeTrue();
}
}