Очередь job получила lease и fencing, телеметрия и прогресс deploy сохраняются, ревизия пишет manifest входов. Обновление префиксов не переписывает неизменённый снимок, большие наборы идут через COPY, а устаревшая ревизия не попадает в deploy. Бандл ноды кэшируется, prune и постановка job больше не держат горячий путь. Co-authored-by: Cursor <cursoragent@cursor.com>
118 lines
2.7 KiB
Go
118 lines
2.7 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"testing"
|
|
|
|
"evobgp/internal/db"
|
|
"evobgp/internal/store"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
func TestEnsurePrefixSnapshotFillsEmptyExistingIntegration(t *testing.T) {
|
|
dsn := os.Getenv("EVOBGP_TEST_DATABASE_URL")
|
|
if dsn == "" {
|
|
t.Skip("EVOBGP_TEST_DATABASE_URL not set")
|
|
}
|
|
ctx := context.Background()
|
|
pool, err := db.OpenPostgresPool(ctx, dsn)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer pool.Close()
|
|
pg, err := NewPostgres(ctx, pool, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
prefixes := []store.PrefixRow{{Prefix: "203.0.113.1/32", Source: "test"}}
|
|
hash := store.PrefixSnapshotHash(prefixes)
|
|
snapID := uuid.NewString()
|
|
if _, err := pool.Exec(ctx, `INSERT INTO prefix_snapshot (id, content_hash) VALUES ($1::uuid, $2)`, snapID, hash); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() {
|
|
_, _ = pool.Exec(ctx, `DELETE FROM prefix_snapshot WHERE id = $1::uuid`, snapID)
|
|
})
|
|
|
|
tx, err := pool.Begin(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() { _ = tx.Rollback(ctx) }()
|
|
|
|
got, err := pg.ensurePrefixSnapshot(ctx, tx, prefixes)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got != snapID {
|
|
t.Fatalf("snap id: got %q want %q", got, snapID)
|
|
}
|
|
var rowCount int
|
|
if err := tx.QueryRow(ctx, `SELECT COUNT(*)::int FROM prefix_snapshot_row WHERE snapshot_id = $1::uuid`, snapID).Scan(&rowCount); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if rowCount != 1 {
|
|
t.Fatalf("row count: got %d", rowCount)
|
|
}
|
|
if err := tx.Commit(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestEnsurePrefixSnapshotIdempotentIntegration(t *testing.T) {
|
|
dsn := os.Getenv("EVOBGP_TEST_DATABASE_URL")
|
|
if dsn == "" {
|
|
t.Skip("EVOBGP_TEST_DATABASE_URL not set")
|
|
}
|
|
ctx := context.Background()
|
|
pool, err := db.OpenPostgresPool(ctx, dsn)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer pool.Close()
|
|
pg, err := NewPostgres(ctx, pool, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
prefixes := []store.PrefixRow{{Prefix: "198.51.100.0/24", Source: "test"}}
|
|
|
|
tx1, err := pool.Begin(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
id1, err := pg.ensurePrefixSnapshot(ctx, tx1, prefixes)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := tx1.Commit(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() {
|
|
_, _ = pool.Exec(ctx, `DELETE FROM prefix_snapshot WHERE id = $1::uuid`, id1)
|
|
})
|
|
|
|
tx2, err := pool.Begin(ctx)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() { _ = tx2.Rollback(ctx) }()
|
|
id2, err := pg.ensurePrefixSnapshot(ctx, tx2, prefixes)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if id1 != id2 {
|
|
t.Fatalf("ids differ: %q vs %q", id1, id2)
|
|
}
|
|
var rowCount int
|
|
if err := tx2.QueryRow(ctx, `SELECT COUNT(*)::int FROM prefix_snapshot_row WHERE snapshot_id = $1::uuid`, id1).Scan(&rowCount); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if rowCount != 1 {
|
|
t.Fatalf("expected 1 row, got %d", rowCount)
|
|
}
|
|
}
|