|
|
@@ -34,18 +34,14 @@ import (
|
|
|
// TestPipelineSend tests that pipeline could send data using roundtripper
|
|
|
// and increase success count in stats.
|
|
|
func TestPipelineSend(t *testing.T) {
|
|
|
- tr := &roundTripperRecorder{}
|
|
|
+ tr := &roundTripperRecorder{rec: testutil.NewRecorderStream()}
|
|
|
picker := mustNewURLPicker(t, []string{"http://localhost:2380"})
|
|
|
tp := &Transport{pipelineRt: tr}
|
|
|
p := startTestPipeline(tp, picker)
|
|
|
|
|
|
p.msgc <- raftpb.Message{Type: raftpb.MsgApp}
|
|
|
- testutil.WaitSchedule()
|
|
|
+ tr.rec.Wait(1)
|
|
|
p.stop()
|
|
|
-
|
|
|
- if tr.Request() == nil {
|
|
|
- t.Errorf("sender fails to post the data")
|
|
|
- }
|
|
|
if p.followerStats.Counts.Success != 1 {
|
|
|
t.Errorf("success = %d, want 1", p.followerStats.Counts.Success)
|
|
|
}
|
|
|
@@ -79,15 +75,12 @@ func TestPipelineExceedMaximumServing(t *testing.T) {
|
|
|
|
|
|
// keep the sender busy and make the buffer full
|
|
|
// nothing can go out as we block the sender
|
|
|
- testutil.WaitSchedule()
|
|
|
for i := 0; i < connPerPipeline+pipelineBufSize; i++ {
|
|
|
select {
|
|
|
case p.msgc <- raftpb.Message{}:
|
|
|
- default:
|
|
|
+ case <-time.After(10 * time.Millisecond):
|
|
|
t.Errorf("failed to send out message")
|
|
|
}
|
|
|
- // force the sender to grab data
|
|
|
- testutil.WaitSchedule()
|
|
|
}
|
|
|
|
|
|
// try to send a data when we are sure the buffer is full
|
|
|
@@ -99,12 +92,11 @@ func TestPipelineExceedMaximumServing(t *testing.T) {
|
|
|
|
|
|
// unblock the senders and force them to send out the data
|
|
|
tr.unblock()
|
|
|
- testutil.WaitSchedule()
|
|
|
|
|
|
// It could send new data after previous ones succeed
|
|
|
select {
|
|
|
case p.msgc <- raftpb.Message{}:
|
|
|
- default:
|
|
|
+ case <-time.After(10 * time.Millisecond):
|
|
|
t.Errorf("failed to send out message")
|
|
|
}
|
|
|
}
|
|
|
@@ -113,11 +105,16 @@ func TestPipelineExceedMaximumServing(t *testing.T) {
|
|
|
// it increases fail count in stats.
|
|
|
func TestPipelineSendFailed(t *testing.T) {
|
|
|
picker := mustNewURLPicker(t, []string{"http://localhost:2380"})
|
|
|
- tp := &Transport{pipelineRt: newRespRoundTripper(0, errors.New("blah"))}
|
|
|
+ rt := newRespRoundTripper(0, errors.New("blah"))
|
|
|
+ rt.rec = testutil.NewRecorderStream()
|
|
|
+ tp := &Transport{pipelineRt: rt}
|
|
|
p := startTestPipeline(tp, picker)
|
|
|
|
|
|
p.msgc <- raftpb.Message{Type: raftpb.MsgApp}
|
|
|
- testutil.WaitSchedule()
|
|
|
+ if _, err := rt.rec.Wait(1); err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
+
|
|
|
p.stop()
|
|
|
|
|
|
if p.followerStats.Counts.Fail != 1 {
|
|
|
@@ -126,34 +123,40 @@ func TestPipelineSendFailed(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
func TestPipelinePost(t *testing.T) {
|
|
|
- tr := &roundTripperRecorder{}
|
|
|
+ tr := &roundTripperRecorder{rec: &testutil.RecorderBuffered{}}
|
|
|
picker := mustNewURLPicker(t, []string{"http://localhost:2380"})
|
|
|
tp := &Transport{ClusterID: types.ID(1), pipelineRt: tr}
|
|
|
p := startTestPipeline(tp, picker)
|
|
|
if err := p.post([]byte("some data")); err != nil {
|
|
|
t.Fatalf("unexpected post error: %v", err)
|
|
|
}
|
|
|
+ act, err := tr.rec.Wait(1)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal(err)
|
|
|
+ }
|
|
|
p.stop()
|
|
|
|
|
|
- if g := tr.Request().Method; g != "POST" {
|
|
|
+ req := act[0].Params[0].(*http.Request)
|
|
|
+
|
|
|
+ if g := req.Method; g != "POST" {
|
|
|
t.Errorf("method = %s, want %s", g, "POST")
|
|
|
}
|
|
|
- if g := tr.Request().URL.String(); g != "http://localhost:2380/raft" {
|
|
|
+ if g := req.URL.String(); g != "http://localhost:2380/raft" {
|
|
|
t.Errorf("url = %s, want %s", g, "http://localhost:2380/raft")
|
|
|
}
|
|
|
- if g := tr.Request().Header.Get("Content-Type"); g != "application/protobuf" {
|
|
|
+ if g := req.Header.Get("Content-Type"); g != "application/protobuf" {
|
|
|
t.Errorf("content type = %s, want %s", g, "application/protobuf")
|
|
|
}
|
|
|
- if g := tr.Request().Header.Get("X-Server-Version"); g != version.Version {
|
|
|
+ if g := req.Header.Get("X-Server-Version"); g != version.Version {
|
|
|
t.Errorf("version = %s, want %s", g, version.Version)
|
|
|
}
|
|
|
- if g := tr.Request().Header.Get("X-Min-Cluster-Version"); g != version.MinClusterVersion {
|
|
|
+ if g := req.Header.Get("X-Min-Cluster-Version"); g != version.MinClusterVersion {
|
|
|
t.Errorf("min version = %s, want %s", g, version.MinClusterVersion)
|
|
|
}
|
|
|
- if g := tr.Request().Header.Get("X-Etcd-Cluster-ID"); g != "1" {
|
|
|
+ if g := req.Header.Get("X-Etcd-Cluster-ID"); g != "1" {
|
|
|
t.Errorf("cluster id = %s, want %s", g, "1")
|
|
|
}
|
|
|
- b, err := ioutil.ReadAll(tr.Request().Body)
|
|
|
+ b, err := ioutil.ReadAll(req.Body)
|
|
|
if err != nil {
|
|
|
t.Fatalf("unexpected ReadAll error: %v", err)
|
|
|
}
|
|
|
@@ -278,21 +281,15 @@ func (t *respRoundTripper) RoundTrip(req *http.Request) (*http.Response, error)
|
|
|
}
|
|
|
|
|
|
type roundTripperRecorder struct {
|
|
|
- req *http.Request
|
|
|
- sync.Mutex
|
|
|
+ rec testutil.Recorder
|
|
|
}
|
|
|
|
|
|
func (t *roundTripperRecorder) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
|
- t.Lock()
|
|
|
- defer t.Unlock()
|
|
|
- t.req = req
|
|
|
+ if t.rec != nil {
|
|
|
+ t.rec.Record(testutil.Action{Name: "req", Params: []interface{}{req}})
|
|
|
+ }
|
|
|
return &http.Response{StatusCode: http.StatusNoContent, Body: &nopReadCloser{}}, nil
|
|
|
}
|
|
|
-func (t *roundTripperRecorder) Request() *http.Request {
|
|
|
- t.Lock()
|
|
|
- defer t.Unlock()
|
|
|
- return t.req
|
|
|
-}
|
|
|
|
|
|
type nopReadCloser struct{}
|
|
|
|