From 90f26e4a560748c9b265fd0e90d68d6834062d91 Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Sat, 25 Oct 2014 18:49:49 -0700 Subject: [PATCH] raft: add test for findConflict --- raft/log.go | 10 ++++++++++ raft/log_test.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/raft/log.go b/raft/log.go index 032fc10d3..eea84a977 100644 --- a/raft/log.go +++ b/raft/log.go @@ -83,6 +83,16 @@ func (l *raftLog) append(after uint64, ents ...pb.Entry) uint64 { return l.lastIndex() } +// findConflict finds the index of the conflict. +// It returns the the first pair of confilcting entries between the existing +// entries and the given entries, if there is any. +// If there is no conflicting entries, and the existing entries contains +// all the given entries, zero will be returned. +// If there is no conflicting entries, but the given entries contains new +// entries, the index of the first new entry will be returned. +// Conflicting entries has the same index but different term. +// The first given entry MUST have the index equal to from. +// The index of the given entries MUST be continously increasing. func (l *raftLog) findConflict(from uint64, ents []pb.Entry) uint64 { for i, ne := range ents { if oe := l.at(from + uint64(i)); oe == nil || oe.Term != ne.Term { diff --git a/raft/log_test.go b/raft/log_test.go index 56ab2b639..dc5e49a0e 100644 --- a/raft/log_test.go +++ b/raft/log_test.go @@ -23,6 +23,42 @@ import ( pb "github.com/coreos/etcd/raft/raftpb" ) +func TestFindConflict(t *testing.T) { + previousEnts := []pb.Entry{{Term: 1}, {Term: 2}, {Term: 3}} + tests := []struct { + from uint64 + ents []pb.Entry + wconflict uint64 + }{ + // no conflict, empty ent + {1, []pb.Entry{}, 0}, + {3, []pb.Entry{}, 0}, + // no conflict + {1, []pb.Entry{{Term: 1}, {Term: 2}, {Term: 3}}, 0}, + {2, []pb.Entry{{Term: 2}, {Term: 3}}, 0}, + {3, []pb.Entry{{Term: 3}}, 0}, + // no conflict, but has new entries + {1, []pb.Entry{{Term: 1}, {Term: 2}, {Term: 3}, {Term: 4}, {Term: 4}}, 4}, + {2, []pb.Entry{{Term: 2}, {Term: 3}, {Term: 4}, {Term: 4}}, 4}, + {3, []pb.Entry{{Term: 3}, {Term: 4}, {Term: 4}}, 4}, + {4, []pb.Entry{{Term: 4}, {Term: 4}}, 4}, + // conflicts with existing entries + {1, []pb.Entry{{Term: 4}, {Term: 4}}, 1}, + {2, []pb.Entry{{Term: 1}, {Term: 4}, {Term: 4}}, 2}, + {3, []pb.Entry{{Term: 1}, {Term: 2}, {Term: 4}, {Term: 4}}, 3}, + } + + for i, tt := range tests { + raftLog := newLog() + raftLog.ents = append(raftLog.ents, previousEnts...) + + gconflict := raftLog.findConflict(tt.from, tt.ents) + if gconflict != tt.wconflict { + t.Errorf("#%d: conflict = %d, want %d", i, gconflict, tt.wconflict) + } + } +} + // TestAppend ensures: // 1. If an existing entry conflicts with a new one (same index // but different terms), delete the existing entry and all that