|
|
|
@ -125,6 +125,74 @@ func Test_SingleNodeInMemExecuteQueryFail(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_StoreLogTruncationMultinode(t *testing.T) {
|
|
|
|
|
s0 := mustNewStore(true)
|
|
|
|
|
defer os.RemoveAll(s0.Path())
|
|
|
|
|
s0.SnapshotThreshold = 4
|
|
|
|
|
s0.SnapshotInterval = 100 * time.Millisecond
|
|
|
|
|
|
|
|
|
|
if err := s0.Open(true); err != nil {
|
|
|
|
|
t.Fatalf("failed to open single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
defer s0.Close(true)
|
|
|
|
|
s0.WaitForLeader(10 * time.Second)
|
|
|
|
|
nSnaps := stats.Get(numSnaphots).String()
|
|
|
|
|
|
|
|
|
|
// Write more than s.SnapshotThreshold statements.
|
|
|
|
|
queries := []string{
|
|
|
|
|
`CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name TEXT)`,
|
|
|
|
|
`INSERT INTO foo(id, name) VALUES(1, "fiona")`,
|
|
|
|
|
`INSERT INTO foo(id, name) VALUES(2, "fiona")`,
|
|
|
|
|
`INSERT INTO foo(id, name) VALUES(3, "fiona")`,
|
|
|
|
|
`INSERT INTO foo(id, name) VALUES(4, "fiona")`,
|
|
|
|
|
`INSERT INTO foo(id, name) VALUES(5, "fiona")`,
|
|
|
|
|
}
|
|
|
|
|
for i := range queries {
|
|
|
|
|
_, err := s0.Execute(&ExecuteRequest{[]string{queries[i]}, false, false})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("failed to execute on single node: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Wait for the snapshot to happen and log to be truncated.
|
|
|
|
|
for {
|
|
|
|
|
time.Sleep(1000 * time.Millisecond)
|
|
|
|
|
if stats.Get(numSnaphots).String() != nSnaps {
|
|
|
|
|
// It's changed, so a snap and truncate has happened.
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fire up new node and ensure it picks up all changes. This will
|
|
|
|
|
// involve getting a snapshot and truncated log.
|
|
|
|
|
s1 := mustNewStore(true)
|
|
|
|
|
if err := s1.Open(true); err != nil {
|
|
|
|
|
t.Fatalf("failed to open single-node store: %s", err.Error())
|
|
|
|
|
}
|
|
|
|
|
defer s1.Close(true)
|
|
|
|
|
|
|
|
|
|
// Join the second node to the first.
|
|
|
|
|
if err := s0.Join(s1.Addr().String()); err != nil {
|
|
|
|
|
t.Fatalf("failed to join to node at %s: %s", s0.Addr(), err.Error())
|
|
|
|
|
}
|
|
|
|
|
s1.WaitForLeader(10 * time.Second)
|
|
|
|
|
// Wait until the log entries have been applied to the follower,
|
|
|
|
|
// and then query.
|
|
|
|
|
if err := s1.WaitForAppliedIndex(8, 5*time.Second); err != nil {
|
|
|
|
|
t.Fatalf("error waiting for follower to apply index: %s:", err.Error())
|
|
|
|
|
}
|
|
|
|
|
r, err := s1.Query(&QueryRequest{[]string{`SELECT count(*) FROM foo`}, false, true, None})
|
|
|
|
|
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 := `[[5]]`, asJSON(r[0].Values); exp != got {
|
|
|
|
|
t.Fatalf("unexpected results for query\nexp: %s\ngot: %s", exp, got)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Test_SingleNodeFileExecuteQuery(t *testing.T) {
|
|
|
|
|
s := mustNewStore(false)
|
|
|
|
|
defer os.RemoveAll(s.Path())
|
|
|
|
|