| package bmdb | 
 |  | 
 | import ( | 
 | 	"context" | 
 | 	"testing" | 
 |  | 
 | 	"source.monogon.dev/cloud/bmaas/bmdb/model" | 
 | ) | 
 |  | 
 | // TestMigrateUpDown performs a full-up and full-down migration test on an | 
 | // in-memory database twice. | 
 | // | 
 | // Doing this the first time allows us to check the up migrations are valid and | 
 | // that the down migrations clean up enough after themselves for earlier down | 
 | // migrations to success. | 
 | // | 
 | // Doing this the second time allows us to make sure the down migrations cleaned | 
 | // up enough after themselves that they have left no table/type behind. | 
 | func TestMigrateUpDown(t *testing.T) { | 
 | 	// Start with an empty database. | 
 | 	b := dut() | 
 | 	_, err := b.Open(false) | 
 | 	if err != nil { | 
 | 		t.Fatalf("Starting empty database failed: %v", err) | 
 | 	} | 
 |  | 
 | 	// Migrations go up. | 
 | 	if err := b.Database.MigrateUp(); err != nil { | 
 | 		t.Fatalf("Initial up migration failed: %v", err) | 
 | 	} | 
 | 	// Migrations go down. | 
 | 	if err := b.Database.MigrateDownDangerDanger(); err != nil { | 
 | 		t.Fatalf("Initial down migration failed: %v", err) | 
 | 	} | 
 | 	// Migrations go up. | 
 | 	if err := b.Database.MigrateUp(); err != nil { | 
 | 		t.Fatalf("Second up migration failed: %v", err) | 
 | 	} | 
 | 	// Migrations go down. | 
 | 	if err := b.Database.MigrateDownDangerDanger(); err != nil { | 
 | 		t.Fatalf("Second down migration failed: %v", err) | 
 | 	} | 
 | } | 
 |  | 
 | // TestMigrateTwice makes sure we don't hit https://review.monogon.dev/1502 again. | 
 | func TestMigrateTwice(t *testing.T) { | 
 | 	// Start with an empty database. | 
 | 	b := dut() | 
 | 	_, err := b.Open(false) | 
 | 	if err != nil { | 
 | 		t.Fatalf("Starting empty database failed: %v", err) | 
 | 	} | 
 |  | 
 | 	// Migrations go up. | 
 | 	if err := b.Database.MigrateUp(); err != nil { | 
 | 		t.Fatalf("Initial up migration failed: %v", err) | 
 | 	} | 
 | 	// Migrations go up again. | 
 | 	if err := b.Database.MigrateUp(); err != nil { | 
 | 		t.Fatalf("Initial up migration failed: %v", err) | 
 | 	} | 
 | } | 
 |  | 
 | func TestMigration1681826233(t *testing.T) { | 
 | 	// This migration adds a new nullable field to backoffs. | 
 |  | 
 | 	// This guarantees that versions [prev, ver] can run concurrently in a cluster. | 
 | 	min := uint(1672749980) | 
 | 	max := uint(1681826233) | 
 |  | 
 | 	ctx, ctxC := context.WithCancel(context.Background()) | 
 | 	defer t.Cleanup(ctxC) | 
 |  | 
 | 	b := dut() | 
 | 	conn, err := b.Open(false) | 
 | 	if err != nil { | 
 | 		t.Fatalf("Starting empty database failed: %v", err) | 
 | 	} | 
 |  | 
 | 	// First, make sure the change can actually progress if we have some backoffs | 
 | 	// already. | 
 | 	if err := b.Database.MigrateUpToIncluding(min); err != nil { | 
 | 		t.Fatalf("Migration to minimum version failed: %v", err) | 
 | 	} | 
 |  | 
 | 	// Create machine and old-style backoff. | 
 | 	q := model.New(conn.db) | 
 | 	machine, err := q.NewMachine(ctx) | 
 | 	if err != nil { | 
 | 		t.Fatalf("Could not create machine: %v", err) | 
 | 	} | 
 | 	_, err = conn.db.Exec(` | 
 | 		INSERT INTO work_backoff | 
 | 		    (machine_id, process, until, cause) | 
 | 		VALUES | 
 | 		    ($1, 'UnitTest1', now(), 'test'); | 
 | 	`, machine.MachineID) | 
 | 	if err != nil { | 
 | 		t.Fatalf("Could not create old-style backoff on old version: %v", err) | 
 | 	} | 
 |  | 
 | 	// Migrate to newer version. | 
 | 	if err := b.Database.MigrateUpToIncluding(max); err != nil { | 
 | 		t.Fatalf("Migration to maximum version failed: %v", err) | 
 | 	} | 
 |  | 
 | 	// The migration should be read succesfully. | 
 | 	boffs, err := q.WorkBackoffOf(ctx, model.WorkBackoffOfParams{ | 
 | 		MachineID: machine.MachineID, | 
 | 		Process:   "UnitTest1", | 
 | 	}) | 
 | 	if err != nil { | 
 | 		t.Fatalf("Reading backoff failed: %v", err) | 
 | 	} | 
 | 	if len(boffs) != 1 { | 
 | 		t.Errorf("No backoff found") | 
 | 	} else { | 
 | 		boff := boffs[0] | 
 | 		if boff.LastIntervalSeconds.Valid { | 
 | 			t.Errorf("Expected interval to be NULL") | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// Simultaneously, any concurrently running bmdb user on an older version should | 
 | 	// still be able to insert and read backoffs old style. | 
 | 	_, err = conn.db.Exec(` | 
 | 		INSERT INTO work_backoff | 
 | 		    (machine_id, process, until, cause) | 
 | 		VALUES | 
 | 		    ($1, 'UnitTest2', now(), 'test'); | 
 | 	`, machine.MachineID) | 
 | 	if err != nil { | 
 | 		t.Fatalf("Could not create old-style backoff on new version: %v", err) | 
 | 	} | 
 | 	rows, err := conn.db.Query(` | 
 | 		SELECT machine_id, process, until, cause FROM work_backoff | 
 | 	`) | 
 | 	for rows.Next() { | 
 | 		var mid, process, until, cause string | 
 | 		if err := rows.Scan(&mid, &process, &until, &cause); err != nil { | 
 | 			t.Errorf("Scan failed: %v", err) | 
 | 		} | 
 | 	} | 
 | } |