1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package raft
16
17 import (
18 "reflect"
19 "testing"
20
21 pb "go.etcd.io/etcd/raft/v3/raftpb"
22 )
23
24 func TestUnstableMaybeFirstIndex(t *testing.T) {
25 tests := []struct {
26 entries []pb.Entry
27 offset uint64
28 snap *pb.Snapshot
29
30 wok bool
31 windex uint64
32 }{
33
34 {
35 []pb.Entry{{Index: 5, Term: 1}}, 5, nil,
36 false, 0,
37 },
38 {
39 []pb.Entry{}, 0, nil,
40 false, 0,
41 },
42
43 {
44 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}},
45 true, 5,
46 },
47 {
48 []pb.Entry{}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}},
49 true, 5,
50 },
51 }
52
53 for i, tt := range tests {
54 u := unstable{
55 entries: tt.entries,
56 offset: tt.offset,
57 snapshot: tt.snap,
58 logger: raftLogger,
59 }
60 index, ok := u.maybeFirstIndex()
61 if ok != tt.wok {
62 t.Errorf("#%d: ok = %t, want %t", i, ok, tt.wok)
63 }
64 if index != tt.windex {
65 t.Errorf("#%d: index = %d, want %d", i, index, tt.windex)
66 }
67 }
68 }
69
70 func TestMaybeLastIndex(t *testing.T) {
71 tests := []struct {
72 entries []pb.Entry
73 offset uint64
74 snap *pb.Snapshot
75
76 wok bool
77 windex uint64
78 }{
79
80 {
81 []pb.Entry{{Index: 5, Term: 1}}, 5, nil,
82 true, 5,
83 },
84 {
85 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}},
86 true, 5,
87 },
88
89 {
90 []pb.Entry{}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}},
91 true, 4,
92 },
93
94 {
95 []pb.Entry{}, 0, nil,
96 false, 0,
97 },
98 }
99
100 for i, tt := range tests {
101 u := unstable{
102 entries: tt.entries,
103 offset: tt.offset,
104 snapshot: tt.snap,
105 logger: raftLogger,
106 }
107 index, ok := u.maybeLastIndex()
108 if ok != tt.wok {
109 t.Errorf("#%d: ok = %t, want %t", i, ok, tt.wok)
110 }
111 if index != tt.windex {
112 t.Errorf("#%d: index = %d, want %d", i, index, tt.windex)
113 }
114 }
115 }
116
117 func TestUnstableMaybeTerm(t *testing.T) {
118 tests := []struct {
119 entries []pb.Entry
120 offset uint64
121 snap *pb.Snapshot
122 index uint64
123
124 wok bool
125 wterm uint64
126 }{
127
128 {
129 []pb.Entry{{Index: 5, Term: 1}}, 5, nil,
130 5,
131 true, 1,
132 },
133 {
134 []pb.Entry{{Index: 5, Term: 1}}, 5, nil,
135 6,
136 false, 0,
137 },
138 {
139 []pb.Entry{{Index: 5, Term: 1}}, 5, nil,
140 4,
141 false, 0,
142 },
143 {
144 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}},
145 5,
146 true, 1,
147 },
148 {
149 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}},
150 6,
151 false, 0,
152 },
153
154 {
155 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}},
156 4,
157 true, 1,
158 },
159 {
160 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}},
161 3,
162 false, 0,
163 },
164 {
165 []pb.Entry{}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}},
166 5,
167 false, 0,
168 },
169 {
170 []pb.Entry{}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}},
171 4,
172 true, 1,
173 },
174 {
175 []pb.Entry{}, 0, nil,
176 5,
177 false, 0,
178 },
179 }
180
181 for i, tt := range tests {
182 u := unstable{
183 entries: tt.entries,
184 offset: tt.offset,
185 snapshot: tt.snap,
186 logger: raftLogger,
187 }
188 term, ok := u.maybeTerm(tt.index)
189 if ok != tt.wok {
190 t.Errorf("#%d: ok = %t, want %t", i, ok, tt.wok)
191 }
192 if term != tt.wterm {
193 t.Errorf("#%d: term = %d, want %d", i, term, tt.wterm)
194 }
195 }
196 }
197
198 func TestUnstableRestore(t *testing.T) {
199 u := unstable{
200 entries: []pb.Entry{{Index: 5, Term: 1}},
201 offset: 5,
202 snapshot: &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}},
203 logger: raftLogger,
204 }
205 s := pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 6, Term: 2}}
206 u.restore(s)
207
208 if u.offset != s.Metadata.Index+1 {
209 t.Errorf("offset = %d, want %d", u.offset, s.Metadata.Index+1)
210 }
211 if len(u.entries) != 0 {
212 t.Errorf("len = %d, want 0", len(u.entries))
213 }
214 if !reflect.DeepEqual(u.snapshot, &s) {
215 t.Errorf("snap = %v, want %v", u.snapshot, &s)
216 }
217 }
218
219 func TestUnstableStableTo(t *testing.T) {
220 tests := []struct {
221 entries []pb.Entry
222 offset uint64
223 snap *pb.Snapshot
224 index, term uint64
225
226 woffset uint64
227 wlen int
228 }{
229 {
230 []pb.Entry{}, 0, nil,
231 5, 1,
232 0, 0,
233 },
234 {
235 []pb.Entry{{Index: 5, Term: 1}}, 5, nil,
236 5, 1,
237 6, 0,
238 },
239 {
240 []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, 5, nil,
241 5, 1,
242 6, 1,
243 },
244 {
245 []pb.Entry{{Index: 6, Term: 2}}, 6, nil,
246 6, 1,
247 6, 1,
248 },
249 {
250 []pb.Entry{{Index: 5, Term: 1}}, 5, nil,
251 4, 1,
252 5, 1,
253 },
254 {
255 []pb.Entry{{Index: 5, Term: 1}}, 5, nil,
256 4, 2,
257 5, 1,
258 },
259
260 {
261 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}},
262 5, 1,
263 6, 0,
264 },
265 {
266 []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}},
267 5, 1,
268 6, 1,
269 },
270 {
271 []pb.Entry{{Index: 6, Term: 2}}, 6, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 5, Term: 1}},
272 6, 1,
273 6, 1,
274 },
275 {
276 []pb.Entry{{Index: 5, Term: 1}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 1}},
277 4, 1,
278 5, 1,
279 },
280 {
281 []pb.Entry{{Index: 5, Term: 2}}, 5, &pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: 4, Term: 2}},
282 4, 1,
283 5, 1,
284 },
285 }
286
287 for i, tt := range tests {
288 u := unstable{
289 entries: tt.entries,
290 offset: tt.offset,
291 snapshot: tt.snap,
292 logger: raftLogger,
293 }
294 u.stableTo(tt.index, tt.term)
295 if u.offset != tt.woffset {
296 t.Errorf("#%d: offset = %d, want %d", i, u.offset, tt.woffset)
297 }
298 if len(u.entries) != tt.wlen {
299 t.Errorf("#%d: len = %d, want %d", i, len(u.entries), tt.wlen)
300 }
301 }
302 }
303
304 func TestUnstableTruncateAndAppend(t *testing.T) {
305 tests := []struct {
306 entries []pb.Entry
307 offset uint64
308 snap *pb.Snapshot
309 toappend []pb.Entry
310
311 woffset uint64
312 wentries []pb.Entry
313 }{
314
315 {
316 []pb.Entry{{Index: 5, Term: 1}}, 5, nil,
317 []pb.Entry{{Index: 6, Term: 1}, {Index: 7, Term: 1}},
318 5, []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 1}},
319 },
320
321 {
322 []pb.Entry{{Index: 5, Term: 1}}, 5, nil,
323 []pb.Entry{{Index: 5, Term: 2}, {Index: 6, Term: 2}},
324 5, []pb.Entry{{Index: 5, Term: 2}, {Index: 6, Term: 2}},
325 },
326 {
327 []pb.Entry{{Index: 5, Term: 1}}, 5, nil,
328 []pb.Entry{{Index: 4, Term: 2}, {Index: 5, Term: 2}, {Index: 6, Term: 2}},
329 4, []pb.Entry{{Index: 4, Term: 2}, {Index: 5, Term: 2}, {Index: 6, Term: 2}},
330 },
331
332 {
333 []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 1}}, 5, nil,
334 []pb.Entry{{Index: 6, Term: 2}},
335 5, []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 2}},
336 },
337 {
338 []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 1}}, 5, nil,
339 []pb.Entry{{Index: 7, Term: 2}, {Index: 8, Term: 2}},
340 5, []pb.Entry{{Index: 5, Term: 1}, {Index: 6, Term: 1}, {Index: 7, Term: 2}, {Index: 8, Term: 2}},
341 },
342 }
343
344 for i, tt := range tests {
345 u := unstable{
346 entries: tt.entries,
347 offset: tt.offset,
348 snapshot: tt.snap,
349 logger: raftLogger,
350 }
351 u.truncateAndAppend(tt.toappend)
352 if u.offset != tt.woffset {
353 t.Errorf("#%d: offset = %d, want %d", i, u.offset, tt.woffset)
354 }
355 if !reflect.DeepEqual(u.entries, tt.wentries) {
356 t.Errorf("#%d: entries = %v, want %v", i, u.entries, tt.wentries)
357 }
358 }
359 }
360
View as plain text