mirror of
https://github.com/prymitive/karma
synced 2026-05-11 03:46:48 +00:00
309 lines
8.9 KiB
Go
309 lines
8.9 KiB
Go
package alertmanager
|
|
|
|
import (
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/prymitive/karma/internal/config"
|
|
)
|
|
|
|
type testCase struct {
|
|
config config.AlertmanagerConfig
|
|
shouldFail bool
|
|
}
|
|
|
|
var testCases = []testCase{
|
|
{
|
|
config: config.AlertmanagerConfig{
|
|
Cluster: "cluster",
|
|
Name: "name",
|
|
URI: "http://localhost:9093",
|
|
ExternalURI: "http://localhost:9093",
|
|
Timeout: time.Second * 30,
|
|
Proxy: false,
|
|
ReadOnly: false,
|
|
Headers: map[string]string{},
|
|
},
|
|
},
|
|
{
|
|
config: config.AlertmanagerConfig{
|
|
Cluster: "cluster",
|
|
Name: "proxy",
|
|
URI: "http://localhost:9094",
|
|
ExternalURI: "http://localhost:9094",
|
|
Timeout: time.Second * 30,
|
|
Proxy: true,
|
|
ReadOnly: false,
|
|
Headers: map[string]string{},
|
|
},
|
|
},
|
|
{
|
|
config: config.AlertmanagerConfig{
|
|
Cluster: "cluster",
|
|
Name: "name",
|
|
URI: "http://localhost:9095",
|
|
ExternalURI: "http://localhost:9095",
|
|
Timeout: time.Second * 30,
|
|
Proxy: false,
|
|
ReadOnly: true,
|
|
Headers: map[string]string{},
|
|
},
|
|
},
|
|
{
|
|
config: config.AlertmanagerConfig{
|
|
Cluster: "cluster",
|
|
Name: "name",
|
|
URI: "%gh&%ij",
|
|
ExternalURI: "http://localhost:9095",
|
|
Timeout: time.Second * 30,
|
|
Proxy: false,
|
|
ReadOnly: true,
|
|
Headers: map[string]string{},
|
|
},
|
|
shouldFail: true,
|
|
},
|
|
{
|
|
config: config.AlertmanagerConfig{
|
|
Cluster: "cluster",
|
|
Name: "name",
|
|
URI: "http://localhost:9095",
|
|
ExternalURI: "%gh&%ij",
|
|
Timeout: time.Second * 30,
|
|
Proxy: false,
|
|
ReadOnly: true,
|
|
Headers: map[string]string{},
|
|
},
|
|
shouldFail: true,
|
|
},
|
|
{
|
|
config: config.AlertmanagerConfig{
|
|
Cluster: "cluster",
|
|
Name: "name",
|
|
URI: "http://localhost:9093",
|
|
ExternalURI: "http://localhost:9093",
|
|
Timeout: time.Second * 30,
|
|
Proxy: false,
|
|
ReadOnly: false,
|
|
Headers: map[string]string{},
|
|
Healthcheck: config.AlertmanagerHealthcheck{
|
|
Filters: map[string][]string{
|
|
"prom1": {"@age>a"},
|
|
},
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
},
|
|
{
|
|
config: config.AlertmanagerConfig{
|
|
Cluster: "cluster",
|
|
Name: "name",
|
|
URI: "http://localhost:9093",
|
|
ExternalURI: "http://localhost:9093",
|
|
Timeout: time.Second * 30,
|
|
Proxy: false,
|
|
ReadOnly: false,
|
|
Headers: map[string]string{},
|
|
Healthcheck: config.AlertmanagerHealthcheck{
|
|
Filters: map[string][]string{
|
|
"prom1": {" "},
|
|
},
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
},
|
|
}
|
|
|
|
func saveUpstreams() map[string]*Alertmanager {
|
|
saved := make(map[string]*Alertmanager, len(upstreams))
|
|
for k, v := range upstreams {
|
|
saved[k] = v
|
|
}
|
|
return saved
|
|
}
|
|
|
|
func restoreUpstreams(saved map[string]*Alertmanager) {
|
|
upstreams = saved
|
|
}
|
|
|
|
func TestUnregisterAll(t *testing.T) {
|
|
// verifies that UnregisterAll removes all registered instances
|
|
saved := saveUpstreams()
|
|
defer restoreUpstreams(saved)
|
|
|
|
am, err := NewAlertmanager("cluster", "unreg-test", "http://localhost")
|
|
if err != nil {
|
|
t.Fatalf("NewAlertmanager failed: %s", err)
|
|
}
|
|
_ = RegisterAlertmanager(am)
|
|
UnregisterAll()
|
|
ams := GetAlertmanagers()
|
|
if len(ams) != 0 {
|
|
t.Errorf("Expected 0 alertmanagers after UnregisterAll, got %d", len(ams))
|
|
}
|
|
}
|
|
|
|
func TestRegisterAlertmanagerDuplicate(t *testing.T) {
|
|
// verifies that registering the same name twice returns an error
|
|
saved := saveUpstreams()
|
|
defer restoreUpstreams(saved)
|
|
UnregisterAll()
|
|
|
|
am, err := NewAlertmanager("cluster", "dup-test", "http://localhost")
|
|
if err != nil {
|
|
t.Fatalf("NewAlertmanager failed: %s", err)
|
|
}
|
|
if regErr := RegisterAlertmanager(am); regErr != nil {
|
|
t.Fatalf("First RegisterAlertmanager failed: %s", regErr)
|
|
}
|
|
|
|
am2, err := NewAlertmanager("cluster", "dup-test", "http://localhost:9094")
|
|
if err != nil {
|
|
t.Fatalf("NewAlertmanager failed: %s", err)
|
|
}
|
|
if err := RegisterAlertmanager(am2); err == nil {
|
|
t.Error("Second RegisterAlertmanager with same name should have returned an error")
|
|
}
|
|
}
|
|
|
|
func TestGetAlertmanagerByName(t *testing.T) {
|
|
saved := saveUpstreams()
|
|
defer restoreUpstreams(saved)
|
|
UnregisterAll()
|
|
|
|
am, err := NewAlertmanager("cluster", "lookup-test", "http://localhost")
|
|
if err != nil {
|
|
t.Fatalf("NewAlertmanager failed: %s", err)
|
|
}
|
|
_ = RegisterAlertmanager(am)
|
|
|
|
// verifies that a registered instance is found by name
|
|
found := GetAlertmanagerByName("lookup-test")
|
|
if found == nil {
|
|
t.Error("GetAlertmanagerByName returned nil for registered instance")
|
|
}
|
|
if found != nil && found.Name != "lookup-test" {
|
|
t.Errorf("GetAlertmanagerByName returned wrong instance: %s", found.Name)
|
|
}
|
|
|
|
// verifies that a non-existent name returns nil
|
|
notFound := GetAlertmanagerByName("does-not-exist")
|
|
if notFound != nil {
|
|
t.Errorf("GetAlertmanagerByName returned non-nil for unregistered name: %s", notFound.Name)
|
|
}
|
|
}
|
|
|
|
func TestWithHealthchecksVisible(t *testing.T) {
|
|
// verifies that WithHealthchecksVisible sets the healthchecksVisible field
|
|
am, err := NewAlertmanager("cluster", "hcv-test", "http://localhost",
|
|
WithHealthchecksVisible(true),
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("NewAlertmanager failed: %s", err)
|
|
}
|
|
if !am.healthchecksVisible {
|
|
t.Error("Expected healthchecksVisible to be true")
|
|
}
|
|
}
|
|
|
|
func TestIsHealthy(t *testing.T) {
|
|
// verifies that a fresh alertmanager with no errors is healthy
|
|
am, err := NewAlertmanager("cluster", "healthy-test", "http://localhost")
|
|
if err != nil {
|
|
t.Fatalf("NewAlertmanager failed: %s", err)
|
|
}
|
|
if !am.IsHealthy() {
|
|
t.Error("Expected fresh alertmanager to be healthy")
|
|
}
|
|
|
|
// verifies that setting lastError makes it unhealthy
|
|
am.lock.Lock()
|
|
am.lastError = "something went wrong"
|
|
am.lock.Unlock()
|
|
if am.IsHealthy() {
|
|
t.Error("Expected alertmanager with lastError to be unhealthy")
|
|
}
|
|
}
|
|
|
|
func TestClusterMemberNames(t *testing.T) {
|
|
saved := saveUpstreams()
|
|
defer restoreUpstreams(saved)
|
|
UnregisterAll()
|
|
|
|
// register three alertmanagers: two in same cluster, one different
|
|
am1, _ := NewAlertmanager("prod", "am-1", "http://localhost:9091")
|
|
am2, _ := NewAlertmanager("prod", "am-2", "http://localhost:9092")
|
|
am3, _ := NewAlertmanager("staging", "am-3", "http://localhost:9093")
|
|
_ = RegisterAlertmanager(am1)
|
|
_ = RegisterAlertmanager(am2)
|
|
_ = RegisterAlertmanager(am3)
|
|
|
|
// verifies that am1 sees itself and am2 as cluster members, but not am3
|
|
members := am1.ClusterMemberNames()
|
|
if len(members) != 2 {
|
|
t.Errorf("Expected 2 cluster members, got %d: %v", len(members), members)
|
|
}
|
|
if members[0] != "am-1" || members[1] != "am-2" {
|
|
t.Errorf("Expected [am-1 am-2], got %v", members)
|
|
}
|
|
|
|
// verifies that am3 only sees itself
|
|
members3 := am3.ClusterMemberNames()
|
|
if len(members3) != 1 {
|
|
t.Errorf("Expected 1 cluster member for staging, got %d: %v", len(members3), members3)
|
|
}
|
|
if members3[0] != "am-3" {
|
|
t.Errorf("Expected [am-3], got %v", members3)
|
|
}
|
|
}
|
|
|
|
func TestOptions(t *testing.T) {
|
|
for _, tc := range testCases {
|
|
var httpTransport http.RoundTripper
|
|
var err error
|
|
if tc.config.TLS.CA != "" || tc.config.TLS.Cert != "" || tc.config.TLS.InsecureSkipVerify {
|
|
httpTransport, err = NewHTTPTransport(tc.config.TLS.CA, tc.config.TLS.Cert, tc.config.TLS.Key, tc.config.TLS.InsecureSkipVerify)
|
|
if err != nil {
|
|
t.Errorf("Failed to create HTTP transport for Alertmanager '%s' with URI '%s': %s", tc.config.Name, tc.config.URI, err)
|
|
}
|
|
}
|
|
|
|
am, err := NewAlertmanager(
|
|
tc.config.Cluster,
|
|
tc.config.Name,
|
|
tc.config.URI,
|
|
WithExternalURI(tc.config.ExternalURI),
|
|
WithRequestTimeout(tc.config.Timeout),
|
|
WithProxy(tc.config.Proxy),
|
|
WithReadOnly(tc.config.ReadOnly),
|
|
WithHTTPTransport(httpTransport), // we will pass a nil unless TLS.CA or TLS.Cert is set
|
|
WithHTTPHeaders(tc.config.Headers),
|
|
WithCORSCredentials(tc.config.CORS.Credentials),
|
|
WithHealthchecks(tc.config.Healthcheck.Filters),
|
|
)
|
|
didFail := err != nil
|
|
if didFail != tc.shouldFail {
|
|
t.Errorf("Alertmanager '%s' error mismatch, shouldFail=%v, err=%v", tc.config.Name, tc.shouldFail, err)
|
|
}
|
|
if err != nil {
|
|
t.Logf("Alertmanager '%s' returned an error: %v", tc.config.Name, err)
|
|
continue
|
|
}
|
|
if am.Name != tc.config.Name {
|
|
t.Errorf("AlertmanagerConfig with name '%s' returned Alertmanager with name '%s'", tc.config.Name, am.Name)
|
|
}
|
|
if am.URI != tc.config.URI {
|
|
t.Errorf("AlertmanagerConfig with name '%s' and URI '%s' returned Alertmanager with URI '%s'", tc.config.Name, tc.config.URI, am.URI)
|
|
}
|
|
if am.ProxyRequests != tc.config.Proxy {
|
|
t.Errorf("AlertmanagerConfig with name '%s' and proxy '%v' returned Alertmanager with proxy '%v'", tc.config.Name, tc.config.Proxy, am.ProxyRequests)
|
|
}
|
|
if am.ReadOnly != tc.config.ReadOnly {
|
|
t.Errorf("AlertmanagerConfig with name '%s' and readonly '%v' returned Alertmanager with readonly '%v'", tc.config.Name, tc.config.ReadOnly, am.ReadOnly)
|
|
}
|
|
if am.CORSCredentials != tc.config.CORS.Credentials {
|
|
t.Errorf("AlertmanagerConfig with name '%s' and cors:credentials '%v' returned Alertmanager with cors:credentials '%v'", tc.config.Name, tc.config.CORS.Credentials, am.CORSCredentials)
|
|
}
|
|
}
|
|
}
|