142 lines
4.1 KiB
Go
142 lines
4.1 KiB
Go
package notify
|
|
|
|
import "context"
|
|
import "encoding/json"
|
|
import "io"
|
|
import "net/http"
|
|
import "net/http/httptest"
|
|
import "testing"
|
|
|
|
import "codit/internal/models"
|
|
import "codit/internal/monitor"
|
|
|
|
func testEvent() models.Event {
|
|
return models.Event{
|
|
Kind: "monitor.down",
|
|
Severity: "critical",
|
|
Title: "api.example.com is down",
|
|
Body: "connection refused",
|
|
SourceType: models.EventSourceMonitor,
|
|
SourceID: "mon-123",
|
|
Payload: `{"state":"down"}`,
|
|
CreatedAt: 1700000000,
|
|
}
|
|
}
|
|
|
|
func TestDeliverWebhookPostsJSONWithAuthHeader(t *testing.T) {
|
|
var gotMethod string
|
|
var gotAuth string
|
|
var gotType string
|
|
var payload webhookPayload
|
|
var srv *httptest.Server
|
|
var d *Dispatcher
|
|
var target models.DeliveryTarget
|
|
var err error
|
|
|
|
srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
var body []byte
|
|
gotMethod = r.Method
|
|
gotAuth = r.Header.Get("X-Token")
|
|
gotType = r.Header.Get("Content-Type")
|
|
body, _ = io.ReadAll(r.Body)
|
|
_ = json.Unmarshal(body, &payload)
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
d = NewDispatcher(nil, "", "", monitor.DefaultEgressPolicy(), "", nil)
|
|
target = models.DeliveryTarget{
|
|
ChannelName: "ops-webhook",
|
|
TransportType: models.TransportTypeWebhook,
|
|
Config: `{"header_name":"X-Token"}`,
|
|
Address: srv.URL,
|
|
}
|
|
err = d.deliverWebhook(context.Background(), target, map[string]string{"token": "s3cr3t"}, testEvent())
|
|
if err != nil {
|
|
t.Fatalf("deliverWebhook returned error: %v", err)
|
|
}
|
|
if gotMethod != http.MethodPost {
|
|
t.Fatalf("expected POST, got %s", gotMethod)
|
|
}
|
|
if gotType != "application/json" {
|
|
t.Fatalf("expected application/json content-type, got %q", gotType)
|
|
}
|
|
if gotAuth != "s3cr3t" {
|
|
t.Fatalf("expected auth header X-Token=s3cr3t, got %q", gotAuth)
|
|
}
|
|
if payload.Kind != "monitor.down" || payload.SourceID != "mon-123" || payload.Channel != "ops-webhook" {
|
|
t.Fatalf("unexpected payload: %+v", payload)
|
|
}
|
|
}
|
|
|
|
func TestDeliverWebhookErrorsOnBadStatus(t *testing.T) {
|
|
var srv *httptest.Server
|
|
var d *Dispatcher
|
|
var err error
|
|
|
|
srv = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer srv.Close()
|
|
|
|
d = NewDispatcher(nil, "", "", monitor.DefaultEgressPolicy(), "", nil)
|
|
err = d.deliverWebhook(context.Background(), models.DeliveryTarget{
|
|
ChannelName: "ops-webhook",
|
|
TransportType: models.TransportTypeWebhook,
|
|
Address: srv.URL,
|
|
}, map[string]string{}, testEvent())
|
|
if err == nil {
|
|
t.Fatalf("expected error on 500 response, got nil")
|
|
}
|
|
}
|
|
|
|
func TestClientForDefaultsToSharedClient(t *testing.T) {
|
|
var d *Dispatcher
|
|
var c *http.Client
|
|
var err error
|
|
d = NewDispatcher(nil, "", "", monitor.DefaultEgressPolicy(), "", nil)
|
|
c, err = d.clientFor(webhookConfig{})
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if c != d.client {
|
|
t.Fatalf("no TLS options should reuse the shared client")
|
|
}
|
|
}
|
|
|
|
func TestClientForInsecureSkipVerifyBuildsClient(t *testing.T) {
|
|
var d *Dispatcher
|
|
var c *http.Client
|
|
var err error
|
|
d = NewDispatcher(nil, "", "", monitor.DefaultEgressPolicy(), "", nil)
|
|
c, err = d.clientFor(webhookConfig{InsecureSkipVerify: true})
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if c == d.client {
|
|
t.Fatalf("insecure_skip_verify should build a dedicated client")
|
|
}
|
|
}
|
|
|
|
func TestClientForFailsClosedWhenCAUnresolvable(t *testing.T) {
|
|
var d *Dispatcher
|
|
var err error
|
|
// nil store => the pinned CA cannot be resolved; must fail closed rather
|
|
// than fall back to system roots.
|
|
d = NewDispatcher(nil, "", "", monitor.DefaultEgressPolicy(), "", nil)
|
|
_, err = d.clientFor(webhookConfig{CARef: "ca-123"})
|
|
if err == nil {
|
|
t.Fatalf("expected fail-closed error when CA cannot be resolved")
|
|
}
|
|
}
|
|
|
|
func TestDeliverWebhookErrorsOnEmptyAddress(t *testing.T) {
|
|
var d *Dispatcher
|
|
var err error
|
|
d = NewDispatcher(nil, "", "", monitor.DefaultEgressPolicy(), "", nil)
|
|
err = d.deliverWebhook(context.Background(), models.DeliveryTarget{ChannelName: "x", TransportType: models.TransportTypeWebhook}, map[string]string{}, testEvent())
|
|
if err == nil {
|
|
t.Fatalf("expected error on empty address, got nil")
|
|
}
|
|
}
|