sdwan_handlers_test.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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/sdwan"
  11. )
  12. func setupTestSDWANServer(t *testing.T) (*Server, *sdwan.Manager) {
  13. tmpDir := t.TempDir()
  14. cfgPath := filepath.Join(tmpDir, "sdwan.json")
  15. sdwanMgr := sdwan.NewManager(cfgPath)
  16. authPath := filepath.Join(tmpDir, "users.json")
  17. authMgr := auth.NewManager(authPath)
  18. srv := &Server{
  19. sdwanMgr: sdwanMgr,
  20. authMgr: authMgr,
  21. mux: http.NewServeMux(),
  22. fsHandler: http.NotFoundHandler(),
  23. }
  24. srv.registerRoutes()
  25. return srv, sdwanMgr
  26. }
  27. func TestSDWANAPIEndpoints(t *testing.T) {
  28. srv, sdwanMgr := setupTestSDWANServer(t)
  29. defer sdwanMgr.Stop()
  30. // 1. GET /api/sdwan/groups (Initial empty list)
  31. req := httptest.NewRequest(http.MethodGet, "/api/sdwan/groups", nil)
  32. rec := httptest.NewRecorder()
  33. srv.mux.ServeHTTP(rec, req)
  34. if rec.Code != http.StatusOK {
  35. t.Fatalf("GET /api/sdwan/groups status = %d; want 200", rec.Code)
  36. }
  37. var groups []*sdwan.SDWANGroup
  38. if err := json.NewDecoder(rec.Body).Decode(&groups); err != nil {
  39. t.Fatalf("failed to decode groups: %v", err)
  40. }
  41. if len(groups) != 0 {
  42. t.Fatalf("expected 0 groups, got %d", len(groups))
  43. }
  44. // 2. POST /api/sdwan/groups (Create group)
  45. newGroup := sdwan.SDWANGroup{
  46. Name: "sdwan0",
  47. Mode: sdwan.ModeWeighted,
  48. AutoNAT: true,
  49. ProbeInterval: 3,
  50. Comment: "Primary Multi-WAN",
  51. }
  52. body, _ := json.Marshal(newGroup)
  53. req = httptest.NewRequest(http.MethodPost, "/api/sdwan/groups", bytes.NewReader(body))
  54. rec = httptest.NewRecorder()
  55. srv.mux.ServeHTTP(rec, req)
  56. if rec.Code != http.StatusOK {
  57. t.Fatalf("POST /api/sdwan/groups status = %d; body = %s", rec.Code, rec.Body.String())
  58. }
  59. // 3. GET /api/sdwan/groups (Check group created)
  60. req = httptest.NewRequest(http.MethodGet, "/api/sdwan/groups", nil)
  61. rec = httptest.NewRecorder()
  62. srv.mux.ServeHTTP(rec, req)
  63. if rec.Code != http.StatusOK {
  64. t.Fatalf("GET /api/sdwan/groups status = %d", rec.Code)
  65. }
  66. groups = nil
  67. _ = json.NewDecoder(rec.Body).Decode(&groups)
  68. if len(groups) != 1 || groups[0].Name != "sdwan0" {
  69. t.Fatalf("expected 1 group named sdwan0, got %+v", groups)
  70. }
  71. groupID := groups[0].ID
  72. // 4. POST /api/sdwan/groups/{id}/members (Add member)
  73. memPayload := map[string]interface{}{
  74. "interface": "eth0",
  75. "gateway": "192.168.1.1",
  76. "weight": 60,
  77. "priority": 1,
  78. "target_probe": "1.1.1.1",
  79. }
  80. body, _ = json.Marshal(memPayload)
  81. req = httptest.NewRequest(http.MethodPost, "/api/sdwan/groups/"+groupID+"/members", bytes.NewReader(body))
  82. rec = httptest.NewRecorder()
  83. srv.mux.ServeHTTP(rec, req)
  84. if rec.Code != http.StatusOK {
  85. t.Fatalf("POST /api/sdwan/groups/%s/members status = %d; body = %s", groupID, rec.Code, rec.Body.String())
  86. }
  87. // 5. GET /api/sdwan/telemetry
  88. req = httptest.NewRequest(http.MethodGet, "/api/sdwan/telemetry", nil)
  89. rec = httptest.NewRecorder()
  90. srv.mux.ServeHTTP(rec, req)
  91. if rec.Code != http.StatusOK {
  92. t.Fatalf("GET /api/sdwan/telemetry status = %d", rec.Code)
  93. }
  94. var telemetry sdwan.TelemetrySummary
  95. if err := json.NewDecoder(rec.Body).Decode(&telemetry); err != nil {
  96. t.Fatalf("failed to decode telemetry: %v", err)
  97. }
  98. if telemetry.TotalGroups != 1 || telemetry.TotalMembers != 1 {
  99. t.Fatalf("unexpected telemetry: %+v", telemetry)
  100. }
  101. // 6. POST /api/sdwan/groups/{id}/state (Disable group)
  102. statePayload := map[string]interface{}{
  103. "disabled": true,
  104. }
  105. body, _ = json.Marshal(statePayload)
  106. req = httptest.NewRequest(http.MethodPost, "/api/sdwan/groups/"+groupID+"/state", bytes.NewReader(body))
  107. rec = httptest.NewRecorder()
  108. srv.mux.ServeHTTP(rec, req)
  109. if rec.Code != http.StatusOK {
  110. t.Fatalf("POST /api/sdwan/groups/%s/state status = %d", groupID, rec.Code)
  111. }
  112. // 7. DELETE /api/sdwan/groups/{id}/members/{iface}
  113. req = httptest.NewRequest(http.MethodDelete, "/api/sdwan/groups/"+groupID+"/members/eth0", nil)
  114. rec = httptest.NewRecorder()
  115. srv.mux.ServeHTTP(rec, req)
  116. if rec.Code != http.StatusOK {
  117. t.Fatalf("DELETE /api/sdwan/groups/%s/members/eth0 status = %d; body = %s", groupID, rec.Code, rec.Body.String())
  118. }
  119. // 8. DELETE /api/sdwan/groups/{id}
  120. req = httptest.NewRequest(http.MethodDelete, "/api/sdwan/groups/"+groupID, nil)
  121. rec = httptest.NewRecorder()
  122. srv.mux.ServeHTTP(rec, req)
  123. if rec.Code != http.StatusOK {
  124. t.Fatalf("DELETE /api/sdwan/groups/%s status = %d; body = %s", groupID, rec.Code, rec.Body.String())
  125. }
  126. }