154 lines
3.7 KiB
Go
154 lines
3.7 KiB
Go
package api
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strconv"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/kandev/kandev/internal/agentctl/server/process"
|
|
)
|
|
|
|
func TestHandleVscodeProxy_ProxiesRequest(t *testing.T) {
|
|
var mu sync.Mutex
|
|
var receivedPath, receivedMethod string
|
|
mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
mu.Lock()
|
|
receivedPath = r.URL.Path
|
|
receivedMethod = r.Method
|
|
mu.Unlock()
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer mock.Close()
|
|
|
|
port := mustParsePort(t, mock.URL)
|
|
|
|
s := newTestServer(t)
|
|
s.procMgr.SetVscodeForTest(process.VscodeStatusRunning, port)
|
|
|
|
// Use a real HTTP server so Gin's responseWriter gets a real http.ResponseWriter
|
|
ts := httptest.NewServer(s.router)
|
|
defer ts.Close()
|
|
|
|
resp, err := http.Get(ts.URL + "/api/v1/vscode/proxy/some/path")
|
|
if err != nil {
|
|
t.Fatalf("request failed: %v", err)
|
|
}
|
|
defer resp.Body.Close() //nolint:errcheck
|
|
_, _ = io.Copy(io.Discard, resp.Body)
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Errorf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
if receivedPath != "/some/path" {
|
|
t.Errorf("expected path /some/path, got %q", receivedPath)
|
|
}
|
|
if receivedMethod != http.MethodGet {
|
|
t.Errorf("expected GET, got %q", receivedMethod)
|
|
}
|
|
}
|
|
|
|
func TestHandleVscodeProxy_RootPath(t *testing.T) {
|
|
var mu sync.Mutex
|
|
var receivedPath string
|
|
mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
mu.Lock()
|
|
receivedPath = r.URL.Path
|
|
mu.Unlock()
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer mock.Close()
|
|
|
|
port := mustParsePort(t, mock.URL)
|
|
|
|
s := newTestServer(t)
|
|
s.procMgr.SetVscodeForTest(process.VscodeStatusRunning, port)
|
|
|
|
ts := httptest.NewServer(s.router)
|
|
defer ts.Close()
|
|
|
|
resp, err := http.Get(ts.URL + "/api/v1/vscode/proxy")
|
|
if err != nil {
|
|
t.Fatalf("request failed: %v", err)
|
|
}
|
|
defer resp.Body.Close() //nolint:errcheck
|
|
_, _ = io.Copy(io.Discard, resp.Body)
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Errorf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
if receivedPath != "/" {
|
|
t.Errorf("expected root path /, got %q", receivedPath)
|
|
}
|
|
}
|
|
|
|
func TestHandleVscodeProxy_OriginHeader(t *testing.T) {
|
|
var mu sync.Mutex
|
|
var receivedOrigin string
|
|
mock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
mu.Lock()
|
|
receivedOrigin = r.Header.Get("Origin")
|
|
mu.Unlock()
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
defer mock.Close()
|
|
|
|
port := mustParsePort(t, mock.URL)
|
|
|
|
s := newTestServer(t)
|
|
s.procMgr.SetVscodeForTest(process.VscodeStatusRunning, port)
|
|
|
|
ts := httptest.NewServer(s.router)
|
|
defer ts.Close()
|
|
|
|
req, _ := http.NewRequest(http.MethodGet, ts.URL+"/api/v1/vscode/proxy/test", nil)
|
|
req.Header.Set("Origin", "http://different-host:9999")
|
|
resp, err := http.DefaultClient.Do(req)
|
|
if err != nil {
|
|
t.Fatalf("request failed: %v", err)
|
|
}
|
|
defer resp.Body.Close() //nolint:errcheck
|
|
_, _ = io.Copy(io.Discard, resp.Body)
|
|
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
expected := "http://127.0.0.1:" + strconv.Itoa(port)
|
|
if receivedOrigin != expected {
|
|
t.Errorf("expected Origin %q, got %q", expected, receivedOrigin)
|
|
}
|
|
}
|
|
|
|
func TestHandleVscodeProxy_NotRunning(t *testing.T) {
|
|
s := newTestServer(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/vscode/proxy/foo", nil)
|
|
w := httptest.NewRecorder()
|
|
s.router.ServeHTTP(w, req)
|
|
|
|
if w.Code != http.StatusServiceUnavailable {
|
|
t.Errorf("expected 503, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func mustParsePort(t *testing.T, rawURL string) int {
|
|
t.Helper()
|
|
u, err := url.Parse(rawURL)
|
|
if err != nil {
|
|
t.Fatalf("failed to parse URL: %v", err)
|
|
}
|
|
port, err := strconv.Atoi(u.Port())
|
|
if err != nil {
|
|
t.Fatalf("failed to parse port: %v", err)
|
|
}
|
|
return port
|
|
}
|