Files
WCTDataMiner/tests/Gpulse.WCT.DataAnalyzer.Tests/Commands/DatabaseMigrationInitializerTests.cs
Scottxjw 7a8a1e9a87 test: 更新分析功能和迁移测试用例
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-25 11:30:16 +08:00

121 lines
5.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
}