func TestNode(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() wants := []Ready{ { SoftState: &SoftState{Lead: 1, RaftState: StateLeader}, HardState: raftpb.HardState{Term: 1, Commit: 1}, Entries: []raftpb.Entry{{}, {Term: 1, Index: 1}}, CommittedEntries: []raftpb.Entry{{Term: 1, Index: 1}}, }, { HardState: raftpb.HardState{Term: 1, Commit: 2}, Entries: []raftpb.Entry{{Term: 1, Index: 2, Data: []byte("foo")}}, CommittedEntries: []raftpb.Entry{{Term: 1, Index: 2, Data: []byte("foo")}}, }, } n := Start(1, []int64{1}, 0, 0) n.Campaign(ctx) if g := <-n.Ready(); !reflect.DeepEqual(g, wants[0]) { t.Errorf("#%d: g = %+v,\n w %+v", 1, g, wants[0]) } n.Propose(ctx, []byte("foo")) if g := <-n.Ready(); !reflect.DeepEqual(g, wants[1]) { t.Errorf("#%d: g = %+v,\n w %+v", 2, g, wants[1]) } select { case rd := <-n.Ready(): t.Errorf("unexpected Ready: %+v", rd) default: } }
func TestHTTPClientDoCancelContextWaitForRoundTrip(t *testing.T) { tr := newFakeTransport() c := &httpClient{transport: tr} donechan := make(chan struct{}) ctx, cancel := context.WithCancel(context.Background()) go func() { c.do(ctx, &fakeAction{}) close(donechan) }() // This should call CancelRequest and begin the cancellation process cancel() select { case <-donechan: t.Fatalf("httpClient.do should not have exited yet") default: } tr.finishCancel <- struct{}{} select { case <-donechan: //expected behavior return case <-time.After(time.Second): t.Fatalf("httpClient.do did not exit within 1s") } }
func TestSet(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() st := store.New() n := raft.Start(1, []int64{1}, 0, 0) n.Campaign(ctx) srv := &etcdserver.Server{ Node: n, Store: st, Send: etcdserver.SendFunc(nopSend), Save: func(st raftpb.State, ents []raftpb.Entry) {}, } etcdserver.Start(srv) defer srv.Stop() h := Handler{ Timeout: time.Hour, Server: srv, } s := httptest.NewServer(h) defer s.Close() resp, err := http.PostForm(s.URL+"/v2/keys/foo", url.Values{"value": {"bar"}}) if err != nil { t.Fatal(err) } if resp.StatusCode != 201 { t.Errorf("StatusCode = %d, expected %d", 201, resp.StatusCode) } g := new(store.Event) if err := json.NewDecoder(resp.Body).Decode(&g); err != nil { t.Fatal(err) } w := &store.NodeExtern{ Key: "/foo/1", Value: stringp("bar"), ModifiedIndex: 1, CreatedIndex: 1, } if !reflect.DeepEqual(g.Node, w) { t.Errorf("g = %+v, want %+v", g.Node, w) } }
// Cancel and Stop should unblock Step() func TestNodeStepUnblock(t *testing.T) { // a node without buffer to block step n := &Node{ propc: make(chan raftpb.Message), done: make(chan struct{}), } ctx, cancel := context.WithCancel(context.Background()) stopFunc := func() { close(n.done) } tests := []struct { unblock func() werr error }{ {stopFunc, ErrStopped}, {cancel, context.Canceled}, } for i, tt := range tests { errc := make(chan error, 1) go func() { err := n.Step(ctx, raftpb.Message{Type: msgProp}) errc <- err }() tt.unblock() select { case err := <-errc: if err != tt.werr { t.Errorf("#%d: err = %v, want %v", err, tt.werr) } //clean up side-effect if ctx.Err() != nil { ctx = context.TODO() } select { case <-n.done: n.done = make(chan struct{}) default: } case <-time.After(time.Millisecond * 100): t.Errorf("#%d: failed to unblock step", i) } } }
func TestWaitForEventCancelledContext(t *testing.T) { cctx, cancel := context.WithCancel(context.Background()) dw := &dummyWatcher{} w := httptest.NewRecorder() var wg sync.WaitGroup var ev *store.Event var err error wg.Add(1) go func() { ev, err = waitForEvent(cctx, w, dw) wg.Done() }() cancel() wg.Wait() if ev != nil { t.Fatalf("non-nil Event returned with cancelled context: %v", ev) } if err == nil { t.Fatalf("nil err returned with cancelled context!") } }
func testServer(t *testing.T, ns int64) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() ss := make([]*Server, ns) send := func(msgs []raftpb.Message) { for _, m := range msgs { t.Logf("m = %+v\n", m) ss[m.To-1].Node.Step(ctx, m) } } peers := make([]int64, ns) for i := int64(0); i < ns; i++ { peers[i] = i + 1 } for i := int64(0); i < ns; i++ { id := i + 1 n := raft.Start(id, peers, 10, 1) tk := time.NewTicker(10 * time.Millisecond) defer tk.Stop() srv := &Server{ Node: n, Store: store.New(), Send: send, Save: func(_ raftpb.State, _ []raftpb.Entry) {}, Ticker: tk.C, } Start(srv) // TODO(xiangli): randomize election timeout // then remove this sleep. time.Sleep(1 * time.Millisecond) ss[i] = srv } for i := 1; i <= 10; i++ { r := pb.Request{ Method: "PUT", Id: int64(i), Path: "/foo", Val: "bar", } j := rand.Intn(len(ss)) t.Logf("ss = %d", j) resp, err := ss[j].Do(ctx, r) if err != nil { t.Fatal(err) } g, w := resp.Event.Node, &store.NodeExtern{ Key: "/foo", ModifiedIndex: uint64(i), CreatedIndex: uint64(i), Value: stringp("bar"), } if !reflect.DeepEqual(g, w) { t.Error("value:", *g.Value) t.Errorf("g = %+v, w %+v", g, w) } } time.Sleep(10 * time.Millisecond) var last interface{} for i, sv := range ss { sv.Stop() g, _ := sv.Store.Get("/", true, true) if last != nil && !reflect.DeepEqual(last, g) { t.Errorf("server %d: Root = %#v, want %#v", i, g, last) } last = g } }