// Ensure that the store can delete a directory if recursive is specified. func TestStoreDeleteDiretory(t *testing.T) { s := newStore() // create directory /foo s.Create("/foo", true, "", false, Permanent) // delete /foo with dir = true and recursive = false // this should succeed, since the directory is empty e, err := s.Delete("/foo", true, false) assert.Nil(t, err, "") assert.Equal(t, e.Action, "delete", "") // check pervNode assert.NotNil(t, e.PrevNode, "") assert.Equal(t, e.PrevNode.Key, "/foo", "") assert.Equal(t, e.PrevNode.Dir, true, "") // create directory /foo and directory /foo/bar s.Create("/foo/bar", true, "", false, Permanent) // delete /foo with dir = true and recursive = false // this should fail, since the directory is not empty _, err = s.Delete("/foo", true, false) assert.NotNil(t, err, "") // delete /foo with dir=false and recursive = true // this should succeed, since recursive implies dir=true // and recursively delete should be able to delete all // items under the given directory e, err = s.Delete("/foo", false, true) assert.Nil(t, err, "") assert.Equal(t, e.Action, "delete", "") }
// Ensures that a Name gets guessed if not specified func TestConfigNameGuess(t *testing.T) { c := New() assert.Nil(t, c.LoadFlags([]string{}), "") assert.Nil(t, c.Sanitize()) name, _ := os.Hostname() assert.Equal(t, c.Name, name, "") }
// Ensures that a DataDir gets guessed if not specified func TestConfigDataDirGuess(t *testing.T) { c := New() assert.Nil(t, c.LoadFlags([]string{}), "") assert.Nil(t, c.Sanitize()) name, _ := os.Hostname() assert.Equal(t, c.DataDir, name+".etcd", "") }
// 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}}`) }
// Ensure that the store doesn't see hidden key creates without an exact path match in recursive mode. func TestStoreWatchRecursiveCreateWithHiddenKey(t *testing.T) { s := newStore() w, _ := s.Watch("/foo", true, false, 0) s.Create("/foo/_bar", false, "baz", false, Permanent) e := nbselect(w.EventChan) assert.Nil(t, e, "") w, _ = s.Watch("/foo", true, false, 0) s.Create("/foo/_baz", true, "", false, Permanent) e = nbselect(w.EventChan) assert.Nil(t, e, "") s.Create("/foo/_baz/quux", false, "quux", false, Permanent) e = nbselect(w.EventChan) assert.Nil(t, e, "") }
// 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, "") }) }
// Ensure that the store can watch for key expiration. func TestStoreWatchExpire(t *testing.T) { s := newStore() stopChan := make(chan bool) defer func() { stopChan <- true }() go mockSyncService(s.DeleteExpiredKeys, stopChan) s.Create("/foo", false, "bar", false, time.Now().Add(500*time.Millisecond)) s.Create("/foofoo", false, "barbarbar", false, time.Now().Add(500*time.Millisecond)) w, _ := s.Watch("/", true, false, 0) c := w.EventChan e := nbselect(c) assert.Nil(t, e, "") time.Sleep(600 * time.Millisecond) e = nbselect(c) assert.Equal(t, e.Action, "expire", "") assert.Equal(t, e.Node.Key, "/foo", "") w, _ = s.Watch("/", true, false, 4) e = nbselect(w.EventChan) assert.Equal(t, e.Action, "expire", "") assert.Equal(t, e.Node.Key, "/foofoo", "") }
// Ensure that the store can recrusively retrieve a directory listing. // Note that hidden files should not be returned. func TestStoreGetDirectory(t *testing.T) { s := newStore() s.Create("/foo", true, "", false, Permanent) s.Create("/foo/bar", false, "X", false, Permanent) s.Create("/foo/_hidden", false, "*", false, Permanent) s.Create("/foo/baz", true, "", false, Permanent) s.Create("/foo/baz/bat", false, "Y", false, Permanent) s.Create("/foo/baz/_hidden", false, "*", false, Permanent) s.Create("/foo/baz/ttl", false, "Y", false, time.Now().Add(time.Second*3)) e, err := s.Get("/foo", true, false) assert.Nil(t, err, "") assert.Equal(t, e.Action, "get", "") assert.Equal(t, e.Node.Key, "/foo", "") assert.Equal(t, len(e.Node.Nodes), 2, "") assert.Equal(t, e.Node.Nodes[0].Key, "/foo/bar", "") assert.Equal(t, e.Node.Nodes[0].Value, "X", "") assert.Equal(t, e.Node.Nodes[0].Dir, false, "") assert.Equal(t, e.Node.Nodes[1].Key, "/foo/baz", "") assert.Equal(t, e.Node.Nodes[1].Dir, true, "") assert.Equal(t, len(e.Node.Nodes[1].Nodes), 2, "") assert.Equal(t, e.Node.Nodes[1].Nodes[0].Key, "/foo/baz/bat", "") assert.Equal(t, e.Node.Nodes[1].Nodes[0].Value, "Y", "") assert.Equal(t, e.Node.Nodes[1].Nodes[0].Dir, false, "") assert.Equal(t, e.Node.Nodes[1].Nodes[1].Key, "/foo/baz/ttl", "") assert.Equal(t, e.Node.Nodes[1].Nodes[1].Value, "Y", "") assert.Equal(t, e.Node.Nodes[1].Nodes[1].Dir, false, "") assert.Equal(t, e.Node.Nodes[1].Nodes[1].TTL, 3, "") }
// Ensures a unique value is added to the key's children. // // $ curl -X POST localhost:4001/v2/keys/foo/bar // $ curl -X POST localhost:4001/v2/keys/foo/bar // $ curl -X POST localhost:4001/v2/keys/foo/baz // func TestV2CreateUnique(t *testing.T) { tests.RunServer(func(s *server.Server) { // POST should add index to list. fullURL := fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar") resp, _ := tests.PostForm(fullURL, nil) assert.Equal(t, resp.StatusCode, http.StatusCreated) body := tests.ReadBodyJSON(resp) assert.Equal(t, body["action"], "create", "") node := body["node"].(map[string]interface{}) assert.Equal(t, node["key"], "/foo/bar/2", "") assert.Nil(t, node["dir"], "") assert.Equal(t, node["modifiedIndex"], 2, "") // Second POST should add next index to list. resp, _ = tests.PostForm(fullURL, nil) assert.Equal(t, resp.StatusCode, http.StatusCreated) body = tests.ReadBodyJSON(resp) node = body["node"].(map[string]interface{}) assert.Equal(t, node["key"], "/foo/bar/3", "") // POST to a different key should add index to that list. resp, _ = tests.PostForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/baz"), nil) assert.Equal(t, resp.StatusCode, http.StatusCreated) body = tests.ReadBodyJSON(resp) node = body["node"].(map[string]interface{}) assert.Equal(t, node["key"], "/foo/baz/4", "") }) }
// Ensure that the store can create a new directory if it doesn't already exist. func TestStoreCreateDirectory(t *testing.T) { s := newStore() e, err := s.Create("/foo", true, "", false, Permanent) assert.Nil(t, err, "") assert.Equal(t, e.Action, "create", "") assert.Equal(t, e.Node.Key, "/foo", "") assert.True(t, e.Node.Dir, "") }
// Ensure that the store can recover from a previously saved state. func TestStoreRecover(t *testing.T) { s := newStore() s.Create("/foo", true, "", false, Permanent) s.Create("/foo/x", false, "bar", false, Permanent) s.Create("/foo/y", false, "baz", false, Permanent) b, err := s.Save() s2 := newStore() s2.Recovery(b) e, err := s.Get("/foo/x", false, false) assert.Nil(t, err, "") assert.Equal(t, e.Node.Value, "bar", "") e, err = s.Get("/foo/y", false, false) assert.Nil(t, err, "") assert.Equal(t, e.Node.Value, "baz", "") }
// Ensure that the store cannot delete a directory if both of recursive // and dir are not specified. func TestStoreDeleteDiretoryFailsIfNonRecursiveAndDir(t *testing.T) { s := newStore() s.Create("/foo", true, "", false, Permanent) e, _err := s.Delete("/foo", false, false) err := _err.(*etcdErr.Error) assert.Equal(t, err.ErrorCode, etcdErr.EcodeNotFile, "") assert.Equal(t, err.Message, "Not a file", "") assert.Nil(t, e, "") }
// Ensure that the store can retrieve an existing value. func TestStoreGetValue(t *testing.T) { s := newStore() s.Create("/foo", false, "bar", false, Permanent) e, err := s.Get("/foo", false, false) assert.Nil(t, err, "") assert.Equal(t, e.Action, "get", "") assert.Equal(t, e.Node.Key, "/foo", "") assert.Equal(t, e.Node.Value, "bar", "") }
// Ensures that an environment variable field is overridden by a command line argument. func TestConfigCLIArgsOverrideEnvVar(t *testing.T) { os.Setenv("ETCD_ADDR", "127.0.0.1:1000") defer os.Setenv("ETCD_ADDR", "") c := New() c.SystemPath = "" assert.Nil(t, c.Load([]string{"-addr", "127.0.0.1:2000"}), "") assert.Equal(t, c.Addr, "http://127.0.0.1:2000", "") }
// Ensures that a directory is created // // $ curl -X PUT localhost:4001/v2/keys/foo/bar?dir=true // func TestV2SetDirectory(t *testing.T) { tests.RunServer(func(s *server.Server) { resp, err := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?dir=true"), url.Values{}) assert.Equal(t, resp.StatusCode, http.StatusCreated) body := tests.ReadBody(resp) assert.Nil(t, err, "") assert.Equal(t, string(body), `{"action":"set","node":{"key":"/foo","dir":true,"modifiedIndex":2,"createdIndex":2}}`, "") }) }
// Ensure that the store cannot update a directory. func TestStoreUpdateFailsIfDirectory(t *testing.T) { s := newStore() s.Create("/foo", true, "", false, Permanent) e, _err := s.Update("/foo", "baz", Permanent) err := _err.(*etcdErr.Error) assert.Equal(t, err.ErrorCode, etcdErr.EcodeNotFile, "") assert.Equal(t, err.Message, "Not a file", "") assert.Equal(t, err.Cause, "/foo", "") assert.Nil(t, e, "") }
// Ensure that the store can watch for hidden keys as long as it's an exact path match. func TestStoreWatchCreateWithHiddenKey(t *testing.T) { s := newStore() w, _ := s.Watch("/_foo", false, false, 0) s.Create("/_foo", false, "bar", false, Permanent) e := nbselect(w.EventChan) assert.Equal(t, e.Action, "create", "") assert.Equal(t, e.Node.Key, "/_foo", "") e = nbselect(w.EventChan) assert.Nil(t, e, "") }
// Ensure that the store cannot conditionally update a key if it has the wrong previous index. func TestStoreCompareAndSwapPrevIndexFailsIfNotMatch(t *testing.T) { s := newStore() s.Create("/foo", false, "bar", false, Permanent) e, _err := s.CompareAndSwap("/foo", "", 100, "baz", Permanent) err := _err.(*etcdErr.Error) assert.Equal(t, err.ErrorCode, etcdErr.EcodeTestFailed, "") assert.Equal(t, err.Message, "Compare failed", "") assert.Nil(t, e, "") e, _ = s.Get("/foo", false, false) assert.Equal(t, e.Node.Value, "bar", "") }
// Ensures that a key is set to a given value. // // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX // func TestV2SetKey(t *testing.T) { tests.RunServer(func(s *server.Server) { v := url.Values{} v.Set("value", "XXX") resp, err := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v) assert.Equal(t, resp.StatusCode, http.StatusCreated) body := tests.ReadBody(resp) assert.Nil(t, err, "") assert.Equal(t, string(body), `{"action":"set","node":{"key":"/foo/bar","value":"XXX","modifiedIndex":2,"createdIndex":2}}`, "") }) }
// Ensures that a configuration can be deserialized from TOML. func TestConfigTOML(t *testing.T) { content := ` addr = "127.0.0.1:4002" ca_file = "/tmp/file.ca" cert_file = "/tmp/file.cert" cors = ["*"] cpu_profile_file = "XXX" data_dir = "/tmp/data" discovery = "http://example.com/foobar" key_file = "/tmp/file.key" bind_addr = "127.0.0.1:4003" peers = ["coreos.com:4001", "coreos.com:4002"] peers_file = "/tmp/peers" max_cluster_size = 10 max_result_buffer = 512 max_retry_attempts = 5 name = "test-name" snapshot = true verbose = true very_verbose = true [peer] addr = "127.0.0.1:7002" ca_file = "/tmp/peer/file.ca" cert_file = "/tmp/peer/file.cert" key_file = "/tmp/peer/file.key" bind_addr = "127.0.0.1:7003" ` c := New() _, err := toml.Decode(content, &c) assert.Nil(t, err, "") assert.Equal(t, c.Addr, "127.0.0.1:4002", "") assert.Equal(t, c.CAFile, "/tmp/file.ca", "") assert.Equal(t, c.CertFile, "/tmp/file.cert", "") assert.Equal(t, c.CorsOrigins, []string{"*"}, "") assert.Equal(t, c.DataDir, "/tmp/data", "") assert.Equal(t, c.Discovery, "http://example.com/foobar", "") assert.Equal(t, c.KeyFile, "/tmp/file.key", "") assert.Equal(t, c.BindAddr, "127.0.0.1:4003", "") assert.Equal(t, c.Peers, []string{"coreos.com:4001", "coreos.com:4002"}, "") assert.Equal(t, c.PeersFile, "/tmp/peers", "") assert.Equal(t, c.MaxClusterSize, 10, "") assert.Equal(t, c.MaxResultBuffer, 512, "") assert.Equal(t, c.MaxRetryAttempts, 5, "") assert.Equal(t, c.Name, "test-name", "") assert.Equal(t, c.Snapshot, true, "") assert.Equal(t, c.Verbose, true, "") assert.Equal(t, c.VeryVerbose, true, "") assert.Equal(t, c.Peer.Addr, "127.0.0.1:7002", "") assert.Equal(t, c.Peer.CAFile, "/tmp/peer/file.ca", "") assert.Equal(t, c.Peer.CertFile, "/tmp/peer/file.cert", "") assert.Equal(t, c.Peer.KeyFile, "/tmp/peer/file.key", "") assert.Equal(t, c.Peer.BindAddr, "127.0.0.1:7003", "") }
// Ensure that the store can delete a value. func TestStoreDeleteValue(t *testing.T) { s := newStore() s.Create("/foo", false, "bar", false, Permanent) e, err := s.Delete("/foo", false, false) assert.Nil(t, err, "") assert.Equal(t, e.Action, "delete", "") // check pervNode assert.NotNil(t, e.PrevNode, "") assert.Equal(t, e.PrevNode.Key, "/foo", "") assert.Equal(t, e.PrevNode.Value, "bar", "") }
// Ensure that the store can watch in streaming mode. func TestStoreWatchStream(t *testing.T) { s := newStore() w, _ := s.Watch("/foo", false, true, 0) // first modification s.Create("/foo", false, "bar", false, Permanent) e := nbselect(w.EventChan) assert.Equal(t, e.Action, "create", "") assert.Equal(t, e.Node.Key, "/foo", "") assert.Equal(t, e.Node.Value, "bar", "") e = nbselect(w.EventChan) assert.Nil(t, e, "") // second modification s.Update("/foo", "baz", Permanent) e = nbselect(w.EventChan) assert.Equal(t, e.Action, "update", "") assert.Equal(t, e.Node.Key, "/foo", "") assert.Equal(t, e.Node.Value, "baz", "") e = nbselect(w.EventChan) assert.Nil(t, e, "") }
// Ensures that a directory is deleted when recursive is set. // // $ curl -X PUT localhost:4001/v2/keys/foo?dir=true // $ curl -X DELETE localhost:4001/v2/keys/foo?recursive=true // func TestV2DeleteDirectoryRecursiveImpliesDir(t *testing.T) { tests.RunServer(func(s *server.Server) { resp, err := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?dir=true"), url.Values{}) tests.ReadBody(resp) resp, err = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?recursive=true"), url.Values{}) assert.Equal(t, resp.StatusCode, http.StatusOK) body := tests.ReadBody(resp) assert.Nil(t, err, "") assert.Equal(t, string(body), `{"action":"delete","node":{"key":"/foo","dir":true,"modifiedIndex":3,"createdIndex":2},"prevNode":{"key":"/foo","dir":true,"modifiedIndex":2,"createdIndex":2}}`, "") }) }
// Ensures that a key is not deleted if the previous index does not match // // $ curl -X PUT localhost:4001/v2/keys/foo -d value=XXX // $ curl -X DELETE localhost:4001/v2/keys/foo?prevIndex=100 // func TestV2DeleteKeyCADOnIndexFail(t *testing.T) { tests.RunServer(func(s *server.Server) { v := url.Values{} v.Set("value", "XXX") resp, err := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo"), v) tests.ReadBody(resp) resp, err = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?prevIndex=100"), url.Values{}) assert.Nil(t, err, "") body := tests.ReadBodyJSON(resp) assert.Equal(t, body["errorCode"], 101) }) }
// Ensures that a custom config field is overridden by an environment variable. func TestConfigEnvVarOverrideCustomConfig(t *testing.T) { os.Setenv("ETCD_PEER_ADDR", "127.0.0.1:8000") defer os.Setenv("ETCD_PEER_ADDR", "") custom := `[peer]` + "\n" + `advertised_url = "127.0.0.1:9000"` withTempFile(custom, func(path string) { c := New() c.SystemPath = "" assert.Nil(t, c.Load([]string{"-config", path}), "") assert.Equal(t, c.Peer.Addr, "http://127.0.0.1:8000", "") }) }
// Ensures that a system config field is overridden by a custom config field. func TestConfigCustomConfigOverrideSystemConfig(t *testing.T) { system := `addr = "127.0.0.1:5000"` custom := `addr = "127.0.0.1:6000"` withTempFile(system, func(p1 string) { withTempFile(custom, func(p2 string) { c := New() c.SystemPath = p1 assert.Nil(t, c.Load([]string{"-config", p2}), "") assert.Equal(t, c.Addr, "http://127.0.0.1:6000", "") }) }) }
// Ensure that the store can create a new key if it doesn't already exist. func TestStoreCreateValue(t *testing.T) { s := newStore() // Create /foo=bar e, err := s.Create("/foo", false, "bar", false, Permanent) assert.Nil(t, err, "") assert.Equal(t, e.Action, "create", "") assert.Equal(t, e.Node.Key, "/foo", "") assert.False(t, e.Node.Dir, "") assert.Equal(t, e.Node.Value, "bar", "") assert.Nil(t, e.Node.Nodes, "") assert.Nil(t, e.Node.Expiration, "") assert.Equal(t, e.Node.TTL, 0, "") assert.Equal(t, e.Node.ModifiedIndex, uint64(1), "") // Create /empty="" e, err = s.Create("/empty", false, "", false, Permanent) assert.Nil(t, err, "") assert.Equal(t, e.Action, "create", "") assert.Equal(t, e.Node.Key, "/empty", "") assert.False(t, e.Node.Dir, "") assert.Equal(t, e.Node.Value, "", "") assert.Nil(t, e.Node.Nodes, "") assert.Nil(t, e.Node.Expiration, "") assert.Equal(t, e.Node.TTL, 0, "") assert.Equal(t, e.Node.ModifiedIndex, uint64(2), "") }
// Ensure that the store can update a key if it already exists. func TestStoreUpdateValue(t *testing.T) { s := newStore() // create /foo=bar s.Create("/foo", false, "bar", false, Permanent) // update /foo="bzr" e, err := s.Update("/foo", "baz", Permanent) assert.Nil(t, err, "") assert.Equal(t, e.Action, "update", "") assert.Equal(t, e.Node.Key, "/foo", "") assert.False(t, e.Node.Dir, "") assert.Equal(t, e.Node.Value, "baz", "") assert.Equal(t, e.Node.TTL, 0, "") assert.Equal(t, e.Node.ModifiedIndex, uint64(2), "") // check prevNode assert.Equal(t, e.PrevNode.Key, "/foo", "") assert.Equal(t, e.PrevNode.Value, "bar", "") assert.Equal(t, e.PrevNode.TTL, 0, "") assert.Equal(t, e.PrevNode.ModifiedIndex, uint64(1), "") e, _ = s.Get("/foo", false, false) assert.Equal(t, e.Node.Value, "baz", "") // update /foo="" e, err = s.Update("/foo", "", Permanent) assert.Nil(t, err, "") assert.Equal(t, e.Action, "update", "") assert.Equal(t, e.Node.Key, "/foo", "") assert.False(t, e.Node.Dir, "") assert.Equal(t, e.Node.Value, "", "") assert.Equal(t, e.Node.TTL, 0, "") assert.Equal(t, e.Node.ModifiedIndex, uint64(3), "") // check prevNode assert.Equal(t, e.PrevNode.Key, "/foo", "") assert.Equal(t, e.PrevNode.Value, "baz", "") assert.Equal(t, e.PrevNode.TTL, 0, "") assert.Equal(t, e.PrevNode.ModifiedIndex, uint64(2), "") e, _ = s.Get("/foo", false, false) assert.Equal(t, e.Node.Value, "", "") }
func TestStoreCompareAndDeletePrevIndex(t *testing.T) { s := newStore() s.Create("/foo", false, "bar", false, Permanent) e, err := s.CompareAndDelete("/foo", "", 1) assert.Nil(t, err, "") assert.Equal(t, e.Action, "compareAndDelete", "") // check pervNode assert.NotNil(t, e.PrevNode, "") assert.Equal(t, e.PrevNode.Key, "/foo", "") assert.Equal(t, e.PrevNode.Value, "bar", "") assert.Equal(t, e.PrevNode.ModifiedIndex, uint64(1), "") assert.Equal(t, e.PrevNode.CreatedIndex, uint64(1), "") }
// Ensure that the store fails to create a key if it already exists. func TestStoreCreateFailsIfExists(t *testing.T) { s := newStore() // create /foo as dir s.Create("/foo", true, "", false, Permanent) // create /foo as dir again e, _err := s.Create("/foo", true, "", false, Permanent) err := _err.(*etcdErr.Error) assert.Equal(t, err.ErrorCode, etcdErr.EcodeNodeExist, "") assert.Equal(t, err.Message, "Key already exists", "") assert.Equal(t, err.Cause, "/foo", "") assert.Equal(t, err.Index, uint64(1), "") assert.Nil(t, e, 0, "") }