2013-04-17 02:28:08 +00:00
package raft
import (
2013-06-23 18:42:31 +00:00
//"reflect"
2013-05-05 19:48:15 +00:00
"sync"
2013-04-17 02:28:08 +00:00
"testing"
2013-05-05 20:01:06 +00:00
"time"
2013-06-11 22:30:13 +00:00
"fmt"
"strconv"
2013-04-17 02:28:08 +00:00
)
//------------------------------------------------------------------------------
//
// Tests
//
//------------------------------------------------------------------------------
2013-04-28 22:49:52 +00:00
//--------------------------------------
// Request Vote
//--------------------------------------
// Ensure that we can request a vote from a server that has not voted.
2013-06-23 18:42:31 +00:00
// func TestServerRequestVote(t *testing.T) {
// server := newTestServer("1", &testTransporter{})
// server.Initialize()
// server.StartLeader()
// defer server.Stop()
// resp, err := server.RequestVote(NewRequestVoteRequest(1, "foo", 0, 0))
// if !(resp.Term == 1 && resp.VoteGranted && err == nil) {
// t.Fatalf("Invalid request vote response: %v/%v (%v)", resp.Term, resp.VoteGranted, err)
// }
// }
// // Ensure that a vote request is denied if it comes from an old term.
// func TestServerRequestVoteDeniedForStaleTerm(t *testing.T) {
// server := newTestServer("1", &testTransporter{})
// server.Initialize()
// server.StartLeader()
// server.state = Leader
// server.currentTerm = 2
// defer server.Stop()
// resp, err := server.RequestVote(NewRequestVoteRequest(1, "foo", 0, 0))
// if !(resp.Term == 2 && !resp.VoteGranted && err != nil && err.Error() == "raft.Server: Stale term: 1 < 2") {
// t.Fatalf("Invalid request vote response: %v/%v (%v)", resp.Term, resp.VoteGranted, err)
// }
// if server.currentTerm != 2 && server.state != Follower {
// t.Fatalf("Server did not update term and demote: %v / %v", server.currentTerm, server.state)
// }
// }
// // Ensure that a vote request is denied if we've already voted for a different candidate.
// func TestServerRequestVoteDeniedIfAlreadyVoted(t *testing.T) {
// server := newTestServer("1", &testTransporter{})
// server.Initialize()
// server.StartLeader()
// server.currentTerm = 2
// defer server.Stop()
// resp, err := server.RequestVote(NewRequestVoteRequest(2, "foo", 0, 0))
// if !(resp.Term == 2 && resp.VoteGranted && err == nil) {
// t.Fatalf("First vote should not have been denied (%v)", err)
// }
// resp, err = server.RequestVote(NewRequestVoteRequest(2, "bar", 0, 0))
// if !(resp.Term == 2 && !resp.VoteGranted && err != nil && err.Error() == "raft.Server: Already voted for foo") {
// t.Fatalf("Second vote should have been denied (%v)", err)
// }
// }
// // Ensure that a vote request is approved if vote occurs in a new term.
// func TestServerRequestVoteApprovedIfAlreadyVotedInOlderTerm(t *testing.T) {
// server := newTestServer("1", &testTransporter{})
// server.Initialize()
// server.StartLeader()
// server.currentTerm = 2
// defer server.Stop()
// resp, err := server.RequestVote(NewRequestVoteRequest(2, "foo", 0, 0))
// if !(resp.Term == 2 && resp.VoteGranted && server.VotedFor() == "foo" && err == nil) {
// t.Fatalf("First vote should not have been denied (%v)", err)
// }
// resp, err = server.RequestVote(NewRequestVoteRequest(3, "bar", 0, 0))
// if !(resp.Term == 3 && resp.VoteGranted && server.VotedFor() == "bar" && err == nil) {
// t.Fatalf("Second vote should have been approved (%v)", err)
// }
// }
// // Ensure that a vote request is denied if the log is out of date.
// func TestServerRequestVoteDenyIfCandidateLogIsBehind(t *testing.T) {
// server := newTestServerWithLog("1", &testTransporter{},
// `cf4aab23 0000000000000001 0000000000000001 cmd_1 {"val":"foo","i":20}`+"\n"+
// `4c08d91f 0000000000000002 0000000000000001 cmd_2 {"x":100}`+"\n"+
// `6ac5807c 0000000000000003 0000000000000002 cmd_1 {"val":"bar","i":0}`+"\n")
// server.Initialize()
// // server.StartLeader()
// // if err := server.Start(); err != nil {
// // t.Fatalf("Unable to start server: %v", err)
// // }
// defer server.Stop()
// resp, err := server.RequestVote(NewRequestVoteRequest(2, "foo", 2, 2))
// if !(resp.Term == 2 && !resp.VoteGranted && err != nil && err.Error() == "raft.Server: Out-of-date log: [3/2] > [2/2]") {
// t.Fatalf("Stale index vote should have been denied [%v/%v] (%v)", resp.Term, resp.VoteGranted, err)
// }
// resp, err = server.RequestVote(NewRequestVoteRequest(2, "foo", 3, 1))
// if !(resp.Term == 2 && !resp.VoteGranted && err != nil && err.Error() == "raft.Server: Out-of-date log: [3/2] > [3/1]") {
// t.Fatalf("Stale term vote should have been denied [%v/%v] (%v)", resp.Term, resp.VoteGranted, err)
// }
// resp, err = server.RequestVote(NewRequestVoteRequest(2, "foo", 3, 2))
// if !(resp.Term == 2 && resp.VoteGranted && err == nil) {
// t.Fatalf("Matching log vote should have been granted (%v)", err)
// }
// resp, err = server.RequestVote(NewRequestVoteRequest(2, "foo", 4, 3))
// if !(resp.Term == 2 && resp.VoteGranted && err == nil) {
// t.Fatalf("Ahead-of-log vote should have been granted (%v)", err)
// }
// }
// //--------------------------------------
// // Promotion
// //--------------------------------------
// // Ensure that we can self-promote a server to candidate, obtain votes and become a fearless leader.
// func TestServerPromoteSelf(t *testing.T) {
// server := newTestServer("1", &testTransporter{})
// server.Initialize()
// server.StartFollower()
// defer server.Stop()
// if success, err := server.promote(); !(success && err == nil && server.state == Leader) {
// t.Fatalf("Server self-promotion failed: %v (%v)", server.state, err)
// }
// }
// // Ensure that we can promote a server within a cluster to a leader.
// func TestServerPromote(t *testing.T) {
// lookup := map[string]*Server{}
// transporter := &testTransporter{}
// transporter.sendVoteRequestFunc = func(server *Server, peer *Peer, req *RequestVoteRequest) (*RequestVoteResponse, error) {
// return lookup[peer.Name()].RequestVote(req)
// }
// transporter.sendAppendEntriesRequestFunc = func(server *Server, peer *Peer, req *AppendEntriesRequest) (*AppendEntriesResponse, error) {
// return lookup[peer.Name()].AppendEntries(req)
// }
// servers := newTestCluster([]string{"1", "2", "3"}, transporter, lookup)
// for _, server := range servers {
// defer server.Stop()
// }
// leader := servers[0]
// if success, err := leader.promote(); !(success && err == nil && leader.state == Leader) {
// t.Fatalf("Server promotion in cluster failed: %v (%v)", leader.state, err)
// }
// }
// // Ensure that a server will restart election if not enough votes are obtained before timeout.
// func TestServerPromoteDoubleElection(t *testing.T) {
// lookup := map[string]*Server{}
// transporter := &testTransporter{}
// transporter.sendVoteRequestFunc = func(server *Server, peer *Peer, req *RequestVoteRequest) (*RequestVoteResponse, error) {
// resp, err := lookup[peer.Name()].RequestVote(req)
// return resp, err
// }
// transporter.sendAppendEntriesRequestFunc = func(server *Server, peer *Peer, req *AppendEntriesRequest) (*AppendEntriesResponse, error) {
// resp, err := lookup[peer.Name()].AppendEntries(req)
// return resp, err
// }
// servers := newTestCluster([]string{"1", "2", "3"}, transporter, lookup)
// lookup["2"].currentTerm, lookup["2"].votedFor = 1, "2"
// lookup["3"].currentTerm, lookup["3"].votedFor = 1, "3"
// lookup["2"].electionTimer.Stop()
// lookup["3"].electionTimer.Stop()
// for _, server := range servers {
// defer server.Stop()
// }
// leader := servers[0]
// if success, err := leader.promote(); !(success && err == nil && leader.state == Leader && leader.currentTerm == 2) {
// t.Fatalf("Server promotion in cluster failed: %v (%v)", leader.state, err)
// }
// time.Sleep(50 * time.Millisecond)
// if lookup["2"].votedFor != "1" {
// t.Fatalf("Unexpected vote for server 2: %v", lookup["2"].votedFor)
// }
// if lookup["3"].votedFor != "1" {
// t.Fatalf("Unexpected vote for server 3: %v", lookup["3"].votedFor)
// }
// }
2013-05-01 05:11:23 +00:00
2013-04-30 04:13:50 +00:00
//--------------------------------------
// Append Entries
//--------------------------------------
// Ensure we can append entries to a server.
2013-06-23 18:42:31 +00:00
// func TestServerAppendEntries(t *testing.T) {
// server := newTestServer("1", &testTransporter{})
// server.Initialize()
// server.StartLeader()
// defer server.Stop()
// // Append single entry.
// entries := []*LogEntry{NewLogEntry(nil, 1, 1, &TestCommand1{"foo", 10})}
// resp, err := server.AppendEntries(NewAppendEntriesRequest(1, "ldr", 0, 0, entries, 0))
// if !(resp.Term == 1 && resp.Success && err == nil) {
// t.Fatalf("AppendEntries failed: %v/%v : %v", resp.Term, resp.Success, err)
// }
// if index, term := server.log.CommitInfo(); !(index == 0 && term == 0) {
// t.Fatalf("Invalid commit info [IDX=%v, TERM=%v]", index, term)
// }
// // Append multiple entries + commit the last one.
// entries = []*LogEntry{NewLogEntry(nil, 2, 1, &TestCommand1{"bar", 20}), NewLogEntry(nil, 3, 1, &TestCommand1{"baz", 30})}
// resp, err = server.AppendEntries(NewAppendEntriesRequest(1, "ldr", 1, 1, entries, 1))
// if !(resp.Term == 1 && resp.Success && err == nil) {
// t.Fatalf("AppendEntries failed: %v/%v : %v", resp.Term, resp.Success, err)
// }
// if index, term := server.log.CommitInfo(); !(index == 1 && term == 1) {
// t.Fatalf("Invalid commit info [IDX=%v, TERM=%v]", index, term)
// }
// // Send zero entries and commit everything.
// resp, err = server.AppendEntries(NewAppendEntriesRequest(2, "ldr", 3, 1, []*LogEntry{}, 3))
// if !(resp.Term == 2 && resp.Success && err == nil) {
// t.Fatalf("AppendEntries failed: %v/%v : %v", resp.Term, resp.Success, err)
// }
// if index, term := server.log.CommitInfo(); !(index == 3 && term == 1) {
// t.Fatalf("Invalid commit info [IDX=%v, TERM=%v]", index, term)
// }
// }
2013-04-30 04:13:50 +00:00
2013-05-01 02:40:56 +00:00
// Ensure that entries with stale terms are rejected.
2013-06-23 18:42:31 +00:00
// func TestServerAppendEntriesWithStaleTermsAreRejected(t *testing.T) {
// server := newTestServer("1", &testTransporter{})
// server.Initialize()
// server.StartLeader()
// defer server.Stop()
// server.currentTerm = 2
// // Append single entry.
// entries := []*LogEntry{NewLogEntry(nil, 1, 1, &TestCommand1{"foo", 10})}
// resp, err := server.AppendEntries(NewAppendEntriesRequest(1, "ldr", 0, 0, entries, 0))
// if !(resp.Term == 2 && !resp.Success && err != nil && err.Error() == "raft.Server: Stale request term") {
// t.Fatalf("AppendEntries should have failed: %v/%v : %v", resp.Term, resp.Success, err)
// }
// if index, term := server.log.CommitInfo(); !(index == 0 && term == 0) {
// t.Fatalf("Invalid commit info [IDX=%v, TERM=%v]", index, term)
// }
// }
2013-05-01 02:40:56 +00:00
2013-05-01 02:45:05 +00:00
// Ensure that we reject entries if the commit log is different.
2013-06-23 18:42:31 +00:00
// func TestServerAppendEntriesRejectedIfAlreadyCommitted(t *testing.T) {
// server := newTestServer("1", &testTransporter{})
// server.Initialize()
// server.StartLeader()
// defer server.Stop()
// // Append single entry + commit.
// entries := []*LogEntry{
// NewLogEntry(nil, 1, 1, &TestCommand1{"foo", 10}),
// NewLogEntry(nil, 2, 1, &TestCommand1{"foo", 15}),
// }
// resp, err := server.AppendEntries(NewAppendEntriesRequest(1, "ldr", 0, 0, entries, 2))
// if !(resp.Term == 1 && resp.Success && err == nil) {
// t.Fatalf("AppendEntries failed: %v/%v : %v", resp.Term, resp.Success, err)
// }
// // Append entry again (post-commit).
// entries = []*LogEntry{NewLogEntry(nil, 2, 1, &TestCommand1{"bar", 20})}
// resp, err = server.AppendEntries(NewAppendEntriesRequest(1, "ldr", 2, 1, entries, 1))
// if !(resp.Term == 1 && !resp.Success && err != nil && err.Error() == "raft.Log: Cannot append entry with earlier index in the same term (1:2 <= 1:2)") {
// t.Fatalf("AppendEntries should have failed: %v/%v : %v", resp.Term, resp.Success, err)
// }
// }
2013-05-01 02:45:05 +00:00
2013-05-01 04:44:16 +00:00
// Ensure that we uncommitted entries are rolled back if new entries overwrite them.
2013-06-23 18:42:31 +00:00
// func TestServerAppendEntriesOverwritesUncommittedEntries(t *testing.T) {
// server := newTestServer("1", &testTransporter{})
// server.Initialize()
// server.StartLeader()
// defer server.Stop()
// entry1 := NewLogEntry(nil, 1, 1, &TestCommand1{"foo", 10})
// entry2 := NewLogEntry(nil, 2, 1, &TestCommand1{"foo", 15})
// entry3 := NewLogEntry(nil, 2, 2, &TestCommand1{"bar", 20})
// // Append single entry + commit.
// entries := []*LogEntry{entry1, entry2}
// resp, err := server.AppendEntries(NewAppendEntriesRequest(1, "ldr", 0, 0, entries, 1))
// if !(resp.Term == 1 && resp.Success && err == nil && server.log.CommitIndex() == 1 && reflect.DeepEqual(server.log.entries, []*LogEntry{entry1, entry2})) {
// t.Fatalf("AppendEntries failed: %v/%v : %v", resp.Term, resp.Success, err)
// }
// // Append entry that overwrites the second (uncommitted) entry.
// entries = []*LogEntry{entry3}
// resp, err = server.AppendEntries(NewAppendEntriesRequest(2, "ldr", 1, 1, entries, 2))
// if !(resp.Term == 2 && resp.Success && err == nil && server.log.CommitIndex() == 2 && reflect.DeepEqual(server.log.entries, []*LogEntry{entry1, entry3})) {
// t.Fatalf("AppendEntries should have succeeded: %v/%v : %v", resp.Term, resp.Success, err)
// }
// }
2013-04-30 04:13:50 +00:00
2013-05-27 02:04:41 +00:00
//--------------------------------------
// Command Execution
//--------------------------------------
// Ensure that a follower cannot execute a command.
2013-06-23 18:42:31 +00:00
// func TestServerDenyCommandExecutionWhenFollower(t *testing.T) {
// server := newTestServer("1", &testTransporter{})
// server.Initialize()
// server.StartFollower()
// defer server.Stop()
// var err error
// if _, err = server.Do(&TestCommand1{"foo", 10}); err != NotLeaderError {
// t.Fatalf("Expected error: %v, got: %v", NotLeaderError, err)
// }
// }
2013-05-27 02:04:41 +00:00
2013-04-28 22:49:52 +00:00
//--------------------------------------
// Membership
//--------------------------------------
2013-04-17 02:28:08 +00:00
// Ensure that we can start a single server and append to its log.
2013-06-23 18:42:31 +00:00
// func TestServerSingleNode(t *testing.T) {
// fmt.Println("-----SignalNodeTest-------")
// server := newTestServer("1", &testTransporter{})
// if server.state != Stopped {
// t.Fatalf("Unexpected server state: %v", server.state)
// }
// server.Initialize()
// // Get the server running.
// // if err := server.Start(); err != nil {
// // t.Fatalf("Unable to start server: %v", err)
// // }
// defer server.Stop()
// if server.state != Follower {
// t.Fatalf("Unexpected server state: %v", server.state)
// }
// server.StartLeader()
// time.Sleep(time.Second)
// // Join the server to itself.
// if _, err := server.Do(&joinCommand{Name: "1"}); err != nil {
// t.Fatalf("Unable to join: %v", err)
// }
// fmt.Println("finish command")
// if server.state != Leader {
// t.Fatalf("Unexpected server state: %v", server.state)
// }
// // Stop the server.
// server.Stop()
// if server.state != Stopped {
// t.Fatalf("Unexpected server state: %v", server.state)
// }
// }
2013-04-28 04:51:17 +00:00
// Ensure that we can start multiple servers and determine a leader.
func TestServerMultiNode ( t * testing . T ) {
2013-06-23 18:42:31 +00:00
fmt . Println ( "------------MultiTest------------" )
2013-06-11 22:30:13 +00:00
2013-04-28 04:51:17 +00:00
// Initialize the servers.
2013-05-05 19:48:15 +00:00
var mutex sync . Mutex
2013-04-28 04:51:17 +00:00
servers := map [ string ] * Server { }
2013-06-11 22:30:13 +00:00
2013-05-28 19:57:38 +00:00
transporter := & testTransporter { }
transporter . sendVoteRequestFunc = func ( server * Server , peer * Peer , req * RequestVoteRequest ) ( * RequestVoteResponse , error ) {
2013-06-23 18:42:31 +00:00
fmt . Println ( "vote request" )
//mutex.Lock()
2013-05-28 19:57:38 +00:00
s := servers [ peer . name ]
2013-06-23 18:42:31 +00:00
fmt . Println ( "vote request 2" )
//mutex.Unlock()
2013-06-04 13:35:43 +00:00
resp , err := s . RequestVote ( req )
2013-06-23 18:42:31 +00:00
fmt . Println ( "finish vote request" )
2013-06-04 13:35:43 +00:00
return resp , err
2013-05-28 19:57:38 +00:00
}
transporter . sendAppendEntriesRequestFunc = func ( server * Server , peer * Peer , req * AppendEntriesRequest ) ( * AppendEntriesResponse , error ) {
2013-06-23 18:42:31 +00:00
//mutex.Lock()
2013-05-28 19:57:38 +00:00
s := servers [ peer . name ]
2013-06-23 18:42:31 +00:00
//mutex.Unlock()
2013-05-28 19:57:38 +00:00
resp , err := s . AppendEntries ( req )
return resp , err
}
2013-06-11 22:30:13 +00:00
disTransporter := & testTransporter { }
disTransporter . sendVoteRequestFunc = func ( server * Server , peer * Peer , req * RequestVoteRequest ) ( * RequestVoteResponse , error ) {
return nil , nil
}
disTransporter . sendAppendEntriesRequestFunc = func ( server * Server , peer * Peer , req * AppendEntriesRequest ) ( * AppendEntriesResponse , error ) {
return nil , nil
}
var names [ ] string
2013-06-23 18:42:31 +00:00
n := 5
2013-06-11 22:30:13 +00:00
// add n servers
for i := 1 ; i <= n ; i ++ {
names = append ( names , strconv . Itoa ( i ) )
}
2013-05-28 18:46:27 +00:00
var leader * Server
2013-04-28 04:51:17 +00:00
for _ , name := range names {
2013-05-28 19:57:38 +00:00
server := newTestServer ( name , transporter )
2013-06-11 22:30:13 +00:00
// if err := server.Start(); err != nil {
// t.Fatalf("Unable to start server[%s]: %v", name, err)
// }
server . Initialize ( )
2013-06-23 18:42:31 +00:00
mutex . Lock ( )
servers [ name ] = server
mutex . Unlock ( )
2013-05-28 18:46:27 +00:00
if name == "1" {
leader = server
2013-06-11 22:30:13 +00:00
// if err := server.Initialize(); err != nil {
// t.Fatalf("Unable to initialize server[%s]: %v", name, err)
// }
server . SetHeartbeatTimeout ( testHeartbeatTimeout )
server . StartLeader ( )
} else {
server . SetElectionTimeout ( testElectionTimeout )
server . SetHeartbeatTimeout ( testHeartbeatTimeout )
server . StartFollower ( )
2013-05-28 18:46:27 +00:00
}
2013-06-09 05:39:50 +00:00
if _ , err := leader . Do ( & joinCommand { Name : name } ) ; err != nil {
2013-04-28 04:51:17 +00:00
t . Fatalf ( "Unable to join server[%s]: %v" , name , err )
}
2013-05-05 19:48:15 +00:00
2013-04-28 04:51:17 +00:00
}
2013-06-04 13:35:43 +00:00
time . Sleep ( 100 * time . Millisecond )
2013-04-28 04:51:17 +00:00
// Check that two peers exist on leader.
2013-05-05 19:48:15 +00:00
mutex . Lock ( )
2013-06-11 22:30:13 +00:00
if leader . MemberCount ( ) != n {
t . Fatalf ( "Expected member count to be %v, got %v" , n , leader . MemberCount ( ) )
2013-04-28 04:51:17 +00:00
}
2013-06-10 04:47:59 +00:00
if servers [ "2" ] . State ( ) == Leader || servers [ "3" ] . State ( ) == Leader {
t . Fatalf ( "Expected leader should be 1: 2=%v, 3=%v\n" , servers [ "2" ] . state , servers [ "3" ] . state )
}
2013-05-05 21:41:55 +00:00
mutex . Unlock ( )
2013-06-11 22:30:13 +00:00
i := 0
for {
i ++
fmt . Println ( "Round " , i )
num := strconv . Itoa ( i % ( len ( servers ) ) + 1 )
toStop := servers [ num ]
// Stop the first server and wait for a re-election.
2013-06-23 18:42:31 +00:00
time . Sleep ( 100 * time . Millisecond )
2013-06-11 22:30:13 +00:00
fmt . Println ( "Disconnect " , toStop . Name ( ) )
toStop . SetTransporter ( disTransporter )
2013-06-23 18:42:31 +00:00
time . Sleep ( 200 * time . Millisecond )
2013-06-11 22:30:13 +00:00
// Check that either server 2 or 3 is the leader now.
2013-06-23 18:42:31 +00:00
//mutex.Lock()
2013-06-11 22:30:13 +00:00
leader := 0
for key , value := range servers {
2013-06-23 18:42:31 +00:00
fmt . Println ( "Play begin" )
2013-06-11 22:30:13 +00:00
if key != num {
if value . State ( ) == Leader {
2013-06-23 18:42:31 +00:00
fmt . Println ( "Found leader" )
for i := 0 ; i < 10 ; i ++ {
fmt . Println ( "[Test] do " , value . Name ( ) )
if _ , err := value . Do ( & TestCommand2 { X : 1 } ) ; err != nil {
t . Fatalf ( "Unable to do command" )
}
fmt . Println ( "[Test] Done" )
}
2013-06-11 22:30:13 +00:00
leader ++
2013-06-23 18:42:31 +00:00
fmt . Println ( "Leader is " , value . Name ( ) , " Index " , value . log . commitIndex )
2013-06-11 22:30:13 +00:00
}
2013-06-23 18:42:31 +00:00
fmt . Println ( "Not Found leader" )
2013-06-11 22:30:13 +00:00
}
}
if leader != 1 {
t . Fatalf ( "wrong leader number %v" , leader )
}
2013-06-23 18:42:31 +00:00
//mutex.Unlock()
2013-06-11 22:30:13 +00:00
toStop . SetTransporter ( transporter )
2013-05-05 21:41:55 +00:00
}
2013-06-11 22:30:13 +00:00
2013-04-28 04:51:17 +00:00
}