557 lines
13 KiB
Go
557 lines
13 KiB
Go
package dependency
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/consul/api"
|
|
)
|
|
|
|
func TestServiceDependencyFetch(t *testing.T) {
|
|
clients, consul := testConsulServer(t)
|
|
defer consul.Stop()
|
|
|
|
dep := &HealthServices{rawKey: "consul", Name: "consul"}
|
|
results, _, err := dep.Fetch(clients, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
typed, ok := results.([]*HealthService)
|
|
if !ok {
|
|
t.Fatal("could not convert result to []*HealthService")
|
|
}
|
|
|
|
if typed[0].ID != "consul" {
|
|
t.Errorf("expected %q to be %q", typed[0].ID, "consul")
|
|
}
|
|
|
|
if len(typed[0].Checks) == 0 {
|
|
t.Fatalf("expected to have at least one associated health check")
|
|
}
|
|
|
|
if typed[0].Checks[0].CheckID != "serfHealth" {
|
|
t.Errorf("expected %q to be %q", typed[0].Checks[0].CheckID, "serfHealth")
|
|
}
|
|
}
|
|
|
|
func TestHealthServiceList_sorts(t *testing.T) {
|
|
a := HealthServiceList{
|
|
&HealthService{Node: "frontend01", ID: "1"},
|
|
&HealthService{Node: "frontend01", ID: "2"},
|
|
&HealthService{Node: "frontend02", ID: "1"},
|
|
}
|
|
b := HealthServiceList{
|
|
&HealthService{Node: "frontend02", ID: "1"},
|
|
&HealthService{Node: "frontend01", ID: "2"},
|
|
&HealthService{Node: "frontend01", ID: "1"},
|
|
}
|
|
c := HealthServiceList{
|
|
&HealthService{Node: "frontend01", ID: "2"},
|
|
&HealthService{Node: "frontend01", ID: "1"},
|
|
&HealthService{Node: "frontend02", ID: "1"},
|
|
}
|
|
|
|
sort.Stable(a)
|
|
sort.Stable(b)
|
|
sort.Stable(c)
|
|
|
|
expected := HealthServiceList{
|
|
&HealthService{Node: "frontend01", ID: "1"},
|
|
&HealthService{Node: "frontend01", ID: "2"},
|
|
&HealthService{Node: "frontend02", ID: "1"},
|
|
}
|
|
|
|
if !reflect.DeepEqual(a, expected) {
|
|
t.Fatal("invalid sort")
|
|
}
|
|
|
|
if !reflect.DeepEqual(b, expected) {
|
|
t.Fatal("invalid sort")
|
|
}
|
|
|
|
if !reflect.DeepEqual(c, expected) {
|
|
t.Fatal("invalid sort")
|
|
}
|
|
}
|
|
|
|
func TestServiceDependencyHashCode_isUnique(t *testing.T) {
|
|
dep1 := &HealthServices{rawKey: "redis@nyc1"}
|
|
dep2 := &HealthServices{rawKey: "redis@nyc2"}
|
|
if dep1.HashCode() == dep2.HashCode() {
|
|
t.Errorf("expected HashCode to be unique")
|
|
}
|
|
}
|
|
|
|
func TestParseHealthServices_emptyString(t *testing.T) {
|
|
_, err := ParseHealthServices("")
|
|
if err == nil {
|
|
t.Fatal("expected error, but nothing was returned")
|
|
}
|
|
|
|
expected := "cannot specify empty health service dependency"
|
|
if !strings.Contains(err.Error(), expected) {
|
|
t.Errorf("expected error %q to contain %q", err.Error(), expected)
|
|
}
|
|
}
|
|
|
|
func TestParseHealthServices_name(t *testing.T) {
|
|
sd, err := ParseHealthServices("webapp")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := &HealthServices{
|
|
rawKey: "webapp",
|
|
Name: "webapp",
|
|
StatusFilter: nil,
|
|
}
|
|
if !reflect.DeepEqual(sd, expected) {
|
|
t.Errorf("expected %#v to equal %#v", sd, expected)
|
|
}
|
|
}
|
|
|
|
func TestParseHealthServices_nameAndAnyStatus(t *testing.T) {
|
|
sd, err := ParseHealthServices("webapp", "passing")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := &HealthServices{
|
|
rawKey: "webapp [passing]",
|
|
Name: "webapp",
|
|
StatusFilter: ServiceStatusFilter{HealthPassing},
|
|
}
|
|
if !reflect.DeepEqual(sd, expected) {
|
|
t.Errorf("expected %#v to equal %#v", sd, expected)
|
|
}
|
|
}
|
|
|
|
func TestParseHealthServices_slashName(t *testing.T) {
|
|
sd, err := ParseHealthServices("web/app")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := &HealthServices{
|
|
rawKey: "web/app",
|
|
Name: "web/app",
|
|
StatusFilter: nil,
|
|
}
|
|
if !reflect.DeepEqual(sd, expected) {
|
|
t.Errorf("expected %#v to equal %#v", sd, expected)
|
|
}
|
|
}
|
|
|
|
func TestParseHealthServices_underscoreName(t *testing.T) {
|
|
sd, err := ParseHealthServices("web_app")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := &HealthServices{
|
|
rawKey: "web_app",
|
|
Name: "web_app",
|
|
StatusFilter: nil,
|
|
}
|
|
if !reflect.DeepEqual(sd, expected) {
|
|
t.Errorf("expected %#v to equal %#v", sd, expected)
|
|
}
|
|
}
|
|
|
|
func TestParseHealthServices_dotTag(t *testing.T) {
|
|
sd, err := ParseHealthServices("first.release.webapp")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := &HealthServices{
|
|
rawKey: "first.release.webapp",
|
|
Name: "webapp",
|
|
Tag: "first.release",
|
|
StatusFilter: nil,
|
|
}
|
|
if !reflect.DeepEqual(sd, expected) {
|
|
t.Errorf("expected %#v to equal %#v", sd, expected)
|
|
}
|
|
}
|
|
|
|
func TestParseHealthServices_nameTag(t *testing.T) {
|
|
sd, err := ParseHealthServices("release.webapp")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := &HealthServices{
|
|
rawKey: "release.webapp",
|
|
Name: "webapp",
|
|
Tag: "release",
|
|
StatusFilter: nil,
|
|
}
|
|
|
|
if !reflect.DeepEqual(sd, expected) {
|
|
t.Errorf("expected %#v to equal %#v", sd, expected)
|
|
}
|
|
}
|
|
|
|
func TestParseHealthServices_nameTagDataCenter(t *testing.T) {
|
|
sd, err := ParseHealthServices("release.webapp@nyc1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := &HealthServices{
|
|
rawKey: "release.webapp@nyc1",
|
|
Name: "webapp",
|
|
Tag: "release",
|
|
DataCenter: "nyc1",
|
|
StatusFilter: nil,
|
|
}
|
|
|
|
if !reflect.DeepEqual(sd, expected) {
|
|
t.Errorf("expected %#v to equal %#v", sd, expected)
|
|
}
|
|
}
|
|
|
|
func TestParseHealthServices_nameTagDataCenterPort(t *testing.T) {
|
|
sd, err := ParseHealthServices("release.webapp@nyc1:8500")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := &HealthServices{
|
|
rawKey: "release.webapp@nyc1:8500",
|
|
Name: "webapp",
|
|
Tag: "release",
|
|
DataCenter: "nyc1",
|
|
StatusFilter: nil,
|
|
}
|
|
|
|
if !reflect.DeepEqual(sd, expected) {
|
|
t.Errorf("expected %#v to equal %#v", sd, expected)
|
|
}
|
|
}
|
|
|
|
func TestParseHealthServices_dataCenterOnly(t *testing.T) {
|
|
_, err := ParseHealthServices("@nyc1")
|
|
if err == nil {
|
|
t.Fatal("expected error, but nothing was returned")
|
|
}
|
|
|
|
expected := "invalid health service dependency format"
|
|
if !strings.Contains(err.Error(), expected) {
|
|
t.Errorf("expected error %q to contain %q", err.Error(), expected)
|
|
}
|
|
}
|
|
|
|
func TestParseHealthServices_nameAndPort(t *testing.T) {
|
|
sd, err := ParseHealthServices("webapp:8500")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := &HealthServices{
|
|
rawKey: "webapp:8500",
|
|
Name: "webapp",
|
|
StatusFilter: nil,
|
|
}
|
|
|
|
if !reflect.DeepEqual(sd, expected) {
|
|
t.Errorf("expected %#v to equal %#v", sd, expected)
|
|
}
|
|
}
|
|
|
|
func TestParseHealthServices_nameAndDataCenter(t *testing.T) {
|
|
sd, err := ParseHealthServices("webapp@nyc1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := &HealthServices{
|
|
rawKey: "webapp@nyc1",
|
|
Name: "webapp",
|
|
DataCenter: "nyc1",
|
|
StatusFilter: nil,
|
|
}
|
|
|
|
if !reflect.DeepEqual(sd, expected) {
|
|
t.Errorf("expected %#v to equal %#v", sd, expected)
|
|
}
|
|
}
|
|
|
|
func TestServiceTagsContains(t *testing.T) {
|
|
s := &HealthService{
|
|
Node: "node",
|
|
Address: "127.0.0.1",
|
|
ID: "id",
|
|
Name: "name",
|
|
Tags: []string{"foo", "baz"},
|
|
Port: 1234,
|
|
}
|
|
if !s.Tags.Contains("foo") {
|
|
t.Error("expected Contains to return true for foo.")
|
|
}
|
|
if s.Tags.Contains("bar") {
|
|
t.Error("expected Contains to return false for bar.")
|
|
}
|
|
if !s.Tags.Contains("baz") {
|
|
t.Error("expected Contains to return true for baz.")
|
|
}
|
|
}
|
|
|
|
func TestStatusFromChecks_nil(t *testing.T) {
|
|
status, err := statusFromChecks(nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := "passing"
|
|
if status != expected {
|
|
t.Fatalf("expected %q to be %q", status, expected)
|
|
}
|
|
}
|
|
|
|
func TestStatusFromChecks_badCbeck(t *testing.T) {
|
|
checks := []*api.HealthCheck{
|
|
&api.HealthCheck{Status: "bacon"},
|
|
}
|
|
_, err := statusFromChecks(checks)
|
|
if err == nil {
|
|
t.Fatal("expected error, but nothing was returned")
|
|
}
|
|
|
|
expected := fmt.Sprintf("unknown status: %q", "bacon")
|
|
if !strings.Contains(err.Error(), expected) {
|
|
t.Fatalf("expected %q to include %q", err.Error(), expected)
|
|
}
|
|
}
|
|
|
|
func TestStatusFromChecks_passing(t *testing.T) {
|
|
checks := []*api.HealthCheck{
|
|
&api.HealthCheck{Status: "passing"},
|
|
&api.HealthCheck{Status: "passing"},
|
|
&api.HealthCheck{Status: "passing"},
|
|
&api.HealthCheck{Status: "passing"},
|
|
}
|
|
status, err := statusFromChecks(checks)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := "passing"
|
|
if status != expected {
|
|
t.Fatalf("expected %q to be %q", status, expected)
|
|
}
|
|
}
|
|
|
|
func TestStatusFromChecks_warning(t *testing.T) {
|
|
checks := []*api.HealthCheck{
|
|
&api.HealthCheck{Status: "passing"},
|
|
&api.HealthCheck{Status: "warning"},
|
|
&api.HealthCheck{Status: "passing"},
|
|
&api.HealthCheck{Status: "passing"},
|
|
}
|
|
status, err := statusFromChecks(checks)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := "warning"
|
|
if status != expected {
|
|
t.Fatalf("expected %q to be %q", status, expected)
|
|
}
|
|
}
|
|
|
|
func TestStatusFromChecks_unknown(t *testing.T) {
|
|
checks := []*api.HealthCheck{
|
|
&api.HealthCheck{Status: "passing"},
|
|
&api.HealthCheck{Status: "warning"},
|
|
&api.HealthCheck{Status: "unknown"},
|
|
&api.HealthCheck{Status: "passing"},
|
|
}
|
|
status, err := statusFromChecks(checks)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := "unknown"
|
|
if status != expected {
|
|
t.Fatalf("expected %q to be %q", status, expected)
|
|
}
|
|
}
|
|
|
|
func TestStatusFromChecks_critical(t *testing.T) {
|
|
checks := []*api.HealthCheck{
|
|
&api.HealthCheck{Status: "passing"},
|
|
&api.HealthCheck{Status: "warning"},
|
|
&api.HealthCheck{Status: "unknown"},
|
|
&api.HealthCheck{Status: "critical"},
|
|
}
|
|
status, err := statusFromChecks(checks)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := "critical"
|
|
if status != expected {
|
|
t.Fatalf("expected %q to be %q", status, expected)
|
|
}
|
|
}
|
|
|
|
func TestStatusFromChecks_nodeMaintenance(t *testing.T) {
|
|
checks := []*api.HealthCheck{
|
|
&api.HealthCheck{Status: "passing"},
|
|
&api.HealthCheck{Status: "warning"},
|
|
&api.HealthCheck{Status: "unknown"},
|
|
&api.HealthCheck{Status: "critical"},
|
|
&api.HealthCheck{CheckID: "_node_maintenance"},
|
|
}
|
|
status, err := statusFromChecks(checks)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := "maintenance"
|
|
if status != expected {
|
|
t.Fatalf("expected %q to be %q", status, expected)
|
|
}
|
|
}
|
|
|
|
func TestStatusFromChecks_serviceMaintenance(t *testing.T) {
|
|
checks := []*api.HealthCheck{
|
|
&api.HealthCheck{Status: "passing"},
|
|
&api.HealthCheck{Status: "warning"},
|
|
&api.HealthCheck{Status: "unknown"},
|
|
&api.HealthCheck{Status: "critical"},
|
|
&api.HealthCheck{CheckID: "_service_maintenance:1234"},
|
|
}
|
|
status, err := statusFromChecks(checks)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := "maintenance"
|
|
if status != expected {
|
|
t.Fatalf("expected %q to be %q", status, expected)
|
|
}
|
|
}
|
|
|
|
// Tests specifically relating to health service filtering
|
|
// -------------------------
|
|
|
|
func TestNewServiceStatusFilter_emptyString(t *testing.T) {
|
|
filter, err := NewServiceStatusFilter("")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var expected ServiceStatusFilter
|
|
if !reflect.DeepEqual(filter, expected) {
|
|
t.Errorf("expected %#v to be %#v", filter, expected)
|
|
}
|
|
}
|
|
|
|
func TestNewServiceStatusFilter_statuses(t *testing.T) {
|
|
statuses := []string{
|
|
HealthAny,
|
|
HealthUnknown,
|
|
HealthPassing,
|
|
HealthWarning,
|
|
HealthCritical,
|
|
}
|
|
for _, status := range statuses {
|
|
filter, err := NewServiceStatusFilter(status)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := ServiceStatusFilter{status}
|
|
if !reflect.DeepEqual(filter, expected) {
|
|
t.Errorf("expected %#v to be %#v", filter, expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNewServiceStatusFilter_any(t *testing.T) {
|
|
filter, err := NewServiceStatusFilter("any")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := ServiceStatusFilter{HealthAny}
|
|
if !reflect.DeepEqual(filter, expected) {
|
|
t.Errorf("expected %#v to be %#v", filter, expected)
|
|
}
|
|
}
|
|
|
|
func TestNewServiceStatusFilter_anyWithMore(t *testing.T) {
|
|
_, err := NewServiceStatusFilter("any, passing")
|
|
if err == nil {
|
|
t.Fatal("expected error, but nothing was returned")
|
|
}
|
|
|
|
expected := fmt.Sprintf("cannot specify extra keys when using %q", "any")
|
|
if !strings.Contains(err.Error(), expected) {
|
|
t.Errorf("expected %q to include %q", err.Error(), expected)
|
|
}
|
|
}
|
|
|
|
func TestNewServiceStatusFilter_statusWithSpaces(t *testing.T) {
|
|
filter, err := NewServiceStatusFilter("passing, critical, , unknown")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected := ServiceStatusFilter{HealthPassing, HealthCritical, HealthUnknown}
|
|
if !reflect.DeepEqual(filter, expected) {
|
|
t.Errorf("expected %#v to be %#v", filter, expected)
|
|
}
|
|
}
|
|
|
|
func TestNewServiceStatusFilter_invalidStatus(t *testing.T) {
|
|
_, err := NewServiceStatusFilter("not_a_valid_status")
|
|
if err == nil {
|
|
t.Fatal("expected error, but nothing was returned")
|
|
}
|
|
|
|
expected := fmt.Sprintf("invalid filter %q", "not_a_valid_status")
|
|
if !strings.Contains(err.Error(), expected) {
|
|
t.Errorf("expected %q to be %q", err.Error(), expected)
|
|
}
|
|
}
|
|
|
|
func TestAccept_any(t *testing.T) {
|
|
filter, err := NewServiceStatusFilter("any")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
statuses := []string{"passing", "warning", "critical"}
|
|
for _, status := range statuses {
|
|
if !filter.Accept(status) {
|
|
t.Errorf("expected filter to accept %q", status)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAccept_multiple(t *testing.T) {
|
|
filter, err := NewServiceStatusFilter("passing, critical")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
statuses := []string{"passing", "critical"}
|
|
for _, status := range statuses {
|
|
if !filter.Accept(status) {
|
|
t.Errorf("expected filter to accept %q", status)
|
|
}
|
|
}
|
|
|
|
if filter.Accept("warning") {
|
|
t.Fatalf("expected filter to not accept %q", "warning")
|
|
}
|
|
}
|