etcdserver/etcdhttp: switch to using fake clock

release-2.0
Jonathan Boulle 2014-10-16 15:50:06 -07:00
parent 3134658ded
commit ec18e46641
2 changed files with 29 additions and 28 deletions

View File

@ -13,6 +13,7 @@ import (
"time"
"github.com/coreos/etcd/Godeps/_workspace/src/code.google.com/p/go.net/context"
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/jonboulle/clockwork"
etcdErr "github.com/coreos/etcd/error"
"github.com/coreos/etcd/etcdserver"
"github.com/coreos/etcd/etcdserver/etcdserverpb"
@ -89,7 +90,7 @@ func (h serverHandler) serveKeys(w http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(context.Background(), h.timeout)
defer cancel()
rr, err := parseRequest(r, etcdserver.GenID())
rr, err := parseRequest(r, etcdserver.GenID(), clockwork.NewRealClock())
if err != nil {
writeError(w, err)
return
@ -225,7 +226,7 @@ func (h serverHandler) serveRaft(w http.ResponseWriter, r *http.Request) {
// parseRequest converts a received http.Request to a server Request,
// performing validation of supplied fields as appropriate.
// If any validation fails, an empty Request and non-nil error is returned.
func parseRequest(r *http.Request, id uint64) (etcdserverpb.Request, error) {
func parseRequest(r *http.Request, id uint64, clock clockwork.Clock) (etcdserverpb.Request, error) {
emptyReq := etcdserverpb.Request{}
err := r.ParseForm()
@ -354,11 +355,9 @@ func parseRequest(r *http.Request, id uint64) (etcdserverpb.Request, error) {
}
// Null TTL is equivalent to unset Expiration
// TODO(jonboulle): use fake clock instead of time module
// https://github.com/coreos/etcd/issues/1021
if ttl != nil {
expr := time.Duration(*ttl) * time.Second
rr.Expiration = time.Now().Add(expr).UnixNano()
rr.Expiration = clock.Now().Add(expr).UnixNano()
}
return rr, nil

View File

@ -16,6 +16,7 @@ import (
"time"
"github.com/coreos/etcd/Godeps/_workspace/src/code.google.com/p/go.net/context"
"github.com/coreos/etcd/Godeps/_workspace/src/github.com/jonboulle/clockwork"
etcdErr "github.com/coreos/etcd/error"
"github.com/coreos/etcd/etcdserver"
"github.com/coreos/etcd/etcdserver/etcdserverpb"
@ -194,7 +195,7 @@ func TestBadParseRequest(t *testing.T) {
},
}
for i, tt := range tests {
got, err := parseRequest(tt.in, 1234)
got, err := parseRequest(tt.in, 1234, clockwork.NewFakeClock())
if err == nil {
t.Errorf("#%d: unexpected nil error!", i)
continue
@ -215,6 +216,8 @@ func TestBadParseRequest(t *testing.T) {
}
func TestGoodParseRequest(t *testing.T) {
fc := clockwork.NewFakeClock()
fc.Tick(1111)
tests := []struct {
in *http.Request
w etcdserverpb.Request
@ -304,6 +307,26 @@ func TestGoodParseRequest(t *testing.T) {
Expiration: 0,
},
},
{
// non-empty TTL specified
mustNewRequest(t, "foo?ttl=5678"),
etcdserverpb.Request{
ID: 1234,
Method: "GET",
Path: "/foo",
Expiration: fc.Now().Add(5678 * time.Second).UnixNano(),
},
},
{
// zero TTL specified
mustNewRequest(t, "foo?ttl=0"),
etcdserverpb.Request{
ID: 1234,
Method: "GET",
Path: "/foo",
Expiration: fc.Now().UnixNano(),
},
},
{
// dir specified
mustNewRequest(t, "foo?dir=true"),
@ -405,7 +428,7 @@ func TestGoodParseRequest(t *testing.T) {
}
for i, tt := range tests {
got, err := parseRequest(tt.in, 1234)
got, err := parseRequest(tt.in, 1234, fc)
if err != nil {
t.Errorf("#%d: err = %v, want %v", i, err, nil)
}
@ -413,27 +436,6 @@ 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)
}
// ensure TTL=0 results in an expiration time
req = mustNewForm(t, "foo", url.Values{"ttl": []string{"0"}})
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