forked from rqlite/rqlite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathremove_test.go
144 lines (121 loc) · 3.47 KB
/
remove_test.go
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package cluster
import (
"fmt"
"net"
"testing"
"time"
"github.com/rqlite/rqlite/v8/cluster/proto"
"github.com/rqlite/rqlite/v8/cluster/servicetest"
pb "google.golang.org/protobuf/proto"
)
func Test_NewRemover(t *testing.T) {
r := NewRemover(nil, 0, nil)
if r == nil {
t.Fatal("expected remover, got nil")
}
}
func Test_RemoveOK(t *testing.T) {
ch := make(chan struct{}, 1)
defer close(ch)
srv := makeServiceRemoveOK(t, ch)
defer srv.Close()
control := &mockControl{leader: srv.Addr()}
client := NewClient(&simpleDialer{}, 0)
r := NewRemover(client, time.Second, control)
if err := r.Do("node-id", true); err != nil {
t.Fatalf("failed to remove node: %s", err.Error())
}
waitForChan(t, ch, time.Second)
}
func Test_RemoveWaitForLeaderFail(t *testing.T) {
srv := makeServiceRemoveOK(t, nil)
defer srv.Close()
control := &mockControl{
leader: srv.Addr(),
waitForLeaderErr: fmt.Errorf("timeout waiting for leader"),
}
client := NewClient(&simpleDialer{}, 0)
r := NewRemover(client, time.Second, control)
if err := r.Do("node-id", true); err == nil {
t.Fatalf("failed to detect timeout waiting for leader")
}
}
func Test_RemoveWaitForRemoveFail(t *testing.T) {
ch := make(chan struct{}, 1)
defer close(ch)
srv := makeServiceRemoveOK(t, ch)
defer srv.Close()
control := &mockControl{
leader: srv.Addr(),
waitForRemovalErr: fmt.Errorf("timeout waiting for removal"),
}
client := NewClient(&simpleDialer{}, 0)
r := NewRemover(client, time.Second, control)
if err := r.Do("node-id", true); err == nil {
t.Fatalf("failed to detect timeout waiting for removal")
}
waitForChan(t, ch, time.Second)
}
func Test_RemoveWaitForRemoveFailOK(t *testing.T) {
ch := make(chan struct{}, 1)
defer close(ch)
srv := makeServiceRemoveOK(t, ch)
defer srv.Close()
control := &mockControl{
leader: srv.Addr(),
waitForRemovalErr: fmt.Errorf("timeout waiting for removal"),
}
client := NewClient(&simpleDialer{}, 0)
r := NewRemover(client, time.Second, control)
if err := r.Do("node-id", false); err != nil {
t.Fatalf("removal timeout not ignored: %s", err.Error())
}
waitForChan(t, ch, time.Second)
}
// makeServiceRemoveOK returns a service that responds to a remove node
// request with a successful response. If ch is nil, the service will
// not instantiate the handler, as the assumption is the caller does not
// expect it to be called.
func makeServiceRemoveOK(t *testing.T, ch chan struct{}) *servicetest.Service {
srv := servicetest.NewService()
if ch != nil {
srv.Handler = func(conn net.Conn) {
var p []byte
var err error
_ = readCommand(conn)
p, err = pb.Marshal(&proto.CommandRemoveNodeResponse{})
if err != nil {
t.Fatalf("failed to marshal response: %s", err.Error())
}
writeBytesWithLength(conn, p)
}
ch <- struct{}{}
} else {
srv.Handler = func(conn net.Conn) {
t.Fatalf("unexpected call to handler")
}
}
srv.Start()
return srv
}
type mockControl struct {
leader string
waitForLeaderErr error
waitForRemovalErr error
}
func (m *mockControl) WaitForLeader(timeout time.Duration) (string, error) {
return m.leader, m.waitForLeaderErr
}
func (m *mockControl) WaitForRemoval(id string, timeout time.Duration) error {
return m.waitForRemovalErr
}
func waitForChan(t *testing.T, ch chan struct{}, timeout time.Duration) {
tmr := time.NewTimer(timeout)
defer tmr.Stop()
select {
case <-ch:
return
case <-tmr.C:
t.Fatal("timed out waiting for channel to receive signal")
}
}