package logging import ( "errors" "testing" pkgerrs "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestFire(t *testing.T) { tests := []struct { name string preEntryFields map[string]interface{} expectedEntryFields map[string]interface{} expectedErr bool }{ { name: "no error", preEntryFields: map[string]interface{}{"foo": "bar"}, expectedEntryFields: map[string]interface{}{"foo": "bar"}, }, { name: "basic (non-pkg/errors) error", preEntryFields: map[string]interface{}{logrus.ErrorKey: errors.New("a normal error")}, expectedEntryFields: map[string]interface{}{logrus.ErrorKey: errors.New("a normal error")}, }, { name: "non-error logged in error field", preEntryFields: map[string]interface{}{logrus.ErrorKey: "not an error"}, expectedEntryFields: map[string]interface{}{logrus.ErrorKey: "not an error"}, expectedErr: true, }, { name: "pkg/errors error", preEntryFields: map[string]interface{}{logrus.ErrorKey: pkgerrs.New("a pkg/errors error")}, expectedEntryFields: map[string]interface{}{ logrus.ErrorKey: pkgerrs.New("a pkg/errors error"), errorFileField: "", errorFunctionField: "TestFire", }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { hook := &ErrorLocationHook{} entry := &logrus.Entry{ Data: logrus.Fields(test.preEntryFields), } // method under test err := hook.Fire(entry) require.Equal(t, test.expectedErr, err != nil) require.Equal(t, len(test.expectedEntryFields), len(entry.Data)) for key, expectedValue := range test.expectedEntryFields { actualValue, found := entry.Data[key] assert.True(t, found, "expected key not found: %s", key) switch key { // test existence of this field only since testing the value // is fragile case errorFileField: case logrus.ErrorKey: if err, ok := expectedValue.(error); ok { assert.Equal(t, err.Error(), actualValue.(error).Error()) } else { assert.Equal(t, expectedValue, actualValue) } default: assert.Equal(t, expectedValue, actualValue) } } }) } } func TestGetInnermostTrace(t *testing.T) { newError := func() error { return errors.New("a normal error") } tests := []struct { name string err error expectedRes error }{ { name: "normal error", err: newError(), expectedRes: nil, }, { name: "pkg/errs error", err: pkgerrs.New("a pkg/errs error"), expectedRes: pkgerrs.New("a pkg/errs error"), }, { name: "one level of stack-ing a normal error", err: pkgerrs.WithStack(newError()), expectedRes: pkgerrs.WithStack(newError()), }, { name: "two levels of stack-ing a normal error", err: pkgerrs.WithStack(pkgerrs.WithStack(newError())), expectedRes: pkgerrs.WithStack(newError()), }, { name: "one level of stack-ing a pkg/errors error", err: pkgerrs.WithStack(pkgerrs.New("a pkg/errs error")), expectedRes: pkgerrs.New("a pkg/errs error"), }, { name: "two levels of stack-ing a pkg/errors error", err: pkgerrs.WithStack(pkgerrs.WithStack(pkgerrs.New("a pkg/errs error"))), expectedRes: pkgerrs.New("a pkg/errs error"), }, { name: "two levels of wrapping a normal error", err: pkgerrs.Wrap(pkgerrs.Wrap(newError(), "wrap 1"), "wrap 2"), expectedRes: pkgerrs.Wrap(newError(), "wrap 1"), }, { name: "two levels of wrapping a pkg/errors error", err: pkgerrs.Wrap(pkgerrs.Wrap(pkgerrs.New("a pkg/errs error"), "wrap 1"), "wrap 2"), expectedRes: pkgerrs.New("a pkg/errs error"), }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { res := getInnermostTrace(test.err) if test.expectedRes == nil { assert.Nil(t, res) return } assert.Equal(t, test.expectedRes.Error(), res.Error()) }) } }