etcd/raft/log_test.go

306 lines
7.0 KiB
Go
Raw Normal View History

2014-06-28 03:15:04 +04:00
package raft
import (
"reflect"
"testing"
2014-08-28 05:53:18 +04:00
pb "github.com/coreos/etcd/raft/raftpb"
2014-06-28 03:15:04 +04:00
)
2014-07-14 21:58:41 +04:00
// TestAppend ensures:
// 1. If an existing entry conflicts with a new one (same index
// but different terms), delete the existing entry and all that
// follow it
// 2.Append any new entries not already in the log
func TestAppend(t *testing.T) {
2014-08-28 05:53:18 +04:00
previousEnts := []pb.Entry{{Term: 1}, {Term: 2}}
previousUnstable := int64(3)
2014-07-14 21:58:41 +04:00
tests := []struct {
after int64
2014-08-28 05:53:18 +04:00
ents []pb.Entry
windex int64
2014-08-28 05:53:18 +04:00
wents []pb.Entry
wunstable int64
2014-07-14 21:58:41 +04:00
}{
{
2,
2014-08-28 05:53:18 +04:00
[]pb.Entry{},
2014-07-14 21:58:41 +04:00
2,
2014-08-28 05:53:18 +04:00
[]pb.Entry{{Term: 1}, {Term: 2}},
3,
2014-07-14 21:58:41 +04:00
},
{
2,
2014-08-28 05:53:18 +04:00
[]pb.Entry{{Term: 2}},
2014-07-14 21:58:41 +04:00
3,
2014-08-28 05:53:18 +04:00
[]pb.Entry{{Term: 1}, {Term: 2}, {Term: 2}},
3,
2014-07-14 21:58:41 +04:00
},
// conflicts with index 1
{
0,
2014-08-28 05:53:18 +04:00
[]pb.Entry{{Term: 2}},
2014-07-14 21:58:41 +04:00
1,
2014-08-28 05:53:18 +04:00
[]pb.Entry{{Term: 2}},
1,
2014-07-14 21:58:41 +04:00
},
// conflicts with index 2
{
1,
2014-08-28 05:53:18 +04:00
[]pb.Entry{{Term: 3}, {Term: 3}},
2014-07-14 21:58:41 +04:00
3,
2014-08-28 05:53:18 +04:00
[]pb.Entry{{Term: 1}, {Term: 3}, {Term: 3}},
2,
2014-07-14 21:58:41 +04:00
},
}
for i, tt := range tests {
2014-07-24 03:15:25 +04:00
raftLog := newLog()
raftLog.ents = append(raftLog.ents, previousEnts...)
raftLog.unstable = previousUnstable
2014-07-24 03:15:25 +04:00
index := raftLog.append(tt.after, tt.ents...)
2014-07-14 21:58:41 +04:00
if index != tt.windex {
t.Errorf("#%d: lastIndex = %d, want %d", i, index, tt.windex)
}
2014-07-24 03:15:25 +04:00
if g := raftLog.entries(1); !reflect.DeepEqual(g, tt.wents) {
2014-07-14 21:58:41 +04:00
t.Errorf("#%d: logEnts = %+v, want %+v", i, g, tt.wents)
}
if g := raftLog.unstable; g != tt.wunstable {
t.Errorf("#%d: unstable = %d, want %d", i, g, tt.wunstable)
}
2014-07-14 21:58:41 +04:00
}
}
2014-07-01 02:15:51 +04:00
// TestCompactionSideEffects ensures that all the log related funcationality works correctly after
// a compaction.
func TestCompactionSideEffects(t *testing.T) {
2014-07-11 09:51:37 +04:00
var i int64
lastIndex := int64(1000)
2014-07-24 03:15:25 +04:00
raftLog := newLog()
2014-07-01 02:15:51 +04:00
2014-07-11 09:51:37 +04:00
for i = 0; i < lastIndex; i++ {
2014-08-28 05:53:18 +04:00
raftLog.append(int64(i), pb.Entry{Term: int64(i + 1), Index: int64(i + 1)})
2014-07-01 02:15:51 +04:00
}
2014-07-24 03:15:25 +04:00
raftLog.compact(500)
2014-07-01 02:15:51 +04:00
2014-07-24 03:15:25 +04:00
if raftLog.lastIndex() != lastIndex {
t.Errorf("lastIndex = %d, want %d", raftLog.lastIndex(), lastIndex)
2014-07-01 02:15:51 +04:00
}
2014-07-24 03:15:25 +04:00
for i := raftLog.offset; i <= raftLog.lastIndex(); i++ {
if raftLog.term(i) != i {
t.Errorf("term(%d) = %d, want %d", i, raftLog.term(i), i)
2014-07-01 02:15:51 +04:00
}
}
2014-07-24 03:15:25 +04:00
for i := raftLog.offset; i <= raftLog.lastIndex(); i++ {
if !raftLog.matchTerm(i, i) {
2014-07-01 02:15:51 +04:00
t.Errorf("matchTerm(%d) = false, want true", i)
}
}
2014-08-02 08:43:08 +04:00
unstableEnts := raftLog.unstableEnts()
if g := len(unstableEnts); g != 500 {
t.Errorf("len(unstableEntries) = %d, want = %d", g, 500)
}
2014-08-02 08:43:08 +04:00
if unstableEnts[0].Index != 501 {
t.Errorf("Index = %d, want = %d", unstableEnts[0].Index, 501)
}
2014-07-24 03:15:25 +04:00
prev := raftLog.lastIndex()
2014-08-28 05:53:18 +04:00
raftLog.append(raftLog.lastIndex(), pb.Entry{Term: raftLog.lastIndex() + 1})
2014-07-24 03:15:25 +04:00
if raftLog.lastIndex() != prev+1 {
t.Errorf("lastIndex = %d, want = %d", raftLog.lastIndex(), prev+1)
2014-07-01 02:15:51 +04:00
}
2014-07-24 03:15:25 +04:00
ents := raftLog.entries(raftLog.lastIndex())
2014-07-01 02:15:51 +04:00
if len(ents) != 1 {
t.Errorf("len(entries) = %d, want = %d", len(ents), 1)
}
}
func TestUnstableEnts(t *testing.T) {
2014-08-28 05:53:18 +04:00
previousEnts := []pb.Entry{{Term: 1, Index: 1}, {Term: 2, Index: 2}}
tests := []struct {
unstable int64
2014-08-28 05:53:18 +04:00
wents []pb.Entry
wunstable int64
}{
2014-08-02 08:43:08 +04:00
{3, nil, 3},
{1, previousEnts, 3},
}
for i, tt := range tests {
raftLog := newLog()
raftLog.ents = append(raftLog.ents, previousEnts...)
raftLog.unstable = tt.unstable
2014-08-02 08:43:08 +04:00
ents := raftLog.unstableEnts()
2014-08-22 23:59:34 +04:00
raftLog.resetUnstable()
if !reflect.DeepEqual(ents, tt.wents) {
t.Errorf("#%d: unstableEnts = %+v, want %+v", i, ents, tt.wents)
}
if g := raftLog.unstable; g != tt.wunstable {
t.Errorf("#%d: unstable = %d, want %d", i, g, tt.wunstable)
}
}
}
2014-07-01 02:15:51 +04:00
//TestCompaction ensures that the number of log entreis is correct after compactions.
func TestCompaction(t *testing.T) {
tests := []struct {
app int
2014-07-11 09:51:37 +04:00
compact []int64
2014-07-01 02:15:51 +04:00
wleft []int
wallow bool
}{
// out of upper bound
2014-07-11 09:51:37 +04:00
{1000, []int64{1001}, []int{-1}, false},
{1000, []int64{300, 500, 800, 900}, []int{701, 501, 201, 101}, true},
2014-07-01 02:15:51 +04:00
// out of lower bound
2014-07-11 09:51:37 +04:00
{1000, []int64{300, 299}, []int{701, -1}, false},
2014-07-01 02:15:51 +04:00
}
for i, tt := range tests {
func() {
defer func() {
if r := recover(); r != nil {
if tt.wallow == true {
t.Errorf("%d: allow = %v, want %v", i, false, true)
}
}
}()
2014-07-24 03:15:25 +04:00
raftLog := newLog()
2014-07-01 02:15:51 +04:00
for i := 0; i < tt.app; i++ {
2014-08-28 05:53:18 +04:00
raftLog.append(int64(i), pb.Entry{})
2014-07-01 02:15:51 +04:00
}
for j := 0; j < len(tt.compact); j++ {
2014-07-24 03:15:25 +04:00
raftLog.compact(tt.compact[j])
if len(raftLog.ents) != tt.wleft[j] {
t.Errorf("#%d.%d len = %d, want %d", i, j, len(raftLog.ents), tt.wleft[j])
2014-07-01 02:15:51 +04:00
}
}
}()
}
}
2014-07-01 23:10:43 +04:00
func TestLogRestore(t *testing.T) {
2014-07-11 09:51:37 +04:00
var i int64
2014-07-24 03:15:25 +04:00
raftLog := newLog()
2014-07-11 09:51:37 +04:00
for i = 0; i < 100; i++ {
2014-08-28 05:53:18 +04:00
raftLog.append(i, pb.Entry{Term: i + 1})
2014-07-01 23:10:43 +04:00
}
2014-07-11 09:51:37 +04:00
index := int64(1000)
term := int64(1000)
2014-08-28 05:53:18 +04:00
raftLog.restore(pb.Snapshot{Index: index, Term: term})
2014-07-01 23:10:43 +04:00
// only has the guard entry
2014-07-24 03:15:25 +04:00
if len(raftLog.ents) != 1 {
t.Errorf("len = %d, want 0", len(raftLog.ents))
2014-07-01 23:10:43 +04:00
}
2014-07-24 03:15:25 +04:00
if raftLog.offset != index {
t.Errorf("offset = %d, want %d", raftLog.offset, index)
2014-07-01 23:10:43 +04:00
}
2014-07-24 03:15:25 +04:00
if raftLog.applied != index {
t.Errorf("applied = %d, want %d", raftLog.applied, index)
2014-07-01 23:10:43 +04:00
}
2014-07-24 03:15:25 +04:00
if raftLog.committed != index {
t.Errorf("comitted = %d, want %d", raftLog.committed, index)
2014-07-01 23:10:43 +04:00
}
if raftLog.unstable != index+1 {
t.Errorf("unstable = %d, want %d", raftLog.unstable, index+1)
}
2014-07-24 03:15:25 +04:00
if raftLog.term(index) != term {
t.Errorf("term = %d, want %d", raftLog.term(index), term)
2014-07-01 23:10:43 +04:00
}
}
2014-06-28 03:15:04 +04:00
func TestIsOutOfBounds(t *testing.T) {
2014-07-11 09:51:37 +04:00
offset := int64(100)
num := int64(100)
2014-08-28 05:53:18 +04:00
l := &raftLog{offset: offset, ents: make([]pb.Entry, num)}
2014-06-28 03:15:04 +04:00
tests := []struct {
2014-07-11 09:51:37 +04:00
index int64
2014-06-28 03:15:04 +04:00
w bool
}{
{offset - 1, true},
{offset, false},
{offset + num/2, false},
{offset + num - 1, false},
{offset + num, true},
}
for i, tt := range tests {
g := l.isOutOfBounds(tt.index)
if g != tt.w {
t.Errorf("#%d: isOutOfBounds = %v, want %v", i, g, tt.w)
}
}
}
func TestAt(t *testing.T) {
2014-07-11 09:51:37 +04:00
var i int64
offset := int64(100)
num := int64(100)
2014-06-28 03:15:04 +04:00
2014-07-24 03:15:25 +04:00
l := &raftLog{offset: offset}
2014-07-11 09:51:37 +04:00
for i = 0; i < num; i++ {
2014-08-28 05:53:18 +04:00
l.ents = append(l.ents, pb.Entry{Term: i})
2014-06-28 03:15:04 +04:00
}
tests := []struct {
2014-07-11 09:51:37 +04:00
index int64
2014-08-28 05:53:18 +04:00
w *pb.Entry
2014-06-28 03:15:04 +04:00
}{
{offset - 1, nil},
2014-08-28 05:53:18 +04:00
{offset, &pb.Entry{Term: 0}},
{offset + num/2, &pb.Entry{Term: num / 2}},
{offset + num - 1, &pb.Entry{Term: num - 1}},
2014-06-28 03:15:04 +04:00
{offset + num, nil},
}
for i, tt := range tests {
g := l.at(tt.index)
if !reflect.DeepEqual(g, tt.w) {
t.Errorf("#%d: at = %v, want %v", i, g, tt.w)
}
}
}
func TestSlice(t *testing.T) {
2014-07-11 09:51:37 +04:00
var i int64
offset := int64(100)
num := int64(100)
2014-06-28 03:15:04 +04:00
2014-07-24 03:15:25 +04:00
l := &raftLog{offset: offset}
2014-07-11 09:51:37 +04:00
for i = 0; i < num; i++ {
2014-08-28 05:53:18 +04:00
l.ents = append(l.ents, pb.Entry{Term: i})
2014-06-28 03:15:04 +04:00
}
tests := []struct {
2014-07-11 09:51:37 +04:00
from int64
to int64
2014-08-28 05:53:18 +04:00
w []pb.Entry
2014-06-28 03:15:04 +04:00
}{
{offset - 1, offset + 1, nil},
2014-08-28 05:53:18 +04:00
{offset, offset + 1, []pb.Entry{{Term: 0}}},
{offset + num/2, offset + num/2 + 1, []pb.Entry{{Term: num / 2}}},
{offset + num - 1, offset + num, []pb.Entry{{Term: num - 1}}},
2014-06-28 03:15:04 +04:00
{offset + num, offset + num + 1, nil},
{offset + num/2, offset + num/2, nil},
{offset + num/2, offset + num/2 - 1, nil},
}
for i, tt := range tests {
g := l.slice(tt.from, tt.to)
if !reflect.DeepEqual(g, tt.w) {
t.Errorf("#%d: from %d to %d = %v, want %v", i, tt.from, tt.to, g, tt.w)
}
}
}