reverse_proxy_handlers_test.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package api
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "net/http"
  6. "net/http/httptest"
  7. "path/filepath"
  8. "testing"
  9. "debtik/internal/auth"
  10. "debtik/internal/reverseproxy"
  11. )
  12. func setupTestProxyServer(t *testing.T) (*Server, *reverseproxy.Manager) {
  13. tmpDir := t.TempDir()
  14. cfgPath := filepath.Join(tmpDir, "reverse_proxy.json")
  15. proxyMgr := reverseproxy.NewManager(cfgPath, nil)
  16. authPath := filepath.Join(tmpDir, "users.json")
  17. authMgr := auth.NewManager(authPath)
  18. srv := &Server{
  19. proxyMgr: proxyMgr,
  20. authMgr: authMgr,
  21. mux: http.NewServeMux(),
  22. fsHandler: http.NotFoundHandler(),
  23. }
  24. srv.registerRoutes()
  25. return srv, proxyMgr
  26. }
  27. func TestProxyAPIEndpoints(t *testing.T) {
  28. srv, _ := setupTestProxyServer(t)
  29. // 1. GET /api/proxy/config
  30. req := httptest.NewRequest(http.MethodGet, "/api/proxy/config", nil)
  31. rec := httptest.NewRecorder()
  32. srv.mux.ServeHTTP(rec, req)
  33. if rec.Code != http.StatusOK {
  34. t.Fatalf("GET /api/proxy/config status = %d; want 200", rec.Code)
  35. }
  36. var cfg reverseproxy.Config
  37. if err := json.NewDecoder(rec.Body).Decode(&cfg); err != nil {
  38. t.Fatalf("failed to decode config: %v", err)
  39. }
  40. if !cfg.Enabled || cfg.HTTPPort != 80 {
  41. t.Errorf("unexpected config defaults: %+v", cfg)
  42. }
  43. // 2. POST /api/proxy/rules (Create Rule)
  44. newRule := reverseproxy.Rule{
  45. Name: "Web App",
  46. Enabled: true,
  47. Domains: []string{"app.example.com"},
  48. Path: "/app1",
  49. TargetURL: "http://10.0.0.10:8080/app1",
  50. Protocol: "both",
  51. }
  52. payload, _ := json.Marshal(newRule)
  53. req = httptest.NewRequest(http.MethodPost, "/api/proxy/rules", bytes.NewReader(payload))
  54. rec = httptest.NewRecorder()
  55. srv.mux.ServeHTTP(rec, req)
  56. if rec.Code != http.StatusOK {
  57. t.Fatalf("POST /api/proxy/rules status = %d; want 200, body: %s", rec.Code, rec.Body.String())
  58. }
  59. var created reverseproxy.Rule
  60. if err := json.NewDecoder(rec.Body).Decode(&created); err != nil {
  61. t.Fatalf("failed to decode created rule: %v", err)
  62. }
  63. if created.ID == "" || created.Name != "Web App" {
  64. t.Errorf("unexpected created rule: %+v", created)
  65. }
  66. // 3. GET /api/proxy/rules
  67. req = httptest.NewRequest(http.MethodGet, "/api/proxy/rules", nil)
  68. rec = httptest.NewRecorder()
  69. srv.mux.ServeHTTP(rec, req)
  70. if rec.Code != http.StatusOK {
  71. t.Fatalf("GET /api/proxy/rules status = %d", rec.Code)
  72. }
  73. var rules []*reverseproxy.Rule
  74. _ = json.NewDecoder(rec.Body).Decode(&rules)
  75. if len(rules) != 1 {
  76. t.Errorf("expected 1 rule, got %d", len(rules))
  77. }
  78. // 4. POST /api/proxy/rules/{id}/state (Toggle state)
  79. statePayload := bytes.NewReader([]byte(`{"enabled":false}`))
  80. req = httptest.NewRequest(http.MethodPost, "/api/proxy/rules/"+created.ID+"/state", statePayload)
  81. rec = httptest.NewRecorder()
  82. srv.mux.ServeHTTP(rec, req)
  83. if rec.Code != http.StatusOK {
  84. t.Fatalf("POST /api/proxy/rules/{id}/state status = %d", rec.Code)
  85. }
  86. // 5. GET /api/proxy/status
  87. req = httptest.NewRequest(http.MethodGet, "/api/proxy/status", nil)
  88. rec = httptest.NewRecorder()
  89. srv.mux.ServeHTTP(rec, req)
  90. if rec.Code != http.StatusOK {
  91. t.Fatalf("GET /api/proxy/status status = %d", rec.Code)
  92. }
  93. var status map[string]any
  94. _ = json.NewDecoder(rec.Body).Decode(&status)
  95. if status["rules_count"].(float64) != 1 {
  96. t.Errorf("expected rules_count 1, got %v", status["rules_count"])
  97. }
  98. // 6. DELETE /api/proxy/rules/{id}
  99. req = httptest.NewRequest(http.MethodDelete, "/api/proxy/rules/"+created.ID, nil)
  100. rec = httptest.NewRecorder()
  101. srv.mux.ServeHTTP(rec, req)
  102. if rec.Code != http.StatusOK {
  103. t.Fatalf("DELETE /api/proxy/rules/{id} status = %d", rec.Code)
  104. }
  105. }