github.com/ghodss/etcd@v0.3.1-0.20140417172404-cc329bfa55cb/server/v2/tests/put_handler_test.go (about)

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