package mail import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/go-chi/chi/v5" "github.com/ultisuite/ulti-backend/internal/api/middleware" "github.com/ultisuite/ulti-backend/internal/auth" ) func newTestIdentityRouter(svc ServiceAPI) http.Handler { h := NewHandlerWithService(svc) r := chi.NewRouter() r.Use(middleware.WithTestClaims(&auth.Claims{ Sub: testExternalID, Email: "user@example.com", })) r.Get("/accounts/{accountID}/identities", h.ListIdentities) r.Post("/accounts/{accountID}/identities", h.CreateIdentity) r.Get("/identities/{identityID}", h.GetIdentity) r.Put("/identities/{identityID}", h.UpdateIdentity) r.Delete("/identities/{identityID}", h.DeleteIdentity) return r } func TestListIdentities(t *testing.T) { svc := newFakeMailService() router := newTestIdentityRouter(svc) req := httptest.NewRequest(http.MethodGet, "/accounts/acc-1/identities", nil) rec := httptest.NewRecorder() router.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status = %d, want %d; body = %s", rec.Code, http.StatusOK, rec.Body.String()) } var body IdentitiesList if err := json.NewDecoder(rec.Body).Decode(&body); err != nil { t.Fatalf("decode body: %v", err) } if len(body.Identities) != 1 { t.Fatalf("identities len = %d, want 1", len(body.Identities)) } if body.Identities[0]["email"] != "sender@example.com" { t.Fatalf("email = %v", body.Identities[0]["email"]) } } func TestCreateIdentity(t *testing.T) { svc := newFakeMailService() router := newTestIdentityRouter(svc) payload := map[string]any{ "email": "alias@example.com", "name": "Alias", } body, err := json.Marshal(payload) if err != nil { t.Fatalf("marshal payload: %v", err) } req := httptest.NewRequest(http.MethodPost, "/accounts/acc-1/identities", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") rec := httptest.NewRecorder() router.ServeHTTP(rec, req) if rec.Code != http.StatusCreated { t.Fatalf("status = %d, want %d; body = %s", rec.Code, http.StatusCreated, rec.Body.String()) } var resp map[string]string if err := json.NewDecoder(rec.Body).Decode(&resp); err != nil { t.Fatalf("decode body: %v", err) } if resp["id"] != "id-new" { t.Fatalf("id = %q, want id-new", resp["id"]) } } func TestGetIdentity(t *testing.T) { svc := newFakeMailService() router := newTestIdentityRouter(svc) req := httptest.NewRequest(http.MethodGet, "/identities/id-1", nil) rec := httptest.NewRecorder() router.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status = %d, want %d; body = %s", rec.Code, http.StatusOK, rec.Body.String()) } var identity map[string]any if err := json.NewDecoder(rec.Body).Decode(&identity); err != nil { t.Fatalf("decode body: %v", err) } if identity["id"] != "id-1" { t.Fatalf("id = %v", identity["id"]) } } func TestUpdateIdentity(t *testing.T) { svc := newFakeMailService() router := newTestIdentityRouter(svc) payload := map[string]any{ "email": "updated@example.com", "name": "Updated", "is_default": false, "signature_html": "

Sig

", "reply_to_addrs": []string{"reply@example.com"}, } body, err := json.Marshal(payload) if err != nil { t.Fatalf("marshal payload: %v", err) } req := httptest.NewRequest(http.MethodPut, "/identities/id-1", bytes.NewReader(body)) req.Header.Set("Content-Type", "application/json") rec := httptest.NewRecorder() router.ServeHTTP(rec, req) if rec.Code != http.StatusNoContent { t.Fatalf("status = %d, want %d; body = %s", rec.Code, http.StatusNoContent, rec.Body.String()) } } func TestDeleteIdentity(t *testing.T) { svc := newFakeMailService() router := newTestIdentityRouter(svc) req := httptest.NewRequest(http.MethodDelete, "/identities/id-1", nil) rec := httptest.NewRecorder() router.ServeHTTP(rec, req) if rec.Code != http.StatusNoContent { t.Fatalf("status = %d, want %d; body = %s", rec.Code, http.StatusNoContent, rec.Body.String()) } } func TestListIdentitiesAccountNotFound(t *testing.T) { svc := newFakeMailService() router := newTestIdentityRouter(svc) req := httptest.NewRequest(http.MethodGet, "/accounts/missing/identities", nil) rec := httptest.NewRecorder() router.ServeHTTP(rec, req) if rec.Code != http.StatusNotFound { t.Fatalf("status = %d, want %d; body = %s", rec.Code, http.StatusNotFound, rec.Body.String()) } }