@@ -38,6 +38,30 @@ func Test_Listen(t *testing.T) {
3838 require .NoError (t , app .Listen (":0" , ListenConfig {DisableStartupMessage : true }))
3939}
4040
41+ // go test -run Test_Listen_ClosesListenerOnBeforeServeError
42+ func Test_Listen_ClosesListenerOnBeforeServeError (t * testing.T ) {
43+ // Grab a free port, then release it so we can bind it via Listen.
44+ probe , err := net .Listen ("tcp" , "127.0.0.1:0" )
45+ require .NoError (t , err )
46+ addr := probe .Addr ().String ()
47+ require .NoError (t , probe .Close ())
48+
49+ app := New ()
50+ err = app .Listen (addr , ListenConfig {
51+ DisableStartupMessage : true ,
52+ BeforeServeFunc : func (_ * App ) error {
53+ return errors .New ("stop before serving" )
54+ },
55+ })
56+ require .Error (t , err )
57+
58+ // The listener must have been closed on the error path, so the port is
59+ // immediately bindable again (a leaked listener would keep it bound).
60+ ln , err := net .Listen ("tcp" , addr )
61+ require .NoError (t , err , "listener leaked: port still bound after BeforeServeFunc error" )
62+ require .NoError (t , ln .Close ())
63+ }
64+
4165// go test -run Test_Listen_Graceful_Shutdown
4266func Test_Listen_Graceful_Shutdown (t * testing.T ) {
4367 t .Run ("Basic Graceful Shutdown" , func (t * testing.T ) {
0 commit comments