put_handler_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. package v2
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/url"
  6. "testing"
  7. "time"
  8. "github.com/coreos/etcd/server"
  9. "github.com/coreos/etcd/tests"
  10. "github.com/coreos/etcd/third_party/github.com/stretchr/testify/assert"
  11. )
  12. // Ensures that a key is set to a given value.
  13. //
  14. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
  15. //
  16. func TestV2SetKey(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. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  22. body := tests.ReadBody(resp)
  23. assert.Nil(t, err, "")
  24. assert.Equal(t, string(body), `{"action":"set","node":{"key":"/foo/bar","value":"XXX","modifiedIndex":3,"createdIndex":3}}`, "")
  25. })
  26. }
  27. // Ensures that a directory is created
  28. //
  29. // $ curl -X PUT localhost:4001/v2/keys/foo/bar?dir=true
  30. //
  31. func TestV2SetDirectory(t *testing.T) {
  32. tests.RunServer(func(s *server.Server) {
  33. resp, err := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?dir=true"), url.Values{})
  34. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  35. body := tests.ReadBody(resp)
  36. assert.Nil(t, err, "")
  37. assert.Equal(t, string(body), `{"action":"set","node":{"key":"/foo","dir":true,"modifiedIndex":3,"createdIndex":3}}`, "")
  38. })
  39. }
  40. // Ensures that a time-to-live is added to a key.
  41. //
  42. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d ttl=20
  43. //
  44. func TestV2SetKeyWithTTL(t *testing.T) {
  45. tests.RunServer(func(s *server.Server) {
  46. t0 := time.Now()
  47. v := url.Values{}
  48. v.Set("value", "XXX")
  49. v.Set("ttl", "20")
  50. resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v)
  51. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  52. body := tests.ReadBodyJSON(resp)
  53. node := body["node"].(map[string]interface{})
  54. assert.Equal(t, node["ttl"], 20, "")
  55. // Make sure the expiration date is correct.
  56. expiration, _ := time.Parse(time.RFC3339Nano, node["expiration"].(string))
  57. assert.Equal(t, expiration.Sub(t0)/time.Second, 20, "")
  58. })
  59. }
  60. // Ensures that an invalid time-to-live is returned as an error.
  61. //
  62. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d ttl=bad_ttl
  63. //
  64. func TestV2SetKeyWithBadTTL(t *testing.T) {
  65. tests.RunServer(func(s *server.Server) {
  66. v := url.Values{}
  67. v.Set("value", "XXX")
  68. v.Set("ttl", "bad_ttl")
  69. resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v)
  70. assert.Equal(t, resp.StatusCode, http.StatusBadRequest)
  71. body := tests.ReadBodyJSON(resp)
  72. assert.Equal(t, body["errorCode"], 202, "")
  73. assert.Equal(t, body["message"], "The given TTL in POST form is not a number", "")
  74. assert.Equal(t, body["cause"], "Update", "")
  75. })
  76. }
  77. // Ensures that a key is conditionally set if it previously did not exist.
  78. //
  79. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d prevExist=false
  80. //
  81. func TestV2CreateKeySuccess(t *testing.T) {
  82. tests.RunServer(func(s *server.Server) {
  83. v := url.Values{}
  84. v.Set("value", "XXX")
  85. v.Set("prevExist", "false")
  86. resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v)
  87. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  88. body := tests.ReadBodyJSON(resp)
  89. node := body["node"].(map[string]interface{})
  90. assert.Equal(t, node["value"], "XXX", "")
  91. })
  92. }
  93. // Ensures that a key is not conditionally set because it previously existed.
  94. //
  95. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d prevExist=false
  96. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d prevExist=false -> fail
  97. //
  98. func TestV2CreateKeyFail(t *testing.T) {
  99. tests.RunServer(func(s *server.Server) {
  100. v := url.Values{}
  101. v.Set("value", "XXX")
  102. v.Set("prevExist", "false")
  103. fullURL := fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar")
  104. resp, _ := tests.PutForm(fullURL, v)
  105. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  106. tests.ReadBody(resp)
  107. resp, _ = tests.PutForm(fullURL, v)
  108. assert.Equal(t, resp.StatusCode, http.StatusPreconditionFailed)
  109. body := tests.ReadBodyJSON(resp)
  110. assert.Equal(t, body["errorCode"], 105, "")
  111. assert.Equal(t, body["message"], "Key already exists", "")
  112. assert.Equal(t, body["cause"], "/foo/bar", "")
  113. })
  114. }
  115. // Ensures that a key is conditionally set only if it previously did exist.
  116. //
  117. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
  118. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevExist=true
  119. //
  120. func TestV2UpdateKeySuccess(t *testing.T) {
  121. tests.RunServer(func(s *server.Server) {
  122. v := url.Values{}
  123. v.Set("value", "XXX")
  124. fullURL := fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar")
  125. resp, _ := tests.PutForm(fullURL, v)
  126. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  127. tests.ReadBody(resp)
  128. v.Set("value", "YYY")
  129. v.Set("prevExist", "true")
  130. resp, _ = tests.PutForm(fullURL, v)
  131. assert.Equal(t, resp.StatusCode, http.StatusOK)
  132. body := tests.ReadBodyJSON(resp)
  133. assert.Equal(t, body["action"], "update", "")
  134. })
  135. }
  136. // Ensures that a key is not conditionally set if it previously did not exist.
  137. //
  138. // $ curl -X PUT localhost:4001/v2/keys/foo?dir=true
  139. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d prevExist=true
  140. //
  141. func TestV2UpdateKeyFailOnValue(t *testing.T) {
  142. tests.RunServer(func(s *server.Server) {
  143. v := url.Values{}
  144. resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo?dir=true"), v)
  145. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  146. v.Set("value", "YYY")
  147. v.Set("prevExist", "true")
  148. resp, _ = tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v)
  149. assert.Equal(t, resp.StatusCode, http.StatusNotFound)
  150. body := tests.ReadBodyJSON(resp)
  151. assert.Equal(t, body["errorCode"], 100, "")
  152. assert.Equal(t, body["message"], "Key not found", "")
  153. assert.Equal(t, body["cause"], "/foo/bar", "")
  154. })
  155. }
  156. // Ensures that a key is not conditionally set if it previously did not exist.
  157. //
  158. // $ curl -X PUT localhost:4001/v2/keys/foo -d value=YYY -d prevExist=true -> fail
  159. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevExist=true -> fail
  160. //
  161. func TestV2UpdateKeyFailOnMissingDirectory(t *testing.T) {
  162. tests.RunServer(func(s *server.Server) {
  163. v := url.Values{}
  164. v.Set("value", "YYY")
  165. v.Set("prevExist", "true")
  166. resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo"), v)
  167. assert.Equal(t, resp.StatusCode, http.StatusNotFound)
  168. body := tests.ReadBodyJSON(resp)
  169. assert.Equal(t, body["errorCode"], 100, "")
  170. assert.Equal(t, body["message"], "Key not found", "")
  171. assert.Equal(t, body["cause"], "/foo", "")
  172. resp, _ = tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v)
  173. assert.Equal(t, resp.StatusCode, http.StatusNotFound)
  174. body = tests.ReadBodyJSON(resp)
  175. assert.Equal(t, body["errorCode"], 100, "")
  176. assert.Equal(t, body["message"], "Key not found", "")
  177. assert.Equal(t, body["cause"], "/foo", "")
  178. })
  179. }
  180. // Ensures that a key could update TTL.
  181. //
  182. // $ curl -X PUT localhost:4001/v2/keys/foo -d value=XXX
  183. // $ curl -X PUT localhost:4001/v2/keys/foo -d value=XXX -d ttl=1000 -d prevExist=true
  184. // $ curl -X PUT localhost:4001/v2/keys/foo -d value=XXX -d ttl= -d prevExist=true
  185. //
  186. func TestV2UpdateKeySuccessWithTTL(t *testing.T) {
  187. tests.RunServer(func(s *server.Server) {
  188. v := url.Values{}
  189. v.Set("value", "XXX")
  190. resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo"), v)
  191. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  192. node := (tests.ReadBodyJSON(resp)["node"]).(map[string]interface{})
  193. createdIndex := node["createdIndex"]
  194. v.Set("ttl", "1000")
  195. v.Set("prevExist", "true")
  196. resp, _ = tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo"), v)
  197. assert.Equal(t, resp.StatusCode, http.StatusOK)
  198. node = (tests.ReadBodyJSON(resp)["node"]).(map[string]interface{})
  199. assert.Equal(t, node["value"], "XXX", "")
  200. assert.Equal(t, node["ttl"], 1000, "")
  201. assert.NotEqual(t, node["expiration"], "", "")
  202. assert.Equal(t, node["createdIndex"], createdIndex, "")
  203. v.Del("ttl")
  204. resp, _ = tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo"), v)
  205. assert.Equal(t, resp.StatusCode, http.StatusOK)
  206. node = (tests.ReadBodyJSON(resp)["node"]).(map[string]interface{})
  207. assert.Equal(t, node["value"], "XXX", "")
  208. assert.Equal(t, node["ttl"], nil, "")
  209. assert.Equal(t, node["expiration"], nil, "")
  210. assert.Equal(t, node["createdIndex"], createdIndex, "")
  211. })
  212. }
  213. // Ensures that a key is set only if the previous index matches.
  214. //
  215. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
  216. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevIndex=1
  217. //
  218. func TestV2SetKeyCASOnIndexSuccess(t *testing.T) {
  219. tests.RunServer(func(s *server.Server) {
  220. v := url.Values{}
  221. v.Set("value", "XXX")
  222. fullURL := fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar")
  223. resp, _ := tests.PutForm(fullURL, v)
  224. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  225. tests.ReadBody(resp)
  226. v.Set("value", "YYY")
  227. v.Set("prevIndex", "3")
  228. resp, _ = tests.PutForm(fullURL, v)
  229. assert.Equal(t, resp.StatusCode, http.StatusOK)
  230. body := tests.ReadBodyJSON(resp)
  231. assert.Equal(t, body["action"], "compareAndSwap", "")
  232. node := body["node"].(map[string]interface{})
  233. assert.Equal(t, node["value"], "YYY", "")
  234. assert.Equal(t, node["modifiedIndex"], 4, "")
  235. })
  236. }
  237. // Ensures that a key is not set if the previous index does not match.
  238. //
  239. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
  240. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevIndex=10
  241. //
  242. func TestV2SetKeyCASOnIndexFail(t *testing.T) {
  243. tests.RunServer(func(s *server.Server) {
  244. v := url.Values{}
  245. v.Set("value", "XXX")
  246. fullURL := fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar")
  247. resp, _ := tests.PutForm(fullURL, v)
  248. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  249. tests.ReadBody(resp)
  250. v.Set("value", "YYY")
  251. v.Set("prevIndex", "10")
  252. resp, _ = tests.PutForm(fullURL, v)
  253. assert.Equal(t, resp.StatusCode, http.StatusPreconditionFailed)
  254. body := tests.ReadBodyJSON(resp)
  255. assert.Equal(t, body["errorCode"], 101, "")
  256. assert.Equal(t, body["message"], "Compare failed", "")
  257. assert.Equal(t, body["cause"], "[10 != 3]", "")
  258. assert.Equal(t, body["index"], 3, "")
  259. })
  260. }
  261. // Ensures that an error is thrown if an invalid previous index is provided.
  262. //
  263. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevIndex=bad_index
  264. //
  265. func TestV2SetKeyCASWithInvalidIndex(t *testing.T) {
  266. tests.RunServer(func(s *server.Server) {
  267. v := url.Values{}
  268. v.Set("value", "YYY")
  269. v.Set("prevIndex", "bad_index")
  270. resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v)
  271. assert.Equal(t, resp.StatusCode, http.StatusBadRequest)
  272. body := tests.ReadBodyJSON(resp)
  273. assert.Equal(t, body["errorCode"], 203, "")
  274. assert.Equal(t, body["message"], "The given index in POST form is not a number", "")
  275. assert.Equal(t, body["cause"], "CompareAndSwap", "")
  276. })
  277. }
  278. // Ensures that a key is set only if the previous value matches.
  279. //
  280. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
  281. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=XXX
  282. //
  283. func TestV2SetKeyCASOnValueSuccess(t *testing.T) {
  284. tests.RunServer(func(s *server.Server) {
  285. v := url.Values{}
  286. v.Set("value", "XXX")
  287. fullURL := fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar")
  288. resp, _ := tests.PutForm(fullURL, v)
  289. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  290. tests.ReadBody(resp)
  291. v.Set("value", "YYY")
  292. v.Set("prevValue", "XXX")
  293. resp, _ = tests.PutForm(fullURL, v)
  294. assert.Equal(t, resp.StatusCode, http.StatusOK)
  295. body := tests.ReadBodyJSON(resp)
  296. assert.Equal(t, body["action"], "compareAndSwap", "")
  297. node := body["node"].(map[string]interface{})
  298. assert.Equal(t, node["value"], "YYY", "")
  299. assert.Equal(t, node["modifiedIndex"], 4, "")
  300. })
  301. }
  302. // Ensures that a key is not set if the previous value does not match.
  303. //
  304. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
  305. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=AAA
  306. //
  307. func TestV2SetKeyCASOnValueFail(t *testing.T) {
  308. tests.RunServer(func(s *server.Server) {
  309. v := url.Values{}
  310. v.Set("value", "XXX")
  311. fullURL := fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar")
  312. resp, _ := tests.PutForm(fullURL, v)
  313. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  314. tests.ReadBody(resp)
  315. v.Set("value", "YYY")
  316. v.Set("prevValue", "AAA")
  317. resp, _ = tests.PutForm(fullURL, v)
  318. assert.Equal(t, resp.StatusCode, http.StatusPreconditionFailed)
  319. body := tests.ReadBodyJSON(resp)
  320. assert.Equal(t, body["errorCode"], 101, "")
  321. assert.Equal(t, body["message"], "Compare failed", "")
  322. assert.Equal(t, body["cause"], "[AAA != XXX]", "")
  323. assert.Equal(t, body["index"], 3, "")
  324. })
  325. }
  326. // Ensures that an error is returned if a blank prevValue is set.
  327. //
  328. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX -d prevValue=
  329. //
  330. func TestV2SetKeyCASWithMissingValueFails(t *testing.T) {
  331. tests.RunServer(func(s *server.Server) {
  332. v := url.Values{}
  333. v.Set("value", "XXX")
  334. v.Set("prevValue", "")
  335. resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v)
  336. assert.Equal(t, resp.StatusCode, http.StatusBadRequest)
  337. body := tests.ReadBodyJSON(resp)
  338. assert.Equal(t, body["errorCode"], 201, "")
  339. assert.Equal(t, body["message"], "PrevValue is Required in POST form", "")
  340. assert.Equal(t, body["cause"], "CompareAndSwap", "")
  341. })
  342. }
  343. // Ensures that a key is not set if both previous value and index do not match.
  344. //
  345. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
  346. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=AAA -d prevIndex=4
  347. //
  348. func TestV2SetKeyCASOnValueAndIndexFail(t *testing.T) {
  349. tests.RunServer(func(s *server.Server) {
  350. v := url.Values{}
  351. v.Set("value", "XXX")
  352. fullURL := fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar")
  353. resp, _ := tests.PutForm(fullURL, v)
  354. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  355. tests.ReadBody(resp)
  356. v.Set("value", "YYY")
  357. v.Set("prevValue", "AAA")
  358. v.Set("prevIndex", "4")
  359. resp, _ = tests.PutForm(fullURL, v)
  360. assert.Equal(t, resp.StatusCode, http.StatusPreconditionFailed)
  361. body := tests.ReadBodyJSON(resp)
  362. assert.Equal(t, body["errorCode"], 101, "")
  363. assert.Equal(t, body["message"], "Compare failed", "")
  364. assert.Equal(t, body["cause"], "[AAA != XXX] [4 != 3]", "")
  365. assert.Equal(t, body["index"], 3, "")
  366. })
  367. }
  368. // Ensures that a key is not set if previous value match but index does not.
  369. //
  370. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
  371. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=XXX -d prevIndex=4
  372. //
  373. func TestV2SetKeyCASOnValueMatchAndIndexFail(t *testing.T) {
  374. tests.RunServer(func(s *server.Server) {
  375. v := url.Values{}
  376. v.Set("value", "XXX")
  377. fullURL := fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar")
  378. resp, _ := tests.PutForm(fullURL, v)
  379. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  380. tests.ReadBody(resp)
  381. v.Set("value", "YYY")
  382. v.Set("prevValue", "XXX")
  383. v.Set("prevIndex", "4")
  384. resp, _ = tests.PutForm(fullURL, v)
  385. assert.Equal(t, resp.StatusCode, http.StatusPreconditionFailed)
  386. body := tests.ReadBodyJSON(resp)
  387. assert.Equal(t, body["errorCode"], 101, "")
  388. assert.Equal(t, body["message"], "Compare failed", "")
  389. assert.Equal(t, body["cause"], "[4 != 3]", "")
  390. assert.Equal(t, body["index"], 3, "")
  391. })
  392. }
  393. // Ensures that a key is not set if previous index matches but value does not.
  394. //
  395. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=XXX
  396. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=YYY -d prevValue=AAA -d prevIndex=3
  397. //
  398. func TestV2SetKeyCASOnIndexMatchAndValueFail(t *testing.T) {
  399. tests.RunServer(func(s *server.Server) {
  400. v := url.Values{}
  401. v.Set("value", "XXX")
  402. fullURL := fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar")
  403. resp, _ := tests.PutForm(fullURL, v)
  404. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  405. tests.ReadBody(resp)
  406. v.Set("value", "YYY")
  407. v.Set("prevValue", "AAA")
  408. v.Set("prevIndex", "3")
  409. resp, _ = tests.PutForm(fullURL, v)
  410. assert.Equal(t, resp.StatusCode, http.StatusPreconditionFailed)
  411. body := tests.ReadBodyJSON(resp)
  412. assert.Equal(t, body["errorCode"], 101, "")
  413. assert.Equal(t, body["message"], "Compare failed", "")
  414. assert.Equal(t, body["cause"], "[AAA != XXX]", "")
  415. assert.Equal(t, body["index"], 3, "")
  416. })
  417. }
  418. // Ensure that we can set an empty value
  419. //
  420. // $ curl -X PUT localhost:4001/v2/keys/foo/bar -d value=
  421. //
  422. func TestV2SetKeyCASWithEmptyValueSuccess(t *testing.T) {
  423. tests.RunServer(func(s *server.Server) {
  424. v := url.Values{}
  425. v.Set("value", "")
  426. resp, _ := tests.PutForm(fmt.Sprintf("%s%s", s.URL(), "/v2/keys/foo/bar"), v)
  427. assert.Equal(t, resp.StatusCode, http.StatusCreated)
  428. body := tests.ReadBody(resp)
  429. assert.Equal(t, string(body), `{"action":"set","node":{"key":"/foo/bar","value":"","modifiedIndex":3,"createdIndex":3}}`)
  430. })
  431. }