-
Notifications
You must be signed in to change notification settings - Fork 219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for chained errors #185
Conversation
56815be
to
7348755
Compare
func TestCaptureExceptionShouldSendEventWithProvidedError(t *testing.T) { | ||
client, scope, transport := setupClientTest() | ||
client.CaptureException(errors.New("custom error"), nil, scope) | ||
assertEqual(t, transport.lastEvent.Exception[0].Type, "*errors.errorString") | ||
assertEqual(t, transport.lastEvent.Exception[0].Value, "custom error") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got replaced by the test SimpleError
below.
func TestCaptureExceptionShouldNotFailWhenPassedNil(t *testing.T) { | ||
client, scope, transport := setupClientTest() | ||
client.CaptureException(nil, nil, scope) | ||
want := &Event{ | ||
Level: "error", | ||
Platform: "go", | ||
Exception: []Exception{ | ||
{ | ||
Type: "sentry.usageError", | ||
Value: "CaptureException called with nil error", | ||
}, | ||
}, | ||
} | ||
opts := cmp.Options{ | ||
cmpopts.IgnoreFields(Event{}, "EventID", "Sdk", "ServerName", "Timestamp"), | ||
cmpopts.IgnoreTypes(&Stacktrace{}), | ||
cmpopts.EquateEmpty(), | ||
} | ||
if diff := cmp.Diff(want, transport.lastEvent, opts); diff != "" { | ||
t.Errorf("event mismatch (-want +got):\n%s", diff) | ||
} | ||
if transport.lastEvent.Exception[0].Stacktrace == nil { | ||
t.Errorf("missing stacktrace") | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got replaced by the test NilError
below.
func TestCaptureExceptionShouldExtractCorrectTypeAndValueForWrappedErrors(t *testing.T) { | ||
client, scope, transport := setupClientTest() | ||
cause := &customErr{} | ||
err := pkgErrors.WithStack(cause) | ||
client.CaptureException(err, nil, scope) | ||
assertEqual(t, transport.lastEvent.Exception[0].Type, "*sentry.customErr") | ||
assertEqual(t, transport.lastEvent.Exception[0].Value, "wat") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got replaced by the test MostRecentErrorHasStack
below.
func TestCaptureExceptionShouldNotUseCauseIfCauseIsNil(t *testing.T) { | ||
client, scope, transport := setupClientTest() | ||
err := &customErrWithCause{cause: nil} | ||
client.CaptureException(err, nil, scope) | ||
assertEqual(t, transport.lastEvent.Exception[0].Type, "*sentry.customErrWithCause") | ||
assertEqual(t, transport.lastEvent.Exception[0].Value, "err") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got replaced with the test ChainWithNilCause
below.
func TestCaptureExceptionShouldUseCauseIfCauseIsNotNil(t *testing.T) { | ||
client, scope, transport := setupClientTest() | ||
err := &customErrWithCause{cause: &customErr{}} | ||
client.CaptureException(err, nil, scope) | ||
assertEqual(t, transport.lastEvent.Exception[0].Type, "*sentry.customErr") | ||
assertEqual(t, transport.lastEvent.Exception[0].Value, "wat") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got replaced with the test ChainWithoutStacktrace
below.
func TestCaptureEvent(t *testing.T) { | ||
client, _, transport := setupClientTest() | ||
|
||
eventID := EventID("0123456789abcdef") | ||
timestamp := time.Now().UTC() | ||
serverName := "testServer" | ||
|
||
client.CaptureEvent(&Event{ | ||
EventID: eventID, | ||
Timestamp: timestamp, | ||
ServerName: serverName, | ||
}, nil, nil) | ||
|
||
if transport.lastEvent == nil { | ||
t.Fatal("missing event") | ||
} | ||
want := &Event{ | ||
EventID: eventID, | ||
Timestamp: timestamp, | ||
ServerName: serverName, | ||
Level: LevelInfo, | ||
Platform: "go", | ||
Sdk: SdkInfo{ | ||
Name: "sentry.go", | ||
Version: Version, | ||
Integrations: []string{}, | ||
Packages: []SdkPackage{ | ||
{ | ||
// FIXME: name format doesn't follow spec in | ||
// https://docs.sentry.io/development/sdk-dev/event-payloads/sdk/ | ||
Name: "sentry-go", | ||
Version: Version, | ||
}, | ||
// TODO: perhaps the list of packages is incomplete or there | ||
// should not be any package at all. | ||
}, | ||
}, | ||
} | ||
got := transport.lastEvent | ||
if diff := cmp.Diff(want, got); diff != "" { | ||
t.Errorf("Event mismatch (-want +got):\n%s", diff) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is notably not a very good test, but a starting point to add tests around code that fills in event fields.
It is so that TestCaptureException
can focus on the list of "exceptions" (errors) instead of dealing with stuff like SDK info, Platform, etc.
Packages: []SdkPackage{ | ||
{ | ||
// FIXME: name format doesn't follow spec in | ||
// https://docs.sentry.io/development/sdk-dev/event-payloads/sdk/ | ||
Name: "sentry-go", | ||
Version: Version, | ||
}, | ||
// TODO: perhaps the list of packages is incomplete or there | ||
// should not be any package at all. | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is something we need to review in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got a lot to contribute here.
return event | ||
} | ||
|
||
// reverse reverses the slice a in place. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// reverse reverses the slice a in place. | |
// reverse reverses the slice in place. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a typo, a
is the name of the argument :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have 0 to contribute.
Maybe useless questions: Is there really no built-in generic array reversal function in Go? Oh, no generic? (I mean, it's an array, forget generics)
Also, what about renaming a
-> exceptions
or, e
?
And finally:
// reverse reverses the slice a in place. | |
// reverse reverses the slice 'a' in place. |
return event | ||
} | ||
|
||
// reverse reverses the slice a in place. | ||
func reverse(a []Exception) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
for _, grp := range tests { | ||
for _, tt := range grp.tests { | ||
tt := tt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it for closure scoping purpose?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Because tt
is in the scope of the subtest, having a new variable for each test prevents running into https://github.com/golang/go/wiki/CommonMistakes and allows us to run tests in parallel if we wanted to.
The observed behavior in the current code base today would be the same without this line, but I like to have it to help whomever will maintain this later.
It is easy to imagine some contribution to make tests run in parallel (not a priority today because they are pretty fast anyway), the tests would be green and we would not realize that we're only running the last test case over and over...
Instead of reporting only the top parent of an error chain, report all errors that are part of the chain.
Supports chains of errors using the
Cause
method (used by popular error packages predating Go 1.13).Support for errors using the
Unwrap
method (introduced in Go 1.13) or a combination ofUnwrap
andCause
will come briefly in a follow up.Fixes #176.
Example report of chained errors