delete_handler_test.go 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. package v2
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/url"
  6. "testing"
  7. "github.com/coreos/etcd/server"
  8. "github.com/coreos/etcd/tests"
  9. "github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
  10. )
  11. // Ensures that a key is deleted.
  12. //
  13. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
  14. // $ curl -X DELETE localhost:4001/v2/keys/foo/bar
  15. //
  16. func TestV2DeleteKey(t *testing.T) {
  17. tests.RunServer(func(s *server.Server) {
  18. v := url.Values{}
  19. v.Set("value", "XXX")
  20. resp, err := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v)
  21. tests.ReadBody(resp)
  22. resp, err = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), url.Values{})
  23. assert.Equal(t, resp.StatusCode, http.StatusOK)
  24. body := tests.ReadBody(resp)
  25. assert.Nil(t, err, "")
  26. assert.Equal(t, string(body), `{"action":"delete","node":{"key":"/foo/bar","modifiedIndex":4,"createdIndex":3},"prevNode":{"key":"/foo/bar","value":"XXX","modifiedIndex":3,"createdIndex":3}}`, "")
  27. })
  28. }
  29. // Ensures that an empty directory is deleted when dir is set.
  30. //
  31. // $ curl -X PUT localhost:4001/v2/keys/foo?dir=true
  32. // $ curl -X DELETE localhost:4001/v2/keys/foo ->fail
  33. // $ curl -X DELETE localhost:4001/v2/keys/foo?dir=true
  34. //
  35. func TestV2DeleteEmptyDirectory(t *testing.T) {
  36. tests.RunServer(func(s *server.Server) {
  37. resp, err := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?dir=true"), url.Values{})
  38. tests.ReadBody(resp)
  39. resp, err = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo"), url.Values{})
  40. assert.Equal(t, resp.StatusCode, http.StatusForbidden)
  41. bodyJson := tests.ReadBodyJSON(resp)
  42. assert.Equal(t, bodyJson["errorCode"], 102, "")
  43. resp, err = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?dir=true"), url.Values{})
  44. assert.Equal(t, resp.StatusCode, http.StatusOK)
  45. body := tests.ReadBody(resp)
  46. assert.Nil(t, err, "")
  47. assert.Equal(t, string(body), `{"action":"delete","node":{"key":"/foo","dir":true,"modifiedIndex":4,"createdIndex":3},"prevNode":{"key":"/foo","dir":true,"modifiedIndex":3,"createdIndex":3}}`, "")
  48. })
  49. }
  50. // Ensures that a not-empty directory is deleted when dir is set.
  51. //
  52. // $ curl -X PUT localhost:4001/v2/keys/foo/bar?dir=true
  53. // $ curl -X DELETE localhost:4001/v2/keys/foo?dir=true ->fail
  54. // $ curl -X DELETE localhost:4001/v2/keys/foo?dir=true&recursive=true
  55. //
  56. func TestV2DeleteNonEmptyDirectory(t *testing.T) {
  57. tests.RunServer(func(s *server.Server) {
  58. resp, err := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar?dir=true"), url.Values{})
  59. tests.ReadBody(resp)
  60. resp, err = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?dir=true"), url.Values{})
  61. assert.Equal(t, resp.StatusCode, http.StatusForbidden)
  62. bodyJson := tests.ReadBodyJSON(resp)
  63. assert.Equal(t, bodyJson["errorCode"], 108, "")
  64. resp, err = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?dir=true&recursive=true"), url.Values{})
  65. assert.Equal(t, resp.StatusCode, http.StatusOK)
  66. body := tests.ReadBody(resp)
  67. assert.Nil(t, err, "")
  68. assert.Equal(t, string(body), `{"action":"delete","node":{"key":"/foo","dir":true,"modifiedIndex":4,"createdIndex":3},"prevNode":{"key":"/foo","dir":true,"modifiedIndex":3,"createdIndex":3}}`, "")
  69. })
  70. }
  71. // Ensures that a directory is deleted when recursive is set.
  72. //
  73. // $ curl -X PUT localhost:4001/v2/keys/foo?dir=true
  74. // $ curl -X DELETE localhost:4001/v2/keys/foo?recursive=true
  75. //
  76. func TestV2DeleteDirectoryRecursiveImpliesDir(t *testing.T) {
  77. tests.RunServer(func(s *server.Server) {
  78. resp, err := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?dir=true"), url.Values{})
  79. tests.ReadBody(resp)
  80. resp, err = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?recursive=true"), url.Values{})
  81. assert.Equal(t, resp.StatusCode, http.StatusOK)
  82. body := tests.ReadBody(resp)
  83. assert.Nil(t, err, "")
  84. assert.Equal(t, string(body), `{"action":"delete","node":{"key":"/foo","dir":true,"modifiedIndex":4,"createdIndex":3},"prevNode":{"key":"/foo","dir":true,"modifiedIndex":3,"createdIndex":3}}`, "")
  85. })
  86. }
  87. // Ensures that a key is deleted if the previous index matches
  88. //
  89. // $ curl -X PUT localhost:4001/v2/keys/foo -d value=XXX
  90. // $ curl -X DELETE localhost:4001/v2/keys/foo?prevIndex=3
  91. //
  92. func TestV2DeleteKeyCADOnIndexSuccess(t *testing.T) {
  93. tests.RunServer(func(s *server.Server) {
  94. v := url.Values{}
  95. v.Set("value", "XXX")
  96. resp, err := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo"), v)
  97. tests.ReadBody(resp)
  98. resp, err = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?prevIndex=3"), url.Values{})
  99. assert.Nil(t, err, "")
  100. body := tests.ReadBodyJSON(resp)
  101. assert.Equal(t, body["action"], "compareAndDelete", "")
  102. node := body["node"].(map[string]interface{})
  103. assert.Equal(t, node["key"], "/foo", "")
  104. assert.Equal(t, node["modifiedIndex"], 4, "")
  105. })
  106. }
  107. // Ensures that a key is not deleted if the previous index does not match
  108. //
  109. // $ curl -X PUT localhost:4001/v2/keys/foo -d value=XXX
  110. // $ curl -X DELETE localhost:4001/v2/keys/foo?prevIndex=100
  111. //
  112. func TestV2DeleteKeyCADOnIndexFail(t *testing.T) {
  113. tests.RunServer(func(s *server.Server) {
  114. v := url.Values{}
  115. v.Set("value", "XXX")
  116. resp, err := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo"), v)
  117. tests.ReadBody(resp)
  118. resp, err = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?prevIndex=100"), url.Values{})
  119. assert.Nil(t, err, "")
  120. body := tests.ReadBodyJSON(resp)
  121. assert.Equal(t, body["errorCode"], 101)
  122. })
  123. }
  124. // Ensures that an error is thrown if an invalid previous index is provided.
  125. //
  126. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
  127. // $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevIndex=bad_index
  128. //
  129. func TestV2DeleteKeyCADWithInvalidIndex(t *testing.T) {
  130. tests.RunServer(func(s *server.Server) {
  131. v := url.Values{}
  132. v.Set("value", "XXX")
  133. resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v)
  134. tests.ReadBody(resp)
  135. resp, _ = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar?prevIndex=bad_index"), v)
  136. body := tests.ReadBodyJSON(resp)
  137. assert.Equal(t, body["errorCode"], 203)
  138. })
  139. }
  140. // Ensures that a key is deleted only if the previous value matches.
  141. //
  142. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
  143. // $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevValue=XXX
  144. //
  145. func TestV2DeleteKeyCADOnValueSuccess(t *testing.T) {
  146. tests.RunServer(func(s *server.Server) {
  147. v := url.Values{}
  148. v.Set("value", "XXX")
  149. resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v)
  150. tests.ReadBody(resp)
  151. resp, _ = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar?prevValue=XXX"), v)
  152. body := tests.ReadBodyJSON(resp)
  153. assert.Equal(t, body["action"], "compareAndDelete", "")
  154. node := body["node"].(map[string]interface{})
  155. assert.Equal(t, node["modifiedIndex"], 4, "")
  156. })
  157. }
  158. // Ensures that a key is not deleted if the previous value does not match.
  159. //
  160. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
  161. // $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevValue=YYY
  162. //
  163. func TestV2DeleteKeyCADOnValueFail(t *testing.T) {
  164. tests.RunServer(func(s *server.Server) {
  165. v := url.Values{}
  166. v.Set("value", "XXX")
  167. resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v)
  168. tests.ReadBody(resp)
  169. resp, _ = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar?prevValue=YYY"), v)
  170. body := tests.ReadBodyJSON(resp)
  171. assert.Equal(t, body["errorCode"], 101)
  172. })
  173. }
  174. // Ensures that an error is thrown if an invalid previous value is provided.
  175. //
  176. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
  177. // $ curl -X DELETE localhost:4001/v2/keys/foo/bar?prevIndex=
  178. //
  179. func TestV2DeleteKeyCADWithInvalidValue(t *testing.T) {
  180. tests.RunServer(func(s *server.Server) {
  181. v := url.Values{}
  182. v.Set("value", "XXX")
  183. resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v)
  184. tests.ReadBody(resp)
  185. resp, _ = tests.DeleteForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar?prevValue="), v)
  186. body := tests.ReadBodyJSON(resp)
  187. assert.Equal(t, body["errorCode"], 201)
  188. })
  189. }