package email import ( "context" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" "time" "git.sendico.io/tech/sxchnge/notifications/model" ) func TestDriversRenderWirePayload(t *testing.T) { for _, driver := range []Driver{SendGrid, Resend} { t.Run(string(driver), func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Authorization") != "Bearer test-secret" { t.Error("missing authorization") } var body map[string]any if err := json.NewDecoder(r.Body).Decode(&body); err != nil { t.Error(err) } if body["subject"] != "Completed" { t.Errorf("subject: %v", body) } if driver == SendGrid { if body["template_id"] != nil { t.Error("provider-managed templates must not be used") } p := body["personalizations"].([]any)[0].(map[string]any) if p["to"].([]any)[0].(map[string]any)["email"] != "user@example.com" { t.Error("wrong recipient") } content := body["content"].([]any) if len(content) != 2 || content[1].(map[string]any)["value"] != "
A & B
" { t.Error("wrong body") } } else { if r.Header.Get("Idempotency-Key") != "delivery-id" { t.Error("missing idempotency key") } if body["html"] != "A & B
" || body["text"] != "A & B" { t.Error("wrong body") } } w.WriteHeader(http.StatusAccepted) })) defer server.Close() c := client{http: server.Client(), key: "test-secret", endpoint: server.URL, settings: Settings{SenderAddress: "sender@example.com", SenderName: "SXCHNGE"}} var sender Sender = &sendgrid{c} if driver == Resend { sender = &resend{c} } outcome := sender.Send(context.Background(), "delivery-id", model.Email{Address: "user@example.com", Subject: "Completed", HTML: "A & B
", Text: "A & B"}) if outcome.State != model.Accepted { t.Fatal(outcome) } }) } } func TestProviderFailures(t *testing.T) { for _, tc := range []struct { code int state model.State }{{429, model.RetryWait}, {400, model.Failed}, {401, model.Failed}, {403, model.Failed}, {500, model.Unknown}, {408, model.Unknown}, {302, model.Failed}} { t.Run(http.StatusText(tc.code), func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Retry-After", "120") w.WriteHeader(tc.code) _, _ = w.Write([]byte("secret provider response")) })) defer server.Close() c := client{http: server.Client(), endpoint: server.URL} out := c.post(context.Background(), "", struct{}{}) if out.State != tc.state || strings.Contains(out.Code, "secret") { t.Fatal(out) } if tc.code == 429 && out.RetryAfter != 2*time.Minute { t.Fatal(out) } }) } ctx, cancel := context.WithCancel(context.Background()) cancel() c := client{http: http.DefaultClient, endpoint: "http://127.0.0.1:1"} if out := c.post(ctx, "", struct{}{}); out.State != model.Unknown { t.Fatal(out) } } func TestDriverConfig(t *testing.T) { t.Setenv("EMAIL_TEST_KEY", "secret") for _, driver := range []Driver{SendGrid, Resend} { if _, err := New(Config{Driver: driver, Settings: map[string]any{"api_key_env": "EMAIL_TEST_KEY", "sender_address": "sender@example.com"}}); err != nil { t.Fatal(err) } } for _, settings := range []map[string]any{{"api_key_env": "MISSING_KEY", "sender_address": "sender@example.com"}, {"api_key_env": "EMAIL_TEST_KEY", "sender_address": "bad"}, {"api_key_env": "EMAIL_TEST_KEY", "sender_address": "sender@example.com", "typo": true}} { if _, err := New(Config{Driver: Resend, Settings: settings}); err == nil { t.Fatal("accepted invalid driver config") } } }