-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(error): handle wrapped errors in IsError() (#375)
`hcloud.IsError()` currently does a type assertion to get our error type. This breaks if the error was previously wrapped, causing it to always return "false". This happens often if the error is passed through multiple functions before error handling is being done. Example of code that is currently broken: ```go // Error returned by hcloud-go err := hcloud.Error{ Code: hcloud.ErrorCodeUnauthorized } // Error gets wrapped at some point in the call-chain err = fmt.Errorf("failed to foobar: %w", err) // Now the error is not properly identified hcloud.IsError(err, hcloud.ErrorCodeUnauthorized) // false ``` --- Backport 83df108 from #374. Co-authored-by: Julian Tölle <julian.toelle@hetzner-cloud.de>
- Loading branch information
1 parent
991ffd8
commit 64902c5
Showing
2 changed files
with
104 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package hcloud | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestError_Error(t *testing.T) { | ||
type fields struct { | ||
Code ErrorCode | ||
Message string | ||
Details interface{} | ||
response *Response | ||
} | ||
tests := []struct { | ||
name string | ||
fields fields | ||
want string | ||
}{ | ||
{ | ||
name: "simple error", | ||
fields: fields{ | ||
Code: ErrorCodeUnauthorized, | ||
Message: "unable to authenticate", | ||
}, | ||
want: "unable to authenticate (unauthorized)", | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
e := Error{ | ||
Code: tt.fields.Code, | ||
Message: tt.fields.Message, | ||
Details: tt.fields.Details, | ||
response: tt.fields.response, | ||
} | ||
assert.Equalf(t, tt.want, e.Error(), "Error()") | ||
}) | ||
} | ||
} | ||
|
||
func TestIsError(t *testing.T) { | ||
type args struct { | ||
err error | ||
code ErrorCode | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want bool | ||
}{ | ||
{ | ||
name: "hcloud error with code", | ||
args: args{ | ||
err: Error{Code: ErrorCodeUnauthorized}, | ||
code: ErrorCodeUnauthorized, | ||
}, | ||
want: true, | ||
}, | ||
{ | ||
name: "hcloud error with different code", | ||
args: args{ | ||
err: Error{Code: ErrorCodeConflict}, | ||
code: ErrorCodeUnauthorized, | ||
}, | ||
want: false, | ||
}, | ||
{ | ||
name: "wrapped hcloud error with code", | ||
args: args{ | ||
err: fmt.Errorf("wrapped: %w", Error{Code: ErrorCodeUnauthorized}), | ||
code: ErrorCodeUnauthorized, | ||
}, | ||
want: true, | ||
}, | ||
{ | ||
name: "wrapped hcloud error with different code", | ||
args: args{ | ||
err: fmt.Errorf("wrapped: %w", Error{Code: ErrorCodeConflict}), | ||
code: ErrorCodeUnauthorized, | ||
}, | ||
want: false, | ||
}, | ||
{ | ||
name: "non-hcloud error", | ||
args: args{ | ||
err: fmt.Errorf("something went wrong"), | ||
code: ErrorCodeUnauthorized, | ||
}, | ||
want: false, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
assert.Equalf(t, tt.want, IsError(tt.args.err, tt.args.code), "IsError(%v, %v)", tt.args.err, tt.args.code) | ||
}) | ||
} | ||
} |