Files
jobtrackingapp/JobTrackerApi.Tests/DatabaseConfigurationTests.cs
T

114 lines
5.4 KiB
C#

using JobTrackerApi.Data;
using JobTrackerApi.Services;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure.Internal;
using Xunit;
namespace JobTrackerApi.Tests;
public sealed class DatabaseConfigurationTests
{
private const string UnreachableMariaDb = "Server=127.0.0.1;Port=1;Database=jt_config_test;User=config_test;Password=synthetic;Connection Timeout=1";
private static IConfiguration Config(string? provider = null, string? connection = null, string? version = null) =>
new ConfigurationBuilder().AddInMemoryCollection(new Dictionary<string, string?>
{
["Database:Provider"] = provider,
["ConnectionStrings:JobTracker"] = connection,
["Database:ServerVersion"] = version,
}).Build();
[Fact]
public void Default_registration_uses_pinned_MariaDb_without_connecting_to_a_server()
{
var configuration = Config(connection: UnreachableMariaDb);
var options = new DbContextOptionsBuilder<JobTrackerContext>();
DatabaseConfiguration.Configure(options, configuration, "unused.db");
Assert.Equal("mariadb", DatabaseConfiguration.GetProvider(configuration));
var relational = Assert.Single(options.Options.Extensions.OfType<RelationalOptionsExtension>());
Assert.Equal(UnreachableMariaDb, relational.ConnectionString);
// Inspect the provider's configured version without opening a connection or generating SQL.
#pragma warning disable EF1001
var mysql = Assert.IsType<MySqlOptionsExtension>(relational);
Assert.IsType<MariaDbServerVersion>(mysql.ServerVersion);
Assert.Equal(new Version(12, 2, 2), mysql.ServerVersion!.Version);
#pragma warning restore EF1001
}
[Theory]
[InlineData(null)]
[InlineData("mariadb")]
[InlineData("mysql")]
public void Missing_MariaDb_connection_fails_closed_instead_of_creating_a_Sqlite_database(string? provider)
{
var options = new DbContextOptionsBuilder<JobTrackerContext>();
Assert.Throws<InvalidOperationException>(() => DatabaseConfiguration.Configure(options, Config(provider), "must-not-create.db"));
Assert.Empty(options.Options.Extensions.OfType<RelationalOptionsExtension>());
}
[Theory]
[InlineData("postgres")]
[InlineData("")]
[InlineData(" ")]
[InlineData("maria-db")]
public void Unknown_provider_is_rejected_even_when_a_connection_is_configured(string provider)
{
Assert.Throws<InvalidOperationException>(() => DatabaseConfiguration.Configure(
new DbContextOptionsBuilder<JobTrackerContext>(), Config(provider, "Data Source=must-not-create.db"), "unused.db"));
Assert.Throws<InvalidOperationException>(() => DatabaseConfiguration.GetProvider(Config(provider)));
}
[Theory]
[InlineData("mariadb")]
[InlineData(" MYSQL ")]
public void MariaDb_server_version_is_configurable_without_auto_detection(string provider)
{
var options = new DbContextOptionsBuilder<JobTrackerContext>();
DatabaseConfiguration.Configure(options, Config(provider, UnreachableMariaDb, "11.4.10"), "unused.db");
#pragma warning disable EF1001
Assert.Equal(new Version(11, 4, 10), options.Options.Extensions.OfType<MySqlOptionsExtension>().Single().ServerVersion!.Version);
#pragma warning restore EF1001
}
[Fact]
public void Invalid_server_version_fails_during_configuration()
{
Assert.Throws<InvalidOperationException>(() => DatabaseConfiguration.Configure(
new DbContextOptionsBuilder<JobTrackerContext>(), Config("mariadb", UnreachableMariaDb, "latest"), "unused.db"));
}
[Theory]
[InlineData(null, "Data Source=preserved.db")]
[InlineData("Data Source=explicit.db", "Data Source=explicit.db")]
public void Explicit_Sqlite_preserves_existing_file_selection(string? connection, string expected)
{
var options = new DbContextOptionsBuilder<JobTrackerContext>();
DatabaseConfiguration.Configure(options, Config(" SQLITE ", connection), "preserved.db");
var relational = Assert.Single(options.Options.Extensions.OfType<RelationalOptionsExtension>());
Assert.Equal("SqliteOptionsExtension", relational.GetType().Name);
Assert.Equal(expected, relational.ConnectionString);
}
[Fact]
public async Task Default_MariaDb_backup_selection_cannot_run_the_Sqlite_backup_path()
{
var root = Path.Combine(Path.GetTempPath(), $"jt-config-backup-{Guid.NewGuid():N}");
var configuration = new ConfigurationBuilder().AddConfiguration(Config(connection: UnreachableMariaDb))
.AddInMemoryCollection(new Dictionary<string, string?> { ["Data:Root"] = root }).Build();
var environment = new Mock<IHostEnvironment>();
environment.SetupGet(x => x.ContentRootPath).Returns(root);
try
{
var runner = new SqliteDatabaseBackupRunner(configuration, new AppPaths(configuration, environment.Object), NullLogger<SqliteDatabaseBackupRunner>.Instance);
Assert.False(runner.IsSupported);
Assert.Null(await runner.RunOnceAsync(default));
Assert.False(Directory.Exists(runner.BackupsRoot));
}
finally { if (Directory.Exists(root)) Directory.Delete(root, true); }
}
}