Files
scadaproj/ZB.MOM.WW.Auth/tests/ZB.MOM.WW.Auth.ApiKeys.Tests/SqliteMigratorTests.cs
T

114 lines
4.0 KiB
C#

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.
}
}
}