1
0
Fork 0
You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

145 lines
3.5 KiB
Go

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")
}
}