yggdrasil-go/src/webui/server_test.go
Andy Oknen 113dcbb72a Add password authentication to WebUI and implement session management
- Updated WebUI configuration to include a password field for authentication.
- Enhanced the WebUI server to handle login and logout functionality with session management.
- Added tests for authentication and session handling.
- Updated README and example configuration to reflect new authentication features.
2025-07-30 08:34:29 +00:00

203 lines
4.7 KiB
Go

package webui
import (
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
"github.com/gologme/log"
"github.com/yggdrasil-network/yggdrasil-go/src/core"
)
// Helper function to create a test logger
func createTestLogger() core.Logger {
return log.New(os.Stderr, "webui_test: ", log.Flags())
}
// Helper function to get available port for testing
func getTestAddress() string {
return "127.0.0.1:0" // Let OS assign available port
}
func TestWebUIServer_Creation(t *testing.T) {
logger := createTestLogger()
listen := getTestAddress()
server := Server(listen, "", logger)
if server == nil {
t.Fatal("Server function returned nil")
}
if server.listen != listen {
t.Errorf("Expected listen address %s, got %s", listen, server.listen)
}
if server.log != logger {
t.Error("Logger not properly set")
}
if server.server != nil {
t.Error("HTTP server should be nil before Start()")
}
}
func TestWebUIServer_StartStop(t *testing.T) {
logger := createTestLogger()
listen := getTestAddress()
server := Server(listen, "", logger)
// Start server in goroutine
errChan := make(chan error, 1)
go func() {
errChan <- server.Start()
}()
// Give server time to start
time.Sleep(100 * time.Millisecond)
// Verify server is running
if server.server == nil {
t.Fatal("HTTP server not initialized after Start()")
}
// Stop server
err := server.Stop()
if err != nil {
t.Errorf("Error stopping server: %v", err)
}
// Check that Start() returns without error after Stop()
select {
case err := <-errChan:
if err != nil {
t.Errorf("Start() returned error: %v", err)
}
case <-time.After(2 * time.Second):
t.Error("Start() did not return after Stop()")
}
}
func TestWebUIServer_StopWithoutStart(t *testing.T) {
logger := createTestLogger()
listen := getTestAddress()
server := Server(listen, "", logger)
// Stop server that was never started should not error
err := server.Stop()
if err != nil {
t.Errorf("Stop() on unstarted server returned error: %v", err)
}
}
func TestWebUIServer_HealthEndpoint(t *testing.T) {
logger := createTestLogger()
// Create a test server using net/http/httptest for reliable testing
mux := http.NewServeMux()
testServer := Server("127.0.0.1:0", "", logger)
setupStaticHandler(mux, testServer)
mux.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
serveFile(rw, r, logger)
})
mux.HandleFunc("/health", func(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(http.StatusOK)
_, _ = rw.Write([]byte("OK"))
})
server := httptest.NewServer(mux)
defer server.Close()
// Test health endpoint
resp, err := http.Get(server.URL + "/health")
if err != nil {
t.Fatalf("Error requesting health endpoint: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Errorf("Expected status 200, got %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatalf("Error reading response body: %v", err)
}
if string(body) != "OK" {
t.Errorf("Expected body 'OK', got '%s'", string(body))
}
}
func TestWebUIServer_Timeouts(t *testing.T) {
logger := createTestLogger()
server := Server("127.0.0.1:0", "", logger)
// Start server
go func() {
_ = server.Start()
}()
defer func() { _ = server.Stop() }()
// Wait for server to start
time.Sleep(200 * time.Millisecond)
if server.server == nil {
t.Fatal("Server not started")
}
// Check that timeouts are properly configured
expectedReadTimeout := 10 * time.Second
expectedWriteTimeout := 10 * time.Second
expectedMaxHeaderBytes := 1 << 20
if server.server.ReadTimeout != expectedReadTimeout {
t.Errorf("Expected ReadTimeout %v, got %v", expectedReadTimeout, server.server.ReadTimeout)
}
if server.server.WriteTimeout != expectedWriteTimeout {
t.Errorf("Expected WriteTimeout %v, got %v", expectedWriteTimeout, server.server.WriteTimeout)
}
if server.server.MaxHeaderBytes != expectedMaxHeaderBytes {
t.Errorf("Expected MaxHeaderBytes %d, got %d", expectedMaxHeaderBytes, server.server.MaxHeaderBytes)
}
}
func TestWebUIServer_ConcurrentStartStop(t *testing.T) {
logger := createTestLogger()
// Test concurrent start/stop operations with separate servers
for i := 0; i < 3; i++ {
server := Server("127.0.0.1:0", "", logger)
// Start server
startDone := make(chan error, 1)
go func() {
startDone <- server.Start()
}()
time.Sleep(100 * time.Millisecond)
// Stop server
err := server.Stop()
if err != nil {
t.Errorf("Iteration %d: Error stopping server: %v", i, err)
}
// Wait for Start() to return
select {
case <-startDone:
// Good, Start() returned
case <-time.After(2 * time.Second):
t.Errorf("Iteration %d: Start() did not return after Stop()", i)
}
time.Sleep(50 * time.Millisecond)
}
}