|
|
|
@ -5,7 +5,6 @@ import (
|
|
|
|
|
"errors"
|
|
|
|
|
"expvar"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"math/rand"
|
|
|
|
|
"net"
|
|
|
|
|
"os"
|
|
|
|
@ -17,6 +16,7 @@ import (
|
|
|
|
|
|
|
|
|
|
"github.com/rqlite/rqlite/command"
|
|
|
|
|
"github.com/rqlite/rqlite/command/encoding"
|
|
|
|
|
"github.com/rqlite/rqlite/db"
|
|
|
|
|
"github.com/rqlite/rqlite/testdata/chinook"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
@ -24,6 +24,371 @@ func init() {
|
|
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_SingleNodeOnDiskFileExecuteQuery(t *testing.T) {
|
|
|
|
|
s, ln := mustNewStore(t, false)
|
|
|
|
|
defer ln.Close()
|
|
|
|
|
|
|
|
|
|
if err := s.Open(); err != nil {
|
|
|
|
|
t.Fatalf("failed to open single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if err := s.Bootstrap(NewServer(s.ID(), s.Addr(), true)); err != nil {
|
|
|
|
|
t.Fatalf("failed to bootstrap single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
defer s.Close(true)
|
|
|
|
|
if _, err := s.WaitForLeader(10 * time.Second); err != nil {
|
|
|
|
|
t.Fatalf("Error waiting for leader: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
er := executeRequestFromStrings([]string{
|
|
|
|
|
`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
|
|
|
|
|
`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
|
|
|
|
|
}, false, false)
|
|
|
|
|
_, err := s.Execute(er)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to execute on single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Every query should return the same results, so use a function for the check.
|
|
|
|
|
check := func(r []*command.QueryRows) {
|
|
|
|
|
if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qr := queryRequestFromString("SELECT * FROM foo", false, false)
|
|
|
|
|
qr.Level = command.QueryRequest_QUERY_REQUEST_LEVEL_NONE
|
|
|
|
|
r, err := s.Query(qr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to query single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
check(r)
|
|
|
|
|
|
|
|
|
|
qr = queryRequestFromString("SELECT * FROM foo", false, false)
|
|
|
|
|
qr.Level = command.QueryRequest_QUERY_REQUEST_LEVEL_WEAK
|
|
|
|
|
r, err = s.Query(qr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to query single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
check(r)
|
|
|
|
|
|
|
|
|
|
qr = queryRequestFromString("SELECT * FROM foo", false, false)
|
|
|
|
|
qr.Level = command.QueryRequest_QUERY_REQUEST_LEVEL_STRONG
|
|
|
|
|
r, err = s.Query(qr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to query single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
check(r)
|
|
|
|
|
|
|
|
|
|
qr = queryRequestFromString("SELECT * FROM foo", false, true)
|
|
|
|
|
qr.Timings = true
|
|
|
|
|
qr.Level = command.QueryRequest_QUERY_REQUEST_LEVEL_NONE
|
|
|
|
|
r, err = s.Query(qr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to query single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
check(r)
|
|
|
|
|
|
|
|
|
|
qr = queryRequestFromString("SELECT * FROM foo", true, false)
|
|
|
|
|
qr.Request.Transaction = true
|
|
|
|
|
qr.Level = command.QueryRequest_QUERY_REQUEST_LEVEL_NONE
|
|
|
|
|
r, err = s.Query(qr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to query single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
check(r)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test_SingleNodeSQLitePath ensures that basic functionality works when the SQLite database path
|
|
|
|
|
// is explicitly specificed.
|
|
|
|
|
func Test_SingleNodeOnDiskSQLitePath(t *testing.T) {
|
|
|
|
|
s, ln, path := mustNewStoreSQLitePath(t)
|
|
|
|
|
defer ln.Close()
|
|
|
|
|
|
|
|
|
|
if err := s.Open(); err != nil {
|
|
|
|
|
t.Fatalf("failed to open single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
defer s.Close(true)
|
|
|
|
|
if err := s.Bootstrap(NewServer(s.ID(), s.Addr(), true)); err != nil {
|
|
|
|
|
t.Fatalf("failed to bootstrap single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if _, err := s.WaitForLeader(10 * time.Second); err != nil {
|
|
|
|
|
t.Fatalf("Error waiting for leader: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
er := executeRequestFromStrings([]string{
|
|
|
|
|
`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
|
|
|
|
|
`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
|
|
|
|
|
}, false, false)
|
|
|
|
|
_, err := s.Execute(er)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to execute on single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qr := queryRequestFromString("SELECT * FROM foo", false, false)
|
|
|
|
|
qr.Level = command.QueryRequest_QUERY_REQUEST_LEVEL_NONE
|
|
|
|
|
r, err := s.Query(qr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to query single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Confirm SQLite file was actually created at supplied path.
|
|
|
|
|
if !pathExists(path) {
|
|
|
|
|
t.Fatalf("SQLite file does not exist at %s", path)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_SingleNodeOnDiskBackupBinary(t *testing.T) {
|
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
|
|
s, ln := mustNewStore(t, false)
|
|
|
|
|
defer ln.Close()
|
|
|
|
|
|
|
|
|
|
if err := s.Open(); err != nil {
|
|
|
|
|
t.Fatalf("failed to open single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if err := s.Bootstrap(NewServer(s.ID(), s.Addr(), true)); err != nil {
|
|
|
|
|
t.Fatalf("failed to bootstrap single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
defer s.Close(true)
|
|
|
|
|
if _, err := s.WaitForLeader(10 * time.Second); err != nil {
|
|
|
|
|
t.Fatalf("Error waiting for leader: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dump := `PRAGMA foreign_keys=OFF;
|
|
|
|
|
BEGIN TRANSACTION;
|
|
|
|
|
CREATE TABLE foo (id integer not null primary key, name text);
|
|
|
|
|
INSERT INTO "foo" VALUES(1,'fiona');
|
|
|
|
|
COMMIT;
|
|
|
|
|
`
|
|
|
|
|
_, err := s.Execute(executeRequestFromString(dump, false, false))
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to load simple dump: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f, err := os.CreateTemp("", "rqlite-baktest-")
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Backup Failed: unable to create temp file, %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
defer os.Remove(f.Name())
|
|
|
|
|
|
|
|
|
|
if err := s.Backup(backupRequestBinary(true), f); err != nil {
|
|
|
|
|
t.Fatalf("Backup failed %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Open the backup file using the DB layer and check the data.
|
|
|
|
|
db, err := db.Open(f.Name(), false, false)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("unable to open backup database, %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
defer db.Close()
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
w := &buf
|
|
|
|
|
if err := db.Dump(w); err != nil {
|
|
|
|
|
t.Fatalf("unable to dump backup database, %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if buf.String() != dump {
|
|
|
|
|
t.Fatalf("backup dump is not as expected, got %s", buf.String())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_SingleNodeOnDiskRestoreNoncompressed(t *testing.T) {
|
|
|
|
|
s, ln := mustNewStore(t, false)
|
|
|
|
|
defer ln.Close()
|
|
|
|
|
|
|
|
|
|
if err := s.Open(); err != nil {
|
|
|
|
|
t.Fatalf("failed to open single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
defer s.Close(true)
|
|
|
|
|
if err := s.Bootstrap(NewServer(s.ID(), s.Addr(), true)); err != nil {
|
|
|
|
|
t.Fatalf("failed to bootstrap single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if _, err := s.WaitForLeader(10 * time.Second); err != nil {
|
|
|
|
|
t.Fatalf("Error waiting for leader: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check restoration from a pre-compressed SQLite database snap.
|
|
|
|
|
// This is to test for backwards compatilibty of this code.
|
|
|
|
|
f, err := os.Open(filepath.Join("testdata", "noncompressed-sqlite-snap.bin"))
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to open snapshot file: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if err := s.Restore(f); err != nil {
|
|
|
|
|
t.Fatalf("failed to restore noncompressed snapshot from disk: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ensure database is back in the expected state.
|
|
|
|
|
r, err := s.Query(queryRequestFromString("SELECT count(*) FROM foo", false, false))
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to query single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if exp, got := `["count(*)"]`, asJSON(r[0].Columns); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
if exp, got := `[[5000]]`, asJSON(r[0].Values); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_SingleNodeInMemOnDiskProvide(t *testing.T) {
|
|
|
|
|
for _, inmem := range []bool{
|
|
|
|
|
true,
|
|
|
|
|
false,
|
|
|
|
|
} {
|
|
|
|
|
func() {
|
|
|
|
|
s0, ln := mustNewStore(t, inmem)
|
|
|
|
|
defer ln.Close()
|
|
|
|
|
|
|
|
|
|
if err := s0.Open(); err != nil {
|
|
|
|
|
t.Fatalf("failed to open single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if err := s0.Bootstrap(NewServer(s0.ID(), s0.Addr(), true)); err != nil {
|
|
|
|
|
t.Fatalf("failed to bootstrap single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
defer s0.Close(true)
|
|
|
|
|
if _, err := s0.WaitForLeader(10 * time.Second); err != nil {
|
|
|
|
|
t.Fatalf("Error waiting for leader: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
er := executeRequestFromStrings([]string{
|
|
|
|
|
`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
|
|
|
|
|
`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
|
|
|
|
|
}, false, false)
|
|
|
|
|
_, err := s0.Execute(er)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to execute on single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
qr := queryRequestFromString("SELECT * FROM foo", false, false)
|
|
|
|
|
qr.Level = command.QueryRequest_QUERY_REQUEST_LEVEL_NONE
|
|
|
|
|
r, err := s0.Query(qr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to query leader node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tempFile := mustCreateTempFile()
|
|
|
|
|
defer os.Remove(tempFile)
|
|
|
|
|
err = s0.Provide(tempFile)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("store failed to provide: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Load the provided data into a new store and check it.
|
|
|
|
|
s1, ln := mustNewStore(t, true)
|
|
|
|
|
defer ln.Close()
|
|
|
|
|
|
|
|
|
|
if err := s1.Open(); err != nil {
|
|
|
|
|
t.Fatalf("failed to open single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if err := s1.Bootstrap(NewServer(s1.ID(), s1.Addr(), true)); err != nil {
|
|
|
|
|
t.Fatalf("failed to bootstrap single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
defer s1.Close(true)
|
|
|
|
|
if _, err := s1.WaitForLeader(10 * time.Second); err != nil {
|
|
|
|
|
t.Fatalf("Error waiting for leader: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = s1.Load(loadRequestFromFile(tempFile))
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to load provided SQLite data: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
qr = queryRequestFromString("SELECT * FROM foo", false, false)
|
|
|
|
|
qr.Level = command.QueryRequest_QUERY_REQUEST_LEVEL_STRONG
|
|
|
|
|
r, err = s1.Query(qr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to query leader node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_SingleNodeSnapshotOnDisk(t *testing.T) {
|
|
|
|
|
s, ln := mustNewStore(t, false)
|
|
|
|
|
defer ln.Close()
|
|
|
|
|
|
|
|
|
|
if err := s.Open(); err != nil {
|
|
|
|
|
t.Fatalf("failed to open single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
defer s.Close(true)
|
|
|
|
|
if err := s.Bootstrap(NewServer(s.ID(), s.Addr(), true)); err != nil {
|
|
|
|
|
t.Fatalf("failed to bootstrap single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if _, err := s.WaitForLeader(10 * time.Second); err != nil {
|
|
|
|
|
t.Fatalf("Error waiting for leader: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
queries := []string{
|
|
|
|
|
`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
|
|
|
|
|
`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
|
|
|
|
|
}
|
|
|
|
|
_, err := s.Execute(executeRequestFromStrings(queries, false, false))
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to execute on single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
_, err = s.Query(queryRequestFromString("SELECT * FROM foo", false, false))
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to query single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Snap the node and write to disk.
|
|
|
|
|
f, err := s.Snapshot()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to snapshot node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
snapDir := t.TempDir()
|
|
|
|
|
snapFile, err := os.Create(filepath.Join(snapDir, "snapshot"))
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to create snapshot file: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
defer snapFile.Close()
|
|
|
|
|
sink := &mockSnapshotSink{snapFile}
|
|
|
|
|
if err := f.Persist(sink); err != nil {
|
|
|
|
|
t.Fatalf("failed to persist snapshot to disk: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check restoration.
|
|
|
|
|
snapFile, err = os.Open(filepath.Join(snapDir, "snapshot"))
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to open snapshot file: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
defer snapFile.Close()
|
|
|
|
|
if err := s.Restore(snapFile); err != nil {
|
|
|
|
|
t.Fatalf("failed to restore snapshot from disk: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ensure database is back in the correct state.
|
|
|
|
|
r, err := s.Query(queryRequestFromString("SELECT * FROM foo", false, false))
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to query single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if exp, got := `["id","name"]`, asJSON(r[0].Columns); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_StoreSingleNodeNotOpen(t *testing.T) {
|
|
|
|
|
s, ln := mustNewStore(t, true)
|
|
|
|
|
defer s.Close(true)
|
|
|
|
@ -675,7 +1040,7 @@ COMMIT;
|
|
|
|
|
t.Fatalf("failed to load simple dump: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f, err := ioutil.TempFile("", "rqlite-baktest-")
|
|
|
|
|
f, err := os.CreateTemp("", "rqlite-baktest-")
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Backup Failed: unable to create temp file, %s", err.Error())
|
|
|
|
|
}
|
|
|
|
@ -687,7 +1052,7 @@ COMMIT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check the backed up data
|
|
|
|
|
bkp, err := ioutil.ReadFile(f.Name())
|
|
|
|
|
bkp, err := os.ReadFile(f.Name())
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Backup Failed: unable to read backup file, %s", err.Error())
|
|
|
|
|
}
|
|
|
|
@ -2539,7 +2904,7 @@ func Test_State(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func mustNewStoreAtPathsLn(id, dataPath, sqlitePath string, inmem, fk bool) (*Store, net.Listener) {
|
|
|
|
|
cfg := NewDBConfig(inmem)
|
|
|
|
|
cfg := NewDBConfig()
|
|
|
|
|
cfg.FKConstraints = fk
|
|
|
|
|
cfg.OnDiskPath = sqlitePath
|
|
|
|
|
|
|
|
|
@ -2622,7 +2987,7 @@ func mustWriteFile(path, contents string) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func mustReadFile(path string) []byte {
|
|
|
|
|
b, err := ioutil.ReadFile(path)
|
|
|
|
|
b, err := os.ReadFile(path)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic("failed to read file")
|
|
|
|
|
}
|
|
|
|
|