File: slowvoter_test.go

package info (click to toggle)
golang-github-hashicorp-raft 1.0.0%2Bgit20180823.82694fb-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 704 kB
  • sloc: makefile: 17; sh: 9
file content (99 lines) | stat: -rw-r--r-- 2,449 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package fuzzy

import (
	"math/rand"
	"testing"
	"time"

	"github.com/hashicorp/raft"
)

// 5 node cluster where 2 nodes always see a delay in getting a request vote msg.
func TestRaft_SlowSendVote(t *testing.T) {
	hooks := NewSlowVoter("sv_0", "sv_1")
	cluster := newRaftCluster(t, testLogWriter, "sv", 5, hooks)
	s := newApplySource("SlowSendVote")
	ac := cluster.ApplyN(t, time.Minute, s, 10000)
	cluster.Stop(t, time.Minute)
	hooks.Report(t)
	cluster.VerifyLog(t, ac)
	cluster.VerifyFSM(t)
}

// 5 node cluster where vote results from 3 nodes are slow to turn up.
// [they see the vote request normally, but their response is slow]
func TestRaft_SlowRecvVote(t *testing.T) {
	hooks := NewSlowVoter("svr_1", "svr_4", "svr_3")
	hooks.mode = SlowRecv
	cluster := newRaftCluster(t, testLogWriter, "svr", 5, hooks)
	s := newApplySource("SlowRecvVote")
	ac := cluster.ApplyN(t, time.Minute, s, 10000)
	cluster.Stop(t, time.Minute)
	hooks.Report(t)
	cluster.VerifyLog(t, ac)
	cluster.VerifyFSM(t)
}

type SlowVoterMode int

const (
	SlowSend SlowVoterMode = iota
	SlowRecv
)

type SlowVoter struct {
	verifier  appendEntriesVerifier
	slowNodes map[string]bool
	delayMin  time.Duration
	delayMax  time.Duration
	mode      SlowVoterMode
}

func NewSlowVoter(slowNodes ...string) *SlowVoter {
	sv := SlowVoter{
		slowNodes: make(map[string]bool, len(slowNodes)),
		delayMin:  time.Second,
		delayMax:  time.Second * 2,
		mode:      SlowSend,
	}
	for _, n := range slowNodes {
		sv.slowNodes[n] = true
	}
	sv.verifier.Init()
	return &sv
}

func (sv *SlowVoter) Report(t *testing.T) {
	sv.verifier.Report(t)
}

func (sv *SlowVoter) PreRPC(s, t string, r *raft.RPC) error {
	return nil
}

func (sv *SlowVoter) nap() {
	d := sv.delayMin + time.Duration(rand.Int63n((sv.delayMax - sv.delayMin).Nanoseconds()))
	time.Sleep(d)
}

func (sv *SlowVoter) PostRPC(src, target string, r *raft.RPC, res *raft.RPCResponse) error {
	if sv.mode == SlowRecv && sv.slowNodes[target] {
		_, ok := r.Command.(*raft.RequestVoteRequest)
		if ok {
			sv.nap()
		}
	}
	return nil
}

func (sv *SlowVoter) PreRequestVote(src, target string, v *raft.RequestVoteRequest) (*raft.RequestVoteResponse, error) {
	if sv.mode == SlowSend && sv.slowNodes[target] {
		sv.nap()
	}
	return nil, nil
}

func (sv *SlowVoter) PreAppendEntries(src, target string, v *raft.AppendEntriesRequest) (*raft.AppendEntriesResponse, error) {
	sv.verifier.PreAppendEntries(src, target, v)
	return nil, nil
}