package api import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "testing" "codeberg.org/SquidSE/ClusterCanvas/service/internal/settings" ) type networkResponseTest struct { Network settings.NetworkSettings `json:"network"` } func TestNetworkGetReturnsDefaults(t *testing.T) { configDir := t.TempDir() cookie := seedCompletedSetup(t, configDir) router := NewRouter(configDir) request := withSession(httptest.NewRequest(http.MethodGet, "/api/v1/network", nil), cookie) recorder := httptest.NewRecorder() router.ServeHTTP(recorder, request) if recorder.Code != http.StatusOK { t.Fatalf("expected status %d, got %d body=%s", http.StatusOK, recorder.Code, recorder.Body.String()) } var payload networkResponseTest if err := json.NewDecoder(recorder.Body).Decode(&payload); err != nil { t.Fatalf("decode response: %v", err) } if payload.Network.ListenAddress != "0.0.0.0" { t.Fatalf("expected listen_address 0.0.0.0, got %q", payload.Network.ListenAddress) } if payload.Network.AccessMode != settings.AccessModeOpen { t.Fatalf("expected access_mode open, got %q", payload.Network.AccessMode) } } func TestNetworkPutPersistsValidSettings(t *testing.T) { configDir := t.TempDir() cookie := seedCompletedSetup(t, configDir) router := NewRouter(configDir) body := []byte(`{ "network": { "listen_address": "127.0.0.1", "public_hostname": "", "access_mode": "open", "rules": [] } }`) request := withSession(httptest.NewRequest(http.MethodPut, "/api/v1/network", bytes.NewReader(body)), cookie) recorder := httptest.NewRecorder() router.ServeHTTP(recorder, request) if recorder.Code != http.StatusOK { t.Fatalf("expected status %d, got %d body=%s", http.StatusOK, recorder.Code, recorder.Body.String()) } getReq := withSession(httptest.NewRequest(http.MethodGet, "/api/v1/network", nil), cookie) getRec := httptest.NewRecorder() router.ServeHTTP(getRec, getReq) if getRec.Code != http.StatusOK { t.Fatalf("expected status %d, got %d", http.StatusOK, getRec.Code) } var payload networkResponseTest if err := json.NewDecoder(getRec.Body).Decode(&payload); err != nil { t.Fatalf("decode response: %v", err) } if payload.Network.ListenAddress != "127.0.0.1" { t.Fatalf("expected listen_address 127.0.0.1, got %q", payload.Network.ListenAddress) } } func TestNetworkPutRejectsInvalidAccessMode(t *testing.T) { configDir := t.TempDir() cookie := seedCompletedSetup(t, configDir) router := NewRouter(configDir) body := []byte(`{ "network": { "listen_address": "0.0.0.0", "public_hostname": "", "access_mode": "maybe", "rules": [] } }`) request := withSession(httptest.NewRequest(http.MethodPut, "/api/v1/network", bytes.NewReader(body)), cookie) recorder := httptest.NewRecorder() router.ServeHTTP(recorder, request) if recorder.Code != http.StatusBadRequest { t.Fatalf("expected status %d, got %d", http.StatusBadRequest, recorder.Code) } } func TestNetworkPutRejectsLockout(t *testing.T) { configDir := t.TempDir() cookie := seedCompletedSetup(t, configDir) router := NewRouter(configDir) body := []byte(`{ "network": { "listen_address": "0.0.0.0", "public_hostname": "", "access_mode": "whitelist", "rules": ["10.0.0.0/8"] } }`) request := withSession(httptest.NewRequest(http.MethodPut, "/api/v1/network", bytes.NewReader(body)), cookie) request.RemoteAddr = "192.168.1.50:12345" recorder := httptest.NewRecorder() router.ServeHTTP(recorder, request) if recorder.Code != http.StatusBadRequest { t.Fatalf("expected status %d, got %d body=%s", http.StatusBadRequest, recorder.Code, recorder.Body.String()) } var payload apiErrorResponseTest if err := json.NewDecoder(recorder.Body).Decode(&payload); err != nil { t.Fatalf("decode response: %v", err) } if payload.Error == "" { t.Fatal("expected lockout error message") } } func TestNetworkPutAllowsWhitelistIncludingClient(t *testing.T) { configDir := t.TempDir() cookie := seedCompletedSetup(t, configDir) router := NewRouter(configDir) body := []byte(`{ "network": { "listen_address": "0.0.0.0", "public_hostname": "", "access_mode": "whitelist", "rules": ["192.168.1.50"] } }`) request := withSession(httptest.NewRequest(http.MethodPut, "/api/v1/network", bytes.NewReader(body)), cookie) request.RemoteAddr = "192.168.1.50:12345" recorder := httptest.NewRecorder() router.ServeHTTP(recorder, request) if recorder.Code != http.StatusOK { t.Fatalf("expected status %d, got %d body=%s", http.StatusOK, recorder.Code, recorder.Body.String()) } }