// 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" "strings" "testing" pb "go.etcd.io/etcd/raft/raftpb" ) var testFormatter EntryFormatter = func(data []byte) string { return strings.ToUpper(string(data)) } func TestDescribeEntry(t *testing.T) { entry := pb.Entry{ Term: 1, Index: 2, Type: pb.EntryNormal, Data: []byte("hello\x00world"), } defaultFormatted := DescribeEntry(entry, nil) if defaultFormatted != "1/2 EntryNormal \"hello\\x00world\"" { t.Errorf("unexpected default output: %s", defaultFormatted) } customFormatted := DescribeEntry(entry, testFormatter) if customFormatted != "1/2 EntryNormal HELLO\x00WORLD" { t.Errorf("unexpected custom output: %s", customFormatted) } } func TestLimitSize(t *testing.T) { ents := []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}, {Index: 6, Term: 6}} tests := []struct { maxsize uint64 wentries []pb.Entry }{ {math.MaxUint64, []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 {0, []pb.Entry{{Index: 4, Term: 4}}}, // limit to 2 {uint64(ents[0].Size() + ents[1].Size()), []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}}}, // limit to 2 {uint64(ents[0].Size() + ents[1].Size() + ents[2].Size()/2), []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}}}, {uint64(ents[0].Size() + ents[1].Size() + ents[2].Size() - 1), []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}}}, // all {uint64(ents[0].Size() + ents[1].Size() + ents[2].Size()), []pb.Entry{{Index: 4, Term: 4}, {Index: 5, Term: 5}, {Index: 6, Term: 6}}}, } for i, tt := range tests { if !reflect.DeepEqual(limitSize(ents, tt.maxsize), tt.wentries) { t.Errorf("#%d: entries = %v, want %v", i, limitSize(ents, tt.maxsize), tt.wentries) } } } func TestIsLocalMsg(t *testing.T) { tests := []struct { msgt pb.MessageType isLocal bool }{ {pb.MsgHup, true}, {pb.MsgBeat, true}, {pb.MsgUnreachable, true}, {pb.MsgSnapStatus, true}, {pb.MsgCheckQuorum, true}, {pb.MsgTransferLeader, false}, {pb.MsgProp, false}, {pb.MsgApp, false}, {pb.MsgAppResp, false}, {pb.MsgVote, false}, {pb.MsgVoteResp, false}, {pb.MsgSnap, false}, {pb.MsgHeartbeat, false}, {pb.MsgHeartbeatResp, false}, {pb.MsgTimeoutNow, false}, {pb.MsgReadIndex, false}, {pb.MsgReadIndexResp, false}, {pb.MsgPreVote, false}, {pb.MsgPreVoteResp, false}, } for i, tt := range tests { got := IsLocalMsg(tt.msgt) if got != tt.isLocal { t.Errorf("#%d: got %v, want %v", i, got, tt.isLocal) } } }