namespace ZB.MOM.WW.Secrets.Replicator.SqlServer.Tests;
///
/// The schema-name allow-list is the injection boundary for the one value that cannot be
/// parameterized (a T-SQL object name), so it gets adversarial coverage rather than a happy path.
///
public sealed class SqlServerSecretsOptionsTests
{
[Theory]
[InlineData("zbsecrets")]
[InlineData("ZbSecrets")]
[InlineData("_private")]
[InlineData("schema_1")]
public void SchemaName_accepts_plain_identifiers(string value)
{
var options = new SqlServerSecretsOptions { SchemaName = value };
Assert.Equal(value, options.SchemaName);
}
[Theory]
// The bracket-escape trick that would otherwise break out of the [quoting] at the use site.
[InlineData("evil]]; DROP TABLE secret; --")]
[InlineData("dbo.secret")]
[InlineData("with space")]
[InlineData("quote'name")]
[InlineData("semi;colon")]
[InlineData("1leading_digit")]
[InlineData("")]
[InlineData(" ")]
public void SchemaName_rejects_anything_that_is_not_a_plain_identifier(string value)
{
Assert.Throws(() => new SqlServerSecretsOptions { SchemaName = value });
}
[Fact]
public void SchemaName_rejects_an_over_long_identifier()
{
Assert.Throws(() =>
new SqlServerSecretsOptions { SchemaName = new string('a', 129) });
}
[Fact]
public void Validate_rejects_a_missing_connection_string()
{
InvalidOperationException ex =
Assert.Throws(() => new SqlServerSecretsOptions().Validate());
Assert.Contains("ConnectionString", ex.Message, StringComparison.Ordinal);
}
[Fact]
public void Validate_rejects_a_non_positive_sync_interval()
{
var options = new SqlServerSecretsOptions
{
ConnectionString = "Server=x;",
SyncInterval = TimeSpan.Zero,
};
Assert.Throws(options.Validate);
}
[Fact]
public void Validate_rejects_a_non_positive_command_timeout()
{
var options = new SqlServerSecretsOptions
{
ConnectionString = "Server=x;",
CommandTimeout = TimeSpan.FromSeconds(-1),
};
Assert.Throws(options.Validate);
}
[Fact]
public void Validate_accepts_a_fully_configured_instance()
{
var options = new SqlServerSecretsOptions { ConnectionString = "Server=x;Database=y;" };
options.Validate();
}
[Fact]
public void CreateSchemaDdl_quotes_the_schema_name_everywhere_it_appears()
{
string ddl = SqlServerSecretsSchema.CreateSchemaDdl("zbsecrets");
Assert.Contains("[zbsecrets].[secret]", ddl, StringComparison.Ordinal);
Assert.Contains("[zbsecrets].[schema_version]", ddl, StringComparison.Ordinal);
// Every DDL statement is guarded, so re-running the migration on a provisioned database is
// a no-op rather than an error.
Assert.Contains("IF NOT EXISTS", ddl, StringComparison.Ordinal);
Assert.Contains("IS NULL", ddl, StringComparison.Ordinal);
}
}