diff --git a/raft/node_test.go b/raft/node_test.go index 313d852cc..240bccf34 100644 --- a/raft/node_test.go +++ b/raft/node_test.go @@ -142,6 +142,47 @@ func TestNodePropose(t *testing.T) { } } +// TestNodeProposeConfig ensures that node.ProposeConfChange sends the given configuration proposal +// to the underlying raft. +func TestNodeProposeConfig(t *testing.T) { + msgs := []raftpb.Message{} + appendStep := func(r *raft, m raftpb.Message) { + msgs = append(msgs, m) + } + + n := newNode() + r := newRaft(1, []uint64{1}, 10, 1) + go n.run(r) + n.Campaign(context.TODO()) + for { + rd := <-n.Ready() + // change the step function to appendStep until this raft becomes leader + if rd.SoftState.Lead == r.id { + r.step = appendStep + n.Advance() + break + } + n.Advance() + } + cc := raftpb.ConfChange{Type: raftpb.ConfChangeAddNode, NodeID: 1} + ccdata, err := cc.Marshal() + if err != nil { + t.Fatal(err) + } + n.ProposeConfChange(context.TODO(), cc) + n.Stop() + + if len(msgs) != 1 { + t.Fatalf("len(msgs) = %d, want %d", len(msgs), 1) + } + if msgs[0].Type != raftpb.MsgProp { + t.Errorf("msg type = %d, want %d", msgs[0].Type, raftpb.MsgProp) + } + if !reflect.DeepEqual(msgs[0].Entries[0].Data, ccdata) { + t.Errorf("data = %v, want %v", msgs[0].Entries[0].Data, ccdata) + } +} + // 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.