mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-06 05:49:12 +02:00
Expose self-host daemon setup URLs from /api/config at runtime so the Add computer dialog renders the operator's own server/app domains, while Multica Cloud defaults stay unchanged. Fixes #3013.
183 lines
5.9 KiB
Go
183 lines
5.9 KiB
Go
package handler
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func TestGetConfigIncludesRuntimeAuthConfig(t *testing.T) {
|
|
origStorage := testHandler.Storage
|
|
testHandler.Storage = &mockStorage{}
|
|
defer func() { testHandler.Storage = origStorage }()
|
|
|
|
t.Setenv("ALLOW_SIGNUP", "false")
|
|
t.Setenv("GOOGLE_CLIENT_ID", "google-client-id")
|
|
t.Setenv("POSTHOG_API_KEY", "phc_test")
|
|
t.Setenv("POSTHOG_HOST", "https://eu.i.posthog.com")
|
|
t.Setenv("MULTICA_PUBLIC_URL", "https://api.example.com/")
|
|
t.Setenv("MULTICA_APP_URL", "https://app.example.com/")
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/config", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
testHandler.GetConfig(w, req)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("GetConfig: expected 200, got %d: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
var cfg AppConfig
|
|
if err := json.Unmarshal(w.Body.Bytes(), &cfg); err != nil {
|
|
t.Fatalf("decode config: %v", err)
|
|
}
|
|
|
|
if cfg.CdnDomain != "cdn.example.com" {
|
|
t.Fatalf("cdn_domain: want cdn.example.com, got %q", cfg.CdnDomain)
|
|
}
|
|
if cfg.AllowSignup {
|
|
t.Fatalf("allow_signup: want false, got true")
|
|
}
|
|
if cfg.GoogleClientID != "google-client-id" {
|
|
t.Fatalf("google_client_id: want google-client-id, got %q", cfg.GoogleClientID)
|
|
}
|
|
if cfg.PosthogKey != "phc_test" {
|
|
t.Fatalf("posthog_key: want phc_test, got %q", cfg.PosthogKey)
|
|
}
|
|
if cfg.PosthogHost != "https://eu.i.posthog.com" {
|
|
t.Fatalf("posthog_host: want https://eu.i.posthog.com, got %q", cfg.PosthogHost)
|
|
}
|
|
if cfg.AnalyticsEnvironment != "dev" {
|
|
t.Fatalf("analytics_environment: want dev, got %q", cfg.AnalyticsEnvironment)
|
|
}
|
|
if cfg.WorkspaceCreationDisabled {
|
|
t.Fatalf("workspace_creation_disabled: want false by default, got true")
|
|
}
|
|
if cfg.DaemonServerURL != "https://api.example.com" {
|
|
t.Fatalf("daemon_server_url: want https://api.example.com, got %q", cfg.DaemonServerURL)
|
|
}
|
|
if cfg.DaemonAppURL != "https://app.example.com" {
|
|
t.Fatalf("daemon_app_url: want https://app.example.com, got %q", cfg.DaemonAppURL)
|
|
}
|
|
}
|
|
|
|
func TestGetConfigUsesAppURLForSameOriginDaemonSetup(t *testing.T) {
|
|
t.Setenv("MULTICA_APP_URL", "https://multica.internal.example/")
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/config", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
testHandler.GetConfig(w, req)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("GetConfig: expected 200, got %d: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
var cfg AppConfig
|
|
if err := json.Unmarshal(w.Body.Bytes(), &cfg); err != nil {
|
|
t.Fatalf("decode config: %v", err)
|
|
}
|
|
if cfg.DaemonServerURL != "https://multica.internal.example" {
|
|
t.Fatalf("daemon_server_url: want same-origin URL, got %q", cfg.DaemonServerURL)
|
|
}
|
|
if cfg.DaemonAppURL != "https://multica.internal.example" {
|
|
t.Fatalf("daemon_app_url: want app URL, got %q", cfg.DaemonAppURL)
|
|
}
|
|
}
|
|
|
|
func TestGetConfigUsesFrontendOriginForSameOriginDaemonSetup(t *testing.T) {
|
|
t.Setenv("FRONTEND_ORIGIN", "https://multica.internal.example/")
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/config", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
testHandler.GetConfig(w, req)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("GetConfig: expected 200, got %d: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
var cfg AppConfig
|
|
if err := json.Unmarshal(w.Body.Bytes(), &cfg); err != nil {
|
|
t.Fatalf("decode config: %v", err)
|
|
}
|
|
if cfg.DaemonServerURL != "https://multica.internal.example" {
|
|
t.Fatalf("daemon_server_url: want same-origin URL, got %q", cfg.DaemonServerURL)
|
|
}
|
|
if cfg.DaemonAppURL != "https://multica.internal.example" {
|
|
t.Fatalf("daemon_app_url: want frontend origin, got %q", cfg.DaemonAppURL)
|
|
}
|
|
}
|
|
|
|
func TestGetConfigOmitsOfficialCloudDaemonSetup(t *testing.T) {
|
|
t.Setenv("MULTICA_PUBLIC_URL", "https://api.multica.ai")
|
|
t.Setenv("FRONTEND_ORIGIN", "https://multica.ai")
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/config", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
testHandler.GetConfig(w, req)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("GetConfig: expected 200, got %d: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
var cfg AppConfig
|
|
if err := json.Unmarshal(w.Body.Bytes(), &cfg); err != nil {
|
|
t.Fatalf("decode config: %v", err)
|
|
}
|
|
if cfg.DaemonServerURL != "" {
|
|
t.Fatalf("daemon_server_url: want omitted for cloud, got %q", cfg.DaemonServerURL)
|
|
}
|
|
if cfg.DaemonAppURL != "" {
|
|
t.Fatalf("daemon_app_url: want omitted for cloud, got %q", cfg.DaemonAppURL)
|
|
}
|
|
}
|
|
|
|
func TestURLHostEqualsCanonicalizesCommonHostForms(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
raw string
|
|
want bool
|
|
}{
|
|
{name: "full URL", raw: "https://api.multica.ai", want: true},
|
|
{name: "bare host", raw: "api.multica.ai", want: true},
|
|
{name: "host port", raw: "api.multica.ai:8080", want: true},
|
|
{name: "trailing dot", raw: "https://api.multica.ai.", want: true},
|
|
{name: "different host", raw: "https://evil.example", want: false},
|
|
{name: "empty", raw: "", want: false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := urlHostEquals(tt.raw, "api.multica.ai"); got != tt.want {
|
|
t.Fatalf("urlHostEquals(%q): want %v, got %v", tt.raw, tt.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestGetConfigExposesWorkspaceCreationDisabled verifies that the self-host
|
|
// gate added by #3433 surfaces to the frontend through /api/config so the UI
|
|
// can hide every "Create workspace" affordance.
|
|
func TestGetConfigExposesWorkspaceCreationDisabled(t *testing.T) {
|
|
origStorage := testHandler.Storage
|
|
testHandler.Storage = &mockStorage{}
|
|
defer func() { testHandler.Storage = origStorage }()
|
|
|
|
t.Setenv("DISABLE_WORKSPACE_CREATION", "true")
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/config", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
testHandler.GetConfig(w, req)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("GetConfig: expected 200, got %d: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
var cfg AppConfig
|
|
if err := json.Unmarshal(w.Body.Bytes(), &cfg); err != nil {
|
|
t.Fatalf("decode config: %v", err)
|
|
}
|
|
if !cfg.WorkspaceCreationDisabled {
|
|
t.Fatalf("workspace_creation_disabled: want true with env on, got false (body=%s)", w.Body.String())
|
|
}
|
|
}
|