Files
galaxy-game/integration/mail_flow_test.go
T
2026-05-06 10:14:55 +03:00

86 lines
2.7 KiB
Go

package integration_test
import (
"context"
"encoding/json"
"net/http"
"testing"
"time"
"galaxy/integration/testenv"
)
// TestMailFlow_LoginCodeAndAdminListing triggers a login code email
// (which uses backend's mail outbox), waits for mailpit to capture
// the SMTP delivery, and verifies the admin endpoints expose the
// same delivery via the typed list response.
//
// Resend on a `sent` row returns 409 (per OpenAPI/decision record);
// this test asserts that contract by attempting a resend on the
// captured (and now sent) delivery.
func TestMailFlow_LoginCodeAndAdminListing(t *testing.T) {
plat := testenv.Bootstrap(t, testenv.BootstrapOptions{})
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
defer cancel()
// Trigger a login code, which writes one mail_deliveries row and
// drains via the worker into mailpit.
sess := testenv.RegisterSession(t, plat, "pilot+mail@example.com")
if sess.DeviceSessionID == "" {
t.Fatalf("session not established")
}
admin := testenv.NewBackendAdminClient(plat.Backend.HTTPURL, plat.Backend.AdminUser, plat.Backend.AdminPassword)
raw, resp, err := admin.Do(ctx, http.MethodGet, "/api/v1/admin/mail/deliveries?page=1&page_size=10", nil)
if err != nil {
t.Fatalf("list deliveries: %v", err)
}
if resp.StatusCode != http.StatusOK {
t.Fatalf("list deliveries: status %d body=%s", resp.StatusCode, string(raw))
}
var list struct {
Items []struct {
DeliveryID string `json:"delivery_id"`
Status string `json:"status"`
TemplateID string `json:"template_id"`
} `json:"items"`
}
if err := json.Unmarshal(raw, &list); err != nil {
t.Fatalf("decode list: %v", err)
}
if len(list.Items) == 0 {
t.Fatalf("admin list returned no deliveries; expected at least the login code row")
}
var sent string
deadline := time.Now().Add(15 * time.Second)
for time.Now().Before(deadline) && sent == "" {
raw, resp, err = admin.Do(ctx, http.MethodGet, "/api/v1/admin/mail/deliveries?page=1&page_size=10", nil)
if err != nil || resp.StatusCode != http.StatusOK {
t.Fatalf("list deliveries during wait: %v status=%v", err, resp)
}
_ = json.Unmarshal(raw, &list)
for _, it := range list.Items {
if it.Status == "sent" {
sent = it.DeliveryID
break
}
}
if sent == "" {
time.Sleep(300 * time.Millisecond)
}
}
if sent == "" {
t.Fatalf("no delivery reached `sent` within 15s; admin list = %+v", list.Items)
}
// Resend on a sent row must return 409.
raw, resp, err = admin.Do(ctx, http.MethodPost, "/api/v1/admin/mail/deliveries/"+sent+"/resend", nil)
if err != nil {
t.Fatalf("resend sent delivery: %v", err)
}
if resp.StatusCode != http.StatusConflict {
t.Fatalf("resend on sent delivery: status %d body=%s, want 409", resp.StatusCode, string(raw))
}
}