2015-04-09 20:23:14 +00:00
|
|
|
package consul
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math/rand"
|
|
|
|
"os"
|
2015-04-29 02:07:10 +00:00
|
|
|
"reflect"
|
2015-04-09 20:23:14 +00:00
|
|
|
"testing"
|
2015-04-13 20:45:42 +00:00
|
|
|
"time"
|
2015-04-09 20:23:14 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/consul/consul/structs"
|
|
|
|
"github.com/hashicorp/consul/testutil"
|
|
|
|
"github.com/hashicorp/serf/coordinate"
|
|
|
|
)
|
|
|
|
|
2015-05-08 08:31:34 +00:00
|
|
|
func init() {
|
|
|
|
// Shorten updatePeriod so we don't have to wait as long
|
|
|
|
updatePeriod = time.Duration(100) * time.Millisecond
|
|
|
|
}
|
|
|
|
|
2015-04-13 20:45:42 +00:00
|
|
|
// getRandomCoordinate generates a random coordinate.
|
2015-04-09 20:23:14 +00:00
|
|
|
func getRandomCoordinate() *coordinate.Coordinate {
|
|
|
|
config := coordinate.DefaultConfig()
|
2015-04-13 20:45:42 +00:00
|
|
|
// Randomly apply updates between n clients
|
|
|
|
n := 5
|
|
|
|
clients := make([]*coordinate.Client, n)
|
|
|
|
for i := 0; i < n; i++ {
|
2015-04-29 01:47:41 +00:00
|
|
|
clients[i], _ = coordinate.NewClient(config)
|
2015-04-09 20:23:14 +00:00
|
|
|
}
|
2015-04-13 20:45:42 +00:00
|
|
|
|
|
|
|
for i := 0; i < n*100; i++ {
|
|
|
|
k1 := rand.Intn(n)
|
|
|
|
k2 := rand.Intn(n)
|
|
|
|
if k1 == k2 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
clients[k1].Update(clients[k2].GetCoordinate(), time.Duration(rand.Int63())*time.Microsecond)
|
|
|
|
}
|
|
|
|
return clients[rand.Intn(n)].GetCoordinate()
|
2015-04-09 20:23:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func coordinatesEqual(a, b *coordinate.Coordinate) bool {
|
2015-04-29 02:07:10 +00:00
|
|
|
return reflect.DeepEqual(a, b)
|
2015-04-09 20:23:14 +00:00
|
|
|
}
|
|
|
|
|
2015-04-29 01:47:41 +00:00
|
|
|
func TestCoordinateUpdate(t *testing.T) {
|
2015-04-09 20:23:14 +00:00
|
|
|
dir1, s1 := testServer(t)
|
|
|
|
defer os.RemoveAll(dir1)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
client := rpcClient(t, s1)
|
|
|
|
defer client.Close()
|
|
|
|
|
|
|
|
testutil.WaitForLeader(t, client.Call, "dc1")
|
|
|
|
|
2015-05-08 08:31:34 +00:00
|
|
|
arg1 := structs.CoordinateUpdateRequest{
|
2015-04-18 21:05:29 +00:00
|
|
|
Datacenter: "dc1",
|
|
|
|
Node: "node1",
|
|
|
|
Op: structs.CoordinateSet,
|
|
|
|
Coord: getRandomCoordinate(),
|
2015-04-09 20:23:14 +00:00
|
|
|
}
|
|
|
|
|
2015-05-08 08:31:34 +00:00
|
|
|
arg2 := structs.CoordinateUpdateRequest{
|
|
|
|
Datacenter: "dc1",
|
|
|
|
Node: "node2",
|
|
|
|
Op: structs.CoordinateSet,
|
|
|
|
Coord: getRandomCoordinate(),
|
|
|
|
}
|
|
|
|
|
|
|
|
updateLastSent = time.Now()
|
|
|
|
|
2015-04-09 20:23:14 +00:00
|
|
|
var out struct{}
|
2015-05-08 08:31:34 +00:00
|
|
|
if err := client.Call("Coordinate.Update", &arg1, &out); err != nil {
|
2015-04-09 20:23:14 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Verify
|
|
|
|
state := s1.fsm.State()
|
|
|
|
_, d, err := state.CoordinateGet("node1")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2015-05-08 08:31:34 +00:00
|
|
|
if d != nil {
|
|
|
|
t.Fatalf("should be nil because the update should be batched")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait a while and send another update; this time the updates should be sent
|
|
|
|
time.Sleep(time.Duration(2) * updatePeriod)
|
|
|
|
if err := client.Call("Coordinate.Update", &arg2, &out); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, d, err = state.CoordinateGet("node1")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if d == nil {
|
|
|
|
t.Fatalf("should return a coordinate but it's nil")
|
|
|
|
}
|
|
|
|
if !coordinatesEqual(d.Coord, arg1.Coord) {
|
|
|
|
t.Fatalf("should be equal\n%v\n%v", d.Coord, arg1.Coord)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, d, err = state.CoordinateGet("node2")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if d == nil {
|
|
|
|
t.Fatalf("should return a coordinate but it's nil")
|
|
|
|
}
|
|
|
|
if !coordinatesEqual(d.Coord, arg2.Coord) {
|
|
|
|
t.Fatalf("should be equal\n%v\n%v", d.Coord, arg2.Coord)
|
2015-04-09 20:23:14 +00:00
|
|
|
}
|
2015-04-29 01:47:41 +00:00
|
|
|
}
|
|
|
|
|
2015-05-08 08:31:34 +00:00
|
|
|
func TestCoordinateGetLAN(t *testing.T) {
|
|
|
|
updatePeriod = time.Duration(0) // to make updates instant
|
|
|
|
|
2015-04-29 01:47:41 +00:00
|
|
|
dir1, s1 := testServer(t)
|
|
|
|
defer os.RemoveAll(dir1)
|
|
|
|
defer s1.Shutdown()
|
|
|
|
client := rpcClient(t, s1)
|
|
|
|
defer client.Close()
|
|
|
|
|
|
|
|
testutil.WaitForLeader(t, client.Call, "dc1")
|
|
|
|
|
|
|
|
arg := structs.CoordinateUpdateRequest{
|
|
|
|
Datacenter: "dc1",
|
|
|
|
Node: "node1",
|
|
|
|
Op: structs.CoordinateSet,
|
|
|
|
Coord: getRandomCoordinate(),
|
|
|
|
}
|
|
|
|
|
|
|
|
var out struct{}
|
|
|
|
if err := client.Call("Coordinate.Update", &arg, &out); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2015-04-13 20:53:43 +00:00
|
|
|
|
|
|
|
// Get via RPC
|
2015-04-18 21:05:29 +00:00
|
|
|
var out2 *structs.IndexedCoordinate
|
2015-05-08 08:31:34 +00:00
|
|
|
arg2 := structs.NodeSpecificRequest{
|
2015-04-13 20:53:43 +00:00
|
|
|
Datacenter: "dc1",
|
|
|
|
Node: "node1",
|
|
|
|
}
|
2015-05-08 08:31:34 +00:00
|
|
|
if err := client.Call("Coordinate.GetLAN", &arg2, &out2); err != nil {
|
2015-04-13 20:53:43 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if !coordinatesEqual(out2.Coord, arg.Coord) {
|
|
|
|
t.Fatalf("should be equal\n%v\n%v", out2.Coord, arg.Coord)
|
|
|
|
}
|
2015-04-16 21:08:56 +00:00
|
|
|
|
|
|
|
// Now let's override the original coordinate; Coordinate.Get should return
|
|
|
|
// the latest coordinate
|
|
|
|
arg.Coord = getRandomCoordinate()
|
|
|
|
if err := client.Call("Coordinate.Update", &arg, &out); err != nil {
|
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
2015-05-08 08:31:34 +00:00
|
|
|
if err := client.Call("Coordinate.GetLAN", &arg2, &out2); err != nil {
|
2015-04-16 21:08:56 +00:00
|
|
|
t.Fatalf("err: %v", err)
|
|
|
|
}
|
|
|
|
if !coordinatesEqual(out2.Coord, arg.Coord) {
|
|
|
|
t.Fatalf("should be equal\n%v\n%v", out2.Coord, arg.Coord)
|
|
|
|
}
|
2015-04-09 20:23:14 +00:00
|
|
|
}
|