|
|
|
@ -441,7 +441,6 @@ func Test_SingleNodeSQLitePath(t *testing.T) {
|
|
|
|
|
if !pathExists(path) {
|
|
|
|
|
t.Fatalf("SQLite file does not exist at %s", path)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_SingleNodeBackupBinary(t *testing.T) {
|
|
|
|
@ -545,7 +544,7 @@ COMMIT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_SingleNodeLoad(t *testing.T) {
|
|
|
|
|
func Test_SingleNodeSingleCommandTrigger(t *testing.T) {
|
|
|
|
|
s, ln := mustNewStore(true)
|
|
|
|
|
defer os.RemoveAll(s.Path())
|
|
|
|
|
defer ln.Close()
|
|
|
|
@ -563,31 +562,35 @@ func Test_SingleNodeLoad(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
dump := `PRAGMA foreign_keys=OFF;
|
|
|
|
|
BEGIN TRANSACTION;
|
|
|
|
|
CREATE TABLE foo (id integer not null primary key, name text);
|
|
|
|
|
INSERT INTO "foo" VALUES(1,'fiona');
|
|
|
|
|
CREATE TABLE foo (id integer primary key asc, name text);
|
|
|
|
|
INSERT INTO "foo" VALUES(1,'bob');
|
|
|
|
|
INSERT INTO "foo" VALUES(2,'alice');
|
|
|
|
|
INSERT INTO "foo" VALUES(3,'eve');
|
|
|
|
|
CREATE TABLE bar (nameid integer, age integer);
|
|
|
|
|
INSERT INTO "bar" VALUES(1,44);
|
|
|
|
|
INSERT INTO "bar" VALUES(2,46);
|
|
|
|
|
INSERT INTO "bar" VALUES(3,8);
|
|
|
|
|
CREATE VIEW foobar as select name as Person, Age as age from foo inner join bar on foo.id == bar.nameid;
|
|
|
|
|
CREATE TRIGGER new_foobar instead of insert on foobar begin insert into foo (name) values (new.Person); insert into bar (nameid, age) values ((select id from foo where name == new.Person), new.Age); end;
|
|
|
|
|
COMMIT;
|
|
|
|
|
`
|
|
|
|
|
_, err := s.Execute(executeRequestFromString(dump, false, false))
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to load simple dump: %s", err.Error())
|
|
|
|
|
t.Fatalf("failed to load dump with trigger: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check that data were loaded correctly.
|
|
|
|
|
qr := queryRequestFromString("SELECT * FROM foo", false, true)
|
|
|
|
|
qr.Level = command.QueryRequest_QUERY_REQUEST_LEVEL_STRONG
|
|
|
|
|
r, err := s.Query(qr)
|
|
|
|
|
// Check that the VIEW and TRIGGER are OK by using both.
|
|
|
|
|
er := executeRequestFromString("INSERT INTO foobar VALUES('jason', 16)", false, true)
|
|
|
|
|
r, err := s.Execute(er)
|
|
|
|
|
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)
|
|
|
|
|
t.Fatalf("failed to insert into view on single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if exp, got := `[[1,"fiona"]]`, asJSON(r[0].Values); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
if exp, got := int64(3), r[0].GetLastInsertId(); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %d\ngot: %d", exp, got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_SingleNodeSingleCommandTrigger(t *testing.T) {
|
|
|
|
|
func Test_SingleNodeLoadText(t *testing.T) {
|
|
|
|
|
s, ln := mustNewStore(true)
|
|
|
|
|
defer os.RemoveAll(s.Path())
|
|
|
|
|
defer ln.Close()
|
|
|
|
@ -605,35 +608,31 @@ func Test_SingleNodeSingleCommandTrigger(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
dump := `PRAGMA foreign_keys=OFF;
|
|
|
|
|
BEGIN TRANSACTION;
|
|
|
|
|
CREATE TABLE foo (id integer primary key asc, name text);
|
|
|
|
|
INSERT INTO "foo" VALUES(1,'bob');
|
|
|
|
|
INSERT INTO "foo" VALUES(2,'alice');
|
|
|
|
|
INSERT INTO "foo" VALUES(3,'eve');
|
|
|
|
|
CREATE TABLE bar (nameid integer, age integer);
|
|
|
|
|
INSERT INTO "bar" VALUES(1,44);
|
|
|
|
|
INSERT INTO "bar" VALUES(2,46);
|
|
|
|
|
INSERT INTO "bar" VALUES(3,8);
|
|
|
|
|
CREATE VIEW foobar as select name as Person, Age as age from foo inner join bar on foo.id == bar.nameid;
|
|
|
|
|
CREATE TRIGGER new_foobar instead of insert on foobar begin insert into foo (name) values (new.Person); insert into bar (nameid, age) values ((select id from foo where name == new.Person), new.Age); end;
|
|
|
|
|
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 dump with trigger: %s", err.Error())
|
|
|
|
|
t.Fatalf("failed to load simple dump: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check that the VIEW and TRIGGER are OK by using both.
|
|
|
|
|
er := executeRequestFromString("INSERT INTO foobar VALUES('jason', 16)", false, true)
|
|
|
|
|
r, err := s.Execute(er)
|
|
|
|
|
// Check that data were loaded correctly.
|
|
|
|
|
qr := queryRequestFromString("SELECT * FROM foo", false, true)
|
|
|
|
|
qr.Level = command.QueryRequest_QUERY_REQUEST_LEVEL_STRONG
|
|
|
|
|
r, err := s.Query(qr)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to insert into view on single node: %s", err.Error())
|
|
|
|
|
t.Fatalf("failed to query single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
if exp, got := int64(3), r[0].GetLastInsertId(); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %d\ngot: %d", exp, got)
|
|
|
|
|
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_SingleNodeLoadNoStatements(t *testing.T) {
|
|
|
|
|
func Test_SingleNodeLoadTextNoStatements(t *testing.T) {
|
|
|
|
|
s, ln := mustNewStore(true)
|
|
|
|
|
defer os.RemoveAll(s.Path())
|
|
|
|
|
defer ln.Close()
|
|
|
|
@ -659,7 +658,7 @@ COMMIT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_SingleNodeLoadEmpty(t *testing.T) {
|
|
|
|
|
func Test_SingleNodeLoadTextEmpty(t *testing.T) {
|
|
|
|
|
s, ln := mustNewStore(true)
|
|
|
|
|
defer os.RemoveAll(s.Path())
|
|
|
|
|
defer ln.Close()
|
|
|
|
@ -682,7 +681,7 @@ func Test_SingleNodeLoadEmpty(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_SingleNodeLoadChinook(t *testing.T) {
|
|
|
|
|
func Test_SingleNodeLoadTextChinook(t *testing.T) {
|
|
|
|
|
s, ln := mustNewStore(true)
|
|
|
|
|
defer os.RemoveAll(s.Path())
|
|
|
|
|
defer ln.Close()
|
|
|
|
@ -745,6 +744,54 @@ func Test_SingleNodeLoadChinook(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_SingleNodeLoadBinary(t *testing.T) {
|
|
|
|
|
s, ln := mustNewStore(true)
|
|
|
|
|
defer os.RemoveAll(s.Path())
|
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err := s.Load(loadRequestFromFile(filepath.Join("testdata", "load.sqlite")))
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to load SQLite file: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check that data were loaded correctly.
|
|
|
|
|
qr := queryRequestFromString("SELECT * FROM foo WHERE id=2", false, true)
|
|
|
|
|
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())
|
|
|
|
|
}
|
|
|
|
|
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 := `[[2,"fiona"]]`, asJSON(r[0].Values); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
qr = queryRequestFromString("SELECT count(*) FROM foo", false, true)
|
|
|
|
|
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())
|
|
|
|
|
}
|
|
|
|
|
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 := `[[3]]`, asJSON(r[0].Values); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test_SingleNodeRecoverNoChange tests a node recovery that doesn't
|
|
|
|
|
// actually change anything.
|
|
|
|
|
func Test_SingleNodeRecoverNoChange(t *testing.T) {
|
|
|
|
@ -1943,6 +1990,14 @@ func mustWriteFile(path, contents string) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func mustReadFile(path string) []byte {
|
|
|
|
|
b, err := ioutil.ReadFile(path)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic("failed to read file")
|
|
|
|
|
}
|
|
|
|
|
return b
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func mustTempDir() string {
|
|
|
|
|
var err error
|
|
|
|
|
path, err := ioutil.TempDir("", "rqlilte-test-")
|
|
|
|
@ -2002,6 +2057,12 @@ func queryRequestFromStrings(s []string, timings, tx bool) *command.QueryRequest
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func loadRequestFromFile(path string) *command.LoadRequest {
|
|
|
|
|
return &command.LoadRequest{
|
|
|
|
|
Data: mustReadFile(path),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// waitForLeaderID waits until the Store's LeaderID is set, or the timeout
|
|
|
|
|
// expires. Because setting Leader ID requires Raft to set the cluster
|
|
|
|
|
// configuration, it's not entirely deterministic when it will be set.
|
|
|
|
|