diff --git a/.gitignore b/.gitignore index 56312f2..c71279c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,4 @@ !*.md !*.mod !*.sum -!*.txt +!*.txt \ No newline at end of file diff --git a/Context.go b/Context.go index 7afb303..5131fa5 100644 --- a/Context.go +++ b/Context.go @@ -81,4 +81,4 @@ func (ctx *context) Status(status int) Context { func (ctx *context) String(body string) error { ctx.response.body = append(ctx.response.body, body...) return nil -} +} \ No newline at end of file diff --git a/Context_test.go b/Context_test.go index b3a6005..ebfd8b2 100644 --- a/Context_test.go +++ b/Context_test.go @@ -66,4 +66,4 @@ func TestRedirect(t *testing.T) { response := s.Request("GET", "/", nil, nil) assert.Equal(t, response.Status(), 301) assert.Equal(t, response.Header("Location"), "/target") -} +} \ No newline at end of file diff --git a/Handler.go b/Handler.go index 96b6cb6..fc27b7a 100644 --- a/Handler.go +++ b/Handler.go @@ -1,4 +1,4 @@ package web // Handler is a function that deals with the given request/response context. -type Handler func(Context) error +type Handler func(Context) error \ No newline at end of file diff --git a/Header.go b/Header.go index b6699fe..ec9325e 100644 --- a/Header.go +++ b/Header.go @@ -4,4 +4,4 @@ package web type Header struct { Key string Value string -} +} \ No newline at end of file diff --git a/Request.go b/Request.go index 6c7ef3c..5ffa025 100644 --- a/Request.go +++ b/Request.go @@ -79,4 +79,4 @@ func (req *request) addParameter(key string, value string) { Key: key, Value: value, }) -} +} \ No newline at end of file diff --git a/Request_test.go b/Request_test.go index 1e079a8..1d705d6 100644 --- a/Request_test.go +++ b/Request_test.go @@ -51,4 +51,4 @@ func TestRequestParam(t *testing.T) { response := s.Request("GET", "/blog/my-article", nil, nil) assert.Equal(t, response.Status(), 200) assert.Equal(t, string(response.Body()), "my-article") -} +} \ No newline at end of file diff --git a/Response.go b/Response.go index f361eb9..e612b73 100644 --- a/Response.go +++ b/Response.go @@ -76,4 +76,4 @@ func (res *response) Write(body []byte) (int, error) { func (res *response) WriteString(body string) (int, error) { res.body = append(res.body, body...) return len(body), nil -} +} \ No newline at end of file diff --git a/Response_test.go b/Response_test.go index 9028acf..37a1142 100644 --- a/Response_test.go +++ b/Response_test.go @@ -97,4 +97,4 @@ func TestResponseHeaderOverwrite(t *testing.T) { assert.Equal(t, response.Status(), 200) assert.Equal(t, response.Header("Content-Type"), "text/html") assert.Equal(t, string(response.Body()), "") -} +} \ No newline at end of file diff --git a/Server.go b/Server.go index ba163a0..bf2bd98 100644 --- a/Server.go +++ b/Server.go @@ -19,6 +19,7 @@ import ( // Server is the interface for an HTTP server. type Server interface { Get(path string, handler Handler) + Ready() chan struct{} Request(method string, path string, headers []Header, body io.Reader) Response Router() *router.Router[Handler] Run(address string) error @@ -31,6 +32,7 @@ type server struct { contextPool sync.Pool router *router.Router[Handler] errorHandler func(Context, error) + ready chan struct{} } // NewServer creates a new HTTP server. @@ -54,6 +56,7 @@ func NewServer() Server { errorHandler: func(ctx Context, err error) { log.Println(ctx.Request().Path(), err) }, + ready: make(chan struct{}), } s.contextPool.New = func() any { return s.newContext() } @@ -65,6 +68,11 @@ func (s *server) Get(path string, handler Handler) { s.Router().Add("GET", path, handler) } +// Ready returns a channel that will be closed once the listener is ready for connection handling. +func (s *server) Ready() chan struct{} { + return s.ready +} + // Request performs a synthetic request and returns the response. // This function keeps the response in memory so it's slightly slower than a real request. // However it is very useful inside tests where you don't want to spin up a real web server. @@ -99,6 +107,7 @@ func (s *server) Run(address string) error { stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt, syscall.SIGTERM) + close(s.ready) <-stop return nil } @@ -261,4 +270,4 @@ func (s *server) newContext() *context { status: 200, }, } -} +} \ No newline at end of file diff --git a/Server_test.go b/Server_test.go index f2c142b..768204f 100644 --- a/Server_test.go +++ b/Server_test.go @@ -35,6 +35,7 @@ func TestRun(t *testing.T) { go func() { defer syscall.Kill(syscall.Getpid(), syscall.SIGTERM) + <-s.Ready() _, err := http.Get("http://127.0.0.1:8080/") assert.Nil(t, err) }() @@ -48,6 +49,7 @@ func TestBadRequest(t *testing.T) { go func() { defer syscall.Kill(syscall.Getpid(), syscall.SIGTERM) + <-s.Ready() conn, err := net.Dial("tcp", ":8080") assert.Nil(t, err) defer conn.Close() @@ -73,6 +75,7 @@ func TestBadRequestHeader(t *testing.T) { go func() { defer syscall.Kill(syscall.Getpid(), syscall.SIGTERM) + <-s.Ready() conn, err := net.Dial("tcp", ":8080") assert.Nil(t, err) defer conn.Close() @@ -95,6 +98,7 @@ func TestBadRequestMethod(t *testing.T) { go func() { defer syscall.Kill(syscall.Getpid(), syscall.SIGTERM) + <-s.Ready() conn, err := net.Dial("tcp", ":8080") assert.Nil(t, err) defer conn.Close() @@ -116,6 +120,7 @@ func TestBadRequestPath(t *testing.T) { go func() { defer syscall.Kill(syscall.Getpid(), syscall.SIGTERM) + <-s.Ready() conn, err := net.Dial("tcp", ":8080") assert.Nil(t, err) defer conn.Close() @@ -141,6 +146,7 @@ func TestBadRequestProtocol(t *testing.T) { go func() { defer syscall.Kill(syscall.Getpid(), syscall.SIGTERM) + <-s.Ready() conn, err := net.Dial("tcp", ":8080") assert.Nil(t, err) defer conn.Close() @@ -163,6 +169,7 @@ func TestConnectionClose(t *testing.T) { go func() { defer syscall.Kill(syscall.Getpid(), syscall.SIGTERM) + <-s.Ready() conn, err := net.Dial("tcp", ":8080") assert.Nil(t, err) defer conn.Close() @@ -183,6 +190,7 @@ func TestEarlyClose(t *testing.T) { go func() { defer syscall.Kill(syscall.Getpid(), syscall.SIGTERM) + <-s.Ready() conn, err := net.Dial("tcp", ":8080") assert.Nil(t, err) @@ -203,4 +211,4 @@ func TestUnavailablePort(t *testing.T) { s := web.NewServer() s.Run(":8080") -} +} \ No newline at end of file diff --git a/examples/hello/main.go b/examples/hello/main.go index b42db84..6015f13 100644 --- a/examples/hello/main.go +++ b/examples/hello/main.go @@ -12,4 +12,4 @@ func main() { }) s.Run(":8080") -} +} \ No newline at end of file diff --git a/go.mod b/go.mod index f2bf46e..1035725 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,6 @@ module git.urbach.dev/go/web go 1.24 require ( - git.urbach.dev/go/assert v0.0.0-20250225153414-fc1f84f19edf - git.urbach.dev/go/router v0.0.0-20250601162231-e35d5715d1a5 -) + git.urbach.dev/go/assert v0.0.0-20250606150337-559d3d3afcda + git.urbach.dev/go/router v0.0.0-20250606151301-c10e38fec918 +) \ No newline at end of file diff --git a/go.sum b/go.sum index 4c3db0c..11cef6e 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,4 @@ -git.urbach.dev/go/assert v0.0.0-20250225153414-fc1f84f19edf h1:BQWa5GKNUsA5CSUa/+UlFWYCEVe3IDDKRbVqBLK0mAE= -git.urbach.dev/go/assert v0.0.0-20250225153414-fc1f84f19edf/go.mod h1:y9jGII9JFiF1HNIju0u87OyPCt82xKCtqnAFyEreCDo= -git.urbach.dev/go/router v0.0.0-20250601162231-e35d5715d1a5 h1:3qlZjgWbrHw4LWM4uBzOTldbpqCLJdeSgvcYK6f3xpc= -git.urbach.dev/go/router v0.0.0-20250601162231-e35d5715d1a5/go.mod h1:O+doTe0DZdT2XMsTY5pe6qUMqEEIAbwtX6Xp6EqHw34= +git.urbach.dev/go/assert v0.0.0-20250606150337-559d3d3afcda h1:VN6ZQwtwLOm2xTms+v8IIeeNjvs55qyEBNArv3dPq9g= +git.urbach.dev/go/assert v0.0.0-20250606150337-559d3d3afcda/go.mod h1:PNI/NSBOqvoeU58/7eBsIR09Yoq2S/qtSRiTrctkiq0= +git.urbach.dev/go/router v0.0.0-20250606151301-c10e38fec918 h1:fdeFr4gwou9KxvQqhcrPbLSYM9xzvaF1pwp53DzU3co= +git.urbach.dev/go/router v0.0.0-20250606151301-c10e38fec918/go.mod h1:seUQ5raGaj6fDeZP6d7JdgnWQys8oTrtFdvBhAp1IZA= \ No newline at end of file diff --git a/http.go b/http.go index b7ec1cc..65de163 100644 --- a/http.go +++ b/http.go @@ -38,4 +38,4 @@ func parseURL(url string) (scheme string, host string, path string, query string path = url return -} +} \ No newline at end of file diff --git a/README.md b/readme.md similarity index 98% rename from README.md rename to readme.md index 149eb93..b9bd107 100644 --- a/README.md +++ b/readme.md @@ -87,4 +87,4 @@ Please see the [license documentation](https://urbach.dev/license). ## Copyright -© 2024 Eduard Urbach +© 2024 Eduard Urbach \ No newline at end of file diff --git a/send/send.go b/send/send.go index 9c4c2ca..db9a1e3 100644 --- a/send/send.go +++ b/send/send.go @@ -46,4 +46,4 @@ func Text(ctx web.Context, body string) error { func XML(ctx web.Context, body string) error { ctx.Response().SetHeader("Content-Type", "text/xml") return ctx.String(body) -} +} \ No newline at end of file diff --git a/send/send_test.go b/send/send_test.go index fec22c3..b4b3de1 100644 --- a/send/send_test.go +++ b/send/send_test.go @@ -64,4 +64,4 @@ func TestContentTypes(t *testing.T) { assert.Equal(t, string(response.Body()), test.Response) }) } -} +} \ No newline at end of file