feat(t224): add incremental freight sync

This commit is contained in:
QiuSW
2026-07-29 00:26:05 +08:00
parent 433db45100
commit c69879650e
35 changed files with 2085 additions and 156 deletions
@@ -117,6 +117,9 @@ func TestFreightImportIsAtomicIdempotentAndRevisioned(t *testing.T) {
if err != nil {
t.Fatalf("migration.New() error = %v", err)
}
if err := runner.Down(ctx); err != nil {
t.Fatalf("date sync migration down: %v", err)
}
if err := runner.Down(ctx); err != nil {
t.Fatalf("procurement migration down: %v", err)
}
@@ -163,6 +166,106 @@ func TestFreightSyncRecoveryAndFailedBatchDoNotPersistOrders(t *testing.T) {
}
}
func TestFreightDateSyncAdvancesWatermarkOnlyOnWholeBatchSuccess(
t *testing.T,
) {
db := openDatabase(t)
store, _ := repository.New(db)
ctx := context.Background()
now := time.Date(2026, 7, 28, 8, 0, 0, 0, time.UTC)
userID := uuid(960)
seedFreightUser(t, db, userID, now)
firstThrough := now.Add(30 * time.Minute)
first := freightDateRun(
961,
userID,
now,
"2026-07-27",
"2026-07-28",
firstThrough,
)
createAndStartFreightRun(t, store, first, "date-success", "6")
if err := store.CompleteFreightDateSync(
ctx,
first,
domain.FreightImportBatch{},
firstThrough,
now.Add(time.Minute),
); err != nil {
t.Fatalf("CompleteFreightDateSync() error = %v", err)
}
watermark, err := store.GetFreightSyncWatermark(ctx, "local-admin")
if err != nil || watermark == nil ||
!watermark.LastSuccessfulTo.Equal(firstThrough) ||
watermark.LastSuccessfulRunID != first.ID {
t.Fatalf("first watermark = %+v, %v", watermark, err)
}
failed := freightDateRun(
962,
userID,
now.Add(time.Hour),
"2026-07-28",
"2026-07-28",
now.Add(2*time.Hour),
)
createAndStartFreightRun(t, store, failed, "date-failed", "7")
if err := store.FailFreightSync(
ctx,
failed.ID,
"ERP_CONNECTOR_UNAVAILABLE",
now.Add(time.Hour+time.Minute),
); err != nil {
t.Fatalf("FailFreightSync() error = %v", err)
}
watermark, _ = store.GetFreightSyncWatermark(ctx, "local-admin")
if !watermark.LastSuccessfulTo.Equal(firstThrough) ||
watermark.LastSuccessfulRunID != first.ID {
t.Fatalf("failed run advanced watermark = %+v", watermark)
}
olderThrough := now.Add(-time.Hour)
older := freightDateRun(
963,
userID,
now.Add(2*time.Hour),
"2026-07-26",
"2026-07-26",
olderThrough,
)
createAndStartFreightRun(t, store, older, "date-older", "8")
if err := store.CompleteFreightDateSync(
ctx,
older,
domain.FreightImportBatch{},
olderThrough,
now.Add(2*time.Hour+time.Minute),
); err != nil {
t.Fatalf("older CompleteFreightDateSync() error = %v", err)
}
watermark, _ = store.GetFreightSyncWatermark(ctx, "local-admin")
if !watermark.LastSuccessfulTo.Equal(firstThrough) ||
watermark.LastSuccessfulRunID != first.ID {
t.Fatalf("older run retreated watermark = %+v", watermark)
}
runner, _ := migration.New(db)
if err := runner.Down(ctx); err == nil {
t.Fatal("date sync migration down succeeded with retained watermark")
}
var foreignKeysEnabled int
if err := db.QueryRow(`PRAGMA foreign_keys`).Scan(
&foreignKeysEnabled,
); err != nil || foreignKeysEnabled != 1 {
t.Fatalf(
"failed down disabled foreign keys = %d, %v",
foreignKeysEnabled,
err,
)
}
}
func seedFreightUser(
t *testing.T,
db *sql.DB,
@@ -200,6 +303,27 @@ func freightRun(
}
}
func freightDateRun(
index int,
userID string,
now time.Time,
createdFrom, createdTo string,
watermarkThrough time.Time,
) domain.FreightSyncRun {
return domain.FreightSyncRun{
ID: uuid(index),
CreatorSubject: "local-admin",
CreatedByUserID: userID,
Mode: domain.FreightSyncCreatedRange,
CreatedFrom: createdFrom,
CreatedTo: createdTo,
WatermarkThrough: &watermarkThrough,
QuerySHA256: repeatHex("b"),
Status: domain.FreightSyncPending,
CreatedAt: now,
}
}
func freightBatch(index int, firstHash, secondHash string) domain.FreightImportBatch {
quantityOne := 1
quantityTwo := 2