|
|
|
package cluster
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/rqlite/rqlite/v8/cluster/servicetest"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
)
|
|
|
|
|
|
|
|
const numAttempts int = 3
|
|
|
|
const attemptInterval = 1 * time.Second
|
|
|
|
|
|
|
|
func Test_SingleJoinOK(t *testing.T) {
|
|
|
|
srv := servicetest.NewService()
|
|
|
|
srv.Handler = func(conn net.Conn) {
|
|
|
|
var p []byte
|
|
|
|
var err error
|
|
|
|
c := readCommand(conn)
|
|
|
|
if c == nil {
|
|
|
|
// Error on connection, so give up, as normal
|
|
|
|
// test exit can cause that too.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if c.Type != Command_COMMAND_TYPE_JOIN {
|
|
|
|
t.Fatalf("unexpected command type: %d", c.Type)
|
|
|
|
}
|
|
|
|
jr := c.GetJoinRequest()
|
|
|
|
if jr == nil {
|
|
|
|
t.Fatal("join request is nil")
|
|
|
|
}
|
|
|
|
if exp, got := "id0", jr.Id; exp != got {
|
|
|
|
t.Fatalf("unexpected id, got %s, exp: %s", got, exp)
|
|
|
|
}
|
|
|
|
if exp, got := "1.2.3.4", jr.Address; exp != got {
|
|
|
|
t.Fatalf("unexpected addr, got %s, exp: %s", got, exp)
|
|
|
|
}
|
|
|
|
|
|
|
|
resp := &CommandJoinResponse{}
|
|
|
|
p, err = proto.Marshal(resp)
|
|
|
|
if err != nil {
|
|
|
|
conn.Close()
|
|
|
|
}
|
|
|
|
writeBytesWithLength(conn, p)
|
|
|
|
}
|
|
|
|
srv.Start()
|
|
|
|
defer srv.Close()
|
|
|
|
|
|
|
|
c := NewClient(&simpleDialer{}, 0)
|
|
|
|
joiner := NewJoiner(c, numAttempts, attemptInterval)
|
|
|
|
addr, err := joiner.Do([]string{srv.Addr()}, "id0", "1.2.3.4", Voter)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if exp, got := srv.Addr(), addr; exp != got {
|
|
|
|
t.Fatalf("unexpected addr, got %s, exp: %s", got, exp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_SingleJoinZeroAttempts(t *testing.T) {
|
|
|
|
srv := servicetest.NewService()
|
|
|
|
srv.Handler = func(conn net.Conn) {
|
|
|
|
t.Fatalf("handler should not have been called")
|
|
|
|
}
|
|
|
|
srv.Start()
|
|
|
|
defer srv.Close()
|
|
|
|
|
|
|
|
c := NewClient(&simpleDialer{}, 0)
|
|
|
|
joiner := NewJoiner(c, 0, attemptInterval)
|
|
|
|
_, err := joiner.Do([]string{srv.Addr()}, "id0", "1.2.3.4", Voter)
|
|
|
|
if err != ErrJoinFailed {
|
|
|
|
t.Fatalf("Incorrect error returned when zero attempts specified")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_SingleJoinFail(t *testing.T) {
|
|
|
|
srv := servicetest.NewService()
|
|
|
|
srv.Handler = func(conn net.Conn) {
|
|
|
|
var p []byte
|
|
|
|
var err error
|
|
|
|
c := readCommand(conn)
|
|
|
|
if c == nil {
|
|
|
|
// Error on connection, so give up, as normal
|
|
|
|
// test exit can cause that too.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
resp := &CommandJoinResponse{
|
|
|
|
Error: "bad request",
|
|
|
|
}
|
|
|
|
p, err = proto.Marshal(resp)
|
|
|
|
if err != nil {
|
|
|
|
conn.Close()
|
|
|
|
}
|
|
|
|
writeBytesWithLength(conn, p)
|
|
|
|
}
|
|
|
|
srv.Start()
|
|
|
|
defer srv.Close()
|
|
|
|
|
|
|
|
c := NewClient(&simpleDialer{}, 0)
|
|
|
|
joiner := NewJoiner(c, numAttempts, attemptInterval)
|
|
|
|
_, err := joiner.Do([]string{srv.Addr()}, "id0", "1.2.3.4", Voter)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("expected error when joining bad node")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_DoubleJoinOKSecondNode(t *testing.T) {
|
|
|
|
srv1 := servicetest.NewService()
|
|
|
|
srv1.Handler = func(conn net.Conn) {
|
|
|
|
var p []byte
|
|
|
|
var err error
|
|
|
|
c := readCommand(conn)
|
|
|
|
if c == nil {
|
|
|
|
// Error on connection, so give up, as normal
|
|
|
|
// test exit can cause that too.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
resp := &CommandJoinResponse{
|
|
|
|
Error: "bad request",
|
|
|
|
}
|
|
|
|
p, err = proto.Marshal(resp)
|
|
|
|
if err != nil {
|
|
|
|
conn.Close()
|
|
|
|
}
|
|
|
|
writeBytesWithLength(conn, p)
|
|
|
|
}
|
|
|
|
srv1.Start()
|
|
|
|
defer srv1.Close()
|
|
|
|
|
|
|
|
srv2 := servicetest.NewService()
|
|
|
|
srv2.Handler = func(conn net.Conn) {
|
|
|
|
var p []byte
|
|
|
|
var err error
|
|
|
|
c := readCommand(conn)
|
|
|
|
if c == nil {
|
|
|
|
// Error on connection, so give up, as normal
|
|
|
|
// test exit can cause that too.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if c.Type != Command_COMMAND_TYPE_JOIN {
|
|
|
|
t.Fatalf("unexpected command type: %d", c.Type)
|
|
|
|
}
|
|
|
|
resp := &CommandJoinResponse{}
|
|
|
|
p, err = proto.Marshal(resp)
|
|
|
|
if err != nil {
|
|
|
|
conn.Close()
|
|
|
|
}
|
|
|
|
writeBytesWithLength(conn, p)
|
|
|
|
}
|
|
|
|
srv2.Start()
|
|
|
|
defer srv2.Close()
|
|
|
|
|
|
|
|
c := NewClient(&simpleDialer{}, 0)
|
|
|
|
joiner := NewJoiner(c, numAttempts, attemptInterval)
|
|
|
|
addr, err := joiner.Do([]string{srv1.Addr(), srv2.Addr()}, "id0", "1.2.3.4", Voter)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if exp, got := srv2.Addr(), addr; exp != got {
|
|
|
|
t.Fatalf("unexpected addr, got %s, exp: %s", got, exp)
|
|
|
|
}
|
|
|
|
}
|