Files
WCTDataMiner/tests/Gpulse.WCT.DataAnalyzer.Tests/Commands/DatabaseMigrationInitializerTests.cs

121 lines
5.2 KiB
C#
Raw Normal View History

using Gpulse.WCT.DataAnalyzer.Core.Infrastructure.LocalData;
using Microsoft.EntityFrameworkCore;
namespace Gpulse.WCT.DataAnalyzer.Tests.Commands;
/// <summary>
/// RV-001EF 迁移替代 EnsureCreated。验证两类场景
/// 1. 全新库经迁移建全部表CliTestHost 已覆盖,此处断言关键新表存在)。
/// 2. 既有 EnsureCreated 库(无迁移历史但有表)经 MigrateOrUpgradeAsync 升级后补齐
/// 本变更新增的 3 张维度表 + test_scenario 的 3 列 FK。
/// </summary>
[TestFixture]
public class DatabaseMigrationInitializerTests
{
/// <summary>全新库经迁移建表后3 张新维度表存在。</summary>
[Test]
public async Task MigrateOrUpgrade_FreshDb_CreatesNewDimensionTables()
{
var dbPath = Path.Combine(Path.GetTempPath(), $"wct_fresh_{Guid.NewGuid():N}.db");
try
{
await using var context = CreateContext(dbPath);
await DatabaseMigrationInitializer.MigrateOrUpgradeAsync(context);
Assert.Multiple(async () =>
{
Assert.That(await TableExistsAsync(context, "manufacturer"), Is.True);
Assert.That(await TableExistsAsync(context, "car_model"), Is.True);
Assert.That(await TableExistsAsync(context, "foreign_object"), Is.True);
});
}
finally
{
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
if (File.Exists(dbPath)) File.Delete(dbPath);
}
}
/// <summary>既有 EnsureCreated 库(旧 schema无新表/FK 列)经升级补齐。</summary>
[Test]
public async Task MigrateOrUpgrade_LegacyEnsureCreatedDb_AddsNewTablesAndFkColumns()
{
var dbPath = Path.Combine(Path.GetTempPath(), $"wct_legacy_{Guid.NewGuid():N}.db");
try
{
// 1. 构造一个"旧 schema"库test_scenario 无 manufacturer_id/car_model_id/foreign_object_id
// 无 __EFMigrationsHistory模拟 EnsureCreated 既有库)
CreateLegacyEnsureCreatedDatabase(dbPath);
// 2. 运行升级
await using var context = CreateContext(dbPath);
await DatabaseMigrationInitializer.MigrateOrUpgradeAsync(context);
// 3. 断言新维度表与 test_scenario 的新 FK 列已补齐
Assert.Multiple(async () =>
{
Assert.That(await TableExistsAsync(context, "manufacturer"), Is.True);
Assert.That(await TableExistsAsync(context, "car_model"), Is.True);
Assert.That(await TableExistsAsync(context, "foreign_object"), Is.True);
Assert.That(await ColumnExistsAsync(context, "test_scenario", "manufacturer_id"), Is.True);
Assert.That(await ColumnExistsAsync(context, "test_scenario", "car_model_id"), Is.True);
Assert.That(await ColumnExistsAsync(context, "test_scenario", "foreign_object_id"), Is.True);
});
}
finally
{
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
if (File.Exists(dbPath)) File.Delete(dbPath);
}
}
private static WctMinerDbContext CreateContext(string dbPath)
{
var dir = Path.GetDirectoryName(dbPath);
if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
Directory.CreateDirectory(dir);
var options = new DbContextOptionsBuilder<WctMinerDbContext>()
.UseSqlite($"Data Source={dbPath};Pooling=False")
.Options;
return new WctMinerDbContext(options);
}
private static void CreateLegacyEnsureCreatedDatabase(string dbPath)
{
using var connection = new Microsoft.Data.Sqlite.SqliteConnection($"Data Source={dbPath};Pooling=False");
connection.Open();
using var cmd = connection.CreateCommand();
cmd.CommandText = """
CREATE TABLE test_scenario (
id TEXT NOT NULL PRIMARY KEY,
tx_panel_id TEXT,
tx_hardware_id TEXT,
tx_software_id TEXT,
rx_type_id TEXT,
test_purpose TEXT,
test_date TEXT,
test_sequence INTEGER,
is_deleted INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE tx_panel (id TEXT NOT NULL PRIMARY KEY, name TEXT, is_deleted INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT (datetime('now')));
""";
cmd.ExecuteNonQuery();
}
private static async Task<bool> TableExistsAsync(WctMinerDbContext context, string tableName)
{
var count = await context.Database.SqlQueryRaw<long>(
$"SELECT count(*) AS Value FROM sqlite_master WHERE type='table' AND name = '{tableName}'").FirstOrDefaultAsync();
return count > 0;
}
private static async Task<bool> ColumnExistsAsync(WctMinerDbContext context, string table, string column)
{
var count = await context.Database.SqlQueryRaw<long>(
$"SELECT count(*) AS Value FROM pragma_table_info('{table}') WHERE name = '{column}'").FirstOrDefaultAsync();
return count > 0;
}
}