mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
248 lines
6.9 KiB
Go
248 lines
6.9 KiB
Go
// Copyright 2015 The etcd Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package raft
|
|
|
|
import (
|
|
"math"
|
|
"reflect"
|
|
"testing"
|
|
|
|
pb "github.com/coreos/etcd/raft/raftpb"
|
|
)
|
|
|
|
// TODO(xiangli): Test panic cases
|
|
|
|
func TestStorageTerm(t *testing.T) {
|
|
ents := []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}}
|
|
tests := []struct {
|
|
i uint64
|
|
|
|
werr error
|
|
wterm uint64
|
|
}{
|
|
{2, ErrCompacted, 0},
|
|
{3, nil, 3},
|
|
{4, nil, 4},
|
|
{5, nil, 5},
|
|
}
|
|
|
|
for i, tt := range tests {
|
|
s := &MemoryStorage{ents: ents}
|
|
term, err := s.Term(tt.i)
|
|
if err != tt.werr {
|
|
t.Errorf("#%d: err = %v, want %v", i, err, tt.werr)
|
|
}
|
|
if term != tt.wterm {
|
|
t.Errorf("#%d: term = %d, want %d", i, term, tt.wterm)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStorageEntries(t *testing.T) {
|
|
ents := []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}, {Index: 6, Term: 6}}
|
|
tests := []struct {
|
|
lo, hi, maxsize uint64
|
|
|
|
werr error
|
|
wentries []pb.Entry
|
|
}{
|
|
{2, 6, math.MaxUint64, ErrCompacted, nil},
|
|
{3, 4, math.MaxUint64, ErrCompacted, nil},
|
|
{4, 5, math.MaxUint64, nil, []pb.Entry{{Index: 4, Term: 4}}},
|
|
{4, 6, math.MaxUint64, nil, []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}}},
|
|
{4, 7, math.MaxUint64, nil, []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}, {Index: 6, Term: 6}}},
|
|
// even if maxsize is zero, the first entry should be returned
|
|
{4, 7, 0, nil, []pb.Entry{{Index: 4, Term: 4}}},
|
|
// limit to 2
|
|
{4, 7, uint64(ents[1].Size() + ents[2].Size()), nil, []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}}},
|
|
// limit to 2
|
|
{4, 7, uint64(ents[1].Size() + ents[2].Size() + ents[3].Size()/2), nil, []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}}},
|
|
{4, 7, uint64(ents[1].Size() + ents[2].Size() + ents[3].Size() - 1), nil, []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}}},
|
|
// all
|
|
{4, 7, uint64(ents[1].Size() + ents[2].Size() + ents[3].Size()), nil, []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}, {Index: 6, Term: 6}}},
|
|
}
|
|
|
|
for i, tt := range tests {
|
|
s := &MemoryStorage{ents: ents}
|
|
entries, err := s.Entries(tt.lo, tt.hi, tt.maxsize)
|
|
if err != tt.werr {
|
|
t.Errorf("#%d: err = %v, want %v", i, err, tt.werr)
|
|
}
|
|
if !reflect.DeepEqual(entries, tt.wentries) {
|
|
t.Errorf("#%d: entries = %v, want %v", i, entries, tt.wentries)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStorageLastIndex(t *testing.T) {
|
|
ents := []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}}
|
|
s := &MemoryStorage{ents: ents}
|
|
|
|
last, err := s.LastIndex()
|
|
if err != nil {
|
|
t.Errorf("err = %v, want nil", err)
|
|
}
|
|
if last != 5 {
|
|
t.Errorf("term = %d, want %d", last, 5)
|
|
}
|
|
|
|
s.Append([]pb.Entry{{Index: 6, Term: 5}})
|
|
last, err = s.LastIndex()
|
|
if err != nil {
|
|
t.Errorf("err = %v, want nil", err)
|
|
}
|
|
if last != 6 {
|
|
t.Errorf("last = %d, want %d", last, 5)
|
|
}
|
|
}
|
|
|
|
func TestStorageFirstIndex(t *testing.T) {
|
|
ents := []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}}
|
|
s := &MemoryStorage{ents: ents}
|
|
|
|
first, err := s.FirstIndex()
|
|
if err != nil {
|
|
t.Errorf("err = %v, want nil", err)
|
|
}
|
|
if first != 4 {
|
|
t.Errorf("first = %d, want %d", first, 4)
|
|
}
|
|
|
|
s.Compact(4)
|
|
first, err = s.FirstIndex()
|
|
if err != nil {
|
|
t.Errorf("err = %v, want nil", err)
|
|
}
|
|
if first != 5 {
|
|
t.Errorf("first = %d, want %d", first, 5)
|
|
}
|
|
}
|
|
|
|
func TestStorageCompact(t *testing.T) {
|
|
ents := []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}}
|
|
tests := []struct {
|
|
i uint64
|
|
|
|
werr error
|
|
windex uint64
|
|
wterm uint64
|
|
wlen int
|
|
}{
|
|
{2, ErrCompacted, 3, 3, 3},
|
|
{3, ErrCompacted, 3, 3, 3},
|
|
{4, nil, 4, 4, 2},
|
|
{5, nil, 5, 5, 1},
|
|
}
|
|
|
|
for i, tt := range tests {
|
|
s := &MemoryStorage{ents: ents}
|
|
err := s.Compact(tt.i)
|
|
if err != tt.werr {
|
|
t.Errorf("#%d: err = %v, want %v", i, err, tt.werr)
|
|
}
|
|
if s.ents[0].Index != tt.windex {
|
|
t.Errorf("#%d: index = %d, want %d", i, s.ents[0].Index, tt.windex)
|
|
}
|
|
if s.ents[0].Term != tt.wterm {
|
|
t.Errorf("#%d: term = %d, want %d", i, s.ents[0].Term, tt.wterm)
|
|
}
|
|
if len(s.ents) != tt.wlen {
|
|
t.Errorf("#%d: len = %d, want %d", i, len(s.ents), tt.wlen)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStorageCreateSnapshot(t *testing.T) {
|
|
ents := []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}}
|
|
cs := &pb.ConfState{Nodes: []uint64{1, 2, 3}}
|
|
data := []byte("data")
|
|
|
|
tests := []struct {
|
|
i uint64
|
|
|
|
werr error
|
|
wsnap pb.Snapshot
|
|
}{
|
|
{4, nil, pb.Snapshot{Data: data, Metadata: pb.SnapshotMetadata{Index: 4, Term: 4, ConfState: *cs}}},
|
|
{5, nil, pb.Snapshot{Data: data, Metadata: pb.SnapshotMetadata{Index: 5, Term: 5, ConfState: *cs}}},
|
|
}
|
|
|
|
for i, tt := range tests {
|
|
s := &MemoryStorage{ents: ents}
|
|
snap, err := s.CreateSnapshot(tt.i, cs, data)
|
|
if err != tt.werr {
|
|
t.Errorf("#%d: err = %v, want %v", i, err, tt.werr)
|
|
}
|
|
if !reflect.DeepEqual(snap, tt.wsnap) {
|
|
t.Errorf("#%d: snap = %+v, want %+v", i, snap, tt.wsnap)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStorageAppend(t *testing.T) {
|
|
ents := []pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}}
|
|
tests := []struct {
|
|
entries []pb.Entry
|
|
|
|
werr error
|
|
wentries []pb.Entry
|
|
}{
|
|
{
|
|
[]pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}},
|
|
nil,
|
|
[]pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}},
|
|
},
|
|
{
|
|
[]pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 6}, {Index: 5, Term: 6}},
|
|
nil,
|
|
[]pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 6}, {Index: 5, Term: 6}},
|
|
},
|
|
{
|
|
[]pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}, {Index: 6, Term: 5}},
|
|
nil,
|
|
[]pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}, {Index: 6, Term: 5}},
|
|
},
|
|
// truncate incoming entries, truncate the existing entries and append
|
|
{
|
|
[]pb.Entry{{Index: 2, Term: 3}, {Index: 3, Term: 3}, {Index: 4, Term: 5}},
|
|
nil,
|
|
[]pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 5}},
|
|
},
|
|
// truncate the existing entries and append
|
|
{
|
|
[]pb.Entry{{Index: 4, Term: 5}},
|
|
nil,
|
|
[]pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 5}},
|
|
},
|
|
// direct append
|
|
{
|
|
[]pb.Entry{{Index: 6, Term: 5}},
|
|
nil,
|
|
[]pb.Entry{{Index: 3, Term: 3}, {Index: 4, Term: 4}, {Index: 5, Term: 5}, {Index: 6, Term: 5}},
|
|
},
|
|
}
|
|
|
|
for i, tt := range tests {
|
|
s := &MemoryStorage{ents: ents}
|
|
err := s.Append(tt.entries)
|
|
if err != tt.werr {
|
|
t.Errorf("#%d: err = %v, want %v", i, err, tt.werr)
|
|
}
|
|
if !reflect.DeepEqual(s.ents, tt.wentries) {
|
|
t.Errorf("#%d: entries = %v, want %v", i, s.ents, tt.wentries)
|
|
}
|
|
}
|
|
}
|