Files
gluetun/internal/pprof/server_test.go
2023-04-20 23:10:02 +00:00

127 lines
3.3 KiB
Go

package pprof
import (
"context"
"io"
"net/http"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/qdm12/gluetun/internal/httpserver"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
//go:generate mockgen -destination=logger_mock_test.go -package $GOPACKAGE github.com/qdm12/gluetun/internal/httpserver Logger
func Test_Server(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)
const address = "127.0.0.1:0"
logger := NewMockLogger(ctrl)
logger.EXPECT().Info(newRegexMatcher("^http server listening on 127.0.0.1:[1-9][0-9]{0,4}$"))
const httpServerShutdownTimeout = 10 * time.Second // 10s in case test worker is slow
settings := Settings{
BlockProfileRate: intPtr(0),
MutexProfileRate: intPtr(0),
HTTPServer: httpserver.Settings{
Address: address,
Logger: logger,
ShutdownTimeout: httpServerShutdownTimeout,
},
}
server, err := New(settings)
require.NoError(t, err)
require.NotNil(t, server)
ctx, cancel := context.WithCancel(context.Background())
ready := make(chan struct{})
done := make(chan struct{})
go server.Run(ctx, ready, done)
select {
case <-ready:
case err := <-done:
t.Fatalf("server crashed before being ready: %s", err)
}
serverAddress := server.GetAddress()
const clientTimeout = 2 * time.Second
httpClient := &http.Client{Timeout: clientTimeout}
pathsToCheck := []string{
"debug/pprof/",
"debug/pprof/cmdline",
"debug/pprof/profile?seconds=1",
"debug/pprof/symbol",
"debug/pprof/trace?seconds=1",
"debug/pprof/block",
"debug/pprof/goroutine",
"debug/pprof/heap",
"debug/pprof/threadcreate",
}
type httpResult struct {
url string
response *http.Response
err error
}
results := make(chan httpResult)
for _, pathToCheck := range pathsToCheck {
url := "http://" + serverAddress + "/" + pathToCheck
request, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
require.NoError(t, err)
go func(client *http.Client, request *http.Request, results chan<- httpResult) {
response, err := client.Do(request) //nolint:bodyclose
results <- httpResult{
url: request.URL.String(),
response: response,
err: err,
}
}(httpClient, request, results)
}
for range pathsToCheck {
httpResult := <-results
require.NoErrorf(t, httpResult.err, "unexpected error for URL %s: %s", httpResult.url, httpResult.err)
assert.Equalf(t, http.StatusOK, httpResult.response.StatusCode,
"unexpected status code for URL %s: %s", httpResult.url, http.StatusText(httpResult.response.StatusCode))
b, err := io.ReadAll(httpResult.response.Body)
require.NoErrorf(t, err, "unexpected error for URL %s: %s", httpResult.url, err)
assert.NotEmptyf(t, b, "response body is empty for URL %s", httpResult.url)
err = httpResult.response.Body.Close()
assert.NoErrorf(t, err, "unexpected error for URL %s: %s", httpResult.url, err)
}
cancel()
<-done
}
func Test_Server_BadSettings(t *testing.T) {
t.Parallel()
settings := Settings{
BlockProfileRate: intPtr(-1),
MutexProfileRate: intPtr(0),
}
server, err := New(settings)
assert.Nil(t, server)
assert.ErrorIs(t, err, ErrBlockProfileRateNegative)
const expectedErrMessage = "pprof settings failed validation: block profile rate cannot be negative"
assert.EqualError(t, err, expectedErrMessage)
}