While fail-fast and best-effort make for good categories at the extreme ends of error handling, we keep finding outselves wanting to operate in a middle ground. This change introduces a new error handling category: FailAfterRecovery. This option tells corso to complete as much of its process as it can, even if it recovers from errors. But at the end of processing, if it recovered from any errors, an error is returned for the operation. This behavior is the new failure handling default, instead of failFast. --- #### Does this PR need a docs update or release note? - [x] ⛔ No #### Type of change - [x] 🌻 Feature #### Test Plan - [x] 💪 Manual - [x] ⚡ Unit test
103 lines
2.2 KiB
Go
103 lines
2.2 KiB
Go
package operations
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
"github.com/alcionai/corso/src/internal/tester"
|
|
"github.com/alcionai/corso/src/pkg/control"
|
|
"github.com/alcionai/corso/src/pkg/fault"
|
|
)
|
|
|
|
type HelpersUnitSuite struct {
|
|
tester.Suite
|
|
}
|
|
|
|
func TestHelpersUnitSuite(t *testing.T) {
|
|
suite.Run(t, &HelpersUnitSuite{Suite: tester.NewUnitSuite(t)})
|
|
}
|
|
|
|
func (suite *HelpersUnitSuite) TestFinalizeErrorHandling() {
|
|
table := []struct {
|
|
name string
|
|
errs func() *fault.Bus
|
|
opts control.Options
|
|
expectErr assert.ErrorAssertionFunc
|
|
}{
|
|
{
|
|
name: "no errors",
|
|
errs: func() *fault.Bus {
|
|
return fault.New(false)
|
|
},
|
|
opts: control.Options{
|
|
FailureHandling: control.FailAfterRecovery,
|
|
},
|
|
expectErr: assert.NoError,
|
|
},
|
|
{
|
|
name: "already failed",
|
|
errs: func() *fault.Bus {
|
|
fn := fault.New(false)
|
|
fn.Fail(assert.AnError)
|
|
return fn
|
|
},
|
|
opts: control.Options{
|
|
FailureHandling: control.FailAfterRecovery,
|
|
},
|
|
expectErr: assert.Error,
|
|
},
|
|
{
|
|
name: "best effort",
|
|
errs: func() *fault.Bus {
|
|
fn := fault.New(false)
|
|
fn.AddRecoverable(assert.AnError)
|
|
return fn
|
|
},
|
|
opts: control.Options{
|
|
FailureHandling: control.BestEffort,
|
|
},
|
|
expectErr: assert.NoError,
|
|
},
|
|
{
|
|
name: "recoverable errors produce hard fail",
|
|
errs: func() *fault.Bus {
|
|
fn := fault.New(false)
|
|
fn.AddRecoverable(assert.AnError)
|
|
return fn
|
|
},
|
|
opts: control.Options{
|
|
FailureHandling: control.FailAfterRecovery,
|
|
},
|
|
expectErr: assert.Error,
|
|
},
|
|
{
|
|
name: "multiple recoverable errors produce hard fail",
|
|
errs: func() *fault.Bus {
|
|
fn := fault.New(false)
|
|
fn.AddRecoverable(assert.AnError)
|
|
fn.AddRecoverable(assert.AnError)
|
|
fn.AddRecoverable(assert.AnError)
|
|
return fn
|
|
},
|
|
opts: control.Options{
|
|
FailureHandling: control.FailAfterRecovery,
|
|
},
|
|
expectErr: assert.Error,
|
|
},
|
|
}
|
|
for _, test := range table {
|
|
suite.Run(test.name, func() {
|
|
ctx, flush := tester.NewContext()
|
|
defer flush()
|
|
|
|
t := suite.T()
|
|
errs := test.errs()
|
|
|
|
finalizeErrorHandling(ctx, test.opts, errs, "test")
|
|
test.expectErr(t, errs.Failure())
|
|
})
|
|
}
|
|
}
|