Initial commit: scadaproj umbrella — sister-project index, auth component normalization (design + GAPS), and the built ZB.MOM.WW.Auth shared library (0.1.0, flattened in).
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
using Microsoft.Data.Sqlite;
|
||||
using ZB.MOM.WW.Auth.ApiKeys.Sqlite;
|
||||
|
||||
namespace ZB.MOM.WW.Auth.ApiKeys.Tests;
|
||||
|
||||
public sealed class SqliteMigratorTests : IDisposable
|
||||
{
|
||||
private readonly string _dbPath =
|
||||
Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".db");
|
||||
|
||||
private AuthSqliteConnectionFactory Factory => new(_dbPath);
|
||||
|
||||
[Fact]
|
||||
public async Task MigrateAsync_CreatesAllThreeTables()
|
||||
{
|
||||
var migrator = new SqliteAuthStoreMigrator(Factory);
|
||||
|
||||
await migrator.MigrateAsync(CancellationToken.None);
|
||||
|
||||
Assert.True(await TableExistsAsync(SqliteAuthSchema.ApiKeysTable));
|
||||
Assert.True(await TableExistsAsync(SqliteAuthSchema.ApiKeyAuditTable));
|
||||
Assert.True(await TableExistsAsync(SqliteAuthSchema.SchemaVersionTable));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MigrateAsync_RunTwice_IsIdempotentAndRecordsCurrentVersion()
|
||||
{
|
||||
var migrator = new SqliteAuthStoreMigrator(Factory);
|
||||
|
||||
await migrator.MigrateAsync(CancellationToken.None);
|
||||
await migrator.MigrateAsync(CancellationToken.None);
|
||||
|
||||
Assert.Equal(SqliteAuthSchema.CurrentVersion, await ReadVersionAsync());
|
||||
Assert.Equal(1, await CountSchemaVersionRowsAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MigrateAsync_FutureSchemaVersion_Throws()
|
||||
{
|
||||
var migrator = new SqliteAuthStoreMigrator(Factory);
|
||||
await migrator.MigrateAsync(CancellationToken.None);
|
||||
|
||||
await SetVersionAsync(99);
|
||||
|
||||
await Assert.ThrowsAsync<AuthStoreMigrationException>(
|
||||
() => migrator.MigrateAsync(CancellationToken.None));
|
||||
}
|
||||
|
||||
private async Task<bool> TableExistsAsync(string tableName)
|
||||
{
|
||||
await using SqliteConnection connection =
|
||||
await Factory.OpenConnectionAsync(CancellationToken.None);
|
||||
await using SqliteCommand command = connection.CreateCommand();
|
||||
command.CommandText =
|
||||
"SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name = $name;";
|
||||
command.Parameters.AddWithValue("$name", tableName);
|
||||
long count = (long)(await command.ExecuteScalarAsync(CancellationToken.None) ?? 0L);
|
||||
return count == 1;
|
||||
}
|
||||
|
||||
private async Task<int> ReadVersionAsync()
|
||||
{
|
||||
await using SqliteConnection connection =
|
||||
await Factory.OpenConnectionAsync(CancellationToken.None);
|
||||
await using SqliteCommand command = connection.CreateCommand();
|
||||
command.CommandText = "SELECT version FROM schema_version WHERE id = 1;";
|
||||
object? value = await command.ExecuteScalarAsync(CancellationToken.None);
|
||||
return Convert.ToInt32(value, System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
private async Task<int> CountSchemaVersionRowsAsync()
|
||||
{
|
||||
await using SqliteConnection connection =
|
||||
await Factory.OpenConnectionAsync(CancellationToken.None);
|
||||
await using SqliteCommand command = connection.CreateCommand();
|
||||
command.CommandText = "SELECT COUNT(*) FROM schema_version;";
|
||||
long count = (long)(await command.ExecuteScalarAsync(CancellationToken.None) ?? 0L);
|
||||
return (int)count;
|
||||
}
|
||||
|
||||
private async Task SetVersionAsync(int version)
|
||||
{
|
||||
await using SqliteConnection connection =
|
||||
await Factory.OpenConnectionAsync(CancellationToken.None);
|
||||
await using SqliteCommand command = connection.CreateCommand();
|
||||
command.CommandText = "UPDATE schema_version SET version = $version WHERE id = 1;";
|
||||
command.Parameters.AddWithValue("$version", version);
|
||||
await command.ExecuteNonQueryAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
SqliteConnection.ClearAllPools();
|
||||
TryDelete(_dbPath);
|
||||
TryDelete(_dbPath + "-wal");
|
||||
TryDelete(_dbPath + "-shm");
|
||||
}
|
||||
|
||||
private static void TryDelete(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
// Best-effort cleanup of the per-test temp database.
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user