From 195568017ad6d722a226d0dfcf0183a481cddce3 Mon Sep 17 00:00:00 2001 From: Stephen J Day Date: Thu, 20 Nov 2014 19:15:09 -0800 Subject: [PATCH] Update error declarations and add missing test This updates API error codes to coincide with changes to the proposal. Mostly, redundant error codes were merged and missing ones were added. The set in the main errors.go file will flow back into the specification. A test case has been added to ensure ErrorCodeUnknown is included in marshaled json. --- errors.go | 43 +++++++++++++++++++++++++++---------------- errors_test.go | 17 +++++++++++++++-- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/errors.go b/errors.go index 9a28e5b6..e2f16ba0 100644 --- a/errors.go +++ b/errors.go @@ -17,20 +17,14 @@ const ( // The following errors can happen during a layer upload. - // ErrorCodeInvalidChecksum is returned when uploading a layer if the - // provided checksum does not match the layer contents. - ErrorCodeInvalidChecksum + // ErrorCodeInvalidDigest is returned when uploading a layer if the + // provided digest does not match the layer contents. + ErrorCodeInvalidDigest // ErrorCodeInvalidLength is returned when uploading a layer if the provided // length does not match the content length. ErrorCodeInvalidLength - // ErrorCodeInvalidTarsum is returned when the provided tarsum does not - // match the computed tarsum of the contents. - ErrorCodeInvalidTarsum - - // The following errors can happen during manifest upload. - // ErrorCodeInvalidName is returned when the name in the manifest does not // match the provided name. ErrorCodeInvalidName @@ -47,6 +41,9 @@ const ( // nonexistent layer. ErrorCodeUnknownLayer + // ErrorCodeUnknownLayerUpload is returned when an upload is accessed. + ErrorCodeUnknownLayerUpload + // ErrorCodeUntrustedSignature is returned when the manifest is signed by an // untrusted source. ErrorCodeUntrustedSignature @@ -54,25 +51,25 @@ const ( var errorCodeStrings = map[ErrorCode]string{ ErrorCodeUnknown: "UNKNOWN", - ErrorCodeInvalidChecksum: "INVALID_CHECKSUM", + ErrorCodeInvalidDigest: "INVALID_DIGEST", ErrorCodeInvalidLength: "INVALID_LENGTH", - ErrorCodeInvalidTarsum: "INVALID_TARSUM", ErrorCodeInvalidName: "INVALID_NAME", ErrorCodeInvalidTag: "INVALID_TAG", ErrorCodeUnverifiedManifest: "UNVERIFIED_MANIFEST", ErrorCodeUnknownLayer: "UNKNOWN_LAYER", + ErrorCodeUnknownLayerUpload: "UNKNOWN_LAYER_UPLOAD", ErrorCodeUntrustedSignature: "UNTRUSTED_SIGNATURE", } var errorCodesMessages = map[ErrorCode]string{ ErrorCodeUnknown: "unknown error", - ErrorCodeInvalidChecksum: "provided checksum did not match uploaded content", + ErrorCodeInvalidDigest: "provided digest did not match uploaded content", ErrorCodeInvalidLength: "provided length did not match content length", - ErrorCodeInvalidTarsum: "provided tarsum did not match binary content", ErrorCodeInvalidName: "Manifest name did not match URI", ErrorCodeInvalidTag: "Manifest tag did not match URI", ErrorCodeUnverifiedManifest: "Manifest failed signature validation", ErrorCodeUnknownLayer: "Referenced layer not available", + ErrorCodeUnknownLayerUpload: "cannot resume unknown layer upload", ErrorCodeUntrustedSignature: "Manifest signed by untrusted source", } @@ -136,7 +133,7 @@ func (ec *ErrorCode) UnmarshalText(text []byte) error { // Error provides a wrapper around ErrorCode with extra Details provided. type Error struct { - Code ErrorCode `json:"code,omitempty"` + Code ErrorCode `json:"code"` Message string `json:"message,omitempty"` Detail interface{} `json:"detail,omitempty"` } @@ -144,7 +141,7 @@ type Error struct { // Error returns a human readable representation of the error. func (e Error) Error() string { return fmt.Sprintf("%s: %s", - strings.Title(strings.Replace(e.Code.String(), "_", " ", -1)), + strings.ToLower(strings.Replace(e.Code.String(), "_", " ", -1)), e.Message) } @@ -167,6 +164,10 @@ func (errs *Errors) Push(code ErrorCode, details ...interface{}) { detail = details[0] } + if err, ok := detail.(error); ok { + detail = err.Error() + } + errs.PushErr(Error{ Code: code, Message: code.Message(), @@ -180,7 +181,7 @@ func (errs *Errors) PushErr(err error) { } func (errs *Errors) Error() string { - switch len(errs.Errors) { + switch errs.Len() { case 0: return "" case 1: @@ -194,6 +195,16 @@ func (errs *Errors) Error() string { } } +// Clear clears the errors. +func (errs *Errors) Clear() { + errs.Errors = errs.Errors[:0] +} + +// Len returns the current number of errors. +func (errs *Errors) Len() int { + return len(errs.Errors) +} + // DetailUnknownLayer provides detail for unknown layer errors, returned by // image manifest push for layers that are not yet transferred. This intended // to only be used on the backend to return detail for this specific error. diff --git a/errors_test.go b/errors_test.go index e6ec72f9..709b6ced 100644 --- a/errors_test.go +++ b/errors_test.go @@ -56,7 +56,7 @@ func TestErrorCodes(t *testing.T) { func TestErrorsManagement(t *testing.T) { var errs Errors - errs.Push(ErrorCodeInvalidChecksum) + errs.Push(ErrorCodeInvalidDigest) var detail DetailUnknownLayer detail.Unknown.BlobSum = "sometestblobsumdoesntmatter" @@ -69,7 +69,20 @@ func TestErrorsManagement(t *testing.T) { t.Fatalf("error marashaling errors: %v", err) } - expectedJSON := "{\"errors\":[{\"code\":\"INVALID_CHECKSUM\",\"message\":\"provided checksum did not match uploaded content\"},{\"code\":\"UNKNOWN_LAYER\",\"message\":\"Referenced layer not available\",\"detail\":{\"unknown\":{\"blobSum\":\"sometestblobsumdoesntmatter\"}}}]}" + expectedJSON := "{\"errors\":[{\"code\":\"INVALID_DIGEST\",\"message\":\"provided digest did not match uploaded content\"},{\"code\":\"UNKNOWN_LAYER\",\"message\":\"Referenced layer not available\",\"detail\":{\"unknown\":{\"blobSum\":\"sometestblobsumdoesntmatter\"}}}]}" + + if string(p) != expectedJSON { + t.Fatalf("unexpected json: %q != %q", string(p), expectedJSON) + } + + errs.Clear() + errs.Push(ErrorCodeUnknown) + expectedJSON = "{\"errors\":[{\"code\":\"UNKNOWN\",\"message\":\"unknown error\"}]}" + p, err = json.Marshal(errs) + + if err != nil { + t.Fatalf("error marashaling errors: %v", err) + } if string(p) != expectedJSON { t.Fatalf("unexpected json: %q != %q", string(p), expectedJSON)