refactor: Storage driver errors

Small refactoring of storagedriver errors.
We change the Enclosed field to Detail and make sure
Errors get properly serialized to JSON.
We also add tests.

Signed-off-by: Milos Gajdos <milosthegajdos@gmail.com>
This commit is contained in:
Milos Gajdos 2023-10-18 10:02:21 +01:00
parent 915ad2d5a6
commit ea41722902
No known key found for this signature in database
3 changed files with 111 additions and 11 deletions

View file

@ -79,12 +79,10 @@ func (base *Base) setDriverName(e error) error {
actual.DriverName = base.StorageDriver.Name() actual.DriverName = base.StorageDriver.Name()
return actual return actual
default: default:
storageError := storagedriver.Error{ return storagedriver.Error{
DriverName: base.StorageDriver.Name(), DriverName: base.StorageDriver.Name(),
Enclosed: e, Detail: e,
} }
return storageError
} }
} }

View file

@ -0,0 +1,80 @@
package driver
import (
"encoding/json"
"errors"
"fmt"
"testing"
)
func TestErrorFormat(t *testing.T) {
drvName := "foo"
errMsg := "unexpected error"
e := Error{
DriverName: drvName,
Detail: errors.New(errMsg),
}
exp := fmt.Sprintf("%s: %s", drvName, errMsg)
if e.Error() != exp {
t.Errorf("expected: %s, got: %s", exp, e.Error())
}
b, err := json.Marshal(&e)
if err != nil {
t.Fatal(err)
}
expJson := `{"driver":"foo","detail":"unexpected error"}`
if gotJson := string(b); gotJson != expJson {
t.Fatalf("expected JSON: %s,\n got: %s", expJson, gotJson)
}
}
func TestErrors(t *testing.T) {
drvName := "foo"
testCases := []struct {
name string
errs Errors
exp string
expJson string
}{
{
name: "no details",
errs: Errors{DriverName: drvName},
exp: fmt.Sprintf("%s: <nil>", drvName),
expJson: `{"driver":"foo","details":[]}`,
},
{
name: "single detail",
errs: Errors{DriverName: drvName, Errs: []error{errors.New("err msg")}},
exp: fmt.Sprintf("%s: err msg", drvName),
expJson: `{"driver":"foo","details":["err msg"]}`,
},
{
name: "multiple details",
errs: Errors{DriverName: drvName, Errs: []error{errors.New("err msg1"), errors.New("err msg2")}},
exp: fmt.Sprintf("%s: errors:\nerr msg1\nerr msg2\n", drvName),
expJson: `{"driver":"foo","details":["err msg1","err msg2"]}`,
},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
if got := tc.errs.Error(); got != tc.exp {
t.Errorf("got error: %s, expected: %s", got, tc.exp)
}
b, err := json.Marshal(&tc.errs)
if err != nil {
t.Fatal(err)
}
if gotJson := string(b); gotJson != tc.expJson {
t.Errorf("expected JSON: %s,\n got: %s", tc.expJson, gotJson)
}
})
}
}

View file

@ -178,20 +178,20 @@ func (err InvalidOffsetError) Error() string {
// the driver type on which it occurred. // the driver type on which it occurred.
type Error struct { type Error struct {
DriverName string DriverName string
Enclosed error Detail error
} }
func (err Error) Error() string { func (err Error) Error() string {
return fmt.Sprintf("%s: %s", err.DriverName, err.Enclosed) return fmt.Sprintf("%s: %s", err.DriverName, err.Detail)
} }
func (err Error) MarshalJSON() ([]byte, error) { func (err Error) MarshalJSON() ([]byte, error) {
return json.Marshal(struct { return json.Marshal(struct {
DriverName string `json:"driver"` DriverName string `json:"driver"`
Enclosed string `json:"enclosed"` Detail string `json:"detail"`
}{ }{
DriverName: err.DriverName, DriverName: err.DriverName,
Enclosed: err.Enclosed.Error(), Detail: err.Detail.Error(),
}) })
} }
@ -207,14 +207,36 @@ var _ error = Errors{}
func (e Errors) Error() string { func (e Errors) Error() string {
switch len(e.Errs) { switch len(e.Errs) {
case 0: case 0:
return "<nil>" return fmt.Sprintf("%s: <nil>", e.DriverName)
case 1: case 1:
return e.Errs[0].Error() return fmt.Sprintf("%s: %s", e.DriverName, e.Errs[0].Error())
default: default:
msg := "errors:\n" msg := "errors:\n"
for _, err := range e.Errs { for _, err := range e.Errs {
msg += err.Error() + "\n" msg += err.Error() + "\n"
} }
return msg return fmt.Sprintf("%s: %s", e.DriverName, msg)
} }
} }
// MarshalJSON converts slice of errors into the format
// that is serializable by JSON.
func (e Errors) MarshalJSON() ([]byte, error) {
tmpErrs := struct {
DriverName string `json:"driver"`
Details []string `json:"details"`
}{
DriverName: e.DriverName,
}
if len(e.Errs) == 0 {
tmpErrs.Details = make([]string, 0)
return json.Marshal(tmpErrs)
}
for _, err := range e.Errs {
tmpErrs.Details = append(tmpErrs.Details, err.Error())
}
return json.Marshal(tmpErrs)
}