114 lines
5.4 KiB
C#
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); }
|
|
}
|
|
}
|