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.
pull/4/head
Stephen J Day 2014-11-20 19:15:09 -08:00
parent 3f479b62b4
commit 195568017a
2 changed files with 42 additions and 18 deletions

View File

@ -17,20 +17,14 @@ const (
// The following errors can happen during a layer upload. // The following errors can happen during a layer upload.
// ErrorCodeInvalidChecksum is returned when uploading a layer if the // ErrorCodeInvalidDigest is returned when uploading a layer if the
// provided checksum does not match the layer contents. // provided digest does not match the layer contents.
ErrorCodeInvalidChecksum ErrorCodeInvalidDigest
// ErrorCodeInvalidLength is returned when uploading a layer if the provided // ErrorCodeInvalidLength is returned when uploading a layer if the provided
// length does not match the content length. // length does not match the content length.
ErrorCodeInvalidLength 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 // ErrorCodeInvalidName is returned when the name in the manifest does not
// match the provided name. // match the provided name.
ErrorCodeInvalidName ErrorCodeInvalidName
@ -47,6 +41,9 @@ const (
// nonexistent layer. // nonexistent layer.
ErrorCodeUnknownLayer ErrorCodeUnknownLayer
// ErrorCodeUnknownLayerUpload is returned when an upload is accessed.
ErrorCodeUnknownLayerUpload
// ErrorCodeUntrustedSignature is returned when the manifest is signed by an // ErrorCodeUntrustedSignature is returned when the manifest is signed by an
// untrusted source. // untrusted source.
ErrorCodeUntrustedSignature ErrorCodeUntrustedSignature
@ -54,25 +51,25 @@ const (
var errorCodeStrings = map[ErrorCode]string{ var errorCodeStrings = map[ErrorCode]string{
ErrorCodeUnknown: "UNKNOWN", ErrorCodeUnknown: "UNKNOWN",
ErrorCodeInvalidChecksum: "INVALID_CHECKSUM", ErrorCodeInvalidDigest: "INVALID_DIGEST",
ErrorCodeInvalidLength: "INVALID_LENGTH", ErrorCodeInvalidLength: "INVALID_LENGTH",
ErrorCodeInvalidTarsum: "INVALID_TARSUM",
ErrorCodeInvalidName: "INVALID_NAME", ErrorCodeInvalidName: "INVALID_NAME",
ErrorCodeInvalidTag: "INVALID_TAG", ErrorCodeInvalidTag: "INVALID_TAG",
ErrorCodeUnverifiedManifest: "UNVERIFIED_MANIFEST", ErrorCodeUnverifiedManifest: "UNVERIFIED_MANIFEST",
ErrorCodeUnknownLayer: "UNKNOWN_LAYER", ErrorCodeUnknownLayer: "UNKNOWN_LAYER",
ErrorCodeUnknownLayerUpload: "UNKNOWN_LAYER_UPLOAD",
ErrorCodeUntrustedSignature: "UNTRUSTED_SIGNATURE", ErrorCodeUntrustedSignature: "UNTRUSTED_SIGNATURE",
} }
var errorCodesMessages = map[ErrorCode]string{ var errorCodesMessages = map[ErrorCode]string{
ErrorCodeUnknown: "unknown error", 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", ErrorCodeInvalidLength: "provided length did not match content length",
ErrorCodeInvalidTarsum: "provided tarsum did not match binary content",
ErrorCodeInvalidName: "Manifest name did not match URI", ErrorCodeInvalidName: "Manifest name did not match URI",
ErrorCodeInvalidTag: "Manifest tag did not match URI", ErrorCodeInvalidTag: "Manifest tag did not match URI",
ErrorCodeUnverifiedManifest: "Manifest failed signature validation", ErrorCodeUnverifiedManifest: "Manifest failed signature validation",
ErrorCodeUnknownLayer: "Referenced layer not available", ErrorCodeUnknownLayer: "Referenced layer not available",
ErrorCodeUnknownLayerUpload: "cannot resume unknown layer upload",
ErrorCodeUntrustedSignature: "Manifest signed by untrusted source", 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. // Error provides a wrapper around ErrorCode with extra Details provided.
type Error struct { type Error struct {
Code ErrorCode `json:"code,omitempty"` Code ErrorCode `json:"code"`
Message string `json:"message,omitempty"` Message string `json:"message,omitempty"`
Detail interface{} `json:"detail,omitempty"` Detail interface{} `json:"detail,omitempty"`
} }
@ -144,7 +141,7 @@ type Error struct {
// Error returns a human readable representation of the error. // Error returns a human readable representation of the error.
func (e Error) Error() string { func (e Error) Error() string {
return fmt.Sprintf("%s: %s", return fmt.Sprintf("%s: %s",
strings.Title(strings.Replace(e.Code.String(), "_", " ", -1)), strings.ToLower(strings.Replace(e.Code.String(), "_", " ", -1)),
e.Message) e.Message)
} }
@ -167,6 +164,10 @@ func (errs *Errors) Push(code ErrorCode, details ...interface{}) {
detail = details[0] detail = details[0]
} }
if err, ok := detail.(error); ok {
detail = err.Error()
}
errs.PushErr(Error{ errs.PushErr(Error{
Code: code, Code: code,
Message: code.Message(), Message: code.Message(),
@ -180,7 +181,7 @@ func (errs *Errors) PushErr(err error) {
} }
func (errs *Errors) Error() string { func (errs *Errors) Error() string {
switch len(errs.Errors) { switch errs.Len() {
case 0: case 0:
return "<nil>" return "<nil>"
case 1: 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 // DetailUnknownLayer provides detail for unknown layer errors, returned by
// image manifest push for layers that are not yet transferred. This intended // 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. // to only be used on the backend to return detail for this specific error.

View File

@ -56,7 +56,7 @@ func TestErrorCodes(t *testing.T) {
func TestErrorsManagement(t *testing.T) { func TestErrorsManagement(t *testing.T) {
var errs Errors var errs Errors
errs.Push(ErrorCodeInvalidChecksum) errs.Push(ErrorCodeInvalidDigest)
var detail DetailUnknownLayer var detail DetailUnknownLayer
detail.Unknown.BlobSum = "sometestblobsumdoesntmatter" detail.Unknown.BlobSum = "sometestblobsumdoesntmatter"
@ -69,7 +69,20 @@ func TestErrorsManagement(t *testing.T) {
t.Fatalf("error marashaling errors: %v", err) 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 { if string(p) != expectedJSON {
t.Fatalf("unexpected json: %q != %q", string(p), expectedJSON) t.Fatalf("unexpected json: %q != %q", string(p), expectedJSON)