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  }