decred.org/dcrdex@v1.0.5/server/db/driver/pg/upgrades_test.go (about) 1 //go:build pgonline 2 3 // This code is available on the terms of the project LICENSE.md file, 4 // also available online at https://blueoakcouncil.org/license/1.0.0. 5 6 package pg 7 8 import ( 9 "bytes" 10 "compress/gzip" 11 "context" 12 "database/sql" 13 "errors" 14 "fmt" 15 "io" 16 "os" 17 "os/exec" 18 "path/filepath" 19 "strings" 20 "testing" 21 ) 22 23 func loadDBSnap(t *testing.T, file string) { 24 t.Helper() 25 pgSnapGZ, err := os.Open(file) 26 if err != nil { 27 t.Fatal(err) 28 } 29 defer pgSnapGZ.Close() 30 31 r, err := gzip.NewReader(pgSnapGZ) 32 if err != nil { 33 t.Fatal(err) 34 } 35 36 tmpDir := t.TempDir() 37 dbPath := filepath.Join(tmpDir, strings.TrimSuffix(file, ".gz")) 38 dbFile, err := os.Create(dbPath) 39 if err != nil { 40 t.Fatal(err) 41 } 42 defer os.Remove(dbPath) 43 44 _, err = io.Copy(dbFile, r) 45 dbFile.Close() 46 if err != nil { 47 t.Fatal(err) 48 } 49 50 var out, stderr bytes.Buffer 51 cmd := exec.Command("psql", "-U", PGTestsUser, "-h", PGTestsHost, "-d", PGTestsDBName, "-a", "-f", dbPath) 52 cmd.Stdout = &out 53 cmd.Stderr = &stderr 54 if err = cmd.Run(); err != nil { 55 t.Fatalf("psql failed: %v / output: %+v\n: %+v", err, out.String(), stderr.String()) 56 } 57 } 58 59 func Test_upgradeDB(t *testing.T) { 60 ctx := context.Background() 61 62 tryUpgrade := func(gzFile string) error { 63 log.Info("start") 64 // Get a clean slate. 65 err := nukeAll(archie.db) 66 if err != nil { 67 return fmt.Errorf("nukeAll: %w", err) 68 } 69 70 // Import the data into the test db. 71 loadDBSnap(t, gzFile) 72 73 // Run the upgrades. 74 err = upgradeDB(ctx, archie.db) 75 if err != nil { 76 return fmt.Errorf("upgradeDB: %w", err) 77 } 78 return nil 79 } 80 81 // These are all positive path tests (no corruption in DB). 82 snaps := []string{ 83 "dcrdex_test_db_v0-master.sql.gz", // v0 DB with no meta table 84 "dcrdex_test_db_v0-release-0.1.sql.gz", // v0 DB with a meta table with state_hash from release-0.1 85 "dcrdex_test_db_v0-release-0.1-matches.sql.gz", // v0 with meta table and a ton of matches for v2 upgrade 86 } 87 88 for _, snap := range snaps { 89 if err := tryUpgrade(snap); err != nil { 90 t.Errorf("upgrade of DB snapshot %q failed: %v", snap, err) 91 } 92 } 93 94 // Try with canceled context. 95 var cancel context.CancelFunc 96 ctx, cancel = context.WithCancel(ctx) 97 cancel() 98 // To try hitting the Exec/Query/etc. errors, attempt to cancel mid upgrade: 99 // go func() { time.Sleep(200 * time.Millisecond); cancel() }() 100 err := tryUpgrade(snaps[2]) // the bigger upgrade 101 if !errors.Is(err, context.Canceled) && !errors.Is(err, sql.ErrTxDone) { 102 t.Fatalf("wrong error for canceled context, got %v", err) 103 } 104 t.Logf("Got an expected error: %v", err) 105 // NOTE: That was a very limited test of cancellation as the transaction 106 // wasn't even started and thus was not rolled back, but it does stop the 107 // upgrade chain cleanly and there should be no schema_version. 108 _, err = DBVersion(archie.db) 109 if err == nil { 110 t.Errorf("expected error from DBVersion with no meta table") 111 } 112 }