129 lines
5.0 KiB
C#
129 lines
5.0 KiB
C#
using Microsoft.Data.Sqlite;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Microsoft.Extensions.Options;
|
|
using ScadaLink.AuditLog.Site;
|
|
|
|
namespace ScadaLink.AuditLog.Tests.Site;
|
|
|
|
/// <summary>
|
|
/// Bundle B (M2-T1) schema-bootstrap tests for <see cref="SqliteAuditWriter"/>.
|
|
/// Uses an in-memory shared-cache SQLite database so the same connection name
|
|
/// reaches the same file-less db across both the writer and the verifier.
|
|
/// </summary>
|
|
public class SqliteAuditWriterSchemaTests
|
|
{
|
|
/// <summary>
|
|
/// Each test uses a unique shared-cache in-memory database. The
|
|
/// "Mode=Memory;Cache=Shared" syntax lets two SqliteConnections see the same
|
|
/// in-memory store as long as both use the same Data Source name.
|
|
/// </summary>
|
|
private static (SqliteAuditWriter writer, string dataSource) CreateWriter(string testName)
|
|
{
|
|
var dataSource = $"file:{testName}-{Guid.NewGuid():N}?mode=memory&cache=shared";
|
|
var options = new SqliteAuditWriterOptions
|
|
{
|
|
DatabasePath = dataSource,
|
|
};
|
|
// The writer uses raw "Data Source={path}" by appending Cache=Shared. Override
|
|
// by passing the full connection string via the connectionStringOverride hook.
|
|
var writer = new SqliteAuditWriter(
|
|
Options.Create(options),
|
|
NullLogger<SqliteAuditWriter>.Instance,
|
|
connectionStringOverride: $"Data Source={dataSource};Cache=Shared");
|
|
return (writer, dataSource);
|
|
}
|
|
|
|
private static SqliteConnection OpenVerifierConnection(string dataSource)
|
|
{
|
|
var connection = new SqliteConnection($"Data Source={dataSource};Cache=Shared");
|
|
connection.Open();
|
|
return connection;
|
|
}
|
|
|
|
[Fact]
|
|
public void Opens_Creates_AuditLog_Table_With_21Columns_And_PK_On_EventId()
|
|
{
|
|
var (writer, dataSource) = CreateWriter(nameof(Opens_Creates_AuditLog_Table_With_21Columns_And_PK_On_EventId));
|
|
using (writer)
|
|
{
|
|
using var connection = OpenVerifierConnection(dataSource);
|
|
using var cmd = connection.CreateCommand();
|
|
cmd.CommandText = "PRAGMA table_info(AuditLog);";
|
|
using var reader = cmd.ExecuteReader();
|
|
|
|
var columns = new List<(string Name, int Pk)>();
|
|
while (reader.Read())
|
|
{
|
|
columns.Add((reader.GetString(1), reader.GetInt32(5)));
|
|
}
|
|
|
|
Assert.Equal(21, columns.Count);
|
|
|
|
var expected = new[]
|
|
{
|
|
"EventId", "OccurredAtUtc", "Channel", "Kind", "CorrelationId",
|
|
"SourceSiteId", "SourceInstanceId", "SourceScript", "Actor", "Target",
|
|
"Status", "HttpStatus", "DurationMs", "ErrorMessage", "ErrorDetail",
|
|
"RequestSummary", "ResponseSummary", "PayloadTruncated", "Extra",
|
|
"ForwardState", "ExecutionId",
|
|
};
|
|
Assert.Equal(expected.OrderBy(n => n), columns.Select(c => c.Name).OrderBy(n => n));
|
|
|
|
// PK is EventId only.
|
|
var pkColumns = columns.Where(c => c.Pk > 0).Select(c => c.Name).ToList();
|
|
Assert.Single(pkColumns);
|
|
Assert.Equal("EventId", pkColumns[0]);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Opens_Creates_IX_ForwardState_Occurred_Index()
|
|
{
|
|
var (writer, dataSource) = CreateWriter(nameof(Opens_Creates_IX_ForwardState_Occurred_Index));
|
|
using (writer)
|
|
{
|
|
using var connection = OpenVerifierConnection(dataSource);
|
|
using var cmd = connection.CreateCommand();
|
|
cmd.CommandText = "PRAGMA index_list(AuditLog);";
|
|
using var reader = cmd.ExecuteReader();
|
|
|
|
var indexNames = new List<string>();
|
|
while (reader.Read())
|
|
{
|
|
indexNames.Add(reader.GetString(1));
|
|
}
|
|
|
|
Assert.Contains("IX_SiteAuditLog_ForwardState_Occurred", indexNames);
|
|
|
|
// Verify the index columns are ForwardState, OccurredAtUtc in that order.
|
|
using var infoCmd = connection.CreateCommand();
|
|
infoCmd.CommandText = "PRAGMA index_info(IX_SiteAuditLog_ForwardState_Occurred);";
|
|
using var infoReader = infoCmd.ExecuteReader();
|
|
|
|
var indexColumns = new List<string>();
|
|
while (infoReader.Read())
|
|
{
|
|
indexColumns.Add(infoReader.GetString(2));
|
|
}
|
|
|
|
Assert.Equal(new[] { "ForwardState", "OccurredAtUtc" }, indexColumns);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void PRAGMA_auto_vacuum_Is_INCREMENTAL()
|
|
{
|
|
var (writer, dataSource) = CreateWriter(nameof(PRAGMA_auto_vacuum_Is_INCREMENTAL));
|
|
using (writer)
|
|
{
|
|
using var connection = OpenVerifierConnection(dataSource);
|
|
using var cmd = connection.CreateCommand();
|
|
cmd.CommandText = "PRAGMA auto_vacuum;";
|
|
var value = Convert.ToInt32(cmd.ExecuteScalar());
|
|
|
|
// INCREMENTAL = 2 (0 = NONE, 1 = FULL, 2 = INCREMENTAL).
|
|
Assert.Equal(2, value);
|
|
}
|
|
}
|
|
}
|