...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package rafttest
16
17 import (
18 "errors"
19 "fmt"
20 "reflect"
21 "testing"
22
23 "github.com/cockroachdb/datadriven"
24 "go.etcd.io/etcd/raft/v3"
25 pb "go.etcd.io/etcd/raft/v3/raftpb"
26 )
27
28 func (env *InteractionEnv) handleAddNodes(t *testing.T, d datadriven.TestData) error {
29 n := firstAsInt(t, d)
30 var snap pb.Snapshot
31 for _, arg := range d.CmdArgs[1:] {
32 for i := range arg.Vals {
33 switch arg.Key {
34 case "voters":
35 var id uint64
36 arg.Scan(t, i, &id)
37 snap.Metadata.ConfState.Voters = append(snap.Metadata.ConfState.Voters, id)
38 case "learners":
39 var id uint64
40 arg.Scan(t, i, &id)
41 snap.Metadata.ConfState.Learners = append(snap.Metadata.ConfState.Learners, id)
42 case "index":
43 arg.Scan(t, i, &snap.Metadata.Index)
44 case "content":
45 arg.Scan(t, i, &snap.Data)
46 }
47 }
48 }
49 return env.AddNodes(n, snap)
50 }
51
52 type snapOverrideStorage struct {
53 Storage
54 snapshotOverride func() (pb.Snapshot, error)
55 }
56
57 func (s snapOverrideStorage) Snapshot() (pb.Snapshot, error) {
58 if s.snapshotOverride != nil {
59 return s.snapshotOverride()
60 }
61 return s.Storage.Snapshot()
62 }
63
64 var _ raft.Storage = snapOverrideStorage{}
65
66
67
68 func (env *InteractionEnv) AddNodes(n int, snap pb.Snapshot) error {
69 bootstrap := !reflect.DeepEqual(snap, pb.Snapshot{})
70 for i := 0; i < n; i++ {
71 id := uint64(1 + len(env.Nodes))
72 s := snapOverrideStorage{
73 Storage: raft.NewMemoryStorage(),
74
75
76
77
78
79
80 snapshotOverride: func() (pb.Snapshot, error) {
81 snaps := env.Nodes[int(id-1)].History
82 return snaps[len(snaps)-1], nil
83 },
84 }
85 if bootstrap {
86
87
88 if snap.Metadata.Index <= 1 {
89 return errors.New("index must be specified as > 1 due to bootstrap")
90 }
91 snap.Metadata.Term = 1
92 if err := s.ApplySnapshot(snap); err != nil {
93 return err
94 }
95 fi, err := s.FirstIndex()
96 if err != nil {
97 return err
98 }
99
100
101
102 if exp := snap.Metadata.Index + 1; fi != exp {
103 return fmt.Errorf("failed to establish first index %d; got %d", exp, fi)
104 }
105 }
106 cfg := defaultRaftConfig(id, snap.Metadata.Index, s)
107 if env.Options.OnConfig != nil {
108 env.Options.OnConfig(cfg)
109 if cfg.ID != id {
110
111
112 return errors.New("OnConfig must not change the ID")
113 }
114 }
115 if cfg.Logger != nil {
116 return errors.New("OnConfig must not set Logger")
117 }
118 cfg.Logger = env.Output
119
120 rn, err := raft.NewRawNode(cfg)
121 if err != nil {
122 return err
123 }
124
125 node := Node{
126 RawNode: rn,
127
128
129 Storage: s,
130 Config: cfg,
131 History: []pb.Snapshot{snap},
132 }
133 env.Nodes = append(env.Nodes, node)
134 }
135 return nil
136 }
137
View as plain text