go.etcd.io/etcd@v3.3.27+incompatible/raft/node_test.go (about)

     1  // Copyright 2015 The etcd Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package raft
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"reflect"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/coreos/etcd/pkg/testutil"
    25  	"github.com/coreos/etcd/raft/raftpb"
    26  )
    27  
    28  // TestNodeStep ensures that node.Step sends msgProp to propc chan
    29  // and other kinds of messages to recvc chan.
    30  func TestNodeStep(t *testing.T) {
    31  	for i, msgn := range raftpb.MessageType_name {
    32  		n := &node{
    33  			propc: make(chan raftpb.Message, 1),
    34  			recvc: make(chan raftpb.Message, 1),
    35  		}
    36  		msgt := raftpb.MessageType(i)
    37  		n.Step(context.TODO(), raftpb.Message{Type: msgt})
    38  		// Proposal goes to proc chan. Others go to recvc chan.
    39  		if msgt == raftpb.MsgProp {
    40  			select {
    41  			case <-n.propc:
    42  			default:
    43  				t.Errorf("%d: cannot receive %s on propc chan", msgt, msgn)
    44  			}
    45  		} else {
    46  			if IsLocalMsg(msgt) {
    47  				select {
    48  				case <-n.recvc:
    49  					t.Errorf("%d: step should ignore %s", msgt, msgn)
    50  				default:
    51  				}
    52  			} else {
    53  				select {
    54  				case <-n.recvc:
    55  				default:
    56  					t.Errorf("%d: cannot receive %s on recvc chan", msgt, msgn)
    57  				}
    58  			}
    59  		}
    60  	}
    61  }
    62  
    63  // Cancel and Stop should unblock Step()
    64  func TestNodeStepUnblock(t *testing.T) {
    65  	// a node without buffer to block step
    66  	n := &node{
    67  		propc: make(chan raftpb.Message),
    68  		done:  make(chan struct{}),
    69  	}
    70  
    71  	ctx, cancel := context.WithCancel(context.Background())
    72  	stopFunc := func() { close(n.done) }
    73  
    74  	tests := []struct {
    75  		unblock func()
    76  		werr    error
    77  	}{
    78  		{stopFunc, ErrStopped},
    79  		{cancel, context.Canceled},
    80  	}
    81  
    82  	for i, tt := range tests {
    83  		errc := make(chan error, 1)
    84  		go func() {
    85  			err := n.Step(ctx, raftpb.Message{Type: raftpb.MsgProp})
    86  			errc <- err
    87  		}()
    88  		tt.unblock()
    89  		select {
    90  		case err := <-errc:
    91  			if err != tt.werr {
    92  				t.Errorf("#%d: err = %v, want %v", i, err, tt.werr)
    93  			}
    94  			//clean up side-effect
    95  			if ctx.Err() != nil {
    96  				ctx = context.TODO()
    97  			}
    98  			select {
    99  			case <-n.done:
   100  				n.done = make(chan struct{})
   101  			default:
   102  			}
   103  		case <-time.After(1 * time.Second):
   104  			t.Fatalf("#%d: failed to unblock step", i)
   105  		}
   106  	}
   107  }
   108  
   109  // TestNodePropose ensures that node.Propose sends the given proposal to the underlying raft.
   110  func TestNodePropose(t *testing.T) {
   111  	msgs := []raftpb.Message{}
   112  	appendStep := func(r *raft, m raftpb.Message) {
   113  		msgs = append(msgs, m)
   114  	}
   115  
   116  	n := newNode()
   117  	s := NewMemoryStorage()
   118  	r := newTestRaft(1, []uint64{1}, 10, 1, s)
   119  	go n.run(r)
   120  	n.Campaign(context.TODO())
   121  	for {
   122  		rd := <-n.Ready()
   123  		s.Append(rd.Entries)
   124  		// change the step function to appendStep until this raft becomes leader
   125  		if rd.SoftState.Lead == r.id {
   126  			r.step = appendStep
   127  			n.Advance()
   128  			break
   129  		}
   130  		n.Advance()
   131  	}
   132  	n.Propose(context.TODO(), []byte("somedata"))
   133  	n.Stop()
   134  
   135  	if len(msgs) != 1 {
   136  		t.Fatalf("len(msgs) = %d, want %d", len(msgs), 1)
   137  	}
   138  	if msgs[0].Type != raftpb.MsgProp {
   139  		t.Errorf("msg type = %d, want %d", msgs[0].Type, raftpb.MsgProp)
   140  	}
   141  	if !bytes.Equal(msgs[0].Entries[0].Data, []byte("somedata")) {
   142  		t.Errorf("data = %v, want %v", msgs[0].Entries[0].Data, []byte("somedata"))
   143  	}
   144  }
   145  
   146  // TestNodeReadIndex ensures that node.ReadIndex sends the MsgReadIndex message to the underlying raft.
   147  // It also ensures that ReadState can be read out through ready chan.
   148  func TestNodeReadIndex(t *testing.T) {
   149  	msgs := []raftpb.Message{}
   150  	appendStep := func(r *raft, m raftpb.Message) {
   151  		msgs = append(msgs, m)
   152  	}
   153  	wrs := []ReadState{{Index: uint64(1), RequestCtx: []byte("somedata")}}
   154  
   155  	n := newNode()
   156  	s := NewMemoryStorage()
   157  	r := newTestRaft(1, []uint64{1}, 10, 1, s)
   158  	r.readStates = wrs
   159  
   160  	go n.run(r)
   161  	n.Campaign(context.TODO())
   162  	for {
   163  		rd := <-n.Ready()
   164  		if !reflect.DeepEqual(rd.ReadStates, wrs) {
   165  			t.Errorf("ReadStates = %v, want %v", rd.ReadStates, wrs)
   166  		}
   167  
   168  		s.Append(rd.Entries)
   169  
   170  		if rd.SoftState.Lead == r.id {
   171  			n.Advance()
   172  			break
   173  		}
   174  		n.Advance()
   175  	}
   176  
   177  	r.step = appendStep
   178  	wrequestCtx := []byte("somedata2")
   179  	n.ReadIndex(context.TODO(), wrequestCtx)
   180  	n.Stop()
   181  
   182  	if len(msgs) != 1 {
   183  		t.Fatalf("len(msgs) = %d, want %d", len(msgs), 1)
   184  	}
   185  	if msgs[0].Type != raftpb.MsgReadIndex {
   186  		t.Errorf("msg type = %d, want %d", msgs[0].Type, raftpb.MsgReadIndex)
   187  	}
   188  	if !bytes.Equal(msgs[0].Entries[0].Data, wrequestCtx) {
   189  		t.Errorf("data = %v, want %v", msgs[0].Entries[0].Data, wrequestCtx)
   190  	}
   191  }
   192  
   193  // TestDisableProposalForwarding ensures that proposals are not forwarded to
   194  // the leader when DisableProposalForwarding is true.
   195  func TestDisableProposalForwarding(t *testing.T) {
   196  	r1 := newTestRaft(1, []uint64{1, 2, 3}, 10, 1, NewMemoryStorage())
   197  	r2 := newTestRaft(2, []uint64{1, 2, 3}, 10, 1, NewMemoryStorage())
   198  	cfg3 := newTestConfig(3, []uint64{1, 2, 3}, 10, 1, NewMemoryStorage())
   199  	cfg3.DisableProposalForwarding = true
   200  	r3 := newRaft(cfg3)
   201  	nt := newNetwork(r1, r2, r3)
   202  
   203  	// elect r1 as leader
   204  	nt.send(raftpb.Message{From: 1, To: 1, Type: raftpb.MsgHup})
   205  
   206  	var testEntries = []raftpb.Entry{{Data: []byte("testdata")}}
   207  
   208  	// send proposal to r2(follower) where DisableProposalForwarding is false
   209  	r2.Step(raftpb.Message{From: 2, To: 2, Type: raftpb.MsgProp, Entries: testEntries})
   210  
   211  	// verify r2(follower) does forward the proposal when DisableProposalForwarding is false
   212  	if len(r2.msgs) != 1 {
   213  		t.Fatalf("len(r2.msgs) expected 1, got %d", len(r2.msgs))
   214  	}
   215  
   216  	// send proposal to r3(follower) where DisableProposalForwarding is true
   217  	r3.Step(raftpb.Message{From: 3, To: 3, Type: raftpb.MsgProp, Entries: testEntries})
   218  
   219  	// verify r3(follower) does not forward the proposal when DisableProposalForwarding is true
   220  	if len(r3.msgs) != 0 {
   221  		t.Fatalf("len(r3.msgs) expected 0, got %d", len(r3.msgs))
   222  	}
   223  }
   224  
   225  // TestNodeReadIndexToOldLeader ensures that raftpb.MsgReadIndex to old leader
   226  // gets forwarded to the new leader and 'send' method does not attach its term.
   227  func TestNodeReadIndexToOldLeader(t *testing.T) {
   228  	r1 := newTestRaft(1, []uint64{1, 2, 3}, 10, 1, NewMemoryStorage())
   229  	r2 := newTestRaft(2, []uint64{1, 2, 3}, 10, 1, NewMemoryStorage())
   230  	r3 := newTestRaft(3, []uint64{1, 2, 3}, 10, 1, NewMemoryStorage())
   231  
   232  	nt := newNetwork(r1, r2, r3)
   233  
   234  	// elect r1 as leader
   235  	nt.send(raftpb.Message{From: 1, To: 1, Type: raftpb.MsgHup})
   236  
   237  	var testEntries = []raftpb.Entry{{Data: []byte("testdata")}}
   238  
   239  	// send readindex request to r2(follower)
   240  	r2.Step(raftpb.Message{From: 2, To: 2, Type: raftpb.MsgReadIndex, Entries: testEntries})
   241  
   242  	// verify r2(follower) forwards this message to r1(leader) with term not set
   243  	if len(r2.msgs) != 1 {
   244  		t.Fatalf("len(r2.msgs) expected 1, got %d", len(r2.msgs))
   245  	}
   246  	readIndxMsg1 := raftpb.Message{From: 2, To: 1, Type: raftpb.MsgReadIndex, Entries: testEntries}
   247  	if !reflect.DeepEqual(r2.msgs[0], readIndxMsg1) {
   248  		t.Fatalf("r2.msgs[0] expected %+v, got %+v", readIndxMsg1, r2.msgs[0])
   249  	}
   250  
   251  	// send readindex request to r3(follower)
   252  	r3.Step(raftpb.Message{From: 3, To: 3, Type: raftpb.MsgReadIndex, Entries: testEntries})
   253  
   254  	// verify r3(follower) forwards this message to r1(leader) with term not set as well.
   255  	if len(r3.msgs) != 1 {
   256  		t.Fatalf("len(r3.msgs) expected 1, got %d", len(r3.msgs))
   257  	}
   258  	readIndxMsg2 := raftpb.Message{From: 3, To: 1, Type: raftpb.MsgReadIndex, Entries: testEntries}
   259  	if !reflect.DeepEqual(r3.msgs[0], readIndxMsg2) {
   260  		t.Fatalf("r3.msgs[0] expected %+v, got %+v", readIndxMsg2, r3.msgs[0])
   261  	}
   262  
   263  	// now elect r3 as leader
   264  	nt.send(raftpb.Message{From: 3, To: 3, Type: raftpb.MsgHup})
   265  
   266  	// let r1 steps the two messages previously we got from r2, r3
   267  	r1.Step(readIndxMsg1)
   268  	r1.Step(readIndxMsg2)
   269  
   270  	// verify r1(follower) forwards these messages again to r3(new leader)
   271  	if len(r1.msgs) != 2 {
   272  		t.Fatalf("len(r1.msgs) expected 1, got %d", len(r1.msgs))
   273  	}
   274  	readIndxMsg3 := raftpb.Message{From: 1, To: 3, Type: raftpb.MsgReadIndex, Entries: testEntries}
   275  	if !reflect.DeepEqual(r1.msgs[0], readIndxMsg3) {
   276  		t.Fatalf("r1.msgs[0] expected %+v, got %+v", readIndxMsg3, r1.msgs[0])
   277  	}
   278  	if !reflect.DeepEqual(r1.msgs[1], readIndxMsg3) {
   279  		t.Fatalf("r1.msgs[1] expected %+v, got %+v", readIndxMsg3, r1.msgs[1])
   280  	}
   281  }
   282  
   283  // TestNodeProposeConfig ensures that node.ProposeConfChange sends the given configuration proposal
   284  // to the underlying raft.
   285  func TestNodeProposeConfig(t *testing.T) {
   286  	msgs := []raftpb.Message{}
   287  	appendStep := func(r *raft, m raftpb.Message) {
   288  		msgs = append(msgs, m)
   289  	}
   290  
   291  	n := newNode()
   292  	s := NewMemoryStorage()
   293  	r := newTestRaft(1, []uint64{1}, 10, 1, s)
   294  	go n.run(r)
   295  	n.Campaign(context.TODO())
   296  	for {
   297  		rd := <-n.Ready()
   298  		s.Append(rd.Entries)
   299  		// change the step function to appendStep until this raft becomes leader
   300  		if rd.SoftState.Lead == r.id {
   301  			r.step = appendStep
   302  			n.Advance()
   303  			break
   304  		}
   305  		n.Advance()
   306  	}
   307  	cc := raftpb.ConfChange{Type: raftpb.ConfChangeAddNode, NodeID: 1}
   308  	ccdata, err := cc.Marshal()
   309  	if err != nil {
   310  		t.Fatal(err)
   311  	}
   312  	n.ProposeConfChange(context.TODO(), cc)
   313  	n.Stop()
   314  
   315  	if len(msgs) != 1 {
   316  		t.Fatalf("len(msgs) = %d, want %d", len(msgs), 1)
   317  	}
   318  	if msgs[0].Type != raftpb.MsgProp {
   319  		t.Errorf("msg type = %d, want %d", msgs[0].Type, raftpb.MsgProp)
   320  	}
   321  	if !bytes.Equal(msgs[0].Entries[0].Data, ccdata) {
   322  		t.Errorf("data = %v, want %v", msgs[0].Entries[0].Data, ccdata)
   323  	}
   324  }
   325  
   326  // TestNodeProposeAddDuplicateNode ensures that two proposes to add the same node should
   327  // not affect the later propose to add new node.
   328  func TestNodeProposeAddDuplicateNode(t *testing.T) {
   329  	n := newNode()
   330  	s := NewMemoryStorage()
   331  	r := newTestRaft(1, []uint64{1}, 10, 1, s)
   332  	go n.run(r)
   333  	n.Campaign(context.TODO())
   334  	rdyEntries := make([]raftpb.Entry, 0)
   335  	ticker := time.NewTicker(time.Millisecond * 100)
   336  	defer ticker.Stop()
   337  	done := make(chan struct{})
   338  	stop := make(chan struct{})
   339  	applyConfChan := make(chan struct{})
   340  
   341  	go func() {
   342  		defer close(done)
   343  		for {
   344  			select {
   345  			case <-stop:
   346  				return
   347  			case <-ticker.C:
   348  				n.Tick()
   349  			case rd := <-n.Ready():
   350  				s.Append(rd.Entries)
   351  				for _, e := range rd.Entries {
   352  					rdyEntries = append(rdyEntries, e)
   353  					switch e.Type {
   354  					case raftpb.EntryNormal:
   355  					case raftpb.EntryConfChange:
   356  						var cc raftpb.ConfChange
   357  						cc.Unmarshal(e.Data)
   358  						n.ApplyConfChange(cc)
   359  						applyConfChan <- struct{}{}
   360  					}
   361  				}
   362  				n.Advance()
   363  			}
   364  		}
   365  	}()
   366  
   367  	cc1 := raftpb.ConfChange{Type: raftpb.ConfChangeAddNode, NodeID: 1}
   368  	ccdata1, _ := cc1.Marshal()
   369  	n.ProposeConfChange(context.TODO(), cc1)
   370  	<-applyConfChan
   371  
   372  	// try add the same node again
   373  	n.ProposeConfChange(context.TODO(), cc1)
   374  	<-applyConfChan
   375  
   376  	// the new node join should be ok
   377  	cc2 := raftpb.ConfChange{Type: raftpb.ConfChangeAddNode, NodeID: 2}
   378  	ccdata2, _ := cc2.Marshal()
   379  	n.ProposeConfChange(context.TODO(), cc2)
   380  	<-applyConfChan
   381  
   382  	close(stop)
   383  	<-done
   384  
   385  	if len(rdyEntries) != 4 {
   386  		t.Errorf("len(entry) = %d, want %d, %v\n", len(rdyEntries), 4, rdyEntries)
   387  	}
   388  	if !bytes.Equal(rdyEntries[1].Data, ccdata1) {
   389  		t.Errorf("data = %v, want %v", rdyEntries[1].Data, ccdata1)
   390  	}
   391  	if !bytes.Equal(rdyEntries[3].Data, ccdata2) {
   392  		t.Errorf("data = %v, want %v", rdyEntries[3].Data, ccdata2)
   393  	}
   394  	n.Stop()
   395  }
   396  
   397  // TestBlockProposal ensures that node will block proposal when it does not
   398  // know who is the current leader; node will accept proposal when it knows
   399  // who is the current leader.
   400  func TestBlockProposal(t *testing.T) {
   401  	n := newNode()
   402  	r := newTestRaft(1, []uint64{1}, 10, 1, NewMemoryStorage())
   403  	go n.run(r)
   404  	defer n.Stop()
   405  
   406  	errc := make(chan error, 1)
   407  	go func() {
   408  		errc <- n.Propose(context.TODO(), []byte("somedata"))
   409  	}()
   410  
   411  	testutil.WaitSchedule()
   412  	select {
   413  	case err := <-errc:
   414  		t.Errorf("err = %v, want blocking", err)
   415  	default:
   416  	}
   417  
   418  	n.Campaign(context.TODO())
   419  	select {
   420  	case err := <-errc:
   421  		if err != nil {
   422  			t.Errorf("err = %v, want %v", err, nil)
   423  		}
   424  	case <-time.After(10 * time.Second):
   425  		t.Errorf("blocking proposal, want unblocking")
   426  	}
   427  }
   428  
   429  // TestNodeTick ensures that node.Tick() will increase the
   430  // elapsed of the underlying raft state machine.
   431  func TestNodeTick(t *testing.T) {
   432  	n := newNode()
   433  	s := NewMemoryStorage()
   434  	r := newTestRaft(1, []uint64{1}, 10, 1, s)
   435  	go n.run(r)
   436  	elapsed := r.electionElapsed
   437  	n.Tick()
   438  
   439  	for len(n.tickc) != 0 {
   440  		time.Sleep(100 * time.Millisecond)
   441  	}
   442  
   443  	n.Stop()
   444  	if r.electionElapsed != elapsed+1 {
   445  		t.Errorf("elapsed = %d, want %d", r.electionElapsed, elapsed+1)
   446  	}
   447  }
   448  
   449  // TestNodeStop ensures that node.Stop() blocks until the node has stopped
   450  // processing, and that it is idempotent
   451  func TestNodeStop(t *testing.T) {
   452  	n := newNode()
   453  	s := NewMemoryStorage()
   454  	r := newTestRaft(1, []uint64{1}, 10, 1, s)
   455  	donec := make(chan struct{})
   456  
   457  	go func() {
   458  		n.run(r)
   459  		close(donec)
   460  	}()
   461  
   462  	status := n.Status()
   463  	n.Stop()
   464  
   465  	select {
   466  	case <-donec:
   467  	case <-time.After(time.Second):
   468  		t.Fatalf("timed out waiting for node to stop!")
   469  	}
   470  
   471  	emptyStatus := Status{}
   472  
   473  	if reflect.DeepEqual(status, emptyStatus) {
   474  		t.Errorf("status = %v, want not empty", status)
   475  	}
   476  	// Further status should return be empty, the node is stopped.
   477  	status = n.Status()
   478  	if !reflect.DeepEqual(status, emptyStatus) {
   479  		t.Errorf("status = %v, want empty", status)
   480  	}
   481  	// Subsequent Stops should have no effect.
   482  	n.Stop()
   483  }
   484  
   485  func TestReadyContainUpdates(t *testing.T) {
   486  	tests := []struct {
   487  		rd       Ready
   488  		wcontain bool
   489  	}{
   490  		{Ready{}, false},
   491  		{Ready{SoftState: &SoftState{Lead: 1}}, true},
   492  		{Ready{HardState: raftpb.HardState{Vote: 1}}, true},
   493  		{Ready{Entries: make([]raftpb.Entry, 1)}, true},
   494  		{Ready{CommittedEntries: make([]raftpb.Entry, 1)}, true},
   495  		{Ready{Messages: make([]raftpb.Message, 1)}, true},
   496  		{Ready{Snapshot: raftpb.Snapshot{Metadata: raftpb.SnapshotMetadata{Index: 1}}}, true},
   497  	}
   498  
   499  	for i, tt := range tests {
   500  		if g := tt.rd.containsUpdates(); g != tt.wcontain {
   501  			t.Errorf("#%d: containUpdates = %v, want %v", i, g, tt.wcontain)
   502  		}
   503  	}
   504  }
   505  
   506  // TestNodeStart ensures that a node can be started correctly. The node should
   507  // start with correct configuration change entries, and can accept and commit
   508  // proposals.
   509  func TestNodeStart(t *testing.T) {
   510  	ctx, cancel := context.WithCancel(context.Background())
   511  	defer cancel()
   512  
   513  	cc := raftpb.ConfChange{Type: raftpb.ConfChangeAddNode, NodeID: 1}
   514  	ccdata, err := cc.Marshal()
   515  	if err != nil {
   516  		t.Fatalf("unexpected marshal error: %v", err)
   517  	}
   518  	wants := []Ready{
   519  		{
   520  			HardState: raftpb.HardState{Term: 1, Commit: 1, Vote: 0},
   521  			Entries: []raftpb.Entry{
   522  				{Type: raftpb.EntryConfChange, Term: 1, Index: 1, Data: ccdata},
   523  			},
   524  			CommittedEntries: []raftpb.Entry{
   525  				{Type: raftpb.EntryConfChange, Term: 1, Index: 1, Data: ccdata},
   526  			},
   527  			MustSync: true,
   528  		},
   529  		{
   530  			HardState:        raftpb.HardState{Term: 2, Commit: 3, Vote: 1},
   531  			Entries:          []raftpb.Entry{{Term: 2, Index: 3, Data: []byte("foo")}},
   532  			CommittedEntries: []raftpb.Entry{{Term: 2, Index: 3, Data: []byte("foo")}},
   533  			MustSync:         true,
   534  		},
   535  	}
   536  	storage := NewMemoryStorage()
   537  	c := &Config{
   538  		ID:              1,
   539  		ElectionTick:    10,
   540  		HeartbeatTick:   1,
   541  		Storage:         storage,
   542  		MaxSizePerMsg:   noLimit,
   543  		MaxInflightMsgs: 256,
   544  	}
   545  	n := StartNode(c, []Peer{{ID: 1}})
   546  	defer n.Stop()
   547  	g := <-n.Ready()
   548  	if !reflect.DeepEqual(g, wants[0]) {
   549  		t.Fatalf("#%d: g = %+v,\n             w   %+v", 1, g, wants[0])
   550  	} else {
   551  		storage.Append(g.Entries)
   552  		n.Advance()
   553  	}
   554  
   555  	n.Campaign(ctx)
   556  	rd := <-n.Ready()
   557  	storage.Append(rd.Entries)
   558  	n.Advance()
   559  
   560  	n.Propose(ctx, []byte("foo"))
   561  	if g2 := <-n.Ready(); !reflect.DeepEqual(g2, wants[1]) {
   562  		t.Errorf("#%d: g = %+v,\n             w   %+v", 2, g2, wants[1])
   563  	} else {
   564  		storage.Append(g2.Entries)
   565  		n.Advance()
   566  	}
   567  
   568  	select {
   569  	case rd := <-n.Ready():
   570  		t.Errorf("unexpected Ready: %+v", rd)
   571  	case <-time.After(time.Millisecond):
   572  	}
   573  }
   574  
   575  func TestNodeRestart(t *testing.T) {
   576  	entries := []raftpb.Entry{
   577  		{Term: 1, Index: 1},
   578  		{Term: 1, Index: 2, Data: []byte("foo")},
   579  	}
   580  	st := raftpb.HardState{Term: 1, Commit: 1}
   581  
   582  	want := Ready{
   583  		HardState: st,
   584  		// commit up to index commit index in st
   585  		CommittedEntries: entries[:st.Commit],
   586  		MustSync:         true,
   587  	}
   588  
   589  	storage := NewMemoryStorage()
   590  	storage.SetHardState(st)
   591  	storage.Append(entries)
   592  	c := &Config{
   593  		ID:              1,
   594  		ElectionTick:    10,
   595  		HeartbeatTick:   1,
   596  		Storage:         storage,
   597  		MaxSizePerMsg:   noLimit,
   598  		MaxInflightMsgs: 256,
   599  	}
   600  	n := RestartNode(c)
   601  	defer n.Stop()
   602  	if g := <-n.Ready(); !reflect.DeepEqual(g, want) {
   603  		t.Errorf("g = %+v,\n             w   %+v", g, want)
   604  	}
   605  	n.Advance()
   606  
   607  	select {
   608  	case rd := <-n.Ready():
   609  		t.Errorf("unexpected Ready: %+v", rd)
   610  	case <-time.After(time.Millisecond):
   611  	}
   612  }
   613  
   614  func TestNodeRestartFromSnapshot(t *testing.T) {
   615  	snap := raftpb.Snapshot{
   616  		Metadata: raftpb.SnapshotMetadata{
   617  			ConfState: raftpb.ConfState{Nodes: []uint64{1, 2}},
   618  			Index:     2,
   619  			Term:      1,
   620  		},
   621  	}
   622  	entries := []raftpb.Entry{
   623  		{Term: 1, Index: 3, Data: []byte("foo")},
   624  	}
   625  	st := raftpb.HardState{Term: 1, Commit: 3}
   626  
   627  	want := Ready{
   628  		HardState: st,
   629  		// commit up to index commit index in st
   630  		CommittedEntries: entries,
   631  		MustSync:         true,
   632  	}
   633  
   634  	s := NewMemoryStorage()
   635  	s.SetHardState(st)
   636  	s.ApplySnapshot(snap)
   637  	s.Append(entries)
   638  	c := &Config{
   639  		ID:              1,
   640  		ElectionTick:    10,
   641  		HeartbeatTick:   1,
   642  		Storage:         s,
   643  		MaxSizePerMsg:   noLimit,
   644  		MaxInflightMsgs: 256,
   645  	}
   646  	n := RestartNode(c)
   647  	defer n.Stop()
   648  	if g := <-n.Ready(); !reflect.DeepEqual(g, want) {
   649  		t.Errorf("g = %+v,\n             w   %+v", g, want)
   650  	} else {
   651  		n.Advance()
   652  	}
   653  
   654  	select {
   655  	case rd := <-n.Ready():
   656  		t.Errorf("unexpected Ready: %+v", rd)
   657  	case <-time.After(time.Millisecond):
   658  	}
   659  }
   660  
   661  func TestNodeAdvance(t *testing.T) {
   662  	ctx, cancel := context.WithCancel(context.Background())
   663  	defer cancel()
   664  
   665  	storage := NewMemoryStorage()
   666  	c := &Config{
   667  		ID:              1,
   668  		ElectionTick:    10,
   669  		HeartbeatTick:   1,
   670  		Storage:         storage,
   671  		MaxSizePerMsg:   noLimit,
   672  		MaxInflightMsgs: 256,
   673  	}
   674  	n := StartNode(c, []Peer{{ID: 1}})
   675  	defer n.Stop()
   676  	rd := <-n.Ready()
   677  	storage.Append(rd.Entries)
   678  	n.Advance()
   679  
   680  	n.Campaign(ctx)
   681  	<-n.Ready()
   682  
   683  	n.Propose(ctx, []byte("foo"))
   684  	select {
   685  	case rd = <-n.Ready():
   686  		t.Fatalf("unexpected Ready before Advance: %+v", rd)
   687  	case <-time.After(time.Millisecond):
   688  	}
   689  	storage.Append(rd.Entries)
   690  	n.Advance()
   691  	select {
   692  	case <-n.Ready():
   693  	case <-time.After(100 * time.Millisecond):
   694  		t.Errorf("expect Ready after Advance, but there is no Ready available")
   695  	}
   696  }
   697  
   698  func TestSoftStateEqual(t *testing.T) {
   699  	tests := []struct {
   700  		st *SoftState
   701  		we bool
   702  	}{
   703  		{&SoftState{}, true},
   704  		{&SoftState{Lead: 1}, false},
   705  		{&SoftState{RaftState: StateLeader}, false},
   706  	}
   707  	for i, tt := range tests {
   708  		if g := tt.st.equal(&SoftState{}); g != tt.we {
   709  			t.Errorf("#%d, equal = %v, want %v", i, g, tt.we)
   710  		}
   711  	}
   712  }
   713  
   714  func TestIsHardStateEqual(t *testing.T) {
   715  	tests := []struct {
   716  		st raftpb.HardState
   717  		we bool
   718  	}{
   719  		{emptyState, true},
   720  		{raftpb.HardState{Vote: 1}, false},
   721  		{raftpb.HardState{Commit: 1}, false},
   722  		{raftpb.HardState{Term: 1}, false},
   723  	}
   724  
   725  	for i, tt := range tests {
   726  		if isHardStateEqual(tt.st, emptyState) != tt.we {
   727  			t.Errorf("#%d, equal = %v, want %v", i, isHardStateEqual(tt.st, emptyState), tt.we)
   728  		}
   729  	}
   730  }