ronantakizawa/codereview-bench huggingface dataset:
Repository: gofiber/fiber
File: helpers.go (Go)

Code before:
		acceptedTypes = append(acceptedTypes, acceptedType{spec, quality, specificity, order})

		// Next
		if commaPos != -1 {
			header = header[commaPos+1:]
		} else {
			break
		}
	}

	// Sort accepted types by quality and specificity, preserving order of equal elements
	if len(acceptedTypes) > 1 {
		for i := 1; i < len(acceptedTypes); i++ {
			swap := false
			lo, hi := 0, i-1
			for lo <= hi {
				mid := (lo + hi) / 2
				if acceptedTypes[i].quality < acceptedTypes[mid].quality ||
					(acceptedTypes[i].quality == acceptedTypes[mid].quality && acceptedTypes[i].specificity < acceptedTypes[mid].specificity) ||
					(acceptedTypes[i].quality == acceptedTypes[mid].quality && acceptedTypes[i].specificity == acceptedTypes[mid].specificity && acceptedTypes[i].order > acceptedTypes[mid].order) {
					lo = mid + 1
				} else {
					hi = mid - 1
				}
			}
			for j := i; j > lo; j-- {
				acceptedTypes[j-1], acceptedTypes[j] = acceptedTypes[j], acceptedTypes[j-1]
				swap = true
			}
			if !swap {
				break
			}
		}
	}

	// Find the first offer that matches the accepted types
	for _, acceptedType := range acceptedTypes {
		for _, offer := range offers {
			if len(offer) == 0 {
				continue
			}
			if isAccepted(acceptedType.spec, offer) {
				return offer
			}
		}
	}

	return ""
}

func matchEtag(s, etag string) bool {

Review comment (suggestion):
also, I have thought that. Does that make sense?
```suggestion
			if len(offer) == 0 || !isAccepted(acceptedType.spec, offer) {
				continue
			}
			return offer
```

Code after:
		}

		// Add to accepted types
		acceptedTypes = append(acceptedTypes, acceptedType{spec, quality, specificity, order})

		// Next
		if commaPos != -1 {
			header = header[commaPos+1:]
		} else {
			break
		}
	}

	if len(acceptedTypes) > 1 {
		// Sort accepted types by quality and specificity, preserving order of equal elements
		sortAcceptedTypes(&acceptedTypes)
	}

	// Find the first offer that matches the accepted types
	for _, acceptedType := range acceptedTypes {
		for _, offer := range offers {
			if len(offer) == 0 {
				continue
			}
			if isAccepted(acceptedType.spec, offer) {
				return offer
			}
		}
	}

	return ""
}

// sortAcceptedTypes sorts accepted types by quality and specificity, preserving order of equal elements
//
// Parameters are not supported, they are ignored when sorting by specificity.
//
// See: https://www.rfc-editor.org/rfc/rfc9110#name-content-negotiation-fields
func sortAcceptedTypes(at *[]acceptedType) {
	if at == nil || len(*at) < 2 {
		return
	}
	acceptedTypes := *at

	for i := 1; i < len(acceptedTypes); i++ {
		lo, hi := 0, i-1
		for lo <= hi {
			mid := (lo + hi) / 2
			if acceptedTypes[i].quality < acceptedTypes[mid].quality ||
				(acceptedTypes[i].quality == acceptedTypes[mid].quality && acceptedTypes[i].specificity < acceptedTypes[mid].specificity) ||
				(acceptedTypes[i].quality == acceptedTypes[mid].quality && acceptedTypes[i].specificity == acceptedTypes[mid].specificity && acceptedTypes[i].order > acceptedTypes[mid].order) {
Repository: gofiber/fiber
File: app.go (Go)

Code before:
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"log"
	"net"
	"net/http"
	"net/http/httputil"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/gofiber/fiber/v2/utils"

	"github.com/valyala/fasthttp"
)

// Version of current fiber package
const Version = "2.46.0"

// Handler defines a function to serve HTTP requests.
type Handler = func(*Ctx) error

// Probe Checker defines a function to check liveness or readiness of the application
type ProbeChecker = func(*Ctx) bool

// Map is a shortcut for map[string]interface{}, useful for JSON returns
type Map map[string]interface{}

// Storage interface for communicating with different database/key-value
// providers
type Storage interface {
	// Get gets the value for the given key.
	// `nil, nil` is returned when the key does not exist
	Get(key string) ([]byte, error)

	// Set stores the given value for the given key along
	// with an expiration value, 0 means no expiration.
	// Empty key or value will be ignored without an error.
	Set(key string, val []byte, exp time.Duration) error

	// Delete deletes the value for the given key.
	// It returns no error if the storage does not contain the key,
	Delete(key string) error

	// Reset resets the storage and delete all keys.
	Reset() error

	// Close closes the storage and will stop any running garbage

Review comment (suggestion):
```suggestion
// ProbeChecker defines a function to check liveness and readiness of the application
```

Code after:
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/http/httputil"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/gofiber/fiber/v2/log"
	"github.com/gofiber/fiber/v2/utils"

	"github.com/valyala/fasthttp"
)

// Version of current fiber package
const Version = "2.47.0"

// Handler defines a function to serve HTTP requests.
type Handler = func(*Ctx) error

// Map is a shortcut for map[string]interface{}, useful for JSON returns
type Map map[string]interface{}

// Storage interface for communicating with different database/key-value
// providers
type Storage interface {
	// Get gets the value for the given key.
	// `nil, nil` is returned when the key does not exist
	Get(key string) ([]byte, error)

	// Set stores the given value for the given key along
	// with an expiration value, 0 means no expiration.
	// Empty key or value will be ignored without an error.
	Set(key string, val []byte, exp time.Duration) error

	// Delete deletes the value for the given key.
	// It returns no error if the storage does not contain the key,
	Delete(key string) error

	// Reset resets the storage and delete all keys.
	Reset() error

	// Close closes the storage and will stop any running garbage
	// collectors and open connections.
	Close() error
}
Repository: gofiber/fiber
File: client.go (Go)

Code before:
// Note that GET and HEAD requests cannot have body.
func (a *Agent) BodyStream(bodyStream io.Reader, bodySize int) *Agent {
	a.req.SetBodyStream(bodyStream, bodySize)

	return a
}

// JSON sends a JSON request.
func (a *Agent) JSON(v interface{}) *Agent {
	if a.jsonEncoder == nil {
		a.jsonEncoder = json.Marshal
	}

	a.req.Header.SetContentType(MIMEApplicationJSON)

	if body, err := a.jsonEncoder(v); err != nil {
		a.errs = append(a.errs, err)
	} else {
		a.req.SetBody(body)
	}

	return a
}

// ProblemJSON sends an RFC7807 JSON request.
func (a *Agent) ProblemJSON(v interface{}) *Agent {
	if a.jsonEncoder == nil {
		a.jsonEncoder = json.Marshal
	}

	a.req.Header.SetContentType(MIMEApplicationProblemJSON)

	if body, err := a.jsonEncoder(v); err != nil {
		a.errs = append(a.errs, err)
	} else {
		a.req.SetBody(body)
	}

	return a
}

// XML sends an XML request.
func (a *Agent) XML(v interface{}) *Agent {
	a.req.Header.SetContentType(MIMEApplicationXML)

	if body, err := xml.Marshal(v); err != nil {
		a.errs = append(a.errs, err)
	} else {
		a.req.SetBody(body)
	}


Review comment (suggestion):
don't really know if we should make separate functions for all json possibilities, then love a functionality that expects the json and a custom json type

Code after:
// Note that GET and HEAD requests cannot have body.
func (a *Agent) BodyStream(bodyStream io.Reader, bodySize int) *Agent {
	a.req.SetBodyStream(bodyStream, bodySize)

	return a
}

// JSON sends a JSON request.
func (a *Agent) JSON(v interface{}, ctype ...string) *Agent {
	if a.jsonEncoder == nil {
		a.jsonEncoder = json.Marshal
	}

	if len(ctype) > 0 {
		a.req.Header.SetContentType(ctype[0])
	} else {
		a.req.Header.SetContentType(MIMEApplicationJSON)
	}

	if body, err := a.jsonEncoder(v); err != nil {
		a.errs = append(a.errs, err)
	} else {
		a.req.SetBody(body)
	}

	return a
}

// XML sends an XML request.
func (a *Agent) XML(v interface{}) *Agent {
	a.req.Header.SetContentType(MIMEApplicationXML)

	if body, err := xml.Marshal(v); err != nil {
		a.errs = append(a.errs, err)
	} else {
		a.req.SetBody(body)
	}

	return a
}

// Form sends form request with body if args is non-nil.
//
// It is recommended obtaining args via AcquireArgs and release it
// manually in performance-critical code.
func (a *Agent) Form(args *Args) *Agent {
	a.req.Header.SetContentType(MIMEApplicationForm)

	if args != nil {
		a.req.SetBody(args.QueryString())
	}
Repository: gofiber/fiber
File: middleware/redirect/redirect_test.go (Go)

Code before:
			url:        "/",
			redirectTo: "/swagger",
			statusCode: fiber.StatusMovedPermanently,
		},
		{
			name:       "no redirect to swagger route",
			url:        "/api/",
			statusCode: fiber.StatusOK,
		},
		{
			name:       "no redirect to swagger route #2",
			url:        "/api/test",
			statusCode: fiber.StatusOK,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			req, err := http.NewRequestWithContext(context.Background(), fiber.MethodGet, tt.url, nil)
			utils.AssertEqual(t, err, nil)
			req.Header.Set("Location", "github.com/gofiber/redirect")
			resp, err := app.Test(req)

			utils.AssertEqual(t, err, nil)
			utils.AssertEqual(t, tt.statusCode, resp.StatusCode)
			utils.AssertEqual(t, tt.redirectTo, resp.Header.Get("Location"))
		})
	}
}

func Test_Next(t *testing.T) {
	// Case 1 : Next function always returns true
	app := *fiber.New()
	app.Use(New(Config{
		Next: func(*fiber.Ctx) bool {
			return true
		},
		Rules: map[string]string{
			"/default": "google.com",
		},
		StatusCode: fiber.StatusMovedPermanently,
	}))

	app.Use(func(c *fiber.Ctx) error {
		return c.SendStatus(fiber.StatusOK)
	})

	req, err := http.NewRequestWithContext(context.Background(), fiber.MethodGet, "/default", nil)
	utils.AssertEqual(t, err, nil)
	resp, err := app.Test(req)
	utils.AssertEqual(t, err, nil)


Review comment (suggestion):
```go
		{
			name:       "redirect with multiple query params",
			url:        "/params?query=abc&query2=cde",
			redirectTo: "/with_params?query=abc&query2=cde",
			statusCode: fiber.StatusMovedPermanently,
		},
```

Code after:
			name:       "access URL without rule",
			url:        "/new",
			statusCode: fiber.StatusOK,
		},
		{
			name:       "redirect to swagger route",
			url:        "/",
			redirectTo: "/swagger",
			statusCode: fiber.StatusMovedPermanently,
		},
		{
			name:       "no redirect to swagger route",
			url:        "/api/",
			statusCode: fiber.StatusOK,
		},
		{
			name:       "no redirect to swagger route #2",
			url:        "/api/test",
			statusCode: fiber.StatusOK,
		},
		{
			name:       "redirect with query params",
			url:        "/params?query=abc",
			redirectTo: "/with_params?query=abc",
			statusCode: fiber.StatusMovedPermanently,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			req, err := http.NewRequestWithContext(context.Background(), fiber.MethodGet, tt.url, nil)
			utils.AssertEqual(t, err, nil)
			req.Header.Set("Location", "github.com/gofiber/redirect")
			resp, err := app.Test(req)

			utils.AssertEqual(t, err, nil)
			utils.AssertEqual(t, tt.statusCode, resp.StatusCode)
			utils.AssertEqual(t, tt.redirectTo, resp.Header.Get("Location"))
		})
	}
}

func Test_Next(t *testing.T) {
	// Case 1 : Next function always returns true
	app := *fiber.New()
	app.Use(New(Config{
		Next: func(*fiber.Ctx) bool {
			return true
		},
		Rules: map[string]string{
			"/default": "google.com",
		},
Repository: gofiber/fiber
File: ctx.go (Go)

Code before:
	var defaultHandler Handler
	for _, h := range handlers {
		if h.MediaType == "default" {
			defaultHandler = h.Handler
			continue
		}
		types = append(types, h.MediaType)
	}
	accept := c.Accepts(types...)

	if accept == "" {
		if defaultHandler == nil {
			return c.SendStatus(StatusNotAcceptable)
		}
		return defaultHandler(c)
	}

	for _, h := range handlers {
		if h.MediaType == accept {
			c.Response().Header.SetContentType(h.MediaType)
			return h.Handler(c)
		}
	}

	// unreachable code
	panic(errors.New("fiber: an Accept was found but no handler was called - please file a bug report"))
}

// AutoFormat performs content-negotiation on the Accept HTTP header.
// It uses Accepts to select a proper format.
// If the header is not specified or there is no proper format, text/plain is used.
func (c *DefaultCtx) AutoFormat(body any) error {
	// Get accepted content type
	accept := c.Accepts("html", "json", "txt", "xml")
	// Set accepted content type
	c.Type(accept)
	// Type convert provided body
	var b string
	switch val := body.(type) {
	case string:
		b = val
	case []byte:
		b = c.app.getString(val)
	default:
		b = fmt.Sprintf("%v", val)
	}

	// Format based on the accept content type
	switch accept {
	case "html":
		return c.SendString("<p>" + b + "</p>")

Review comment (suggestion):
```suggestion
return errors.New("fiber: no matching handler found for Accept header")
```

Code after:

	// Using an int literal as the slice capacity allows for the slice to be
	// allocated on the stack. The number was chosen arbitrarily as an
	// approximation of the maximum number of content types a user might handle.
	// If the user goes over, it just causes allocations, so it's not a problem.
	types := make([]string, 0, 8)
	var defaultHandler Handler
	for _, h := range handlers {
		if h.MediaType == "default" {
			defaultHandler = h.Handler
			continue
		}
		types = append(types, h.MediaType)
	}
	accept := c.Accepts(types...)

	if accept == "" {
		if defaultHandler == nil {
			return c.SendStatus(StatusNotAcceptable)
		}
		return defaultHandler(c)
	}

	for _, h := range handlers {
		if h.MediaType == accept {
			c.Response().Header.SetContentType(h.MediaType)
			return h.Handler(c)
		}
	}

	return fmt.Errorf("%w: format: an Accept was found but no handler was called", errUnreachable)
}

// AutoFormat performs content-negotiation on the Accept HTTP header.
// It uses Accepts to select a proper format.
// The supported content types are text/html, text/plain, application/json, and application/xml.
// For more flexible content negotiation, use Format.
// If the header is not specified or there is no proper format, text/plain is used.
func (c *DefaultCtx) AutoFormat(body any) error {
	// Get accepted content type
	accept := c.Accepts("html", "json", "txt", "xml")
	// Set accepted content type
	c.Type(accept)
	// Type convert provided body
	var b string
	switch val := body.(type) {
	case string:
		b = val
	case []byte:
		b = c.app.getString(val)
	default:
Repository: gofiber/fiber
File: ctx.go (Go)

Code before:
		}
		return defaultHandler(c)
	}

	for _, h := range handlers {
		if h.MediaType == accept {
			c.Response().Header.SetContentType(h.MediaType)
			return h.Handler(c)
		}
	}

	// unreachable code
	panic(errors.New("fiber: an Accept was found but no handler was called - please file a bug report"))
}

// AutoFormat performs content-negotiation on the Accept HTTP header.
// It uses Accepts to select a proper format.
// If the header is not specified or there is no proper format, text/plain is used.
func (c *DefaultCtx) AutoFormat(body any) error {
	// Get accepted content type
	accept := c.Accepts("html", "json", "txt", "xml")
	// Set accepted content type
	c.Type(accept)
	// Type convert provided body
	var b string
	switch val := body.(type) {
	case string:
		b = val
	case []byte:
		b = c.app.getString(val)
	default:
		b = fmt.Sprintf("%v", val)
	}

	// Format based on the accept content type
	switch accept {
	case "html":
		return c.SendString("<p>" + b + "</p>")
	case "json":
		return c.JSON(body)
	case "txt":
		return c.SendString(b)
	case "xml":
		return c.XML(body)
	}
	return c.SendString(b)
}

// FormFile returns the first file by key from a MultipartForm.
func (c *DefaultCtx) FormFile(key string) (*multipart.FileHeader, error) {
	return c.fasthttp.FormFile(key)

Review comment (suggestion):
```suggestion
func (c *DefaultCtx) AutoFormat(body interface{}) error {
```

Code after:
	}
	accept := c.Accepts(types...)

	if accept == "" {
		if defaultHandler == nil {
			return c.SendStatus(StatusNotAcceptable)
		}
		return defaultHandler(c)
	}

	for _, h := range handlers {
		if h.MediaType == accept {
			c.Response().Header.SetContentType(h.MediaType)
			return h.Handler(c)
		}
	}

	return fmt.Errorf("%w: format: an Accept was found but no handler was called", errUnreachable)
}

// AutoFormat performs content-negotiation on the Accept HTTP header.
// It uses Accepts to select a proper format.
// The supported content types are text/html, text/plain, application/json, and application/xml.
// For more flexible content negotiation, use Format.
// If the header is not specified or there is no proper format, text/plain is used.
func (c *DefaultCtx) AutoFormat(body any) error {
	// Get accepted content type
	accept := c.Accepts("html", "json", "txt", "xml")
	// Set accepted content type
	c.Type(accept)
	// Type convert provided body
	var b string
	switch val := body.(type) {
	case string:
		b = val
	case []byte:
		b = c.app.getString(val)
	default:
		b = fmt.Sprintf("%v", val)
	}

	// Format based on the accept content type
	switch accept {
	case "html":
		return c.SendString("<p>" + b + "</p>")
	case "json":
		return c.JSON(body)
	case "txt":
		return c.SendString(b)
	case "xml":
		return c.XML(body)
Repository: gofiber/fiber
File: app_test.go (Go)

Code before:
	require.Equal(t, "hi, i'm an error", string(body))

	_, err = app.Test(httptest.NewRequest(MethodGet, "/", strings.NewReader("big body")))
	if err != nil {
		require.Equal(t, "body size exceeds the given limit", err.Error(), "app.Test(req)")
	}
}

type customConstraint struct{}

func (*customConstraint) Name() string {
	return "test"
}

func (*customConstraint) Execute(param string, args ...string) bool {
	if param == "test" && len(args) == 1 && args[0] == "test" {
		return true
	}

	if len(args) == 0 && param == "c" {
		return true
	}

	return false
}

func Test_App_CustomConstraint(t *testing.T) {
	app := New()
	app.RegisterCustomConstraint(&customConstraint{})

	app.Get("/test/:param<test(test)>", func(c Ctx) error {
		return c.SendString("test")
	})

	app.Get("/test2/:param<test>", func(c Ctx) error {
		return c.SendString("test")
	})

	app.Get("/test3/:param<test()>", func(c Ctx) error {
		return c.SendString("test")
	})

	resp, err := app.Test(httptest.NewRequest(MethodGet, "/test/test", nil))
	require.NoError(t, err, "app.Test(req)")
	require.Equal(t, 200, resp.StatusCode, "Status code")

	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test/test2", nil))
	require.NoError(t, err, "app.Test(req)")
	require.Equal(t, 404, resp.StatusCode, "Status code")

	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test2/c", nil))

Review comment (performance):
please add a benchmark for a custom contraints which is simple so that we can test the runtime performance
and later get to know if it gets worse or if we could actively optimize it

Code after:

	_, err = app.Test(httptest.NewRequest(MethodGet, "/", strings.NewReader("big body")))
	if err != nil {
		require.Equal(t, "body size exceeds the given limit", err.Error(), "app.Test(req)")
	}
}

type customConstraint struct{}

func (*customConstraint) Name() string {
	return "test"
}

func (*customConstraint) Execute(param string, args ...string) bool {
	if param == "test" && len(args) == 1 && args[0] == "test" {
		return true
	}

	if len(args) == 0 && param == "c" {
		return true
	}

	return false
}

func Test_App_CustomConstraint(t *testing.T) {
	app := New()
	app.RegisterCustomConstraint(&customConstraint{})

	app.Get("/test/:param<test(test)>", func(c Ctx) error {
		return c.SendString("test")
	})

	app.Get("/test2/:param<test>", func(c Ctx) error {
		return c.SendString("test")
	})

	app.Get("/test3/:param<test()>", func(c Ctx) error {
		return c.SendString("test")
	})

	resp, err := app.Test(httptest.NewRequest(MethodGet, "/test/test", nil))
	require.NoError(t, err, "app.Test(req)")
	require.Equal(t, 200, resp.StatusCode, "Status code")

	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test/test2", nil))
	require.NoError(t, err, "app.Test(req)")
	require.Equal(t, 404, resp.StatusCode, "Status code")

	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test2/c", nil))
	require.NoError(t, err, "app.Test(req)")
Repository: gofiber/fiber
File: app_test.go (Go)

Code before:
	}()

	timer := time.NewTimer(time.Second * 5)
	select {
	case <-timer.C:
		t.Fatal("idle connections not closed on shutdown")
	case err := <-shutdownErr:
		if err == nil || !errors.Is(err, context.DeadlineExceeded) {
			t.Fatalf("unexpected err %v. Expecting %v", err, context.DeadlineExceeded)
		}
	}
}

func Test_App_ShutdownWithContext(t *testing.T) {
	t.Parallel()

	app := New()
	app.Get("/", func(ctx Ctx) error {
		time.Sleep(5 * time.Second)
		return ctx.SendString("body")
	})

	ln := fasthttputil.NewInmemoryListener()

	go func() {
		require.NoError(t, app.Listener(ln)) //nolint:testifylint // Needed for test
	}()

	time.Sleep(1 * time.Second)

	go func() {
		conn, err := ln.Dial()
		if err != nil {
			t.Errorf("unexepcted error: %v", err)
		}

		if _, err = conn.Write([]byte("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")); err != nil {
			t.Errorf("unexpected error: %v", err)
		}
	}()

	time.Sleep(1 * time.Second)

	shutdownErr := make(chan error)
	go func() {
		ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
		defer cancel()
		shutdownErr <- app.ShutdownWithContext(ctx)
	}()

	select {

Review comment (bug):
Apparently, there are issues with handling test failures in goroutines (even in the standard testing package).

https://github.com/Antonboom/testifylint?tab=readme-ov-file#go-require

The biggest problem is when t.FailNow is called (i.e. `require`), but the author of testifylint says that simply switching to `assert` still leaves you with code smells.

Here is an example of that they recommend https://github.com/ipfs/kubo/issues/2043#issuecomment-164136026

Adding nolint directives is probably best for this PR, though.

Code after:
	}()

	timer := time.NewTimer(time.Second * 5)
	select {
	case <-timer.C:
		t.Fatal("idle connections not closed on shutdown")
	case err := <-shutdownErr:
		if err == nil || !errors.Is(err, context.DeadlineExceeded) {
			t.Fatalf("unexpected err %v. Expecting %v", err, context.DeadlineExceeded)
		}
	}
}

func Test_App_ShutdownWithContext(t *testing.T) {
	t.Parallel()

	app := New()
	app.Get("/", func(ctx Ctx) error {
		time.Sleep(5 * time.Second)
		return ctx.SendString("body")
	})

	ln := fasthttputil.NewInmemoryListener()

	go func() {
		require.NoError(t, app.Listener(ln))
	}()

	time.Sleep(1 * time.Second)

	go func() {
		conn, err := ln.Dial()
		if err != nil {
			t.Errorf("unexepcted error: %v", err)
		}

		if _, err = conn.Write([]byte("GET / HTTP/1.1\r\nHost: google.com\r\n\r\n")); err != nil {
			t.Errorf("unexpected error: %v", err)
		}
	}()

	time.Sleep(1 * time.Second)

	shutdownErr := make(chan error)
	go func() {
		ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
		defer cancel()
		shutdownErr <- app.ShutdownWithContext(ctx)
	}()

	select {