95 lines
3.6 KiB
C#
95 lines
3.6 KiB
C#
using Microsoft.AspNetCore.DataProtection;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
using ScadaLink.Commons.Entities.Deployment;
|
|
using ScadaLink.ConfigurationDatabase;
|
|
|
|
namespace ScadaLink.ConfigurationDatabase.Tests;
|
|
|
|
/// <summary>
|
|
/// Test DbContext that adapts SQL Server-specific features for SQLite:
|
|
/// - Maps DateTimeOffset to sortable ISO 8601 strings (SQLite has no native DateTimeOffset ORDER BY)
|
|
/// - Replaces SQL Server RowVersion with a nullable byte[] column (SQLite can't auto-generate rowversion)
|
|
///
|
|
/// Constructed with an explicit ephemeral Data Protection provider so secret-bearing
|
|
/// columns are write-capable in tests. The schema-only no-provider constructor would
|
|
/// throw on a secret-column write (ConfigurationDatabase-013); passing a provider here
|
|
/// makes the test fixture's intent explicit at the call site.
|
|
/// </summary>
|
|
public class SqliteTestDbContext : ScadaLinkDbContext
|
|
{
|
|
public SqliteTestDbContext(DbContextOptions<ScadaLinkDbContext> options)
|
|
: base(options, new EphemeralDataProtectionProvider())
|
|
{
|
|
}
|
|
|
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
{
|
|
base.OnModelCreating(modelBuilder);
|
|
|
|
// SQLite cannot auto-generate SQL Server rowversion values.
|
|
// Replace with a nullable byte[] column so inserts don't fail with NOT NULL constraint.
|
|
modelBuilder.Entity<DeploymentRecord>(builder =>
|
|
{
|
|
builder.Property(d => d.RowVersion)
|
|
.IsRequired(false)
|
|
.IsConcurrencyToken(false)
|
|
.ValueGeneratedNever();
|
|
});
|
|
|
|
// Convert DateTimeOffset to ISO 8601 string for SQLite so ORDER BY works
|
|
var converter = new ValueConverter<DateTimeOffset, string>(
|
|
v => v.UtcDateTime.ToString("o"),
|
|
v => DateTimeOffset.Parse(v));
|
|
|
|
var nullableConverter = new ValueConverter<DateTimeOffset?, string?>(
|
|
v => v.HasValue ? v.Value.UtcDateTime.ToString("o") : null,
|
|
v => v != null ? DateTimeOffset.Parse(v) : null);
|
|
|
|
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
|
|
{
|
|
foreach (var property in entityType.GetProperties())
|
|
{
|
|
if (property.ClrType == typeof(DateTimeOffset))
|
|
{
|
|
property.SetValueConverter(converter);
|
|
property.SetColumnType("TEXT");
|
|
}
|
|
else if (property.ClrType == typeof(DateTimeOffset?))
|
|
{
|
|
property.SetValueConverter(nullableConverter);
|
|
property.SetColumnType("TEXT");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static class SqliteTestHelper
|
|
{
|
|
public static ScadaLinkDbContext CreateInMemoryContext()
|
|
{
|
|
var options = new DbContextOptionsBuilder<ScadaLinkDbContext>()
|
|
.UseSqlite("DataSource=:memory:")
|
|
.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning))
|
|
.Options;
|
|
|
|
var context = new SqliteTestDbContext(options);
|
|
context.Database.OpenConnection();
|
|
context.Database.EnsureCreated();
|
|
return context;
|
|
}
|
|
|
|
public static ScadaLinkDbContext CreateFileContext(string dbPath)
|
|
{
|
|
var options = new DbContextOptionsBuilder<ScadaLinkDbContext>()
|
|
.UseSqlite($"DataSource={dbPath}")
|
|
.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning))
|
|
.Options;
|
|
|
|
var context = new SqliteTestDbContext(options);
|
|
return context;
|
|
}
|
|
}
|