- Added configuration options for Stalwart hosted mail in .env.example. - Updated Docker Compose to include Stalwart service with health checks. - Introduced new API endpoints for managing mail domains and migration projects. - Enhanced Authentik blueprints for user enrollment and post-migration security. - Updated OAuth handling for Google and Microsoft migration processes. - Improved error handling and response structures in the mail API. - Added integration tests for email claiming and migration workflows.
118 lines
3.2 KiB
Go
118 lines
3.2 KiB
Go
//go:build integration
|
|
|
|
package migration_test
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
|
|
"github.com/ultisuite/ulti-backend/internal/integrationtest"
|
|
"github.com/ultisuite/ulti-backend/internal/mail/credentials"
|
|
"github.com/ultisuite/ulti-backend/internal/nextcloud"
|
|
"github.com/ultisuite/ulti-backend/internal/users"
|
|
)
|
|
|
|
func mockNextcloudServer(t *testing.T) *httptest.Server {
|
|
t.Helper()
|
|
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
switch r.Method {
|
|
case http.MethodPut, "MKCOL", "MKCALENDAR":
|
|
w.WriteHeader(http.StatusCreated)
|
|
case http.MethodDelete:
|
|
w.WriteHeader(http.StatusNoContent)
|
|
case "PROPFIND", "REPORT", http.MethodGet:
|
|
w.WriteHeader(http.StatusOK)
|
|
_, _ = w.Write([]byte(`<?xml version="1.0"?><d:multistatus xmlns:d="DAV:"></d:multistatus>`))
|
|
default:
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
}))
|
|
}
|
|
|
|
func testCredentialManager(t *testing.T) *credentials.Manager {
|
|
t.Helper()
|
|
mgr, err := credentials.NewManager(
|
|
"v1:MDEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNkZWY=",
|
|
"v1",
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("credential manager: %v", err)
|
|
}
|
|
return mgr
|
|
}
|
|
|
|
func mockNextcloudClient(t *testing.T, pool *pgxpool.Pool, email string) (*nextcloud.Client, string) {
|
|
t.Helper()
|
|
srv := mockNextcloudServer(t)
|
|
t.Cleanup(srv.Close)
|
|
|
|
ncUserID := nextcloud.UserIDFromClaims(email, "")
|
|
store := nextcloud.NewDAVCredentialStore(pool, testCredentialManager(t))
|
|
if err := store.SaveToken(context.Background(), ncUserID, "mock-app-password"); err != nil {
|
|
t.Fatalf("seed dav token: %v", err)
|
|
}
|
|
client := nextcloud.NewClient(srv.URL, "admin", "admin").WithDAVCredentials(store)
|
|
return client, ncUserID
|
|
}
|
|
|
|
func insertMigrationTestUser(t *testing.T, pool *pgxpool.Pool, prefix string) (userID, email string) {
|
|
t.Helper()
|
|
claims := integrationtest.RegularUser(integrationtest.NewExternalID(prefix))
|
|
claims.Email = prefix + "-" + uuid.NewString() + "@migration.test"
|
|
id, err := users.EnsureUser(context.Background(), pool, claims)
|
|
integrationtest.FailIf(err, t, "ensure user")
|
|
return id, claims.Email
|
|
}
|
|
|
|
func googleRewriteClient(t *testing.T, handler http.HandlerFunc) *http.Client {
|
|
t.Helper()
|
|
srv := httptest.NewServer(handler)
|
|
t.Cleanup(srv.Close)
|
|
return &http.Client{
|
|
Transport: &hostRewriteTransport{
|
|
mockBase: srv.URL,
|
|
match: func(host string) bool {
|
|
return strings.Contains(host, "googleapis.com")
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func graphRewriteClient(t *testing.T, handler http.HandlerFunc) *http.Client {
|
|
t.Helper()
|
|
srv := httptest.NewServer(handler)
|
|
t.Cleanup(srv.Close)
|
|
return &http.Client{
|
|
Transport: &hostRewriteTransport{
|
|
mockBase: srv.URL,
|
|
match: func(host string) bool {
|
|
return strings.Contains(host, "graph.microsoft.com")
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
type hostRewriteTransport struct {
|
|
mockBase string
|
|
match func(host string) bool
|
|
}
|
|
|
|
func (rt *hostRewriteTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
if rt.match(req.URL.Host) {
|
|
mockURL, err := url.Parse(rt.mockBase)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req.URL.Scheme = mockURL.Scheme
|
|
req.URL.Host = mockURL.Host
|
|
}
|
|
return http.DefaultTransport.RoundTrip(req)
|
|
}
|