| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- package reverseproxy
- import (
- "fmt"
- "io"
- "net/http"
- "net/http/httptest"
- "os"
- "path/filepath"
- "testing"
- )
- func TestReverseProxyManagerEndToEnd(t *testing.T) {
- // 1. Setup mock backend server that echoes received request path and headers
- backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("X-Echo-Path", r.URL.Path)
- w.Header().Set("X-Echo-Query", r.URL.RawQuery)
- w.Header().Set("X-Echo-Host", r.Host)
- w.WriteHeader(http.StatusOK)
- _, _ = fmt.Fprintf(w, "OK: %s", r.URL.Path)
- }))
- defer backend.Close()
- // 2. Setup manager with temporary config file
- tmpDir := t.TempDir()
- cfgPath := filepath.Join(tmpDir, "reverse_proxy.json")
- mgr := NewManager(cfgPath, nil)
- defer mgr.Stop()
- // 3. Add Rule for /app1 pointing to backend/app1
- rule1, err := mgr.SaveRule(&Rule{
- Name: "App1 Rule",
- Enabled: true,
- Domains: []string{"example.com"},
- Path: "/app1",
- TargetURL: backend.URL + "/app1",
- StripPath: false,
- })
- if err != nil {
- t.Fatalf("failed to save rule: %v", err)
- }
- // 4. Test request to /app1/module1/attribute1
- req := httptest.NewRequest(http.MethodGet, "http://example.com/app1/module1/attribute1?page=2", nil)
- rec := httptest.NewRecorder()
- handled := mgr.HandleHTTP(rec, req)
- if !handled {
- t.Fatalf("expected request to be handled by reverse proxy")
- }
- res := rec.Result()
- if res.StatusCode != http.StatusOK {
- t.Fatalf("unexpected status code: %d", res.StatusCode)
- }
- if got := res.Header.Get("X-Echo-Path"); got != "/app1/module1/attribute1" {
- t.Errorf("X-Echo-Path = %q; want %q", got, "/app1/module1/attribute1")
- }
- if got := res.Header.Get("X-Echo-Query"); got != "page=2" {
- t.Errorf("X-Echo-Query = %q; want %q", got, "page=2")
- }
- body, _ := io.ReadAll(res.Body)
- if string(body) != "OK: /app1/module1/attribute1" {
- t.Errorf("body = %q; want %q", string(body), "OK: /app1/module1/attribute1")
- }
- // 5. Test Rule Stats
- updatedRule, err := mgr.GetRule(rule1.ID)
- if err != nil {
- t.Fatalf("failed to get rule: %v", err)
- }
- if updatedRule.Stats.Requests != 1 {
- t.Errorf("expected 1 request in stats, got %d", updatedRule.Stats.Requests)
- }
- // 6. Test Request to unmapped path /unmapped - should NOT be handled
- req2 := httptest.NewRequest(http.MethodGet, "http://example.com/unmapped", nil)
- rec2 := httptest.NewRecorder()
- if mgr.HandleHTTP(rec2, req2) {
- t.Errorf("expected unmapped request to NOT be handled by proxy")
- }
- // 7. Test StripPath option
- rule2, err := mgr.SaveRule(&Rule{
- Name: "Strip Path Rule",
- Enabled: true,
- Domains: []string{"strip.example.com"},
- Path: "/service",
- TargetURL: backend.URL,
- StripPath: true,
- })
- if err != nil {
- t.Fatalf("failed to save rule2: %v", err)
- }
- req3 := httptest.NewRequest(http.MethodGet, "http://strip.example.com/service/sub/item", nil)
- rec3 := httptest.NewRecorder()
- if !mgr.HandleHTTP(rec3, req3) {
- t.Fatalf("expected strip path request to be handled")
- }
- res3 := rec3.Result()
- if got := res3.Header.Get("X-Echo-Path"); got != "/sub/item" {
- t.Errorf("X-Echo-Path with stripPath = %q; want %q", got, "/sub/item")
- }
- // 8. Test HTTP to HTTPS redirect
- _, err = mgr.SaveRule(&Rule{
- Name: "HTTPS Only Rule",
- Enabled: true,
- Domains: []string{"secure.example.com"},
- Path: "/",
- TargetURL: backend.URL,
- Protocol: ProtocolHTTPS,
- HTTPToHTTPS: true,
- })
- if err != nil {
- t.Fatalf("failed to save https rule: %v", err)
- }
- req4 := httptest.NewRequest(http.MethodGet, "http://secure.example.com/login", nil)
- rec4 := httptest.NewRecorder()
- if !mgr.HandleHTTP(rec4, req4) {
- t.Fatalf("expected HTTP to HTTPS redirect to be handled")
- }
- res4 := rec4.Result()
- if res4.StatusCode != http.StatusMovedPermanently {
- t.Errorf("expected status 301, got %d", res4.StatusCode)
- }
- if loc := res4.Header.Get("Location"); loc != "https://secure.example.com/login" {
- t.Errorf("redirect Location = %q; want %q", loc, "https://secure.example.com/login")
- }
- // Clean up temp file
- _ = os.Remove(cfgPath)
- _ = rule2
- }
|