blob: fe5b75c00c0ac9122f71c20717e673880eadf227 [file] [log] [blame]
Tim Windelschmidt6d33a432025-02-04 14:34:25 +01001// Copyright The Monogon Project Authors.
2// SPDX-License-Identifier: Apache-2.0
3
Serge Bazanski48e9bab2023-02-20 15:28:59 +01004package bmdb
5
6import (
Serge Bazanski3ea40da2023-04-19 14:32:37 +02007 "context"
Serge Bazanski48e9bab2023-02-20 15:28:59 +01008 "testing"
Serge Bazanski3ea40da2023-04-19 14:32:37 +02009
10 "source.monogon.dev/cloud/bmaas/bmdb/model"
Serge Bazanski48e9bab2023-02-20 15:28:59 +010011)
12
13// TestMigrateUpDown performs a full-up and full-down migration test on an
14// in-memory database twice.
15//
16// Doing this the first time allows us to check the up migrations are valid and
17// that the down migrations clean up enough after themselves for earlier down
18// migrations to success.
19//
20// Doing this the second time allows us to make sure the down migrations cleaned
21// up enough after themselves that they have left no table/type behind.
22func TestMigrateUpDown(t *testing.T) {
23 // Start with an empty database.
24 b := dut()
25 _, err := b.Open(false)
26 if err != nil {
27 t.Fatalf("Starting empty database failed: %v", err)
28 }
29
30 // Migrations go up.
31 if err := b.Database.MigrateUp(); err != nil {
32 t.Fatalf("Initial up migration failed: %v", err)
33 }
34 // Migrations go down.
35 if err := b.Database.MigrateDownDangerDanger(); err != nil {
36 t.Fatalf("Initial down migration failed: %v", err)
37 }
38 // Migrations go up.
39 if err := b.Database.MigrateUp(); err != nil {
40 t.Fatalf("Second up migration failed: %v", err)
41 }
42 // Migrations go down.
43 if err := b.Database.MigrateDownDangerDanger(); err != nil {
44 t.Fatalf("Second down migration failed: %v", err)
45 }
46}
Serge Bazanski6963c632023-04-06 14:55:49 +020047
48// TestMigrateTwice makes sure we don't hit https://review.monogon.dev/1502 again.
49func TestMigrateTwice(t *testing.T) {
50 // Start with an empty database.
51 b := dut()
52 _, err := b.Open(false)
53 if err != nil {
54 t.Fatalf("Starting empty database failed: %v", err)
55 }
56
57 // Migrations go up.
58 if err := b.Database.MigrateUp(); err != nil {
59 t.Fatalf("Initial up migration failed: %v", err)
60 }
61 // Migrations go up again.
62 if err := b.Database.MigrateUp(); err != nil {
63 t.Fatalf("Initial up migration failed: %v", err)
64 }
65}
Serge Bazanski3ea40da2023-04-19 14:32:37 +020066
67func TestMigration1681826233(t *testing.T) {
68 // This migration adds a new nullable field to backoffs.
69
70 // This guarantees that versions [prev, ver] can run concurrently in a cluster.
Tim Windelschmidt38105672024-04-11 01:37:29 +020071 minVer := uint(1672749980)
72 maxVer := uint(1681826233)
Serge Bazanski3ea40da2023-04-19 14:32:37 +020073
74 ctx, ctxC := context.WithCancel(context.Background())
75 defer t.Cleanup(ctxC)
76
77 b := dut()
78 conn, err := b.Open(false)
79 if err != nil {
80 t.Fatalf("Starting empty database failed: %v", err)
81 }
82
83 // First, make sure the change can actually progress if we have some backoffs
84 // already.
Tim Windelschmidt38105672024-04-11 01:37:29 +020085 if err := b.Database.MigrateUpToIncluding(minVer); err != nil {
Serge Bazanski3ea40da2023-04-19 14:32:37 +020086 t.Fatalf("Migration to minimum version failed: %v", err)
87 }
88
89 // Create machine and old-style backoff.
90 q := model.New(conn.db)
91 machine, err := q.NewMachine(ctx)
92 if err != nil {
93 t.Fatalf("Could not create machine: %v", err)
94 }
95 _, err = conn.db.Exec(`
96 INSERT INTO work_backoff
97 (machine_id, process, until, cause)
98 VALUES
99 ($1, 'UnitTest1', now(), 'test');
100 `, machine.MachineID)
101 if err != nil {
102 t.Fatalf("Could not create old-style backoff on old version: %v", err)
103 }
104
105 // Migrate to newer version.
Tim Windelschmidt38105672024-04-11 01:37:29 +0200106 if err := b.Database.MigrateUpToIncluding(maxVer); err != nil {
Serge Bazanski3ea40da2023-04-19 14:32:37 +0200107 t.Fatalf("Migration to maximum version failed: %v", err)
108 }
109
110 // The migration should be read succesfully.
111 boffs, err := q.WorkBackoffOf(ctx, model.WorkBackoffOfParams{
112 MachineID: machine.MachineID,
113 Process: "UnitTest1",
114 })
115 if err != nil {
116 t.Fatalf("Reading backoff failed: %v", err)
117 }
118 if len(boffs) != 1 {
119 t.Errorf("No backoff found")
120 } else {
121 boff := boffs[0]
122 if boff.LastIntervalSeconds.Valid {
123 t.Errorf("Expected interval to be NULL")
124 }
125 }
126
127 // Simultaneously, any concurrently running bmdb user on an older version should
128 // still be able to insert and read backoffs old style.
129 _, err = conn.db.Exec(`
130 INSERT INTO work_backoff
131 (machine_id, process, until, cause)
132 VALUES
133 ($1, 'UnitTest2', now(), 'test');
134 `, machine.MachineID)
135 if err != nil {
136 t.Fatalf("Could not create old-style backoff on new version: %v", err)
137 }
138 rows, err := conn.db.Query(`
139 SELECT machine_id, process, until, cause FROM work_backoff
140 `)
Tim Windelschmidt096654a2024-04-18 23:10:19 +0200141 if err != nil {
142 t.Fatalf("Could not fetch old-style backoff data: %v", err)
143 }
Serge Bazanski3ea40da2023-04-19 14:32:37 +0200144 for rows.Next() {
145 var mid, process, until, cause string
146 if err := rows.Scan(&mid, &process, &until, &cause); err != nil {
147 t.Errorf("Scan failed: %v", err)
148 }
149 }
150}