Skip to content
Snippets Groups Projects
db_test.go 4.05 KiB
Newer Older
ale's avatar
ale committed
package sqlutil

import (
	"context"
	"database/sql"
	"os"
	"testing"
)

func init() {
	DebugMigrations = true
}

func TestOpenDB(t *testing.T) {
ale's avatar
ale committed
	dir, err := os.MkdirTemp("", "")
ale's avatar
ale committed
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	db, err := OpenDB(dir + "/test.db")
ale's avatar
ale committed
	if err != nil {
		t.Fatal(err)
	}
	db.Close()
}

func getTestValue(db *sql.DB, id int) (out string, err error) {
	err = WithReadonlyTx(context.Background(), db, func(tx *sql.Tx) error {
		return tx.QueryRow("SELECT value FROM test WHERE id=?", id).Scan(&out)
	})
	return
}

func checkTestValue(t *testing.T, db *sql.DB) {
	value, err := getTestValue(db, 1)
	if err != nil {
		t.Fatal(err)
	}
	if value != "test" {
		t.Fatalf("got bad value '%s', expected 'test'", value)
	}
}

func TestOpenDB_Migrations_MultipleStatements(t *testing.T) {
ale's avatar
ale committed
	dir, err := os.MkdirTemp("", "")
ale's avatar
ale committed
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	db, err := OpenDB(dir+"/test.db", WithMigrations([]func(*sql.Tx) error{
ale's avatar
ale committed
		Statement("CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, value TEXT)"),
		Statement("CREATE INDEX idx_test_value ON test(value)"),
		Statement("INSERT INTO test (id, value) VALUES (1, 'test')"),
ale's avatar
ale committed
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()

	checkTestValue(t, db)
}

func TestOpenDB_Migrations_SingleStatement(t *testing.T) {
ale's avatar
ale committed
	dir, err := os.MkdirTemp("", "")
ale's avatar
ale committed
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	db, err := OpenDB(dir+"/test.db", WithMigrations([]func(*sql.Tx) error{
ale's avatar
ale committed
		Statement(
			"CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, value TEXT)",
			"CREATE INDEX idx_test_value ON test(value)",
			"INSERT INTO test (id, value) VALUES (1, 'test')",
		),
ale's avatar
ale committed
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()

	checkTestValue(t, db)
}

func TestOpenDB_Migrations_Versions(t *testing.T) {
ale's avatar
ale committed
	dir, err := os.MkdirTemp("", "")
ale's avatar
ale committed
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	migrations := []func(*sql.Tx) error{
		Statement("CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, value TEXT)"),
		Statement("CREATE INDEX idx_test_value ON test(value)"),
	}

	db, err := OpenDB(dir+"/test.db", WithMigrations(migrations))
ale's avatar
ale committed
	if err != nil {
		t.Fatal("first open: ", err)
	}
	db.Close()

	migrations = append(migrations, Statement("INSERT INTO test (id, value) VALUES (1, 'test')"))
	db, err = OpenDB(dir+"/test.db", WithMigrations(migrations))
ale's avatar
ale committed
	if err != nil {
		t.Fatal("second open: ", err)
	}
	defer db.Close()

	checkTestValue(t, db)
}

func TestOpenDB_Write(t *testing.T) {
ale's avatar
ale committed
	dir, err := os.MkdirTemp("", "")
ale's avatar
ale committed
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	db, err := OpenDB(dir+"/test.db", WithMigrations([]func(*sql.Tx) error{
ale's avatar
ale committed
		Statement(
			"CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, value TEXT)",
			"CREATE INDEX idx_test_value ON test(value)",
		),
ale's avatar
ale committed
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()

	err = WithTx(context.Background(), db, func(tx *sql.Tx) error {
		_, err := tx.Exec("INSERT INTO test (id, value) VALUES (?, ?)", 1, "test")
		return err
	})
	if err != nil {
		t.Fatalf("INSERT error: %v", err)
	}

	checkTestValue(t, db)
}
ale's avatar
ale committed

func TestOpenDB_Migrations_Legacy(t *testing.T) {
ale's avatar
ale committed
	dir, err := os.MkdirTemp("", "")
ale's avatar
ale committed
	if err != nil {
		t.Fatal(err)
	}
	defer os.RemoveAll(dir)

	db, err := sql.Open("sqlite3", dir+"/test.db")
	if err != nil {
		t.Fatal(err)
	}
	for _, stmt := range []string{
		"CREATE TABLE schema_migrations (version uint64,dirty bool)",
		"INSERT INTO schema_migrations (version, dirty) VALUES (2, 0)",
		"CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, value TEXT)",
		"CREATE INDEX idx_test_value ON test(value)",
	} {
		if _, err := db.Exec(stmt); err != nil {
			t.Fatalf("statement '%s': %v", stmt, err)
		}
	}
	db.Close()

	migrations := []func(*sql.Tx) error{
		Statement("CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, value TEXT)"),
		Statement("CREATE INDEX idx_test_value ON test(value)"),
		Statement("INSERT INTO test (id, value) VALUES (1, 'test')"),
	}

	db, err = OpenDB(dir+"/test.db", WithMigrations(migrations))
	if err != nil {
		t.Fatal("first open: ", err)
	}
	defer db.Close()

	checkTestValue(t, db)
}