Files

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")
}
}