grafana/pkg/middleware/loggermw/logger_test.go
Marcus Efraimsson 040b7d2571
Chore: Add errutils helpers (#73577)
Add helpers for the errutil package in favor of errutil.NewBase.
2023-08-22 12:52:24 +02:00

214 lines
4.8 KiB
Go

package loggermw
import (
"fmt"
"net/http"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util/errutil"
"github.com/grafana/grafana/pkg/web"
)
func Test_sanitizeURL(t *testing.T) {
tests := []struct {
name string
input string
want string
expectError bool
}{
{
name: "Receiving empty string should return it",
input: "",
want: "",
},
{
name: "Receiving valid URL string should return it parsed",
input: "https://grafana.com/",
want: "https://grafana.com/",
},
{
name: "Receiving invalid URL string should return empty string",
input: "this is not a valid URL",
want: "",
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
url, err := SanitizeURL(tt.input)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
assert.Equalf(t, tt.want, url, "SanitizeURL(%v)", tt.input)
})
}
}
func Test_prepareLog(t *testing.T) {
type opts struct {
Features []any
RouterLogging bool
}
grafanaFlavoredErr := errutil.NotFound("test.notFound").Errorf("got error")
tests := []struct {
name string
opts opts
req *http.Request
response web.ResponseWriter
duration time.Duration
error error
expectFields map[string]any
expectAbsence map[string]struct{}
expectedLevel errutil.LogLevel
}{
{
name: "base case",
req: mustRequest(http.NewRequest(http.MethodGet, "/", nil)),
response: mockResponseWriter{},
expectFields: map[string]any{
"method": "GET",
"path": "/",
"status": 0,
"remote_addr": "",
"time_ms": 0,
"duration": "0s",
"size": 0,
"referer": "",
},
expectAbsence: map[string]struct{}{
"error": {},
"db_call_count": {},
},
},
{
name: "base case",
req: mustRequest(http.NewRequest(http.MethodGet, "/", nil)),
response: mockResponseWriter{},
expectFields: map[string]any{
"method": "GET",
"path": "/",
"status": 0,
"remote_addr": "",
"time_ms": 0,
"duration": "0s",
"size": 0,
"referer": "",
},
expectAbsence: map[string]struct{}{
"error": {},
"db_call_count": {},
},
expectedLevel: errutil.LevelInfo,
},
{
name: "regular Go error",
req: mustRequest(http.NewRequest(http.MethodGet, "/", nil)),
response: mockResponseWriter{
status: http.StatusInternalServerError,
},
error: fmt.Errorf("got an error"),
expectFields: map[string]any{
"status": http.StatusInternalServerError,
"error": "got an error",
},
expectAbsence: map[string]struct{}{
"errorReason": {},
"errorMessageID": {},
},
expectedLevel: errutil.LevelError,
},
{
name: "Grafana-style error",
req: mustRequest(http.NewRequest(http.MethodGet, "/", nil)),
response: mockResponseWriter{
status: http.StatusNotFound,
},
error: grafanaFlavoredErr,
expectFields: map[string]any{
"status": http.StatusNotFound,
"error": "got error",
"errorReason": errutil.StatusNotFound,
"errorMessageID": "test.notFound",
},
expectedLevel: errutil.LevelInfo,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
cfg := setting.NewCfg()
cfg.RouterLogging = tc.opts.RouterLogging
l := Provide(cfg, featuremgmt.WithFeatures(tc.opts.Features...))
service, ok := l.(*loggerImpl)
require.Truef(t, ok, "expected service to be of type (*loggerImpl), got (%T)", l)
c := &contextmodel.ReqContext{
Context: &web.Context{
Req: tc.req,
Resp: tc.response,
},
Error: tc.error,
}
logs, level := service.prepareLogParams(c, tc.duration)
require.Zero(t, len(logs)%2, "Each key must have an accompanying value")
kv := map[any]any{}
for i := 0; i < len(logs); i += 2 {
kv[logs[i]] = logs[i+1]
}
for key, val := range tc.expectFields {
assert.Contains(t, kv, key)
if val != nil {
assert.EqualValues(t, val, kv[key])
}
}
for key := range tc.expectAbsence {
assert.NotContains(t, kv, key)
}
if tc.expectedLevel != "" {
assert.Equal(t, tc.expectedLevel, level)
}
})
}
}
func mustRequest(r *http.Request, err error) *http.Request {
if err != nil {
panic(fmt.Errorf("expected no error when creating request, got: %w", err))
}
return r
}
type mockResponseWriter struct {
web.ResponseWriter
status int
size int
}
func (m mockResponseWriter) Status() int {
return m.status
}
func (m mockResponseWriter) Size() int {
return m.size
}