From d646d7c16ae77cc3a1946aec47c46e3a0f6ba254 Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Thu, 5 Dec 2013 20:46:52 -0500 Subject: [PATCH] tests add tests for dir flag --- server/v2/tests/delete_handler_test.go | 56 ++++++++++++ server/v2/tests/put_handler_test.go | 13 +++ store/store.go | 5 ++ store/store_test.go | 120 ++++++++++++++++++++++--- 4 files changed, 182 insertions(+), 12 deletions(-) diff --git a/server/v2/tests/delete_handler_test.go b/server/v2/tests/delete_handler_test.go index 82d59321a..08e0f355a 100644 --- a/server/v2/tests/delete_handler_test.go +++ b/server/v2/tests/delete_handler_test.go @@ -27,3 +27,59 @@ func TestV2DeleteKey(t *testing.T) { assert.Equal(t, string(body), `{"action":"delete","node":{"key":"/foo/bar","prevValue":"XXX","modifiedIndex":3,"createdIndex":2}}`, "") }) } + +// Ensures that an empty directory is deleted when dir is set. +// +// $ curl -X PUT localhost:4001/v2/keys/foo?dir=true +// $ curl -X PUT localhost:4001/v2/keys/foo ->fail +// $ curl -X DELETE localhost:4001/v2/keys/foo?dir=true +// +func TestV2DeleteEmptyDirectory(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"), url.Values{}) + bodyJson := tests.ReadBodyJSON(resp) + assert.Equal(t, bodyJson["errorCode"], 102, "") + resp, err = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?dir=true"), url.Values{}) + body := tests.ReadBody(resp) + assert.Nil(t, err, "") + assert.Equal(t, string(body), `{"action":"delete","node":{"key":"/foo","dir":true,"modifiedIndex":3,"createdIndex":2}}`, "") + }) +} + +// Ensures that a not-empty directory is deleted when dir is set. +// +// $ curl -X PUT localhost:4001/v2/keys/foo/bar?dir=true +// $ curl -X DELETE localhost:4001/v2/keys/foo?dir=true ->fail +// $ curl -X DELETE localhost:4001/v2/keys/foo?dir=true&recursive=true +// +func TestV2DeleteNonEmptyDirectory(t *testing.T) { + tests.RunServer(func(s *server.Server) { + resp, err := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar?dir=true"), url.Values{}) + tests.ReadBody(resp) + resp, err = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?dir=true"), url.Values{}) + bodyJson := tests.ReadBodyJSON(resp) + assert.Equal(t, bodyJson["errorCode"], 108, "") + resp, err = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?dir=true&recursive=true"), url.Values{}) + body := tests.ReadBody(resp) + assert.Nil(t, err, "") + assert.Equal(t, string(body), `{"action":"delete","node":{"key":"/foo","dir":true,"modifiedIndex":3,"createdIndex":2}}`, "") + }) +} + +// 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{}) + body := tests.ReadBody(resp) + assert.Nil(t, err, "") + assert.Equal(t, string(body), `{"action":"delete","node":{"key":"/foo","dir":true,"modifiedIndex":3,"createdIndex":2}}`, "") + }) +} diff --git a/server/v2/tests/put_handler_test.go b/server/v2/tests/put_handler_test.go index 42200db82..ac8ca89f3 100644 --- a/server/v2/tests/put_handler_test.go +++ b/server/v2/tests/put_handler_test.go @@ -26,6 +26,19 @@ func TestV2SetKey(t *testing.T) { }) } +// 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{}) + body := tests.ReadBody(resp) + assert.Nil(t, err, "") + assert.Equal(t, string(body), `{"action":"set","node":{"key":"/foo","dir":true,"modifiedIndex":2,"createdIndex":2}}`, "") + }) +} + // Ensures that a time-to-live is added to a key. // // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d ttl=20 diff --git a/store/store.go b/store/store.go index ae2e284f3..662d832b8 100644 --- a/store/store.go +++ b/store/store.go @@ -252,6 +252,11 @@ func (s *store) Delete(nodePath string, dir, recursive bool) (*Event, error) { s.worldLock.Lock() defer s.worldLock.Unlock() + // recursive implies dir + if recursive == true { + dir = true + } + nextIndex := s.CurrentIndex + 1 n, err := s.internalGet(nodePath) diff --git a/store/store_test.go b/store/store_test.go index 6d21ccd07..be92c0a28 100644 --- a/store/store_test.go +++ b/store/store_test.go @@ -84,9 +84,53 @@ func TestStoreGetSorted(t *testing.T) { assert.Equal(t, e.Node.Nodes[2].Key, "/foo/z", "") } +func TestSet(t *testing.T) { + s := newStore() + + // Set /foo="" + e, err := s.Set("/foo", false, "", Permanent) + assert.Nil(t, err, "") + assert.Equal(t, e.Action, "set", "") + assert.Equal(t, e.Node.Key, "/foo", "") + assert.False(t, e.Node.Dir, "") + assert.Equal(t, e.Node.PrevValue, "", "") + 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(1), "") + + // Set /foo="bar" + e, err = s.Set("/foo", false, "bar", Permanent) + assert.Nil(t, err, "") + assert.Equal(t, e.Action, "set", "") + assert.Equal(t, e.Node.Key, "/foo", "") + assert.False(t, e.Node.Dir, "") + assert.Equal(t, e.Node.PrevValue, "", "") + 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(2), "") + + // Set /dir as a directory + e, err = s.Set("/dir", true, "", Permanent) + assert.Nil(t, err, "") + assert.Equal(t, e.Action, "set", "") + assert.Equal(t, e.Node.Key, "/dir", "") + assert.True(t, e.Node.Dir, "") + assert.Equal(t, e.Node.PrevValue, "", "") + 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(3), "") +} + // 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", "") @@ -98,6 +142,20 @@ func TestStoreCreateValue(t *testing.T) { 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.PrevValue, "", "") + 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 create a new directory if it doesn't already exist. @@ -113,7 +171,10 @@ func TestStoreCreateDirectory(t *testing.T) { // 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, "") @@ -126,7 +187,9 @@ func TestStoreCreateFailsIfExists(t *testing.T) { // 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", "") @@ -138,6 +201,19 @@ func TestStoreUpdateValue(t *testing.T) { assert.Equal(t, e.Node.ModifiedIndex, uint64(2), "") 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.PrevValue, "baz", "") + assert.Equal(t, e.Node.Value, "", "") + assert.Equal(t, e.Node.TTL, 0, "") + assert.Equal(t, e.Node.ModifiedIndex, uint64(3), "") + e, _ = s.Get("/foo", false, false) + assert.Equal(t, e.Node.Value, "", "") } // Ensure that the store cannot update a directory. @@ -207,10 +283,41 @@ func TestStoreDeleteValue(t *testing.T) { // 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) - e, err := s.Delete("/foo", true, true) + // delete /foo with dir = true and recursive = false + // this should success, since the directory is empty + e, err := s.Delete("/foo", true, false) assert.Nil(t, err, "") assert.Equal(t, e.Action, "delete", "") + + // 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 success, 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", "") + +} + +// 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, "") } func TestRootRdOnly(t *testing.T) { @@ -233,17 +340,6 @@ func TestRootRdOnly(t *testing.T) { } -// Ensure that the store cannot delete a directory if recursive is not specified. -func TestStoreDeleteDiretoryFailsIfNonRecursive(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 conditionally update a key if it has a previous value. func TestStoreCompareAndSwapPrevValue(t *testing.T) { s := newStore()