1
0
Fork 0

System-level testing of Booting

master
Philip O'Toole 9 months ago
parent 140f106acc
commit b70212cffc

@ -1809,6 +1809,50 @@ func Test_MultiNodeClusterNoReapReadOnlyZero(t *testing.T) {
}
}
func Test_MultiNodeCluster_Boot(t *testing.T) {
node1 := mustNewLeaderNode()
defer node1.Deprovision()
_, err := node1.Boot("testdata/auto-restore.sqlite")
if err != nil {
t.Fatalf("failed to boot: %s", err.Error())
}
// Join a second node, check it gets the data via a snapshot.
node2 := mustNewNode(false)
defer node2.Deprovision()
if err := node2.Join(node1); err != nil {
t.Fatalf("node failed to join leader: %s", err.Error())
}
_, err = node2.WaitForLeader()
if err != nil {
t.Fatalf("failed waiting for leader: %s", err.Error())
}
// Send a few Noops through to ensure SQLite database has been updated on each node.
for i := 0; i < 5; i++ {
node1.Noop("some_id")
}
// Check the database on each node
for _, n := range []*Node{node1, node2} {
rows, err := n.QueryNoneConsistency(`SELECT COUNT(*) FROM foo`)
if err != nil {
t.Fatalf("failed to query node: %s", err.Error())
}
if got, exp := rows, `{"results":[{"columns":["COUNT(*)"],"types":["integer"],"values":[[3]]}]}`; got != exp {
t.Fatalf("got incorrect results from node exp: %s got: %s", exp, got)
}
}
// One last test -- the leader should refuse any more Boot requests because it
// is now part of a cluster.
_, err = node1.Boot("testdata/auto-restore.sqlite")
if err == nil {
t.Fatalf("expected error booting")
}
}
func sleepForSecond() {
time.Sleep(mustParseDuration("1s"))
}

@ -192,6 +192,16 @@ func (n *Node) RequestMultiParameterized(stmt []interface{}) (string, error) {
return n.postRequest(string(j))
}
// Load loads a SQLite database file into the node.
func (n *Node) Load(filename string) (string, error) {
return n.postFile("/db/load", filename)
}
// Load loads a SQLite database file into the node.
func (n *Node) Boot(filename string) (string, error) {
return n.postFile("/boot", filename)
}
// Noop inserts a noop command into the Store's Raft log.
func (n *Node) Noop(id string) error {
af, err := n.Store.Noop(id)
@ -463,6 +473,28 @@ func (n *Node) postRequest(stmt string) (string, error) {
return string(body), nil
}
func (n *Node) postFile(url, filename string) (string, error) {
f, err := os.Open(filename)
if err != nil {
return "", err
}
defer f.Close()
resp, err := http.Post("http://"+n.APIAddr+url, "application/octet-stream", f)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("file endpoint returned: %s", resp.Status)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(body), nil
}
// PostExecuteStmt performs a HTTP execute request
func PostExecuteStmt(apiAddr string, stmt string) (string, error) {
return PostExecuteStmtMulti(apiAddr, []string{stmt})

@ -1363,3 +1363,30 @@ func Test_SingleNodeAutoRestore(t *testing.T) {
t.Fatalf("test received wrong result got %s", r)
}
}
func Test_SingleNodeBoot_OK(t *testing.T) {
node := mustNewLeaderNode()
defer node.Deprovision()
_, err := node.Boot(filepath.Join("testdata", "auto-restore.sqlite"))
if err != nil {
t.Fatalf("failed to load data: %s", err.Error())
}
r, err := node.Query("SELECT * FROM foo WHERE id=2")
if err != nil {
t.Fatalf("failed to execute query: %s", err.Error())
}
if r != `{"results":[{"columns":["id","name"],"types":["integer","text"],"values":[[2,"fiona"]]}]}` {
t.Fatalf("test received wrong result got %s", r)
}
}
func Test_SingleNodeBoot_FailNotLeader(t *testing.T) {
node := mustNewNode(false)
defer node.Deprovision()
_, err := node.Boot(filepath.Join("testdata", "auto-restore.sqlite"))
if err == nil {
t.Fatalf("expected error loading data")
}
}

Loading…
Cancel
Save