forked from aegis/pyserveX
- Introduced IgnoreRequestPath option in proxy configuration to allow exact match routing. - Implemented proxy_pass directive in routing extension to handle backend requests. - Enhanced error handling for backend unavailability and timeouts. - Added integration tests for reverse proxy, including basic requests, exact match routes, regex routes, header forwarding, and query string preservation. - Created helper functions for setting up test servers and backends, along with assertion utilities for response validation. - Updated server initialization to support extension management and middleware chaining. - Improved logging for debugging purposes during request handling.
177 lines
4.3 KiB
Go
177 lines
4.3 KiB
Go
package extension
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/konduktor/konduktor/internal/logging"
|
|
)
|
|
|
|
func newTestLogger() *logging.Logger {
|
|
logger, _ := logging.New(logging.Config{Level: "DEBUG"})
|
|
return logger
|
|
}
|
|
|
|
func TestNewManager(t *testing.T) {
|
|
logger := newTestLogger()
|
|
manager := NewManager(logger)
|
|
|
|
if manager == nil {
|
|
t.Fatal("Expected manager, got nil")
|
|
}
|
|
|
|
// Check built-in factories are registered
|
|
if _, ok := manager.registry["routing"]; !ok {
|
|
t.Error("Expected routing factory to be registered")
|
|
}
|
|
if _, ok := manager.registry["security"]; !ok {
|
|
t.Error("Expected security factory to be registered")
|
|
}
|
|
if _, ok := manager.registry["caching"]; !ok {
|
|
t.Error("Expected caching factory to be registered")
|
|
}
|
|
}
|
|
|
|
func TestManager_LoadExtension(t *testing.T) {
|
|
logger := newTestLogger()
|
|
manager := NewManager(logger)
|
|
|
|
err := manager.LoadExtension("security", map[string]interface{}{})
|
|
if err != nil {
|
|
t.Errorf("Failed to load security extension: %v", err)
|
|
}
|
|
|
|
exts := manager.Extensions()
|
|
if len(exts) != 1 {
|
|
t.Errorf("Expected 1 extension, got %d", len(exts))
|
|
}
|
|
}
|
|
|
|
func TestManager_LoadExtension_Unknown(t *testing.T) {
|
|
logger := newTestLogger()
|
|
manager := NewManager(logger)
|
|
|
|
err := manager.LoadExtension("unknown", map[string]interface{}{})
|
|
if err == nil {
|
|
t.Error("Expected error for unknown extension type")
|
|
}
|
|
}
|
|
|
|
func TestManager_GetExtension(t *testing.T) {
|
|
logger := newTestLogger()
|
|
manager := NewManager(logger)
|
|
|
|
manager.LoadExtension("security", map[string]interface{}{})
|
|
|
|
ext := manager.GetExtension("security")
|
|
if ext == nil {
|
|
t.Error("Expected to find security extension")
|
|
}
|
|
|
|
ext = manager.GetExtension("nonexistent")
|
|
if ext != nil {
|
|
t.Error("Expected nil for nonexistent extension")
|
|
}
|
|
}
|
|
|
|
func TestManager_ProcessRequest(t *testing.T) {
|
|
logger := newTestLogger()
|
|
manager := NewManager(logger)
|
|
|
|
// Load security extension with blocked IP
|
|
manager.LoadExtension("security", map[string]interface{}{
|
|
"blocked_ips": []interface{}{"192.168.1.1"},
|
|
})
|
|
|
|
// Create test request
|
|
req := httptest.NewRequest("GET", "/test", nil)
|
|
req.RemoteAddr = "192.168.1.1:12345"
|
|
rr := httptest.NewRecorder()
|
|
|
|
handled, err := manager.ProcessRequest(context.Background(), rr, req)
|
|
if err != nil {
|
|
t.Errorf("Unexpected error: %v", err)
|
|
}
|
|
|
|
if !handled {
|
|
t.Error("Expected request to be handled (blocked)")
|
|
}
|
|
|
|
if rr.Code != http.StatusForbidden {
|
|
t.Errorf("Expected status 403, got %d", rr.Code)
|
|
}
|
|
}
|
|
|
|
func TestManager_Handler(t *testing.T) {
|
|
logger := newTestLogger()
|
|
manager := NewManager(logger)
|
|
|
|
// Load routing extension with a simple route
|
|
manager.LoadExtension("routing", map[string]interface{}{
|
|
"regex_locations": map[string]interface{}{
|
|
"=/health": map[string]interface{}{
|
|
"return": "200 OK",
|
|
},
|
|
},
|
|
})
|
|
|
|
baseHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
})
|
|
|
|
handler := manager.Handler(baseHandler)
|
|
|
|
// Test health route
|
|
req := httptest.NewRequest("GET", "/health", nil)
|
|
rr := httptest.NewRecorder()
|
|
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
if rr.Code != http.StatusOK {
|
|
t.Errorf("Expected status 200, got %d", rr.Code)
|
|
}
|
|
}
|
|
|
|
func TestManager_Priority(t *testing.T) {
|
|
logger := newTestLogger()
|
|
manager := NewManager(logger)
|
|
|
|
// Load extensions in any order
|
|
manager.LoadExtension("routing", map[string]interface{}{}) // Priority 50
|
|
manager.LoadExtension("security", map[string]interface{}{}) // Priority 10
|
|
manager.LoadExtension("caching", map[string]interface{}{}) // Priority 20
|
|
|
|
exts := manager.Extensions()
|
|
if len(exts) != 3 {
|
|
t.Fatalf("Expected 3 extensions, got %d", len(exts))
|
|
}
|
|
|
|
// Check order by priority
|
|
if exts[0].Name() != "security" {
|
|
t.Errorf("Expected security first, got %s", exts[0].Name())
|
|
}
|
|
if exts[1].Name() != "caching" {
|
|
t.Errorf("Expected caching second, got %s", exts[1].Name())
|
|
}
|
|
if exts[2].Name() != "routing" {
|
|
t.Errorf("Expected routing third, got %s", exts[2].Name())
|
|
}
|
|
}
|
|
|
|
func TestManager_Cleanup(t *testing.T) {
|
|
logger := newTestLogger()
|
|
manager := NewManager(logger)
|
|
|
|
manager.LoadExtension("security", map[string]interface{}{})
|
|
manager.LoadExtension("routing", map[string]interface{}{})
|
|
|
|
manager.Cleanup()
|
|
|
|
exts := manager.Extensions()
|
|
if len(exts) != 0 {
|
|
t.Errorf("Expected 0 extensions after cleanup, got %d", len(exts))
|
|
}
|
|
}
|