catch basic notFound graph errors (#5052)
make the NotFound error comparison more lenient so that it catches the broader set of not-found error responses from graph. --- #### Does this PR need a docs update or release note? - [x] ⛔ No #### Type of change - [x] 🐛 Bugfix #### Test Plan - [x] ⚡ Unit test - [x] 💚 E2E
This commit is contained in:
parent
b8b1299514
commit
232ebba13a
@ -66,6 +66,7 @@ const (
|
|||||||
// @microsoft.graph.conflictBehavior=fail finds a conflicting file.
|
// @microsoft.graph.conflictBehavior=fail finds a conflicting file.
|
||||||
nameAlreadyExists errorCode = "nameAlreadyExists"
|
nameAlreadyExists errorCode = "nameAlreadyExists"
|
||||||
NotAllowed errorCode = "notAllowed"
|
NotAllowed errorCode = "notAllowed"
|
||||||
|
notFound errorCode = "NotFound"
|
||||||
noResolvedUsers errorCode = "noResolvedUsers"
|
noResolvedUsers errorCode = "noResolvedUsers"
|
||||||
QuotaExceeded errorCode = "ErrorQuotaExceeded"
|
QuotaExceeded errorCode = "ErrorQuotaExceeded"
|
||||||
RequestResourceNotFound errorCode = "Request_ResourceNotFound"
|
RequestResourceNotFound errorCode = "Request_ResourceNotFound"
|
||||||
@ -128,10 +129,10 @@ func stackWithCoreErr(ctx context.Context, err error, traceDepth int) error {
|
|||||||
err = clues.Stack(core.ErrResourceNotAccessible, err)
|
err = clues.Stack(core.ErrResourceNotAccessible, err)
|
||||||
case isErrInsufficientAuthorization(ode, err):
|
case isErrInsufficientAuthorization(ode, err):
|
||||||
err = clues.Stack(core.ErrInsufficientAuthorization, err)
|
err = clues.Stack(core.ErrInsufficientAuthorization, err)
|
||||||
case isErrNotFound(ode, err):
|
|
||||||
err = clues.Stack(core.ErrNotFound, err)
|
|
||||||
case isErrItemAlreadyExists(ode, err):
|
case isErrItemAlreadyExists(ode, err):
|
||||||
err = clues.Stack(core.ErrAlreadyExists, err)
|
err = clues.Stack(core.ErrAlreadyExists, err)
|
||||||
|
case isErrNotFound(ode, err):
|
||||||
|
err = clues.Stack(core.ErrNotFound, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return stackWithDepth(ctx, err, 1+traceDepth)
|
return stackWithDepth(ctx, err, 1+traceDepth)
|
||||||
@ -140,7 +141,8 @@ func stackWithCoreErr(ctx context.Context, err error, traceDepth int) error {
|
|||||||
// unexported categorizers, for use with stackWithCoreErr
|
// unexported categorizers, for use with stackWithCoreErr
|
||||||
|
|
||||||
func isErrApplicationThrottled(ode oDataErr, err error) bool {
|
func isErrApplicationThrottled(ode oDataErr, err error) bool {
|
||||||
return ode.hasErrorCode(err, ApplicationThrottled)
|
return ode.hasErrorCode(err, ApplicationThrottled) ||
|
||||||
|
ode.hasResponseCode(err, http.StatusTooManyRequests)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isErrInsufficientAuthorization(ode oDataErr, err error) bool {
|
func isErrInsufficientAuthorization(ode oDataErr, err error) bool {
|
||||||
@ -149,11 +151,13 @@ func isErrInsufficientAuthorization(ode oDataErr, err error) bool {
|
|||||||
|
|
||||||
func isErrNotFound(ode oDataErr, err error) bool {
|
func isErrNotFound(ode oDataErr, err error) bool {
|
||||||
return clues.HasLabel(err, LabelStatus(http.StatusNotFound)) ||
|
return clues.HasLabel(err, LabelStatus(http.StatusNotFound)) ||
|
||||||
|
ode.hasResponseCode(err, http.StatusNotFound) ||
|
||||||
ode.hasErrorCode(
|
ode.hasErrorCode(
|
||||||
err,
|
err,
|
||||||
ErrorItemNotFound,
|
ErrorItemNotFound,
|
||||||
ItemNotFound,
|
ItemNotFound,
|
||||||
syncFolderNotFound)
|
syncFolderNotFound,
|
||||||
|
notFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isErrUserNotFound(ode oDataErr, err error) bool {
|
func isErrUserNotFound(ode oDataErr, err error) bool {
|
||||||
@ -177,8 +181,7 @@ func isErrItemAlreadyExists(ode oDataErr, err error) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isErrResourceLocked(ode oDataErr, err error) bool {
|
func isErrResourceLocked(ode oDataErr, err error) bool {
|
||||||
return ode.hasInnerErrorCode(err, ResourceLocked) ||
|
return ode.hasErrorCode(err, ResourceLocked, NotAllowed) ||
|
||||||
ode.hasErrorCode(err, NotAllowed) ||
|
|
||||||
ode.errMessageMatchesAllFilters(
|
ode.errMessageMatchesAllFilters(
|
||||||
err,
|
err,
|
||||||
filters.In([]string{"the service principal for resource"}),
|
filters.In([]string{"the service principal for resource"}),
|
||||||
@ -285,7 +288,7 @@ func IsErrSiteNotFound(err error) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func IsErrSharingDisabled(err error) bool {
|
func IsErrSharingDisabled(err error) bool {
|
||||||
return parseODataErr(err).hasInnerErrorCode(err, sharingDisabled)
|
return parseODataErr(err).hasErrorCode(err, sharingDisabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -577,20 +580,9 @@ func (ode oDataErr) hasErrorCode(err error, codes ...errorCode) bool {
|
|||||||
cs[i] = string(c)
|
cs[i] = string(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
return filters.Equal(cs).Compare(ode.Main.Code)
|
eq := filters.Equal(cs)
|
||||||
}
|
|
||||||
|
|
||||||
func (ode oDataErr) hasInnerErrorCode(err error, codes ...errorCode) bool {
|
return eq.CompareAny(ode.Main.Code, ode.Inner.Code)
|
||||||
if !ode.isODataErr {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
cs := make([]string, len(codes))
|
|
||||||
for i, c := range codes {
|
|
||||||
cs[i] = string(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
return filters.Equal(cs).Compare(ode.Inner.Code)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// only use this as a last resort. Prefer the code or statuscode if possible.
|
// only use this as a last resort. Prefer the code or statuscode if possible.
|
||||||
|
|||||||
@ -83,6 +83,11 @@ func (suite *GraphErrorsUnitSuite) TestIsErrApplicationThrottled() {
|
|||||||
err: graphTD.ODataErr(string(ApplicationThrottled)),
|
err: graphTD.ODataErr(string(ApplicationThrottled)),
|
||||||
expect: assert.True,
|
expect: assert.True,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "too many requests resp status",
|
||||||
|
err: graphTD.ODataErrWithStatus(http.StatusTooManyRequests, "err"),
|
||||||
|
expect: assert.True,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, test := range table {
|
for _, test := range table {
|
||||||
suite.Run(test.name, func() {
|
suite.Run(test.name, func() {
|
||||||
@ -165,6 +170,7 @@ func (suite *GraphErrorsUnitSuite) TestIsErrNotFound() {
|
|||||||
table := []struct {
|
table := []struct {
|
||||||
name string
|
name string
|
||||||
err error
|
err error
|
||||||
|
inner error
|
||||||
expect assert.BoolAssertionFunc
|
expect assert.BoolAssertionFunc
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -180,23 +186,49 @@ func (suite *GraphErrorsUnitSuite) TestIsErrNotFound() {
|
|||||||
{
|
{
|
||||||
name: "non-matching oDataErr",
|
name: "non-matching oDataErr",
|
||||||
err: graphTD.ODataErr("fnords"),
|
err: graphTD.ODataErr("fnords"),
|
||||||
|
inner: graphTD.ODataInner("fnords"),
|
||||||
expect: assert.False,
|
expect: assert.False,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "not-found oDataErr",
|
name: "not-found oDataErr",
|
||||||
|
err: graphTD.ODataErr(string(notFound)),
|
||||||
|
inner: graphTD.ODataInner(string(notFound)),
|
||||||
|
expect: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "error item not-found oDataErr",
|
||||||
err: graphTD.ODataErr(string(ErrorItemNotFound)),
|
err: graphTD.ODataErr(string(ErrorItemNotFound)),
|
||||||
|
inner: graphTD.ODataInner(string(ErrorItemNotFound)),
|
||||||
|
expect: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "item not-found oDataErr",
|
||||||
|
err: graphTD.ODataErr(string(ItemNotFound)),
|
||||||
|
inner: graphTD.ODataInner(string(ItemNotFound)),
|
||||||
expect: assert.True,
|
expect: assert.True,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "sync-not-found oDataErr",
|
name: "sync-not-found oDataErr",
|
||||||
err: graphTD.ODataErr(string(syncFolderNotFound)),
|
err: graphTD.ODataErr(string(syncFolderNotFound)),
|
||||||
|
inner: graphTD.ODataInner(string(syncFolderNotFound)),
|
||||||
|
expect: assert.True,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "not found resp status",
|
||||||
|
err: graphTD.ODataErrWithStatus(http.StatusNotFound, "err"),
|
||||||
expect: assert.True,
|
expect: assert.True,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range table {
|
for _, test := range table {
|
||||||
suite.Run(test.name, func() {
|
suite.Run(test.name, func() {
|
||||||
|
t := suite.T()
|
||||||
|
|
||||||
ode := parseODataErr(test.err)
|
ode := parseODataErr(test.err)
|
||||||
test.expect(suite.T(), isErrNotFound(ode, test.err))
|
test.expect(t, isErrNotFound(ode, test.err))
|
||||||
|
|
||||||
|
if test.inner != nil {
|
||||||
|
test.expect(t, isErrNotFound(ode, test.inner))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,6 +36,18 @@ func ODataErrWithMsg(code, message string) *odataerrors.ODataError {
|
|||||||
return odErr
|
return odErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ODataErrWithStatus(status int, code string) *odataerrors.ODataError {
|
||||||
|
odErr := odataerrors.NewODataError()
|
||||||
|
merr := odataerrors.NewMainError()
|
||||||
|
merr.SetCode(&code)
|
||||||
|
// graph sdk expects the message to be available
|
||||||
|
merr.SetMessage(&code)
|
||||||
|
odErr.SetErrorEscaped(merr)
|
||||||
|
odErr.SetStatusCode(status)
|
||||||
|
|
||||||
|
return odErr
|
||||||
|
}
|
||||||
|
|
||||||
func ODataInner(innerCode string) *odataerrors.ODataError {
|
func ODataInner(innerCode string) *odataerrors.ODataError {
|
||||||
odErr := odataerrors.NewODataError()
|
odErr := odataerrors.NewODataError()
|
||||||
inerr := odataerrors.NewInnerError()
|
inerr := odataerrors.NewInnerError()
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user