// Ensure that we can start a v2 cluster from the logs of a v1 cluster. func TestV1ClusterMigration(t *testing.T) { path, _ := ioutil.TempDir("", "etcd-") os.RemoveAll(path) defer os.RemoveAll(path) nodes := []string{"node0", "node2"} for i, node := range nodes { nodepath := filepath.Join(path, node) fixturepath, _ := filepath.Abs(filepath.Join("../fixtures/v1.cluster/", node)) fmt.Println("FIXPATH =", fixturepath) fmt.Println("NODEPATH =", nodepath) os.MkdirAll(filepath.Dir(nodepath), 0777) // Copy over fixture files. c := exec.Command("cp", "-rf", fixturepath, nodepath) if out, err := c.CombinedOutput(); err != nil { fmt.Println(">>>>>>\n", string(out), "<<<<<<") panic("Fixture initialization error:" + err.Error()) } procAttr := new(os.ProcAttr) procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr} args := []string{"etcd", fmt.Sprintf("-data-dir=%s", nodepath)} args = append(args, "-addr", fmt.Sprintf("127.0.0.1:%d", 4001+i)) args = append(args, "-peer-addr", fmt.Sprintf("127.0.0.1:%d", 7001+i)) args = append(args, "-name", node) process, err := os.StartProcess(EtcdBinPath, args, procAttr) if err != nil { t.Fatal("start process failed:" + err.Error()) return } defer process.Kill() time.Sleep(time.Second) } // Ensure deleted message is removed. resp, err := tests.Get("http://localhost:4001/v2/keys/message") body := tests.ReadBody(resp) assert.Nil(t, err, "") assert.Equal(t, resp.StatusCode, http.StatusNotFound) assert.Equal(t, string(body), `{"errorCode":100,"message":"Key not found","cause":"/message","index":11}`+"\n") // Ensure TTL'd message is removed. resp, err = tests.Get("http://localhost:4001/v2/keys/foo") body = tests.ReadBody(resp) assert.Nil(t, err, "") assert.Equal(t, resp.StatusCode, 200, "") assert.Equal(t, string(body), `{"action":"get","node":{"key":"/foo","value":"one","modifiedIndex":9,"createdIndex":9}}`) }
// Ensures that a value can be retrieve for a given key. // // $ curl localhost:4001/v2/keys/foo/bar -> fail // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX // $ curl localhost:4001/v2/keys/foo/bar // func TestV2GetKey(t *testing.T) { tests.RunServer(func(s *server.Server) { v := url.Values{} v.Set("value", "XXX") fullURL := fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar") resp, _ := tests.Get(fullURL) assert.Equal(t, resp.StatusCode, http.StatusNotFound) resp, _ = tests.PutForm(fullURL, v) tests.ReadBody(resp) resp, _ = tests.Get(fullURL) assert.Equal(t, resp.StatusCode, http.StatusOK) body := tests.ReadBodyJSON(resp) assert.Equal(t, body["action"], "get", "") node := body["node"].(map[string]interface{}) assert.Equal(t, node["key"], "/foo/bar", "") assert.Equal(t, node["value"], "XXX", "") assert.Equal(t, node["modifiedIndex"], 2, "") }) }
// Ensures that a watcher can wait for a value to be set after a given index. // // $ curl localhost:4001/v2/keys/foo/bar?wait=true&waitIndex=4 // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY // func TestV2WatchKeyWithIndex(t *testing.T) { tests.RunServer(func(s *server.Server) { var body map[string]interface{} c := make(chan bool) go func() { resp, _ := tests.Get(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar?wait=true&waitIndex=3")) body = tests.ReadBodyJSON(resp) c <- true }() // Make sure response didn't fire early. time.Sleep(1 * time.Millisecond) assert.Nil(t, body, "") // Set a value (before given index). v := url.Values{} v.Set("value", "XXX") resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v) tests.ReadBody(resp) // Make sure response didn't fire early. time.Sleep(1 * time.Millisecond) assert.Nil(t, body, "") // Set a value (before given index). v.Set("value", "YYY") resp, _ = tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v) tests.ReadBody(resp) // A response should follow from the GET above. time.Sleep(1 * time.Millisecond) select { case <-c: default: t.Fatal("cannot get watch result") } assert.NotNil(t, body, "") assert.Equal(t, body["action"], "set", "") node := body["node"].(map[string]interface{}) assert.Equal(t, node["key"], "/foo/bar", "") assert.Equal(t, node["value"], "YYY", "") assert.Equal(t, node["modifiedIndex"], 3, "") }) }
// Ensures that a watcher can wait for a value to be set after a given index. // // $ curl localhost:4001/v2/keys/keyindir/bar?wait=true // $ curl -X PUT localhost:4001/v2/keys/keyindir -d dir=true -d ttl=1 // $ curl -X PUT localhost:4001/v2/keys/keyindir/bar -d value=YYY // func TestV2WatchKeyInDir(t *testing.T) { tests.RunServer(func(s *server.Server) { var body map[string]interface{} c := make(chan bool) // Set a value (before given index). v := url.Values{} v.Set("dir", "true") v.Set("ttl", "1") resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/keyindir"), v) tests.ReadBody(resp) // Set a value (before given index). v = url.Values{} v.Set("value", "XXX") resp, _ = tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/keyindir/bar"), v) tests.ReadBody(resp) go func() { resp, _ := tests.Get(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/keyindir/bar?wait=true")) body = tests.ReadBodyJSON(resp) c <- true }() // wait for expiration, we do have a up to 500 millisecond delay time.Sleep(2000 * time.Millisecond) select { case <-c: default: t.Fatal("cannot get watch result") } assert.NotNil(t, body, "") assert.Equal(t, body["action"], "expire", "") node := body["node"].(map[string]interface{}) assert.Equal(t, node["key"], "/keyindir", "") }) }
// Ensure that we can start a v2 node from the log of a v1 node. func TestV1SoloMigration(t *testing.T) { path, _ := ioutil.TempDir("", "etcd-") os.MkdirAll(path, 0777) defer os.RemoveAll(path) nodepath := filepath.Join(path, "node0") fixturepath, _ := filepath.Abs("../fixtures/v1.solo/node0") fmt.Println("DATA_DIR =", nodepath) // Copy over fixture files. c := exec.Command("cp", "-rf", fixturepath, nodepath) if out, err := c.CombinedOutput(); err != nil { fmt.Println(">>>>>>\n", string(out), "<<<<<<") panic("Fixture initialization error:" + err.Error()) } procAttr := new(os.ProcAttr) procAttr.Files = []*os.File{nil, os.Stdout, os.Stderr} args := []string{"etcd", fmt.Sprintf("-data-dir=%s", nodepath)} args = append(args, "-addr", "127.0.0.1:4001") args = append(args, "-peer-addr", "127.0.0.1:7001") args = append(args, "-name", "v1") process, err := os.StartProcess(EtcdBinPath, args, procAttr) if err != nil { t.Fatal("start process failed:" + err.Error()) return } defer process.Kill() time.Sleep(time.Second) // Ensure deleted message is removed. resp, err := tests.Get("http://localhost:4001/v2/keys/message") tests.ReadBody(resp) assert.Nil(t, err, "") assert.Equal(t, resp.StatusCode, 200, "") }
// Ensures that a directory of values can be recursively retrieved for a given key. // // $ curl -X PUT localhost:4001/v2/keys/foo/x -d value=XXX // $ curl -X PUT localhost:4001/v2/keys/foo/y/z -d value=YYY // $ curl localhost:4001/v2/keys/foo -d recursive=true // func TestV2GetKeyRecursively(t *testing.T) { tests.RunServer(func(s *server.Server) { v := url.Values{} v.Set("value", "XXX") v.Set("ttl", "10") resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/x"), v) tests.ReadBody(resp) v.Set("value", "YYY") resp, _ = tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/y/z"), v) tests.ReadBody(resp) resp, _ = tests.Get(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?recursive=true")) assert.Equal(t, resp.StatusCode, http.StatusOK) body := tests.ReadBodyJSON(resp) assert.Equal(t, body["action"], "get", "") node := body["node"].(map[string]interface{}) assert.Equal(t, node["key"], "/foo", "") assert.Equal(t, node["dir"], true, "") assert.Equal(t, node["modifiedIndex"], 2, "") assert.Equal(t, len(node["nodes"].([]interface{})), 2, "") node0 := node["nodes"].([]interface{})[0].(map[string]interface{}) assert.Equal(t, node0["key"], "/foo/x", "") assert.Equal(t, node0["value"], "XXX", "") assert.Equal(t, node0["ttl"], 10, "") node1 := node["nodes"].([]interface{})[1].(map[string]interface{}) assert.Equal(t, node1["key"], "/foo/y", "") assert.Equal(t, node1["dir"], true, "") node2 := node1["nodes"].([]interface{})[0].(map[string]interface{}) assert.Equal(t, node2["key"], "/foo/y/z", "") assert.Equal(t, node2["value"], "YYY", "") }) }
func testGetLockValue(s *server.Server, key string) (string, int, error) { resp, err := tests.Get(fmt.Sprintf("%s/mod/v2/lock/%s", s.URL(), key)) ret := tests.ReadBody(resp) return string(ret), resp.StatusCode, err }