Skip to content

Commit 7992f01

Browse files
committed
specerror: Add NewRFCError and NewRFCErrorOrPanic
So we don't have to dance around with casting to extract structured information from NewError's returned error. Signed-off-by: W. Trevor King <[email protected]>
1 parent 9185c46 commit 7992f01

File tree

3 files changed

+41
-19
lines changed

3 files changed

+41
-19
lines changed

cmd/runtimetest/main.go

+4-6
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,13 @@ type complianceTester struct {
109109
}
110110

111111
func (c *complianceTester) Ok(test bool, condition specerror.Code, version string, description string) (rfcError *rfc2119.Error, err error) {
112-
err = specerror.NewError(condition, errors.New(description), version)
113-
runtimeError, ok := err.(*specerror.Error)
114-
if !ok {
115-
return nil, fmt.Errorf("cannot convert %v to a runtime-spec error", err)
112+
rfcError, err = specerror.NewRFCError(condition, errors.New(description), version)
113+
if err != nil {
114+
return nil, err
116115
}
117-
rfcError = &runtimeError.Err
118116
if test {
119117
c.harness.Pass(description)
120-
} else if runtimeError.Err.Level < c.complianceLevel {
118+
} else if rfcError.Level < c.complianceLevel {
121119
c.harness.Skip(1, description)
122120
} else {
123121
c.harness.Fail(description)

specerror/error.go

+30-7
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,34 @@ func (err *Error) Error() string {
6161
return err.Err.Error()
6262
}
6363

64+
// NewRFCError creates an rfc2119.Error referencing a spec violation.
65+
//
66+
// A version string (for the version of the spec that was violated)
67+
// must be set to get a working URL.
68+
func NewRFCError(code Code, err error, version string) (*rfc2119.Error, error) {
69+
template := ociErrors[code]
70+
reference, err2 := template.Reference(version)
71+
if err2 != nil {
72+
return nil, err2
73+
}
74+
return &rfc2119.Error{
75+
Level: template.Level,
76+
Reference: reference,
77+
Err: err,
78+
}, nil
79+
}
80+
81+
// NewRFCErrorOrPanic creates an rfc2119.Error referencing a spec
82+
// violation and panics on failure. This is handy for situations
83+
// where you can't be bothered to check NewRFCError for failure.
84+
func NewRFCErrorOrPanic(code Code, err error, version string) *rfc2119.Error {
85+
rfcError, err2 := NewRFCError(code, err, version)
86+
if err2 != nil {
87+
panic(err2.Error())
88+
}
89+
return rfcError
90+
}
91+
6492
// NewError creates an Error referencing a spec violation. The error
6593
// can be cast to an *Error for extracting structured information
6694
// about the level of the violation and a reference to the violated
@@ -69,17 +97,12 @@ func (err *Error) Error() string {
6997
// A version string (for the version of the spec that was violated)
7098
// must be set to get a working URL.
7199
func NewError(code Code, err error, version string) error {
72-
template := ociErrors[code]
73-
reference, err2 := template.Reference(version)
100+
rfcError, err2 := NewRFCError(code, err, version)
74101
if err2 != nil {
75102
return err2
76103
}
77104
return &Error{
78-
Err: rfc2119.Error{
79-
Level: template.Level,
80-
Reference: reference,
81-
Err: err,
82-
},
105+
Err: *rfcError,
83106
Code: code,
84107
}
85108
}

validation/state.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/mndrix/tap-go"
88
rspecs "github.com/opencontainers/runtime-spec/specs-go"
9+
rfc2119 "github.com/opencontainers/runtime-tools/error"
910
"github.com/opencontainers/runtime-tools/specerror"
1011
"github.com/opencontainers/runtime-tools/validation/util"
1112
uuid "github.com/satori/go.uuid"
@@ -26,11 +27,11 @@ func main() {
2627
id string
2728
action util.LifecycleAction
2829
errExpected bool
29-
err error
30+
err *rfc2119.Error
3031
}{
31-
{"", util.LifecycleActionNone, false, specerror.NewError(specerror.QueryWithoutIDGenError, fmt.Errorf("state MUST generate an error if it is not provided the ID of a container"), rspecs.Version)},
32-
{containerID, util.LifecycleActionNone, false, specerror.NewError(specerror.QueryNonExistGenError, fmt.Errorf("state MUST generate an error if a container that does not exist"), rspecs.Version)},
33-
{containerID, util.LifecycleActionCreate | util.LifecycleActionDelete, true, specerror.NewError(specerror.QueryStateImplement, fmt.Errorf("state MUST return the state of a container as specified in the State section"), rspecs.Version)},
32+
{"", util.LifecycleActionNone, false, specerror.NewRFCErrorOrPanic(specerror.QueryWithoutIDGenError, fmt.Errorf("state MUST generate an error if it is not provided the ID of a container"), rspecs.Version)},
33+
{containerID, util.LifecycleActionNone, false, specerror.NewRFCErrorOrPanic(specerror.QueryNonExistGenError, fmt.Errorf("state MUST generate an error if a container that does not exist"), rspecs.Version)},
34+
{containerID, util.LifecycleActionCreate | util.LifecycleActionDelete, true, specerror.NewRFCErrorOrPanic(specerror.QueryStateImplement, fmt.Errorf("state MUST return the state of a container as specified in the State section"), rspecs.Version)},
3435
}
3536

3637
for _, c := range cases {
@@ -57,9 +58,9 @@ func main() {
5758
continue
5859
}
5960

60-
t.Ok((err == nil) == c.errExpected, c.err.(*specerror.Error).Err.Err.Error())
61+
t.Ok((err == nil) == c.errExpected, c.err.Error())
6162
diagnostic := map[string]string{
62-
"reference": c.err.(*specerror.Error).Err.Reference,
63+
"reference": c.err.Reference,
6364
}
6465
if err != nil {
6566
diagnostic["error"] = err.Error()

0 commit comments

Comments
 (0)