279d1760ef
V004_normalize_snapshots_schema.sql had an unguarded FK to a table V2
creates. Under DbUp's default ordinal filename sort, the zero-padded
"V003_"/"V004_" migrations sorted before "V1__", so on a brand-new
database V004 would hard-fail on that FK and abort every migration
after it - V1 through V8 would never run. Confirmed via production
that neither V003 nor V004 had ever actually applied.
Fix: renamed them to V9__/V10__ and added MigrationScriptNameComparer,
which sorts DbUp scripts by numeric V{n} value instead of raw string
order, so double-digit versions can never again sort ahead of earlier
single-digit ones. Added regression tests for both the fixed case and
the original bug shape.
Also updates docs/db/quantengine.dbml (renamed migrations, and closes
out the engine_history/quantengine table-name-collision question -
both schemas are live, backing different code paths, not duplicates)
and CLAUDE.md (migration ordering fix, KIS/OpenDART/KRX credential
env-var-name reference, including a CI secret/env-var name mismatch
found for OpenDART that still needs a decision).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
52 lines
2.3 KiB
C#
52 lines
2.3 KiB
C#
using System.Linq;
|
|
using QuantEngine.Infrastructure.Data;
|
|
|
|
namespace QuantEngine.Core.Tests;
|
|
|
|
public class MigrationScriptNameComparerTests
|
|
{
|
|
[Fact]
|
|
public void Sorts_DoubleDigit_Version_After_SingleDigit_Versions()
|
|
{
|
|
var scripts = new[]
|
|
{
|
|
"QuantEngine.Infrastructure.Migrations.V10__Normalize_Snapshots_Schema.sql",
|
|
"QuantEngine.Infrastructure.Migrations.V2__Add_Kis_Collections.sql",
|
|
"QuantEngine.Infrastructure.Migrations.V9__Add_Audit_Trail_Tables.sql",
|
|
"QuantEngine.Infrastructure.Migrations.V1__Initial_Schema.sql",
|
|
"QuantEngine.Infrastructure.Migrations.V8__PostgreSQL_History_First_Schema.sql",
|
|
};
|
|
|
|
var sorted = scripts.OrderBy(s => s, new MigrationScriptNameComparer()).ToArray();
|
|
|
|
Assert.Equal(new[]
|
|
{
|
|
"QuantEngine.Infrastructure.Migrations.V1__Initial_Schema.sql",
|
|
"QuantEngine.Infrastructure.Migrations.V2__Add_Kis_Collections.sql",
|
|
"QuantEngine.Infrastructure.Migrations.V8__PostgreSQL_History_First_Schema.sql",
|
|
"QuantEngine.Infrastructure.Migrations.V9__Add_Audit_Trail_Tables.sql",
|
|
"QuantEngine.Infrastructure.Migrations.V10__Normalize_Snapshots_Schema.sql",
|
|
}, sorted);
|
|
}
|
|
|
|
[Fact]
|
|
public void Regression_ZeroPadded_Script_No_Longer_Sorts_Before_V1()
|
|
{
|
|
// This is the exact bug that shipped 2026-07-24: "V003_..." sorted before "V1__..."
|
|
// under plain ordinal comparison, so a migration with unmet table dependencies ran
|
|
// first. The comparer must treat "V003" as version 3, landing it between V2 and V4.
|
|
var scripts = new[]
|
|
{
|
|
"QuantEngine.Infrastructure.Migrations.V003_add_audit_trail_tables.sql",
|
|
"QuantEngine.Infrastructure.Migrations.V1__Initial_Schema.sql",
|
|
"QuantEngine.Infrastructure.Migrations.V4__Add_Initial_Admin.sql",
|
|
};
|
|
|
|
var sorted = scripts.OrderBy(s => s, new MigrationScriptNameComparer()).ToArray();
|
|
|
|
Assert.Equal("QuantEngine.Infrastructure.Migrations.V1__Initial_Schema.sql", sorted[0]);
|
|
Assert.Equal("QuantEngine.Infrastructure.Migrations.V003_add_audit_trail_tables.sql", sorted[1]);
|
|
Assert.Equal("QuantEngine.Infrastructure.Migrations.V4__Add_Initial_Admin.sql", sorted[2]);
|
|
}
|
|
}
|