2017-04-19 23:00:11 +00:00
|
|
|
package testrpc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
2017-07-06 10:34:00 +00:00
|
|
|
"github.com/hashicorp/consul/agent/structs"
|
2019-03-27 12:54:56 +00:00
|
|
|
"github.com/hashicorp/consul/sdk/testutil/retry"
|
2017-04-19 23:00:11 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type rpcFn func(string, interface{}, interface{}) error
|
|
|
|
|
2018-08-10 19:04:07 +00:00
|
|
|
// WaitForLeader ensures we have a leader and a node registration.
|
2017-04-19 23:00:11 +00:00
|
|
|
func WaitForLeader(t *testing.T, rpc rpcFn, dc string) {
|
|
|
|
var out structs.IndexedNodes
|
2017-05-05 11:48:34 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
2017-04-19 23:00:11 +00:00
|
|
|
args := &structs.DCSpecificRequest{Datacenter: dc}
|
|
|
|
if err := rpc("Catalog.ListNodes", args, &out); err != nil {
|
2017-05-05 11:48:34 +00:00
|
|
|
r.Fatalf("Catalog.ListNodes failed: %v", err)
|
2017-04-19 23:00:11 +00:00
|
|
|
}
|
|
|
|
if !out.QueryMeta.KnownLeader {
|
2017-05-05 11:48:34 +00:00
|
|
|
r.Fatalf("No leader")
|
2017-04-19 23:00:11 +00:00
|
|
|
}
|
2018-08-06 23:46:09 +00:00
|
|
|
if out.Index < 2 {
|
|
|
|
r.Fatalf("Consul index should be at least 2")
|
2017-04-19 23:00:11 +00:00
|
|
|
}
|
2017-05-05 11:48:34 +00:00
|
|
|
})
|
2017-04-19 23:00:11 +00:00
|
|
|
}
|
2018-08-10 19:04:07 +00:00
|
|
|
|
2018-08-23 16:06:39 +00:00
|
|
|
// WaitUntilNoLeader ensures no leader is present, useful for testing lost leadership.
|
|
|
|
func WaitUntilNoLeader(t *testing.T, rpc rpcFn, dc string) {
|
|
|
|
var out structs.IndexedNodes
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
args := &structs.DCSpecificRequest{Datacenter: dc}
|
|
|
|
if err := rpc("Catalog.ListNodes", args, &out); err == nil {
|
2018-08-28 16:37:34 +00:00
|
|
|
r.Fatalf("It still has a leader: %#v", out)
|
2018-08-23 16:06:39 +00:00
|
|
|
}
|
|
|
|
if out.QueryMeta.KnownLeader {
|
|
|
|
r.Fatalf("Has still a leader")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-01-25 16:01:21 +00:00
|
|
|
type waitOption struct {
|
|
|
|
Token string
|
|
|
|
}
|
|
|
|
|
|
|
|
func WithToken(token string) waitOption {
|
|
|
|
return waitOption{Token: token}
|
|
|
|
}
|
|
|
|
|
2018-08-10 19:04:07 +00:00
|
|
|
// WaitForTestAgent ensures we have a node with serfHealth check registered
|
2019-01-25 16:01:21 +00:00
|
|
|
func WaitForTestAgent(t *testing.T, rpc rpcFn, dc string, options ...waitOption) {
|
2018-08-10 19:04:07 +00:00
|
|
|
var nodes structs.IndexedNodes
|
|
|
|
var checks structs.IndexedHealthChecks
|
|
|
|
|
2019-01-25 16:01:21 +00:00
|
|
|
// first extra arg is an optional acl token
|
|
|
|
var token string
|
|
|
|
for _, opt := range options {
|
|
|
|
if opt.Token != "" {
|
|
|
|
token = opt.Token
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-10 19:04:07 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
2019-01-25 16:01:21 +00:00
|
|
|
dcReq := &structs.DCSpecificRequest{
|
|
|
|
Datacenter: dc,
|
|
|
|
QueryOptions: structs.QueryOptions{Token: token},
|
|
|
|
}
|
2018-08-10 19:04:07 +00:00
|
|
|
if err := rpc("Catalog.ListNodes", dcReq, &nodes); err != nil {
|
|
|
|
r.Fatalf("Catalog.ListNodes failed: %v", err)
|
|
|
|
}
|
|
|
|
if len(nodes.Nodes) == 0 {
|
|
|
|
r.Fatalf("No registered nodes")
|
|
|
|
}
|
|
|
|
|
|
|
|
// This assumes that there is a single agent per dc, typically a TestAgent
|
2019-01-25 16:01:21 +00:00
|
|
|
nodeReq := &structs.NodeSpecificRequest{
|
|
|
|
Datacenter: dc,
|
|
|
|
Node: nodes.Nodes[0].Node,
|
|
|
|
QueryOptions: structs.QueryOptions{Token: token},
|
|
|
|
}
|
2018-08-10 19:04:07 +00:00
|
|
|
if err := rpc("Health.NodeChecks", nodeReq, &checks); err != nil {
|
|
|
|
r.Fatalf("Health.NodeChecks failed: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var found bool
|
|
|
|
for _, check := range checks.HealthChecks {
|
|
|
|
if check.CheckID == "serfHealth" {
|
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
|
|
|
r.Fatalf("serfHealth check not found")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|