Add DB.UpdatedAt() tests
This commit is contained in:
107
db_test.go
Normal file
107
db_test.go
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package litestream_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/benbjohnson/litestream"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Ensure we can check the last modified time of the real database and its WAL.
|
||||||
|
func TestDB_UpdatedAt(t *testing.T) {
|
||||||
|
t.Run("ErrNotExist", func(t *testing.T) {
|
||||||
|
db := MustOpenDB(t)
|
||||||
|
defer MustCloseDB(t, db)
|
||||||
|
if _, err := db.UpdatedAt(); !os.IsNotExist(err) {
|
||||||
|
t.Fatalf("unexpected error: %#v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("DB", func(t *testing.T) {
|
||||||
|
db, sqldb := MustOpenDBs(t)
|
||||||
|
defer MustCloseDBs(t, db, sqldb)
|
||||||
|
|
||||||
|
if t0, err := db.UpdatedAt(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if time.Since(t0) > 10*time.Second {
|
||||||
|
t.Fatalf("unexpected updated at time: %s", t0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("WAL", func(t *testing.T) {
|
||||||
|
db, sqldb := MustOpenDBs(t)
|
||||||
|
defer MustCloseDBs(t, db, sqldb)
|
||||||
|
|
||||||
|
t0, err := db.UpdatedAt()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := sqldb.Exec(`CREATE TABLE t (id INT);`); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if t1, err := db.UpdatedAt(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if !t1.After(t0) {
|
||||||
|
t.Fatalf("expected newer updated at time: %s > %s", t1, t0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustOpenDBs returns a new instance of a DB & associated SQL DB.
|
||||||
|
func MustOpenDBs(tb testing.TB) (*litestream.DB, *sql.DB) {
|
||||||
|
db := MustOpenDB(tb)
|
||||||
|
return db, MustOpenSQLDB(tb, db.Path())
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustCloseDBs closes db & sqldb and removes the parent directory.
|
||||||
|
func MustCloseDBs(tb testing.TB, db *litestream.DB, sqldb *sql.DB) {
|
||||||
|
MustCloseDB(tb, db)
|
||||||
|
MustCloseSQLDB(tb, sqldb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustOpenDB returns a new instance of a DB.
|
||||||
|
func MustOpenDB(tb testing.TB) *litestream.DB {
|
||||||
|
tb.Helper()
|
||||||
|
|
||||||
|
dir := tb.TempDir()
|
||||||
|
db := litestream.NewDB(filepath.Join(dir, "db"))
|
||||||
|
if err := db.Open(); err != nil {
|
||||||
|
tb.Fatal(err)
|
||||||
|
}
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustCloseDB closes db and removes its parent directory.
|
||||||
|
func MustCloseDB(tb testing.TB, db *litestream.DB) {
|
||||||
|
tb.Helper()
|
||||||
|
if err := db.Close(); err != nil {
|
||||||
|
tb.Fatal(err)
|
||||||
|
} else if err := os.RemoveAll(filepath.Dir(db.Path())); err != nil {
|
||||||
|
tb.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustOpenSQLDB returns a database/sql DB.
|
||||||
|
func MustOpenSQLDB(tb testing.TB, path string) *sql.DB {
|
||||||
|
tb.Helper()
|
||||||
|
d, err := sql.Open("sqlite3", path)
|
||||||
|
if err != nil {
|
||||||
|
tb.Fatal(err)
|
||||||
|
} else if _, err := d.Exec(`PRAGMA journal_mode = wal;`); err != nil {
|
||||||
|
tb.Fatal(err)
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustCloseSQLDB closes a database/sql DB.
|
||||||
|
func MustCloseSQLDB(tb testing.TB, d *sql.DB) {
|
||||||
|
tb.Helper()
|
||||||
|
if err := d.Close(); err != nil {
|
||||||
|
tb.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -256,41 +255,6 @@ func (r *gzipReadCloser) Close() error {
|
|||||||
return r.closer.Close()
|
return r.closer.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// HexDump returns hexdump output but with duplicate lines removed.
|
|
||||||
func HexDump(b []byte) string {
|
|
||||||
const prefixN = len("00000000")
|
|
||||||
|
|
||||||
var output []string
|
|
||||||
var prev string
|
|
||||||
var ellipsis bool
|
|
||||||
|
|
||||||
lines := strings.Split(strings.TrimSpace(hex.Dump(b)), "\n")
|
|
||||||
for i, line := range lines {
|
|
||||||
// Add line to output if it is not repeating or the last line.
|
|
||||||
if i == 0 || i == len(lines)-1 || trimPrefixN(line, prefixN) != trimPrefixN(prev, prefixN) {
|
|
||||||
output = append(output, line)
|
|
||||||
prev, ellipsis = line, false
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an ellipsis for the first duplicate line.
|
|
||||||
if !ellipsis {
|
|
||||||
output = append(output, "...")
|
|
||||||
ellipsis = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(output, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func trimPrefixN(s string, n int) string {
|
|
||||||
if len(s) < n {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return s[n:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func assert(condition bool, message string) {
|
func assert(condition bool, message string) {
|
||||||
if !condition {
|
if !condition {
|
||||||
panic("assertion failed: " + message)
|
panic("assertion failed: " + message)
|
||||||
|
|||||||
Reference in New Issue
Block a user