mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
etcdserver/etcdhttp: add tests for serveKeys
This commit is contained in:
parent
43acdef660
commit
27cf7747ea
@ -246,10 +246,10 @@ func parseRequest(r *http.Request, id int64) (etcdserverpb.Request, error) {
|
|||||||
rr.PrevExists = pe
|
rr.PrevExists = pe
|
||||||
}
|
}
|
||||||
|
|
||||||
if ttl > 0 {
|
|
||||||
expr := time.Duration(ttl) * time.Second
|
|
||||||
// TODO(jonboulle): use fake clock instead of time module
|
// TODO(jonboulle): use fake clock instead of time module
|
||||||
// https://github.com/coreos/etcd/issues/1021
|
// https://github.com/coreos/etcd/issues/1021
|
||||||
|
if ttl > 0 {
|
||||||
|
expr := time.Duration(ttl) * time.Second
|
||||||
rr.Expiration = time.Now().Add(expr).UnixNano()
|
rr.Expiration = time.Now().Add(expr).UnixNano()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package etcdhttp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -33,9 +34,10 @@ func mustNewURL(t *testing.T, s string) *url.URL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mustNewRequest takes a path, appends it to the standard keysPrefix, and constructs
|
// mustNewRequest takes a path, appends it to the standard keysPrefix, and constructs
|
||||||
// an *http.Request referencing the resulting URL
|
// a GET *http.Request referencing the resulting URL
|
||||||
func mustNewRequest(t *testing.T, p string) *http.Request {
|
func mustNewRequest(t *testing.T, p string) *http.Request {
|
||||||
return &http.Request{
|
return &http.Request{
|
||||||
|
Method: "GET",
|
||||||
URL: mustNewURL(t, path.Join(keysPrefix, p)),
|
URL: mustNewURL(t, path.Join(keysPrefix, p)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,6 +194,7 @@ func TestGoodParseRequest(t *testing.T) {
|
|||||||
mustNewRequest(t, "foo"),
|
mustNewRequest(t, "foo"),
|
||||||
etcdserverpb.Request{
|
etcdserverpb.Request{
|
||||||
Id: 1234,
|
Id: 1234,
|
||||||
|
Method: "GET",
|
||||||
Path: "/foo",
|
Path: "/foo",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -782,21 +785,65 @@ func mustMarshalMsg(t *testing.T, m raftpb.Message) []byte {
|
|||||||
|
|
||||||
func TestServeRaft(t *testing.T) {
|
func TestServeRaft(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
reqBody io.Reader
|
method string
|
||||||
|
body io.Reader
|
||||||
serverErr error
|
serverErr error
|
||||||
|
|
||||||
wcode int
|
wcode int
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
// bad method
|
||||||
|
"GET",
|
||||||
|
bytes.NewReader(
|
||||||
|
mustMarshalMsg(
|
||||||
|
t,
|
||||||
|
raftpb.Message{},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
nil,
|
||||||
|
http.StatusMethodNotAllowed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// bad method
|
||||||
|
"PUT",
|
||||||
|
bytes.NewReader(
|
||||||
|
mustMarshalMsg(
|
||||||
|
t,
|
||||||
|
raftpb.Message{},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
nil,
|
||||||
|
http.StatusMethodNotAllowed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// bad method
|
||||||
|
"DELETE",
|
||||||
|
bytes.NewReader(
|
||||||
|
mustMarshalMsg(
|
||||||
|
t,
|
||||||
|
raftpb.Message{},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
nil,
|
||||||
|
http.StatusMethodNotAllowed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// bad request body
|
||||||
|
"POST",
|
||||||
&errReader{},
|
&errReader{},
|
||||||
nil,
|
nil,
|
||||||
http.StatusBadRequest,
|
http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// bad request JSON
|
||||||
|
"POST",
|
||||||
strings.NewReader("malformed garbage"),
|
strings.NewReader("malformed garbage"),
|
||||||
nil,
|
nil,
|
||||||
http.StatusBadRequest,
|
http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// good request, etcdserver.Server error
|
||||||
|
"POST",
|
||||||
bytes.NewReader(
|
bytes.NewReader(
|
||||||
mustMarshalMsg(
|
mustMarshalMsg(
|
||||||
t,
|
t,
|
||||||
@ -807,6 +854,8 @@ func TestServeRaft(t *testing.T) {
|
|||||||
http.StatusInternalServerError,
|
http.StatusInternalServerError,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// good request
|
||||||
|
"POST",
|
||||||
bytes.NewReader(
|
bytes.NewReader(
|
||||||
mustMarshalMsg(
|
mustMarshalMsg(
|
||||||
t,
|
t,
|
||||||
@ -818,7 +867,7 @@ func TestServeRaft(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, tt := range testCases {
|
for i, tt := range testCases {
|
||||||
req, err := http.NewRequest("POST", "foo", tt.reqBody)
|
req, err := http.NewRequest(tt.method, "foo", tt.body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("#%d: could not create request: %#v", i, err)
|
t.Fatalf("#%d: could not create request: %#v", i, err)
|
||||||
}
|
}
|
||||||
@ -834,3 +883,198 @@ func TestServeRaft(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resServer implements the etcd.Server interface for testing.
|
||||||
|
// It returns the given responsefrom any Do calls, and nil error
|
||||||
|
type resServer struct {
|
||||||
|
res etcdserver.Response
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *resServer) Do(ctx context.Context, r etcdserverpb.Request) (etcdserver.Response, error) {
|
||||||
|
return rs.res, nil
|
||||||
|
}
|
||||||
|
func (rs *resServer) Process(ctx context.Context, m raftpb.Message) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (rs *resServer) Start() {}
|
||||||
|
func (rs *resServer) Stop() {}
|
||||||
|
|
||||||
|
func mustMarshalEvent(t *testing.T, ev *store.Event) string {
|
||||||
|
b := new(bytes.Buffer)
|
||||||
|
if err := json.NewEncoder(b).Encode(ev); err != nil {
|
||||||
|
t.Fatalf("error marshalling event %#v: #v", ev, err)
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBadServeKeys(t *testing.T) {
|
||||||
|
testBadCases := []struct {
|
||||||
|
req *http.Request
|
||||||
|
server etcdserver.Server
|
||||||
|
|
||||||
|
wcode int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// bad method
|
||||||
|
&http.Request{
|
||||||
|
Method: "CONNECT",
|
||||||
|
},
|
||||||
|
&resServer{},
|
||||||
|
|
||||||
|
http.StatusMethodNotAllowed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// bad method
|
||||||
|
&http.Request{
|
||||||
|
Method: "TRACE",
|
||||||
|
},
|
||||||
|
&resServer{},
|
||||||
|
|
||||||
|
http.StatusMethodNotAllowed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// parseRequest error
|
||||||
|
&http.Request{
|
||||||
|
Body: nil,
|
||||||
|
Method: "PUT",
|
||||||
|
},
|
||||||
|
&resServer{},
|
||||||
|
|
||||||
|
http.StatusBadRequest,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// etcdserver.Server error
|
||||||
|
mustNewRequest(t, "foo"),
|
||||||
|
&errServer{
|
||||||
|
errors.New("blah"),
|
||||||
|
},
|
||||||
|
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// timeout waiting for event (watcher never returns)
|
||||||
|
mustNewRequest(t, "foo"),
|
||||||
|
&resServer{
|
||||||
|
etcdserver.Response{
|
||||||
|
Watcher: &dummyWatcher{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
http.StatusGatewayTimeout,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// non-event/watcher response from etcdserver.Server
|
||||||
|
mustNewRequest(t, "foo"),
|
||||||
|
&resServer{
|
||||||
|
etcdserver.Response{},
|
||||||
|
},
|
||||||
|
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i, tt := range testBadCases {
|
||||||
|
h := &serverHandler{
|
||||||
|
timeout: 0, // context times out immediately
|
||||||
|
server: tt.server,
|
||||||
|
peers: nil,
|
||||||
|
}
|
||||||
|
rw := httptest.NewRecorder()
|
||||||
|
h.serveKeys(rw, tt.req)
|
||||||
|
if rw.Code != tt.wcode {
|
||||||
|
t.Errorf("#%d: got code=%d, want %d", i, rw.Code, tt.wcode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServeKeysEvent(t *testing.T) {
|
||||||
|
req := mustNewRequest(t, "foo")
|
||||||
|
server := &resServer{
|
||||||
|
etcdserver.Response{
|
||||||
|
Event: &store.Event{
|
||||||
|
Action: store.Get,
|
||||||
|
Node: &store.NodeExtern{
|
||||||
|
Key: "foo",
|
||||||
|
ModifiedIndex: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
h := &serverHandler{
|
||||||
|
timeout: time.Hour,
|
||||||
|
server: server,
|
||||||
|
peers: nil,
|
||||||
|
}
|
||||||
|
rw := httptest.NewRecorder()
|
||||||
|
|
||||||
|
h.serveKeys(rw, req)
|
||||||
|
|
||||||
|
wcode := http.StatusOK
|
||||||
|
wbody := mustMarshalEvent(
|
||||||
|
t,
|
||||||
|
&store.Event{
|
||||||
|
Action: store.Get,
|
||||||
|
Node: &store.NodeExtern{
|
||||||
|
Key: "foo",
|
||||||
|
ModifiedIndex: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if rw.Code != wcode {
|
||||||
|
t.Errorf("got code=%d, want %d", rw.Code, wcode)
|
||||||
|
}
|
||||||
|
g := rw.Body.String()
|
||||||
|
if g != wbody {
|
||||||
|
t.Errorf("got body=%#v, want %#v", g, wbody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServeKeysWatch(t *testing.T) {
|
||||||
|
req := mustNewRequest(t, "/foo/bar")
|
||||||
|
ec := make(chan *store.Event)
|
||||||
|
dw := &dummyWatcher{
|
||||||
|
echan: ec,
|
||||||
|
}
|
||||||
|
server := &resServer{
|
||||||
|
etcdserver.Response{
|
||||||
|
Watcher: dw,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
h := &serverHandler{
|
||||||
|
timeout: time.Hour,
|
||||||
|
server: server,
|
||||||
|
peers: nil,
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
ec <- &store.Event{
|
||||||
|
Action: store.Get,
|
||||||
|
Node: &store.NodeExtern{
|
||||||
|
Key: "/foo/bar",
|
||||||
|
ModifiedIndex: 12345,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
rw := httptest.NewRecorder()
|
||||||
|
|
||||||
|
h.serveKeys(rw, req)
|
||||||
|
|
||||||
|
wcode := http.StatusOK
|
||||||
|
wbody := mustMarshalEvent(
|
||||||
|
t,
|
||||||
|
&store.Event{
|
||||||
|
Action: store.Get,
|
||||||
|
Node: &store.NodeExtern{
|
||||||
|
Key: "/foo/bar",
|
||||||
|
ModifiedIndex: 12345,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if rw.Code != wcode {
|
||||||
|
t.Errorf("got code=%d, want %d", rw.Code, wcode)
|
||||||
|
}
|
||||||
|
g := rw.Body.String()
|
||||||
|
if g != wbody {
|
||||||
|
t.Errorf("got body=%#v, want %#v", g, wbody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user