// TestBlockProposal ensures that node will block proposal when it does not // know who is the current leader; node will accept proposal when it knows // who is the current leader. func TestBlockProposal(t *testing.T) { n := newNode() r := newRaft(1, []int64{1}, 10, 1) go n.run(r) defer n.Stop() errc := make(chan error, 1) go func() { errc <- n.Propose(context.TODO(), []byte("somedata")) }() forceGosched() select { case err := <-errc: t.Errorf("err = %v, want blocking", err) default: } n.Campaign(context.TODO()) forceGosched() select { case err := <-errc: if err != nil { t.Errorf("err = %v, want %v", err, nil) } default: t.Errorf("blocking proposal, want unblocking") } }
func (h serverHandler) serveRaft(w http.ResponseWriter, r *http.Request) { if !allowMethod(w, r.Method, "POST") { return } b, err := ioutil.ReadAll(r.Body) if err != nil { log.Println("etcdhttp: error reading raft message:", err) http.Error(w, "error reading raft message", http.StatusBadRequest) return } var m raftpb.Message if err := m.Unmarshal(b); err != nil { log.Println("etcdhttp: error unmarshaling raft message:", err) http.Error(w, "error unmarshaling raft message", http.StatusBadRequest) return } log.Printf("etcdhttp: raft recv message from %#x: %+v", m.From, m) if err := h.server.Process(context.TODO(), m); err != nil { log.Println("etcdhttp: error processing raft message:", err) writeError(w, err) return } w.WriteHeader(http.StatusNoContent) }
// TestNodeStep ensures that node.Step sends msgProp to propc chan // and other kinds of messages to recvc chan. func TestNodeStep(t *testing.T) { for i := range mtmap { n := &node{ propc: make(chan raftpb.Message, 1), recvc: make(chan raftpb.Message, 1), } msgt := int64(i) n.Step(context.TODO(), raftpb.Message{Type: msgt}) // Proposal goes to proc chan. Others go to recvc chan. if int64(i) == msgProp { select { case <-n.propc: default: t.Errorf("%d: cannot receive %s on propc chan", i, mtmap[i]) } } else { if msgt == msgBeat || msgt == msgHup { select { case <-n.recvc: t.Errorf("%d: step should ignore msgHub/msgBeat", i, mtmap[i]) default: } } else { select { case <-n.recvc: default: t.Errorf("%d: cannot receive %s on recvc chan", i, mtmap[i]) } } } } }
// 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) } } }
// TestNodeStep ensures that node.Step sends msgProp to propc chan // and other kinds of messages to recvc chan. func TestNodeStep(t *testing.T) { for i := range mtmap { n := &Node{ propc: make(chan raftpb.Message, 1), recvc: make(chan raftpb.Message, 1), } n.Step(context.TODO(), raftpb.Message{Type: int64(i)}) // Proposal goes to proc chan. Others go to recvc chan. if int64(i) == msgProp { select { case <-n.propc: default: t.Errorf("%d: cannot receive %s on propc chan", i, mtmap[i]) } } else { select { case <-n.recvc: default: t.Errorf("%d: cannot receive %s on recvc chan", i, mtmap[i]) } } } }