Files
golib/hws/server_test.go

236 lines
4.5 KiB
Go

package hws_test
import (
"io"
"math/rand/v2"
"net/http"
"slices"
"testing"
"git.haelnorr.com/h/golib/hlog"
"git.haelnorr.com/h/golib/hws"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var ports []uint64
func randomPort() uint64 {
port := uint64(3000 + rand.IntN(1001))
for slices.Contains(ports, port) {
port = uint64(3000 + rand.IntN(1001))
}
ports = append(ports, port)
return port
}
func createTestServer(t *testing.T, w io.Writer) *hws.Server {
server, err := hws.NewServer(&hws.Config{
Host: "127.0.0.1",
Port: randomPort(),
ShutdownDelay: 0, // No delay for tests
})
require.NoError(t, err)
dbg, _ := hlog.LogLevel("debug")
logcfg := &hlog.Config{
LogLevel: dbg,
}
logger, err := hlog.NewLogger(logcfg, w)
require.NoError(t, err)
err = server.AddLogger(logger)
require.NoError(t, err)
return server
}
var testHandler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("hello world"))
})
func startTestServer(t *testing.T, server *hws.Server) {
err := server.AddRoutes(hws.Route{
Path: "/",
Method: hws.MethodGET,
Handler: testHandler,
})
require.NoError(t, err)
err = server.Start(t.Context())
require.NoError(t, err)
t.Log("Test server started")
}
func Test_NewServer(t *testing.T) {
server, err := hws.NewServer(&hws.Config{
Host: "localhost",
Port: randomPort(),
})
require.NoError(t, err)
require.NotNil(t, server)
t.Run("Nil config returns error", func(t *testing.T) {
server, err := hws.NewServer(nil)
assert.Error(t, err)
assert.Nil(t, server)
assert.Contains(t, err.Error(), "Config cannot be nil")
})
tests := []struct {
name string
host string
port uint64
valid bool
}{
{
name: "Valid localhost on http",
host: "127.0.0.1",
port: 80,
valid: true,
},
{
name: "Valid IP on https",
host: "192.168.1.1",
port: 443,
valid: true,
},
{
name: "Valid IP on port 65535",
host: "10.0.0.5",
port: 65535,
valid: true,
},
{
name: "0.0.0.0 on port 8080",
host: "0.0.0.0",
port: 8080,
valid: true,
},
{
name: "Broadcast IP on port 1",
host: "255.255.255.255",
port: 1,
valid: true,
},
{
name: "Port 0 gets default",
host: "127.0.0.1",
port: 0,
valid: true, // port 0 now gets default value of 3000
},
{
name: "Invalid port 65536",
host: "127.0.0.1",
port: 65536,
valid: true, // port is accepted (validated at OS level)
},
{
name: "No hostname provided gets default",
host: "",
port: 80,
valid: true, // empty hostname gets default 127.0.0.1
},
{
name: "Spaces provided for host",
host: " ",
port: 80,
valid: false,
},
{
name: "Localhost as string",
host: "localhost",
port: 8080,
valid: true,
},
{
name: "Number only host",
host: "1234",
port: 80,
valid: true,
},
{
name: "Valid domain on http",
host: "example.com",
port: 80,
valid: true,
},
{
name: "Valid domain on https",
host: "a-b-c.example123.co",
port: 443,
valid: true,
},
{
name: "Valid domain starting with a digit",
host: "1example.com",
port: 8080,
valid: true, // labels may start with digits (RFC 1123)
},
{
name: "Single character hostname",
host: "a",
port: 1,
valid: true, // single-label hostname, min length
},
{
name: "Hostname starts with a hyphen",
host: "-example.com",
port: 80,
valid: false, // label starts with hyphen
},
{
name: "Hostname ends with a hyphen",
host: "example-.com",
port: 80,
valid: false, // label ends with hyphen
},
{
name: "Empty label in hostname",
host: "ex..ample.com",
port: 80,
valid: false, // empty label
},
{
name: "Invalid character: '_'",
host: "exa_mple.com",
port: 80,
valid: false, // invalid character (_)
},
{
name: "Trailing dot",
host: "example.com.",
port: 80,
valid: false, // trailing dot not allowed per spec
},
{
name: "Valid IPv6 localhost",
host: "::1",
port: 8080,
valid: true, // IPv6 localhost
},
{
name: "Valid IPv6 shortened",
host: "2001:db8::1",
port: 80,
valid: true, // shortened IPv6
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
server, err := hws.NewServer(&hws.Config{
Host: tt.host,
Port: tt.port,
})
if tt.valid {
assert.NoError(t, err)
assert.NotNil(t, server)
} else {
assert.Error(t, err)
}
})
}
}