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 TestFindConflict(t *testing.T) {
25 previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}
26 tests := []struct {
27 ents []pb.Entry
28 wconflict uint64
29 }{
30
31 {[]pb.Entry{}, 0},
32
33 {[]pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}, 0},
34 {[]pb.Entry{{Index: 2, Term: 2}, {Index: 3, Term: 3}}, 0},
35 {[]pb.Entry{{Index: 3, Term: 3}}, 0},
36
37 {[]pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 4}}, 4},
38 {[]pb.Entry{{Index: 2, Term: 2}, {Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 4}}, 4},
39 {[]pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 4}}, 4},
40 {[]pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 4}}, 4},
41
42 {[]pb.Entry{{Index: 1, Term: 4}, {Index: 2, Term: 4}}, 1},
43 {[]pb.Entry{{Index: 2, Term: 1}, {Index: 3, Term: 4}, {Index: 4, Term: 4}}, 2},
44 {[]pb.Entry{{Index: 3, Term: 1}, {Index: 4, Term: 2}, {Index: 5, Term: 4}, {Index: 6, Term: 4}}, 3},
45 }
46
47 for i, tt := range tests {
48 raftLog := newLog(NewMemoryStorage(), raftLogger)
49 raftLog.append(previousEnts...)
50
51 gconflict := raftLog.findConflict(tt.ents)
52 if gconflict != tt.wconflict {
53 t.Errorf("#%d: conflict = %d, want %d", i, gconflict, tt.wconflict)
54 }
55 }
56 }
57
58 func TestIsUpToDate(t *testing.T) {
59 previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}
60 raftLog := newLog(NewMemoryStorage(), raftLogger)
61 raftLog.append(previousEnts...)
62 tests := []struct {
63 lastIndex uint64
64 term uint64
65 wUpToDate bool
66 }{
67
68 {raftLog.lastIndex() - 1, 4, true},
69 {raftLog.lastIndex(), 4, true},
70 {raftLog.lastIndex() + 1, 4, true},
71
72 {raftLog.lastIndex() - 1, 2, false},
73 {raftLog.lastIndex(), 2, false},
74 {raftLog.lastIndex() + 1, 2, false},
75
76 {raftLog.lastIndex() - 1, 3, false},
77 {raftLog.lastIndex(), 3, true},
78 {raftLog.lastIndex() + 1, 3, true},
79 }
80
81 for i, tt := range tests {
82 gUpToDate := raftLog.isUpToDate(tt.lastIndex, tt.term)
83 if gUpToDate != tt.wUpToDate {
84 t.Errorf("#%d: uptodate = %v, want %v", i, gUpToDate, tt.wUpToDate)
85 }
86 }
87 }
88
89 func TestAppend(t *testing.T) {
90 previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}}
91 tests := []struct {
92 ents []pb.Entry
93 windex uint64
94 wents []pb.Entry
95 wunstable uint64
96 }{
97 {
98 []pb.Entry{},
99 2,
100 []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}},
101 3,
102 },
103 {
104 []pb.Entry{{Index: 3, Term: 2}},
105 3,
106 []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 2}},
107 3,
108 },
109
110 {
111 []pb.Entry{{Index: 1, Term: 2}},
112 1,
113 []pb.Entry{{Index: 1, Term: 2}},
114 1,
115 },
116
117 {
118 []pb.Entry{{Index: 2, Term: 3}, {Index: 3, Term: 3}},
119 3,
120 []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 3}, {Index: 3, Term: 3}},
121 2,
122 },
123 }
124
125 for i, tt := range tests {
126 storage := NewMemoryStorage()
127 storage.Append(previousEnts)
128 raftLog := newLog(storage, raftLogger)
129
130 index := raftLog.append(tt.ents...)
131 if index != tt.windex {
132 t.Errorf("#%d: lastIndex = %d, want %d", i, index, tt.windex)
133 }
134 g, err := raftLog.entries(1, noLimit)
135 if err != nil {
136 t.Fatalf("#%d: unexpected error %v", i, err)
137 }
138 if !reflect.DeepEqual(g, tt.wents) {
139 t.Errorf("#%d: logEnts = %+v, want %+v", i, g, tt.wents)
140 }
141 if goff := raftLog.unstable.offset; goff != tt.wunstable {
142 t.Errorf("#%d: unstable = %d, want %d", i, goff, tt.wunstable)
143 }
144 }
145 }
146
147
148
149
150
151
152
153
154
155
156
157 func TestLogMaybeAppend(t *testing.T) {
158 previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}
159 lastindex := uint64(3)
160 lastterm := uint64(3)
161 commit := uint64(1)
162
163 tests := []struct {
164 logTerm uint64
165 index uint64
166 committed uint64
167 ents []pb.Entry
168
169 wlasti uint64
170 wappend bool
171 wcommit uint64
172 wpanic bool
173 }{
174
175 {
176 lastterm - 1, lastindex, lastindex, []pb.Entry{{Index: lastindex + 1, Term: 4}},
177 0, false, commit, false,
178 },
179
180 {
181 lastterm, lastindex + 1, lastindex, []pb.Entry{{Index: lastindex + 2, Term: 4}},
182 0, false, commit, false,
183 },
184
185 {
186 lastterm, lastindex, lastindex, nil,
187 lastindex, true, lastindex, false,
188 },
189 {
190 lastterm, lastindex, lastindex + 1, nil,
191 lastindex, true, lastindex, false,
192 },
193 {
194 lastterm, lastindex, lastindex - 1, nil,
195 lastindex, true, lastindex - 1, false,
196 },
197 {
198 lastterm, lastindex, 0, nil,
199 lastindex, true, commit, false,
200 },
201 {
202 0, 0, lastindex, nil,
203 0, true, commit, false,
204 },
205 {
206 lastterm, lastindex, lastindex, []pb.Entry{{Index: lastindex + 1, Term: 4}},
207 lastindex + 1, true, lastindex, false,
208 },
209 {
210 lastterm, lastindex, lastindex + 1, []pb.Entry{{Index: lastindex + 1, Term: 4}},
211 lastindex + 1, true, lastindex + 1, false,
212 },
213 {
214 lastterm, lastindex, lastindex + 2, []pb.Entry{{Index: lastindex + 1, Term: 4}},
215 lastindex + 1, true, lastindex + 1, false,
216 },
217 {
218 lastterm, lastindex, lastindex + 2, []pb.Entry{{Index: lastindex + 1, Term: 4}, {Index: lastindex + 2, Term: 4}},
219 lastindex + 2, true, lastindex + 2, false,
220 },
221
222 {
223 lastterm - 1, lastindex - 1, lastindex, []pb.Entry{{Index: lastindex, Term: 4}},
224 lastindex, true, lastindex, false,
225 },
226 {
227 lastterm - 2, lastindex - 2, lastindex, []pb.Entry{{Index: lastindex - 1, Term: 4}},
228 lastindex - 1, true, lastindex - 1, false,
229 },
230 {
231 lastterm - 3, lastindex - 3, lastindex, []pb.Entry{{Index: lastindex - 2, Term: 4}},
232 lastindex - 2, true, lastindex - 2, true,
233 },
234 {
235 lastterm - 2, lastindex - 2, lastindex, []pb.Entry{{Index: lastindex - 1, Term: 4}, {Index: lastindex, Term: 4}},
236 lastindex, true, lastindex, false,
237 },
238 }
239
240 for i, tt := range tests {
241 raftLog := newLog(NewMemoryStorage(), raftLogger)
242 raftLog.append(previousEnts...)
243 raftLog.committed = commit
244 func() {
245 defer func() {
246 if r := recover(); r != nil {
247 if !tt.wpanic {
248 t.Errorf("%d: panic = %v, want %v", i, true, tt.wpanic)
249 }
250 }
251 }()
252 glasti, gappend := raftLog.maybeAppend(tt.index, tt.logTerm, tt.committed, tt.ents...)
253 gcommit := raftLog.committed
254
255 if glasti != tt.wlasti {
256 t.Errorf("#%d: lastindex = %d, want %d", i, glasti, tt.wlasti)
257 }
258 if gappend != tt.wappend {
259 t.Errorf("#%d: append = %v, want %v", i, gappend, tt.wappend)
260 }
261 if gcommit != tt.wcommit {
262 t.Errorf("#%d: committed = %d, want %d", i, gcommit, tt.wcommit)
263 }
264 if gappend && len(tt.ents) != 0 {
265 gents, err := raftLog.slice(raftLog.lastIndex()-uint64(len(tt.ents))+1, raftLog.lastIndex()+1, noLimit)
266 if err != nil {
267 t.Fatalf("unexpected error %v", err)
268 }
269 if !reflect.DeepEqual(tt.ents, gents) {
270 t.Errorf("#%d: appended entries = %v, want %v", i, gents, tt.ents)
271 }
272 }
273 }()
274 }
275 }
276
277
278
279 func TestCompactionSideEffects(t *testing.T) {
280 var i uint64
281
282 lastIndex := uint64(1000)
283 unstableIndex := uint64(750)
284 lastTerm := lastIndex
285 storage := NewMemoryStorage()
286 for i = 1; i <= unstableIndex; i++ {
287 storage.Append([]pb.Entry{{Term: i, Index: i}})
288 }
289 raftLog := newLog(storage, raftLogger)
290 for i = unstableIndex; i < lastIndex; i++ {
291 raftLog.append(pb.Entry{Term: i + 1, Index: i + 1})
292 }
293
294 ok := raftLog.maybeCommit(lastIndex, lastTerm)
295 if !ok {
296 t.Fatalf("maybeCommit returned false")
297 }
298 raftLog.appliedTo(raftLog.committed)
299
300 offset := uint64(500)
301 storage.Compact(offset)
302
303 if raftLog.lastIndex() != lastIndex {
304 t.Errorf("lastIndex = %d, want %d", raftLog.lastIndex(), lastIndex)
305 }
306
307 for j := offset; j <= raftLog.lastIndex(); j++ {
308 if mustTerm(raftLog.term(j)) != j {
309 t.Errorf("term(%d) = %d, want %d", j, mustTerm(raftLog.term(j)), j)
310 }
311 }
312
313 for j := offset; j <= raftLog.lastIndex(); j++ {
314 if !raftLog.matchTerm(j, j) {
315 t.Errorf("matchTerm(%d) = false, want true", j)
316 }
317 }
318
319 unstableEnts := raftLog.unstableEntries()
320 if g := len(unstableEnts); g != 250 {
321 t.Errorf("len(unstableEntries) = %d, want = %d", g, 250)
322 }
323 if unstableEnts[0].Index != 751 {
324 t.Errorf("Index = %d, want = %d", unstableEnts[0].Index, 751)
325 }
326
327 prev := raftLog.lastIndex()
328 raftLog.append(pb.Entry{Index: raftLog.lastIndex() + 1, Term: raftLog.lastIndex() + 1})
329 if raftLog.lastIndex() != prev+1 {
330 t.Errorf("lastIndex = %d, want = %d", raftLog.lastIndex(), prev+1)
331 }
332
333 ents, err := raftLog.entries(raftLog.lastIndex(), noLimit)
334 if err != nil {
335 t.Fatalf("unexpected error %v", err)
336 }
337 if len(ents) != 1 {
338 t.Errorf("len(entries) = %d, want = %d", len(ents), 1)
339 }
340 }
341
342 func TestHasNextEnts(t *testing.T) {
343 snap := pb.Snapshot{
344 Metadata: pb.SnapshotMetadata{Term: 1, Index: 3},
345 }
346 ents := []pb.Entry{
347 {Term: 1, Index: 4},
348 {Term: 1, Index: 5},
349 {Term: 1, Index: 6},
350 }
351 tests := []struct {
352 applied uint64
353 hasNext bool
354 }{
355 {0, true},
356 {3, true},
357 {4, true},
358 {5, false},
359 }
360 for i, tt := range tests {
361 storage := NewMemoryStorage()
362 storage.ApplySnapshot(snap)
363 raftLog := newLog(storage, raftLogger)
364 raftLog.append(ents...)
365 raftLog.maybeCommit(5, 1)
366 raftLog.appliedTo(tt.applied)
367
368 hasNext := raftLog.hasNextEnts()
369 if hasNext != tt.hasNext {
370 t.Errorf("#%d: hasNext = %v, want %v", i, hasNext, tt.hasNext)
371 }
372 }
373 }
374
375 func TestNextEnts(t *testing.T) {
376 snap := pb.Snapshot{
377 Metadata: pb.SnapshotMetadata{Term: 1, Index: 3},
378 }
379 ents := []pb.Entry{
380 {Term: 1, Index: 4},
381 {Term: 1, Index: 5},
382 {Term: 1, Index: 6},
383 }
384 tests := []struct {
385 applied uint64
386 wents []pb.Entry
387 }{
388 {0, ents[:2]},
389 {3, ents[:2]},
390 {4, ents[1:2]},
391 {5, nil},
392 }
393 for i, tt := range tests {
394 storage := NewMemoryStorage()
395 storage.ApplySnapshot(snap)
396 raftLog := newLog(storage, raftLogger)
397 raftLog.append(ents...)
398 raftLog.maybeCommit(5, 1)
399 raftLog.appliedTo(tt.applied)
400
401 nents := raftLog.nextEnts()
402 if !reflect.DeepEqual(nents, tt.wents) {
403 t.Errorf("#%d: nents = %+v, want %+v", i, nents, tt.wents)
404 }
405 }
406 }
407
408
409
410 func TestUnstableEnts(t *testing.T) {
411 previousEnts := []pb.Entry{{Term: 1, Index: 1}, {Term: 2, Index: 2}}
412 tests := []struct {
413 unstable uint64
414 wents []pb.Entry
415 }{
416 {3, nil},
417 {1, previousEnts},
418 }
419
420 for i, tt := range tests {
421
422 storage := NewMemoryStorage()
423 storage.Append(previousEnts[:tt.unstable-1])
424
425
426 raftLog := newLog(storage, raftLogger)
427 raftLog.append(previousEnts[tt.unstable-1:]...)
428
429 ents := raftLog.unstableEntries()
430 if l := len(ents); l > 0 {
431 raftLog.stableTo(ents[l-1].Index, ents[l-1].Term)
432 }
433 if !reflect.DeepEqual(ents, tt.wents) {
434 t.Errorf("#%d: unstableEnts = %+v, want %+v", i, ents, tt.wents)
435 }
436 w := previousEnts[len(previousEnts)-1].Index + 1
437 if g := raftLog.unstable.offset; g != w {
438 t.Errorf("#%d: unstable = %d, want %d", i, g, w)
439 }
440 }
441 }
442
443 func TestCommitTo(t *testing.T) {
444 previousEnts := []pb.Entry{{Term: 1, Index: 1}, {Term: 2, Index: 2}, {Term: 3, Index: 3}}
445 commit := uint64(2)
446 tests := []struct {
447 commit uint64
448 wcommit uint64
449 wpanic bool
450 }{
451 {3, 3, false},
452 {1, 2, false},
453 {4, 0, true},
454 }
455 for i, tt := range tests {
456 func() {
457 defer func() {
458 if r := recover(); r != nil {
459 if !tt.wpanic {
460 t.Errorf("%d: panic = %v, want %v", i, true, tt.wpanic)
461 }
462 }
463 }()
464 raftLog := newLog(NewMemoryStorage(), raftLogger)
465 raftLog.append(previousEnts...)
466 raftLog.committed = commit
467 raftLog.commitTo(tt.commit)
468 if raftLog.committed != tt.wcommit {
469 t.Errorf("#%d: committed = %d, want %d", i, raftLog.committed, tt.wcommit)
470 }
471 }()
472 }
473 }
474
475 func TestStableTo(t *testing.T) {
476 tests := []struct {
477 stablei uint64
478 stablet uint64
479 wunstable uint64
480 }{
481 {1, 1, 2},
482 {2, 2, 3},
483 {2, 1, 1},
484 {3, 1, 1},
485 }
486 for i, tt := range tests {
487 raftLog := newLog(NewMemoryStorage(), raftLogger)
488 raftLog.append([]pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}}...)
489 raftLog.stableTo(tt.stablei, tt.stablet)
490 if raftLog.unstable.offset != tt.wunstable {
491 t.Errorf("#%d: unstable = %d, want %d", i, raftLog.unstable.offset, tt.wunstable)
492 }
493 }
494 }
495
496 func TestStableToWithSnap(t *testing.T) {
497 snapi, snapt := uint64(5), uint64(2)
498 tests := []struct {
499 stablei uint64
500 stablet uint64
501 newEnts []pb.Entry
502
503 wunstable uint64
504 }{
505 {snapi + 1, snapt, nil, snapi + 1},
506 {snapi, snapt, nil, snapi + 1},
507 {snapi - 1, snapt, nil, snapi + 1},
508
509 {snapi + 1, snapt + 1, nil, snapi + 1},
510 {snapi, snapt + 1, nil, snapi + 1},
511 {snapi - 1, snapt + 1, nil, snapi + 1},
512
513 {snapi + 1, snapt, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 2},
514 {snapi, snapt, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1},
515 {snapi - 1, snapt, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1},
516
517 {snapi + 1, snapt + 1, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1},
518 {snapi, snapt + 1, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1},
519 {snapi - 1, snapt + 1, []pb.Entry{{Index: snapi + 1, Term: snapt}}, snapi + 1},
520 }
521 for i, tt := range tests {
522 s := NewMemoryStorage()
523 s.ApplySnapshot(pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: snapi, Term: snapt}})
524 raftLog := newLog(s, raftLogger)
525 raftLog.append(tt.newEnts...)
526 raftLog.stableTo(tt.stablei, tt.stablet)
527 if raftLog.unstable.offset != tt.wunstable {
528 t.Errorf("#%d: unstable = %d, want %d", i, raftLog.unstable.offset, tt.wunstable)
529 }
530 }
531 }
532
533
534 func TestCompaction(t *testing.T) {
535 tests := []struct {
536 lastIndex uint64
537 compact []uint64
538 wleft []int
539 wallow bool
540 }{
541
542 {1000, []uint64{1001}, []int{-1}, false},
543 {1000, []uint64{300, 500, 800, 900}, []int{700, 500, 200, 100}, true},
544
545 {1000, []uint64{300, 299}, []int{700, -1}, false},
546 }
547
548 for i, tt := range tests {
549 func() {
550 defer func() {
551 if r := recover(); r != nil {
552 if tt.wallow {
553 t.Errorf("%d: allow = %v, want %v: %v", i, false, true, r)
554 }
555 }
556 }()
557
558 storage := NewMemoryStorage()
559 for i := uint64(1); i <= tt.lastIndex; i++ {
560 storage.Append([]pb.Entry{{Index: i}})
561 }
562 raftLog := newLog(storage, raftLogger)
563 raftLog.maybeCommit(tt.lastIndex, 0)
564 raftLog.appliedTo(raftLog.committed)
565
566 for j := 0; j < len(tt.compact); j++ {
567 err := storage.Compact(tt.compact[j])
568 if err != nil {
569 if tt.wallow {
570 t.Errorf("#%d.%d allow = %t, want %t", i, j, false, tt.wallow)
571 }
572 continue
573 }
574 if len(raftLog.allEntries()) != tt.wleft[j] {
575 t.Errorf("#%d.%d len = %d, want %d", i, j, len(raftLog.allEntries()), tt.wleft[j])
576 }
577 }
578 }()
579 }
580 }
581
582 func TestLogRestore(t *testing.T) {
583 index := uint64(1000)
584 term := uint64(1000)
585 snap := pb.SnapshotMetadata{Index: index, Term: term}
586 storage := NewMemoryStorage()
587 storage.ApplySnapshot(pb.Snapshot{Metadata: snap})
588 raftLog := newLog(storage, raftLogger)
589
590 if len(raftLog.allEntries()) != 0 {
591 t.Errorf("len = %d, want 0", len(raftLog.allEntries()))
592 }
593 if raftLog.firstIndex() != index+1 {
594 t.Errorf("firstIndex = %d, want %d", raftLog.firstIndex(), index+1)
595 }
596 if raftLog.committed != index {
597 t.Errorf("committed = %d, want %d", raftLog.committed, index)
598 }
599 if raftLog.unstable.offset != index+1 {
600 t.Errorf("unstable = %d, want %d", raftLog.unstable.offset, index+1)
601 }
602 if mustTerm(raftLog.term(index)) != term {
603 t.Errorf("term = %d, want %d", mustTerm(raftLog.term(index)), term)
604 }
605 }
606
607 func TestIsOutOfBounds(t *testing.T) {
608 offset := uint64(100)
609 num := uint64(100)
610 storage := NewMemoryStorage()
611 storage.ApplySnapshot(pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: offset}})
612 l := newLog(storage, raftLogger)
613 for i := uint64(1); i <= num; i++ {
614 l.append(pb.Entry{Index: i + offset})
615 }
616
617 first := offset + 1
618 tests := []struct {
619 lo, hi uint64
620 wpanic bool
621 wErrCompacted bool
622 }{
623 {
624 first - 2, first + 1,
625 false,
626 true,
627 },
628 {
629 first - 1, first + 1,
630 false,
631 true,
632 },
633 {
634 first, first,
635 false,
636 false,
637 },
638 {
639 first + num/2, first + num/2,
640 false,
641 false,
642 },
643 {
644 first + num - 1, first + num - 1,
645 false,
646 false,
647 },
648 {
649 first + num, first + num,
650 false,
651 false,
652 },
653 {
654 first + num, first + num + 1,
655 true,
656 false,
657 },
658 {
659 first + num + 1, first + num + 1,
660 true,
661 false,
662 },
663 }
664
665 for i, tt := range tests {
666 func() {
667 defer func() {
668 if r := recover(); r != nil {
669 if !tt.wpanic {
670 t.Errorf("%d: panic = %v, want %v: %v", i, true, false, r)
671 }
672 }
673 }()
674 err := l.mustCheckOutOfBounds(tt.lo, tt.hi)
675 if tt.wpanic {
676 t.Errorf("#%d: panic = %v, want %v", i, false, true)
677 }
678 if tt.wErrCompacted && err != ErrCompacted {
679 t.Errorf("#%d: err = %v, want %v", i, err, ErrCompacted)
680 }
681 if !tt.wErrCompacted && err != nil {
682 t.Errorf("#%d: unexpected err %v", i, err)
683 }
684 }()
685 }
686 }
687
688 func TestTerm(t *testing.T) {
689 var i uint64
690 offset := uint64(100)
691 num := uint64(100)
692
693 storage := NewMemoryStorage()
694 storage.ApplySnapshot(pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: offset, Term: 1}})
695 l := newLog(storage, raftLogger)
696 for i = 1; i < num; i++ {
697 l.append(pb.Entry{Index: offset + i, Term: i})
698 }
699
700 tests := []struct {
701 index uint64
702 w uint64
703 }{
704 {offset - 1, 0},
705 {offset, 1},
706 {offset + num/2, num / 2},
707 {offset + num - 1, num - 1},
708 {offset + num, 0},
709 }
710
711 for j, tt := range tests {
712 term := mustTerm(l.term(tt.index))
713 if term != tt.w {
714 t.Errorf("#%d: at = %d, want %d", j, term, tt.w)
715 }
716 }
717 }
718
719 func TestTermWithUnstableSnapshot(t *testing.T) {
720 storagesnapi := uint64(100)
721 unstablesnapi := storagesnapi + 5
722
723 storage := NewMemoryStorage()
724 storage.ApplySnapshot(pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: storagesnapi, Term: 1}})
725 l := newLog(storage, raftLogger)
726 l.restore(pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: unstablesnapi, Term: 1}})
727
728 tests := []struct {
729 index uint64
730 w uint64
731 }{
732
733 {storagesnapi, 0},
734
735 {storagesnapi + 1, 0},
736 {unstablesnapi - 1, 0},
737
738 {unstablesnapi, 1},
739 }
740
741 for i, tt := range tests {
742 term := mustTerm(l.term(tt.index))
743 if term != tt.w {
744 t.Errorf("#%d: at = %d, want %d", i, term, tt.w)
745 }
746 }
747 }
748
749 func TestSlice(t *testing.T) {
750 var i uint64
751 offset := uint64(100)
752 num := uint64(100)
753 last := offset + num
754 half := offset + num/2
755 halfe := pb.Entry{Index: half, Term: half}
756
757 storage := NewMemoryStorage()
758 storage.ApplySnapshot(pb.Snapshot{Metadata: pb.SnapshotMetadata{Index: offset}})
759 for i = 1; i < num/2; i++ {
760 storage.Append([]pb.Entry{{Index: offset + i, Term: offset + i}})
761 }
762 l := newLog(storage, raftLogger)
763 for i = num / 2; i < num; i++ {
764 l.append(pb.Entry{Index: offset + i, Term: offset + i})
765 }
766
767 tests := []struct {
768 from uint64
769 to uint64
770 limit uint64
771
772 w []pb.Entry
773 wpanic bool
774 }{
775
776 {offset - 1, offset + 1, noLimit, nil, false},
777 {offset, offset + 1, noLimit, nil, false},
778 {half - 1, half + 1, noLimit, []pb.Entry{{Index: half - 1, Term: half - 1}, {Index: half, Term: half}}, false},
779 {half, half + 1, noLimit, []pb.Entry{{Index: half, Term: half}}, false},
780 {last - 1, last, noLimit, []pb.Entry{{Index: last - 1, Term: last - 1}}, false},
781 {last, last + 1, noLimit, nil, true},
782
783
784 {half - 1, half + 1, 0, []pb.Entry{{Index: half - 1, Term: half - 1}}, false},
785 {half - 1, half + 1, uint64(halfe.Size() + 1), []pb.Entry{{Index: half - 1, Term: half - 1}}, false},
786 {half - 2, half + 1, uint64(halfe.Size() + 1), []pb.Entry{{Index: half - 2, Term: half - 2}}, false},
787 {half - 1, half + 1, uint64(halfe.Size() * 2), []pb.Entry{{Index: half - 1, Term: half - 1}, {Index: half, Term: half}}, false},
788 {half - 1, half + 2, uint64(halfe.Size() * 3), []pb.Entry{{Index: half - 1, Term: half - 1}, {Index: half, Term: half}, {Index: half + 1, Term: half + 1}}, false},
789 {half, half + 2, uint64(halfe.Size()), []pb.Entry{{Index: half, Term: half}}, false},
790 {half, half + 2, uint64(halfe.Size() * 2), []pb.Entry{{Index: half, Term: half}, {Index: half + 1, Term: half + 1}}, false},
791 }
792
793 for j, tt := range tests {
794 func() {
795 defer func() {
796 if r := recover(); r != nil {
797 if !tt.wpanic {
798 t.Errorf("%d: panic = %v, want %v: %v", j, true, false, r)
799 }
800 }
801 }()
802 g, err := l.slice(tt.from, tt.to, tt.limit)
803 if tt.from <= offset && err != ErrCompacted {
804 t.Fatalf("#%d: err = %v, want %v", j, err, ErrCompacted)
805 }
806 if tt.from > offset && err != nil {
807 t.Fatalf("#%d: unexpected error %v", j, err)
808 }
809 if !reflect.DeepEqual(g, tt.w) {
810 t.Errorf("#%d: from %d to %d = %v, want %v", j, tt.from, tt.to, g, tt.w)
811 }
812 }()
813 }
814 }
815
816 func mustTerm(term uint64, err error) uint64 {
817 if err != nil {
818 panic(err)
819 }
820 return term
821 }
822
View as plain text