Pass original invalid version storage error details into standardized errors

Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
This commit is contained in:
Riyaz Faizullabhoy 2016-01-11 13:58:22 -08:00
parent a60f228189
commit 8d0ff6c996
3 changed files with 51 additions and 0 deletions

View File

@ -44,6 +44,12 @@ var (
Description: "An error occurred when attempting to apply an update at the storage layer.",
HTTPStatusCode: http.StatusInternalServerError,
})
ErrOldVersion = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "VERSION",
Message: "A newer version of metadata is already available.",
Description: "A newer version of the repository's metadata is already available in storage.",
HTTPStatusCode: http.StatusBadRequest,
})
ErrMetadataNotFound = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "METADATA_NOT_FOUND",
Message: "You have requested metadata that does not exist.",

View File

@ -96,6 +96,11 @@ func atomicUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Req
}
err = store.UpdateMany(gun, updates)
if err != nil {
// If we have an old version error, surface to user with error code
if _, ok := err.(storage.ErrOldVersion); ok {
return errors.ErrOldVersion.WithDetail(err)
}
// More generic storage update error, possibly due to attempted rollback
return errors.ErrUpdating.WithDetail(nil)
}
return nil

View File

@ -385,3 +385,43 @@ func TestAtomicUpdateNonValidationFailureNotPropagated(t *testing.T) {
assert.Equal(t, errors.ErrInvalidUpdate, errorObj.Code)
assert.Nil(t, errorObj.Detail)
}
type invalidVersionStore struct {
storage.MemStorage
}
func (s *invalidVersionStore) UpdateMany(_ string, _ []storage.MetaUpdate) error {
return storage.ErrOldVersion{}
}
// a non-validation failure, such as the storage failing, will be propagated
// as a detail in the error (which gets serialized as the body of the response)
func TestAtomicUpdateVersionErrorPropagated(t *testing.T) {
metaStore := storage.NewMemStorage()
gun := "testGUN"
vars := map[string]string{"imageName": gun}
kdb, repo, cs := testutils.EmptyRepo()
copyTimestampKey(t, kdb, metaStore, gun)
state := handlerState{store: &invalidVersionStore{*metaStore}, crypto: cs}
r, tg, sn, ts, err := testutils.Sign(repo)
assert.NoError(t, err)
rs, tgs, sns, _, err := testutils.Serialize(r, tg, sn, ts)
assert.NoError(t, err)
req, err := store.NewMultiPartMetaRequest("", map[string][]byte{
data.CanonicalRootRole: rs,
data.CanonicalTargetsRole: tgs,
data.CanonicalSnapshotRole: sns,
})
rw := httptest.NewRecorder()
err = atomicUpdateHandler(getContext(state), rw, req, vars)
assert.Error(t, err)
errorObj, ok := err.(errcode.Error)
assert.True(t, ok, "Expected an errcode.Error, got %v", err)
assert.Equal(t, errors.ErrOldVersion, errorObj.Code)
assert.Equal(t, storage.ErrOldVersion{}, errorObj.Detail)
}