Browse Source

Merge pull request #1158 from jonboulle/1158_unset_ttl

"unsetting" a TTL fails
Jonathan Boulle 11 years ago
parent
commit
98561f6b5d
2 changed files with 39 additions and 5 deletions
  1. 8 5
      etcdserver/etcdhttp/http.go
  2. 31 0
      etcdserver/etcdhttp/http_test.go

+ 8 - 5
etcdserver/etcdhttp/http.go

@@ -178,11 +178,14 @@ func parseRequest(r *http.Request, id int64) (etcdserverpb.Request, error) {
 			`invalid value for "waitIndex"`,
 		)
 	}
-	if ttl, err = getUint64(r.Form, "ttl"); err != nil {
-		return emptyReq, etcdErr.NewRequestError(
-			etcdErr.EcodeTTLNaN,
-			`invalid value for "ttl"`,
-		)
+	// An empty TTL value is equivalent to it being unset entirely
+	if len(r.FormValue("ttl")) > 0 {
+		if ttl, err = getUint64(r.Form, "ttl"); err != nil {
+			return emptyReq, etcdErr.NewRequestError(
+				etcdErr.EcodeTTLNaN,
+				`invalid value for "ttl"`,
+			)
+		}
 	}
 
 	var rec, sort, wait, stream bool

+ 31 - 0
etcdserver/etcdhttp/http_test.go

@@ -285,6 +285,26 @@ func TestGoodParseRequest(t *testing.T) {
 				Path:   "/foo",
 			},
 		},
+		{
+			// zero TTL specified
+			mustNewRequest(t, "foo?ttl=0"),
+			etcdserverpb.Request{
+				Id:         1234,
+				Method:     "GET",
+				Path:       "/foo",
+				Expiration: 0,
+			},
+		},
+		{
+			// empty TTL specified
+			mustNewRequest(t, "foo?ttl="),
+			etcdserverpb.Request{
+				Id:         1234,
+				Method:     "GET",
+				Path:       "/foo",
+				Expiration: 0,
+			},
+		},
 		{
 			// prevExist should be non-null if specified
 			mustNewForm(
@@ -374,6 +394,17 @@ func TestGoodParseRequest(t *testing.T) {
 			t.Errorf("#%d: request=%#v, want %#v", i, got, tt.w)
 		}
 	}
+
+	// Test TTL separately until we don't rely on the time module...
+	now := time.Now().UnixNano()
+	req := mustNewForm(t, "foo", url.Values{"ttl": []string{"100"}})
+	got, err := parseRequest(req, 1234)
+	if err != nil {
+		t.Fatalf("err = %v, want nil", err)
+	}
+	if got.Expiration <= now {
+		t.Fatalf("expiration = %v, wanted > %v", got.Expiration, now)
+	}
 }
 
 // eventingWatcher immediately returns a simple event of the given action on its channel