diff --git a/Makefile b/Makefile index 250d1b4..c7d0d1e 100644 --- a/Makefile +++ b/Makefile @@ -22,10 +22,11 @@ linux: @echo "Building Linux binary..." GOOS=linux GOARCH=amd64 go build -o $(BUILD_DIR)/$(APP_NAME)-linux-amd64 -# for testing things +# for testing proxy.Process simple-responder: @echo "Building simple responder" - go build -o $(BUILD_DIR)/simple-responder misc/simple-responder/simple-responder.go + GOOS=darwin GOARCH=arm64 go build -o $(BUILD_DIR)/simple-responder_darwin_arm64 misc/simple-responder/simple-responder.go + GOOS=linux GOARCH=amd64 go build -o $(BUILD_DIR)/simple-responder_linux_amd64 misc/simple-responder/simple-responder.go # Ensure build directory exists $(BUILD_DIR): diff --git a/misc/simple-responder/simple-responder.go b/misc/simple-responder/simple-responder.go index f20ea40..a7a1fea 100644 --- a/misc/simple-responder/simple-responder.go +++ b/misc/simple-responder/simple-responder.go @@ -39,7 +39,7 @@ func main() { w.Write([]byte(response)) }) - address := ":" + *port // Address with the specified port + address := "127.0.0.1:" + *port // Address with the specified port fmt.Printf("Server is listening on port %s\n", *port) // Start the server and log any error if it occurs diff --git a/proxy/manager.go b/proxy/manager.go index f177ce8..4831e1f 100644 --- a/proxy/manager.go +++ b/proxy/manager.go @@ -38,7 +38,6 @@ func (pm *ProxyManager) HandleFunc(w http.ResponseWriter, r *http.Request) { } else { http.Error(w, "no strategy to handle request", http.StatusBadRequest) } - } } diff --git a/proxy/process.go b/proxy/process.go index 0c85864..8226cb0 100644 --- a/proxy/process.go +++ b/proxy/process.go @@ -21,6 +21,10 @@ type Process struct { config ModelConfig cmd *exec.Cmd logMonitor *LogMonitor + + // Only useful for go testing the proxy functionality + // will leave the start/stop of process to go code + overrideProxyFunc *func(w http.ResponseWriter, r *http.Request) } func NewProcess(ID string, config ModelConfig, logMonitor *LogMonitor) *Process { @@ -115,6 +119,7 @@ func (p *Process) checkHealthEndpoint(cmdCtx context.Context, healthCheckTimeout startTime := time.Now() for { + time.Sleep(time.Second) req, err := http.NewRequest("GET", healthURL, nil) if err != nil { return err @@ -141,7 +146,6 @@ func (p *Process) checkHealthEndpoint(cmdCtx context.Context, healthCheckTimeout // wait a bit longer for TCP connection issues if strings.Contains(err.Error(), "connection refused") { fmt.Fprintf(p.logMonitor, "Connection refused on %s, ttl %.0fs\n", healthURL, ttl) - time.Sleep(5 * time.Second) } else { time.Sleep(time.Second) @@ -162,13 +166,23 @@ func (p *Process) checkHealthEndpoint(cmdCtx context.Context, healthCheckTimeout if ttl < 0 { return fmt.Errorf("failed to check health from: %s", healthURL) } - - time.Sleep(time.Second) } } -// sends the request to the upstream process func (p *Process) ProxyRequest(w http.ResponseWriter, r *http.Request) { + if p.overrideProxyFunc != nil { + (*p.overrideProxyFunc)(w, r) + } else { + p.defaultProxyHandler(w, r) + } +} + +func (p *Process) SetOverride(f func(http.ResponseWriter, *http.Request)) { + p.overrideProxyFunc = &f +} + +// sends the request to the upstream process +func (p *Process) defaultProxyHandler(w http.ResponseWriter, r *http.Request) { if p.cmd == nil { http.Error(w, "process not started", http.StatusInternalServerError) return diff --git a/proxy/process_test.go b/proxy/process_test.go new file mode 100644 index 0000000..2dd16ec --- /dev/null +++ b/proxy/process_test.go @@ -0,0 +1,93 @@ +package proxy + +import ( + "fmt" + "math/rand" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "runtime" + "strings" + "testing" +) + +// Check if the binary exists +func TestMain(m *testing.M) { + binaryPath := getBinaryPath() + if _, err := os.Stat(binaryPath); os.IsNotExist(err) { + fmt.Printf("simple-responder not found at %s, did you `make simple-responder`?\n", binaryPath) + os.Exit(1) + } + m.Run() +} + +// Helper function to get the binary path +func getBinaryPath() string { + goos := runtime.GOOS + goarch := runtime.GOARCH + return filepath.Join("..", "build", fmt.Sprintf("simple-responder_%s_%s", goos, goarch)) +} + +func TestProcess_StartProxyStop(t *testing.T) { + // Define the range + min := 12000 + max := 13000 + + // Generate a random number between 12000 and 13000 + randomPort := rand.Intn(max-min+1) + min + + binaryPath := getBinaryPath() + + // Create a log monitor + logMonitor := NewLogMonitor() + + expectedMessage := "testing91931" + + // Create a process configuration + config := ModelConfig{ + Cmd: fmt.Sprintf("%s --port %d --respond '%s'", binaryPath, randomPort, expectedMessage), + Proxy: fmt.Sprintf("http://127.0.0.1:%d", randomPort), + CheckEndpoint: "/health", + } + + // Create a process + process := NewProcess("test-process", config, logMonitor) + + // Start the process + t.Logf("Starting %s on port %d", binaryPath, randomPort) + err := process.Start(5) + if err != nil { + t.Fatalf("Failed to start process: %v", err) + } + + // Create a test request + req := httptest.NewRequest("GET", "/", nil) + w := httptest.NewRecorder() + + // Proxy the request + process.ProxyRequest(w, req) + + // Check the response + if w.Code != http.StatusOK { + t.Errorf("Expected status code %d, got %d", http.StatusOK, w.Code) + } + + if !strings.Contains(w.Body.String(), expectedMessage) { + t.Errorf("Expected body to contain '%s', got %q", expectedMessage, w.Body.String()) + } + + // Stop the process + process.Stop() + + req = httptest.NewRequest("GET", "/", nil) + w = httptest.NewRecorder() + + // Proxy the request + process.ProxyRequest(w, req) + + // Check the response + if w.Code == http.StatusInternalServerError { + t.Errorf("Expected status code %d, got %d", http.StatusInternalServerError, w.Code) + } +}