mirror of
https://github.com/grafana/grafana.git
synced 2024-12-02 05:29:42 -06:00
040b7d2571
Add helpers for the errutil package in favor of errutil.NewBase.
214 lines
4.8 KiB
Go
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
|
|
}
|