mirror of https://github.com/docker/docs.git
Move validation errors to tuf, since that is the expected server interface.
Also make the validation errors serializable as JSON. Signed-off-by: Ying Li <ying.li@docker.com>
This commit is contained in:
parent
4208945fc1
commit
3aa13e6645
|
@ -1,56 +0,0 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// VALIDATION ERRORS:
|
||||
|
||||
// ErrValidation represents a general validation error
|
||||
type ErrValidation struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
func (err ErrValidation) Error() string {
|
||||
return fmt.Sprintf("An error occurred during validation: %s", err.msg)
|
||||
}
|
||||
|
||||
// ErrBadHierarchy represents a missing snapshot at this current time.
|
||||
// When delegations are implemented it will also represent a missing
|
||||
// delegation parent
|
||||
type ErrBadHierarchy struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
func (err ErrBadHierarchy) Error() string {
|
||||
return fmt.Sprintf("Hierarchy of updates in incorrect: %s", err.msg)
|
||||
}
|
||||
|
||||
// ErrBadRoot represents a failure validating the root
|
||||
type ErrBadRoot struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
func (err ErrBadRoot) Error() string {
|
||||
return fmt.Sprintf("The root being updated is invalid: %s", err.msg)
|
||||
}
|
||||
|
||||
// ErrBadTargets represents a failure to validate a targets (incl delegations)
|
||||
type ErrBadTargets struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
func (err ErrBadTargets) Error() string {
|
||||
return fmt.Sprintf("The targets being updated is invalid: %s", err.msg)
|
||||
}
|
||||
|
||||
// ErrBadSnapshot represents a failure to validate the snapshot
|
||||
type ErrBadSnapshot struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
func (err ErrBadSnapshot) Error() string {
|
||||
return fmt.Sprintf("The snapshot being updated is invalid: %s", err.msg)
|
||||
}
|
||||
|
||||
// END VALIDATION ERRORS
|
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/docker/notary/tuf/keys"
|
||||
"github.com/docker/notary/tuf/signed"
|
||||
"github.com/docker/notary/tuf/utils"
|
||||
"github.com/docker/notary/tuf/validation"
|
||||
)
|
||||
|
||||
// validateUpload checks that the updates being pushed
|
||||
|
@ -49,26 +50,26 @@ func validateUpdate(cs signed.CryptoService, gun string, updates []storage.MetaU
|
|||
// against a previous root
|
||||
if root, err = validateRoot(gun, oldRootJSON, rootUpdate.Data, store); err != nil {
|
||||
logrus.Error("ErrBadRoot: ", err.Error())
|
||||
return nil, ErrBadRoot{msg: err.Error()}
|
||||
return nil, validation.ErrBadRoot{Msg: err.Error()}
|
||||
}
|
||||
|
||||
// setting root will update keys db
|
||||
if err = repo.SetRoot(root); err != nil {
|
||||
logrus.Error("ErrValidation: ", err.Error())
|
||||
return nil, ErrValidation{msg: err.Error()}
|
||||
return nil, validation.ErrValidation{Msg: err.Error()}
|
||||
}
|
||||
logrus.Debug("Successfully validated root")
|
||||
} else {
|
||||
if oldRootJSON == nil {
|
||||
return nil, ErrValidation{msg: "no pre-existing root and no root provided in update."}
|
||||
return nil, validation.ErrValidation{Msg: "no pre-existing root and no root provided in update."}
|
||||
}
|
||||
parsedOldRoot := &data.SignedRoot{}
|
||||
if err := json.Unmarshal(oldRootJSON, parsedOldRoot); err != nil {
|
||||
return nil, ErrValidation{msg: "pre-existing root is corrupted and no root provided in update."}
|
||||
return nil, validation.ErrValidation{Msg: "pre-existing root is corrupted and no root provided in update."}
|
||||
}
|
||||
if err = repo.SetRoot(parsedOldRoot); err != nil {
|
||||
logrus.Error("ErrValidation: ", err.Error())
|
||||
return nil, ErrValidation{msg: err.Error()}
|
||||
return nil, validation.ErrValidation{Msg: err.Error()}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,7 +78,7 @@ func validateUpdate(cs signed.CryptoService, gun string, updates []storage.MetaU
|
|||
if _, ok := roles[targetsRole]; ok {
|
||||
if t, err = validateTargets(targetsRole, roles, kdb); err != nil {
|
||||
logrus.Error("ErrBadTargets: ", err.Error())
|
||||
return nil, ErrBadTargets{msg: err.Error()}
|
||||
return nil, validation.ErrBadTargets{Msg: err.Error()}
|
||||
}
|
||||
repo.SetTargets(targetsRole, t)
|
||||
}
|
||||
|
@ -100,7 +101,7 @@ func validateUpdate(cs signed.CryptoService, gun string, updates []storage.MetaU
|
|||
|
||||
if err := validateSnapshot(snapshotRole, oldSnap, roles[snapshotRole], roles, kdb); err != nil {
|
||||
logrus.Error("ErrBadSnapshot: ", err.Error())
|
||||
return nil, ErrBadSnapshot{msg: err.Error()}
|
||||
return nil, validation.ErrBadSnapshot{Msg: err.Error()}
|
||||
}
|
||||
logrus.Debug("Successfully validated snapshot")
|
||||
} else {
|
||||
|
@ -154,12 +155,12 @@ func prepRepo(gun string, repo *tuf.Repo, store storage.MetaStore) error {
|
|||
func generateSnapshot(gun string, kdb *keys.KeyDB, repo *tuf.Repo, store storage.MetaStore) (*storage.MetaUpdate, error) {
|
||||
role := kdb.GetRole(data.RoleName(data.CanonicalSnapshotRole))
|
||||
if role == nil {
|
||||
return nil, ErrBadRoot{msg: "root did not include snapshot role"}
|
||||
return nil, validation.ErrBadRoot{Msg: "root did not include snapshot role"}
|
||||
}
|
||||
|
||||
algo, keyBytes, err := store.GetKey(gun, data.CanonicalSnapshotRole)
|
||||
if role == nil {
|
||||
return nil, ErrBadRoot{msg: "root did not include snapshot key"}
|
||||
return nil, validation.ErrBadRoot{Msg: "root did not include snapshot key"}
|
||||
}
|
||||
foundK := data.NewPublicKey(algo, keyBytes)
|
||||
|
||||
|
@ -171,7 +172,7 @@ func generateSnapshot(gun string, kdb *keys.KeyDB, repo *tuf.Repo, store storage
|
|||
}
|
||||
}
|
||||
if !validKey {
|
||||
return nil, ErrBadHierarchy{msg: "no snapshot was included in update and server does not hold current snapshot key for repository"}
|
||||
return nil, validation.ErrBadHierarchy{Msg: "no snapshot was included in update and server does not hold current snapshot key for repository"}
|
||||
}
|
||||
|
||||
currentJSON, err := store.GetCurrent(gun, data.CanonicalSnapshotRole)
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/docker/notary/tuf/keys"
|
||||
"github.com/docker/notary/tuf/signed"
|
||||
"github.com/docker/notary/tuf/testutils"
|
||||
"github.com/docker/notary/tuf/validation"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/docker/notary/server/storage"
|
||||
|
@ -211,7 +212,7 @@ func TestValidateNoRoot(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrValidation{}, err)
|
||||
assert.IsType(t, validation.ErrValidation{}, err)
|
||||
}
|
||||
|
||||
func TestValidateSnapshotMissing(t *testing.T) {
|
||||
|
@ -228,7 +229,7 @@ func TestValidateSnapshotMissing(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadHierarchy{}, err)
|
||||
assert.IsType(t, validation.ErrBadHierarchy{}, err)
|
||||
}
|
||||
|
||||
func TestValidateSnapshotGenerateNoPrev(t *testing.T) {
|
||||
|
@ -463,7 +464,7 @@ func TestValidateRootNoTimestampKey(t *testing.T) {
|
|||
// do not copy the targets key to the storage, and try to update the root
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadRoot{}, err)
|
||||
assert.IsType(t, validation.ErrBadRoot{}, err)
|
||||
|
||||
// there should still be no timestamp keys - one should not have been
|
||||
// created
|
||||
|
@ -493,7 +494,7 @@ func TestValidateRootInvalidTimestampKey(t *testing.T) {
|
|||
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadRoot{}, err)
|
||||
assert.IsType(t, validation.ErrBadRoot{}, err)
|
||||
}
|
||||
|
||||
// If the timestamp role has a threshold > 1, validation fails.
|
||||
|
@ -542,7 +543,7 @@ func TestValidateRootInvalidZeroThreshold(t *testing.T) {
|
|||
|
||||
// ### Role missing negative tests ###
|
||||
// These tests remove a role from the Root file and
|
||||
// check for a ErrBadRoot
|
||||
// check for a validation.ErrBadRoot
|
||||
func TestValidateRootRoleMissing(t *testing.T) {
|
||||
kdb, repo, cs := testutils.EmptyRepo()
|
||||
store := storage.NewMemStorage()
|
||||
|
@ -559,7 +560,7 @@ func TestValidateRootRoleMissing(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadRoot{}, err)
|
||||
assert.IsType(t, validation.ErrBadRoot{}, err)
|
||||
}
|
||||
|
||||
func TestValidateTargetsRoleMissing(t *testing.T) {
|
||||
|
@ -578,7 +579,7 @@ func TestValidateTargetsRoleMissing(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadRoot{}, err)
|
||||
assert.IsType(t, validation.ErrBadRoot{}, err)
|
||||
}
|
||||
|
||||
func TestValidateSnapshotRoleMissing(t *testing.T) {
|
||||
|
@ -597,7 +598,7 @@ func TestValidateSnapshotRoleMissing(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadRoot{}, err)
|
||||
assert.IsType(t, validation.ErrBadRoot{}, err)
|
||||
}
|
||||
|
||||
// ### End role missing negative tests ###
|
||||
|
@ -622,7 +623,7 @@ func TestValidateRootSigMissing(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadRoot{}, err)
|
||||
assert.IsType(t, validation.ErrBadRoot{}, err)
|
||||
}
|
||||
|
||||
func TestValidateTargetsSigMissing(t *testing.T) {
|
||||
|
@ -642,7 +643,7 @@ func TestValidateTargetsSigMissing(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadTargets{}, err)
|
||||
assert.IsType(t, validation.ErrBadTargets{}, err)
|
||||
}
|
||||
|
||||
func TestValidateSnapshotSigMissing(t *testing.T) {
|
||||
|
@ -662,7 +663,7 @@ func TestValidateSnapshotSigMissing(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadSnapshot{}, err)
|
||||
assert.IsType(t, validation.ErrBadSnapshot{}, err)
|
||||
}
|
||||
|
||||
// ### End signature missing negative tests ###
|
||||
|
@ -685,7 +686,7 @@ func TestValidateRootCorrupt(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadRoot{}, err)
|
||||
assert.IsType(t, validation.ErrBadRoot{}, err)
|
||||
}
|
||||
|
||||
func TestValidateTargetsCorrupt(t *testing.T) {
|
||||
|
@ -705,7 +706,7 @@ func TestValidateTargetsCorrupt(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadTargets{}, err)
|
||||
assert.IsType(t, validation.ErrBadTargets{}, err)
|
||||
}
|
||||
|
||||
func TestValidateSnapshotCorrupt(t *testing.T) {
|
||||
|
@ -725,7 +726,7 @@ func TestValidateSnapshotCorrupt(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadSnapshot{}, err)
|
||||
assert.IsType(t, validation.ErrBadSnapshot{}, err)
|
||||
}
|
||||
|
||||
// ### End corrupted metadata negative tests ###
|
||||
|
@ -752,7 +753,7 @@ func TestValidateRootModifiedSize(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadRoot{}, err)
|
||||
assert.IsType(t, validation.ErrBadRoot{}, err)
|
||||
}
|
||||
|
||||
func TestValidateTargetsModifiedSize(t *testing.T) {
|
||||
|
@ -773,7 +774,7 @@ func TestValidateTargetsModifiedSize(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadSnapshot{}, err)
|
||||
assert.IsType(t, validation.ErrBadSnapshot{}, err)
|
||||
}
|
||||
|
||||
// ### End snapshot size mismatch negative tests ###
|
||||
|
@ -801,7 +802,7 @@ func TestValidateRootModifiedHash(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadSnapshot{}, err)
|
||||
assert.IsType(t, validation.ErrBadSnapshot{}, err)
|
||||
}
|
||||
|
||||
func TestValidateTargetsModifiedHash(t *testing.T) {
|
||||
|
@ -826,7 +827,7 @@ func TestValidateTargetsModifiedHash(t *testing.T) {
|
|||
copyTimestampKey(t, kdb, store, "testGUN")
|
||||
_, err = validateUpdate(cs, "testGUN", updates, store)
|
||||
assert.Error(t, err)
|
||||
assert.IsType(t, ErrBadSnapshot{}, err)
|
||||
assert.IsType(t, validation.ErrBadSnapshot{}, err)
|
||||
}
|
||||
|
||||
// ### End snapshot hash mismatch negative tests ###
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
package validation
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// VALIDATION ERRORS
|
||||
|
||||
// ErrValidation represents a general validation error
|
||||
type ErrValidation struct {
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (err ErrValidation) Error() string {
|
||||
return fmt.Sprintf("An error occurred during validation: %s", err.Msg)
|
||||
}
|
||||
|
||||
// ErrBadHierarchy represents missing metadata. Currently: a missing snapshot
|
||||
// at this current time. When delegations are implemented it will also
|
||||
// represent a missing delegation parent
|
||||
type ErrBadHierarchy struct {
|
||||
Missing string
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (err ErrBadHierarchy) Error() string {
|
||||
return fmt.Sprintf("Metadata hierarchy is incomplete: %s", err.Msg)
|
||||
}
|
||||
|
||||
// ErrBadRoot represents a failure validating the root
|
||||
type ErrBadRoot struct {
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (err ErrBadRoot) Error() string {
|
||||
return fmt.Sprintf("The root metadata is invalid: %s", err.Msg)
|
||||
}
|
||||
|
||||
// ErrBadTargets represents a failure to validate a targets (incl delegations)
|
||||
type ErrBadTargets struct {
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (err ErrBadTargets) Error() string {
|
||||
return fmt.Sprintf("The targets metadata is invalid: %s", err.Msg)
|
||||
}
|
||||
|
||||
// ErrBadSnapshot represents a failure to validate the snapshot
|
||||
type ErrBadSnapshot struct {
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (err ErrBadSnapshot) Error() string {
|
||||
return fmt.Sprintf("The snapshot metadata is invalid: %s", err.Msg)
|
||||
}
|
||||
|
||||
// END VALIDATION ERRORS
|
||||
|
||||
// SerializableError is a struct that can be used to serialize an error as JSON
|
||||
type SerializableError struct {
|
||||
Name string
|
||||
Error error
|
||||
}
|
||||
|
||||
// UnmarshalJSON attempts to unmarshal the error into the right type
|
||||
func (s *SerializableError) UnmarshalJSON(text []byte) (err error) {
|
||||
var x struct{ Name string }
|
||||
err = json.Unmarshal(text, &x)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var theError error
|
||||
switch x.Name {
|
||||
case "ErrValidation":
|
||||
var e struct{ Error ErrValidation }
|
||||
err = json.Unmarshal(text, &e)
|
||||
theError = e.Error
|
||||
case "ErrBadHierarchy":
|
||||
var e struct{ Error ErrBadHierarchy }
|
||||
err = json.Unmarshal(text, &e)
|
||||
theError = e.Error
|
||||
case "ErrBadRoot":
|
||||
var e struct{ Error ErrBadRoot }
|
||||
err = json.Unmarshal(text, &e)
|
||||
theError = e.Error
|
||||
case "ErrBadTargets":
|
||||
var e struct{ Error ErrBadTargets }
|
||||
err = json.Unmarshal(text, &e)
|
||||
theError = e.Error
|
||||
case "ErrBadSnapshot":
|
||||
var e struct{ Error ErrBadSnapshot }
|
||||
err = json.Unmarshal(text, &e)
|
||||
theError = e.Error
|
||||
default:
|
||||
err = fmt.Errorf("do not know how to unmarshall %s", x.Name)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
s.Name = x.Name
|
||||
s.Error = theError
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewSerializableError serializes one of the above errors into JSON
|
||||
func NewSerializableError(err error) (*SerializableError, error) {
|
||||
// make sure it's one of our errors
|
||||
var name string
|
||||
switch err.(type) {
|
||||
case ErrValidation:
|
||||
name = "ErrValidation"
|
||||
case ErrBadHierarchy:
|
||||
name = "ErrBadHierarchy"
|
||||
case ErrBadRoot:
|
||||
name = "ErrBadRoot"
|
||||
case ErrBadTargets:
|
||||
name = "ErrBadTargets"
|
||||
case ErrBadSnapshot:
|
||||
name = "ErrBadSnapshot"
|
||||
default:
|
||||
return nil, fmt.Errorf("does not support serializing non-validation errors")
|
||||
}
|
||||
return &SerializableError{Name: name, Error: err}, nil
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package validation
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// NewSerializableError errors if some random error is not returned
|
||||
func TestNewSerializableErrorNonValidationError(t *testing.T) {
|
||||
_, err := NewSerializableError(fmt.Errorf("not validation error"))
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
// NewSerializableError succeeds if a validation error is passed to it
|
||||
func TestNewSerializableErrorValidationError(t *testing.T) {
|
||||
vError := ErrValidation{"validation error"}
|
||||
s, err := NewSerializableError(vError)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "ErrValidation", s.Name)
|
||||
assert.Equal(t, vError, s.Error)
|
||||
}
|
||||
|
||||
// We can unmarshal a marshalled SerializableError
|
||||
func TestUnmarshalSerialiableErrorSuccessfully(t *testing.T) {
|
||||
origS, err := NewSerializableError(ErrBadHierarchy{Missing: "root", Msg: "badness"})
|
||||
assert.NoError(t, err)
|
||||
|
||||
b, err := json.Marshal(origS)
|
||||
assert.NoError(t, err)
|
||||
|
||||
jsonBytes := [][]byte{
|
||||
b,
|
||||
[]byte(`{"Name":"ErrBadHierarchy","Error":{"Missing":"root","Msg":"badness"}}`),
|
||||
}
|
||||
|
||||
for _, toUnmarshal := range jsonBytes {
|
||||
var newS SerializableError
|
||||
err = json.Unmarshal(toUnmarshal, &newS)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "ErrBadHierarchy", newS.Name)
|
||||
e, ok := newS.Error.(ErrBadHierarchy)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, "root", e.Missing)
|
||||
assert.Equal(t, "badness", e.Msg)
|
||||
}
|
||||
}
|
||||
|
||||
// If the name is unrecognized, unmarshalling will error
|
||||
func TestUnmarshalUnknownErrorName(t *testing.T) {
|
||||
origS := SerializableError{Name: "boop", Error: ErrBadRoot{"bad"}}
|
||||
b, err := json.Marshal(origS)
|
||||
assert.NoError(t, err)
|
||||
|
||||
var newS SerializableError
|
||||
err = json.Unmarshal(b, &newS)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
// If the error is unmarshallable, unmarshalling will error even if the name
|
||||
// is valid
|
||||
func TestUnmarshalInvalidError(t *testing.T) {
|
||||
var newS SerializableError
|
||||
err := json.Unmarshal([]byte(`{"Name": "ErrBadRoot", "Error": "meh"}`), &newS)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
// If there is no name, unmarshalling will error even if the error is valid
|
||||
func TestUnmarshalNoName(t *testing.T) {
|
||||
origS := SerializableError{Error: ErrBadRoot{"bad"}}
|
||||
b, err := json.Marshal(origS)
|
||||
assert.NoError(t, err)
|
||||
|
||||
var newS SerializableError
|
||||
err = json.Unmarshal(b, &newS)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestUnmarshalInvalidJSON(t *testing.T) {
|
||||
var newS SerializableError
|
||||
err := json.Unmarshal([]byte("{"), &newS)
|
||||
assert.Error(t, err)
|
||||
}
|
Loading…
Reference in New Issue