forked from grafana/k6
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an errext package with error types, helpers and exitcodes
- Loading branch information
Showing
5 changed files
with
274 additions
and
0 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
/* | ||
* | ||
* k6 - a next-generation load testing tool | ||
* Copyright (C) 2021 Load Impact | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Affero General Public License as | ||
* published by the Free Software Foundation, either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
package errext | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func assertHasHint(t *testing.T, err error, hint string) { | ||
var typederr HasHint | ||
require.ErrorAs(t, err, &typederr) | ||
assert.Equal(t, typederr.Hint(), hint) | ||
assert.Contains(t, err.Error(), typederr.Error()) | ||
} | ||
|
||
func assertHasExitCode(t *testing.T, err error, exitcode ExitCode) { | ||
var typederr HasExitCode | ||
require.ErrorAs(t, err, &typederr) | ||
assert.Equal(t, typederr.ExitCode(), exitcode) | ||
assert.Contains(t, err.Error(), typederr.Error()) | ||
} | ||
|
||
func TestErrextHelpers(t *testing.T) { | ||
t.Parallel() | ||
|
||
const testExitCode ExitCode = 13 | ||
assert.Nil(t, WithHint(nil, "test hint")) | ||
assert.Nil(t, WithExitCode(nil, testExitCode)) | ||
|
||
errBase := errors.New("base error") | ||
errBaseWithHint := WithHint(errBase, "test hint") | ||
assertHasHint(t, errBaseWithHint, "test hint") | ||
errBaseWithTwoHints := WithHint(errBaseWithHint, "better hint") | ||
assertHasHint(t, errBaseWithTwoHints, "better hint (test hint)") | ||
|
||
errWrapperWithHints := fmt.Errorf("wrapper error: %w", errBaseWithTwoHints) | ||
assertHasHint(t, errWrapperWithHints, "better hint (test hint)") | ||
|
||
errWithExitCode := WithExitCode(errWrapperWithHints, testExitCode) | ||
assertHasHint(t, errWithExitCode, "better hint (test hint)") | ||
assertHasExitCode(t, errWithExitCode, testExitCode) | ||
|
||
errWithExitCodeAgain := WithExitCode(errWithExitCode, ExitCode(27)) | ||
assertHasHint(t, errWithExitCodeAgain, "better hint (test hint)") | ||
assertHasExitCode(t, errWithExitCodeAgain, testExitCode) | ||
|
||
errBaseWithThreeHints := WithHint(errWithExitCodeAgain, "best hint") | ||
assertHasHint(t, errBaseWithThreeHints, "best hint (better hint (test hint))") | ||
|
||
finalErrorMess := fmt.Errorf("woot: %w", errBaseWithThreeHints) | ||
assert.Equal(t, finalErrorMess.Error(), "woot: wrapper error: base error") | ||
assertHasHint(t, finalErrorMess, "best hint (better hint (test hint))") | ||
assertHasExitCode(t, finalErrorMess, testExitCode) | ||
} |
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,29 @@ | ||
/* | ||
* | ||
* k6 - a next-generation load testing tool | ||
* Copyright (C) 2021 Load Impact | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Affero General Public License as | ||
* published by the Free Software Foundation, either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
// Package errext contains extensions for normal Go errors that are used in k6. | ||
package errext | ||
|
||
// Exception represents errors that resulted from a script exception and contain | ||
// a stack trace that lead to them. | ||
type Exception interface { | ||
error | ||
StackTrace() string | ||
} |
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,66 @@ | ||
/* | ||
* | ||
* k6 - a next-generation load testing tool | ||
* Copyright (C) 2021 Load Impact | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Affero General Public License as | ||
* published by the Free Software Foundation, either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
package errext | ||
|
||
import "errors" | ||
|
||
// ExitCode is the code with which the application should exit if this error | ||
// bubbles up to the top of the scope. Values should be between 0 and 125: | ||
// https://unix.stackexchange.com/questions/418784/what-is-the-min-and-max-values-of-exit-codes-in-linux | ||
type ExitCode uint8 | ||
|
||
// HasExitCode is a wrapper around an error with an attached exit code. | ||
type HasExitCode interface { | ||
error | ||
ExitCode() ExitCode | ||
} | ||
|
||
// WithExitCode can attach an exit code to the given error, if it doesn't have | ||
// one already. It won't do anything if the error already had an exit code | ||
// attached. Similarly, if there is no error (i.e. the given error is nil), it | ||
// also won't do anything. | ||
func WithExitCode(err error, exitCode ExitCode) error { | ||
if err == nil { | ||
// No error, do nothing | ||
return nil | ||
} | ||
var ecerr HasExitCode | ||
if errors.As(err, &ecerr) { | ||
// The given error already has an exit code, do nothing | ||
return err | ||
} | ||
return withExitCode{err, exitCode} | ||
} | ||
|
||
type withExitCode struct { | ||
error | ||
exitCode ExitCode | ||
} | ||
|
||
func (wh withExitCode) Unwrap() error { | ||
return wh.error | ||
} | ||
|
||
func (wh withExitCode) ExitCode() ExitCode { | ||
return wh.exitCode | ||
} | ||
|
||
var _ HasExitCode = withExitCode{} |
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,39 @@ | ||
/* | ||
* | ||
* k6 - a next-generation load testing tool | ||
* Copyright (C) 2021 Load Impact | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Affero General Public License as | ||
* published by the Free Software Foundation, either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
// Package exitcodes contains the constants representing possible k6 exit error codes. | ||
//nolint: golint | ||
package exitcodes | ||
|
||
import "go.k6.io/k6/errext" | ||
|
||
const ( | ||
CloudTestRunFailed errext.ExitCode = 97 // This used to be 99 before k6 v0.33.0 | ||
CloudFailedToGetProgress errext.ExitCode = 98 | ||
ThresholdsHaveFailed errext.ExitCode = 99 | ||
SetupTimeout errext.ExitCode = 100 | ||
TeardownTimeout errext.ExitCode = 101 | ||
GenericTimeout errext.ExitCode = 102 // TODO: remove? | ||
GenericEngine errext.ExitCode = 103 | ||
InvalidConfig errext.ExitCode = 104 | ||
ExternalAbort errext.ExitCode = 105 | ||
CannotStartRESTAPI errext.ExitCode = 106 | ||
ScriptException errext.ExitCode = 107 | ||
) |
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,63 @@ | ||
/* | ||
* | ||
* k6 - a next-generation load testing tool | ||
* Copyright (C) 2021 Load Impact | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU Affero General Public License as | ||
* published by the Free Software Foundation, either version 3 of the | ||
* License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU Affero General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Affero General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
* | ||
*/ | ||
|
||
package errext | ||
|
||
import "errors" | ||
|
||
// HasHint is a wrapper around an error with an attached user hint. These hints | ||
// can be used to give extra human-readable information about the error, | ||
// including suggestions on how the error can be fixed. | ||
type HasHint interface { | ||
error | ||
Hint() string | ||
} | ||
|
||
// WithHint is a helper that can attach a hint to the given error. If there is | ||
// no error (i.e. the given error is nil), it won't do anything. If the given | ||
// error already had a hint, this helper will wrap it so that the new hint is | ||
// "new hint (old hint)". | ||
func WithHint(err error, hint string) error { | ||
if err == nil { | ||
// No error, do nothing | ||
return nil | ||
} | ||
var oldhint HasHint | ||
if errors.As(err, &oldhint) { | ||
// The given error already had a hint, wrap it | ||
hint = hint + " (" + oldhint.Hint() + ")" | ||
} | ||
return withHint{err, hint} | ||
} | ||
|
||
type withHint struct { | ||
error | ||
hint string | ||
} | ||
|
||
func (wh withHint) Unwrap() error { | ||
return wh.error | ||
} | ||
|
||
func (wh withHint) Hint() string { | ||
return wh.hint | ||
} | ||
|
||
var _ HasHint = withHint{} |