Merge pull request #8237 from smarterclayton/continue_on_error

Make ContinueOnError actually work
This commit is contained in:
Jeff Lowdermilk
2015-05-15 12:57:29 -07:00
4 changed files with 148 additions and 33 deletions

View File

@@ -614,6 +614,9 @@ func (b *Builder) Do() *Result {
helpers = append(helpers, RetrieveLazy)
}
r.visitor = NewDecoratedVisitor(r.visitor, helpers...)
if b.continueOnError {
r.visitor = ContinueOnErrorVisitor{r.visitor}
}
return r
}

View File

@@ -18,6 +18,7 @@ package resource
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
@@ -606,6 +607,36 @@ func TestMultipleObject(t *testing.T) {
}
}
func TestContinueOnErrorVisitor(t *testing.T) {
r, _, _ := streamTestData()
req := NewBuilder(latest.RESTMapper, api.Scheme, fakeClient()).
ContinueOnError().
NamespaceParam("test").Stream(r, "STDIN").Flatten().
Do()
count := 0
testErr := fmt.Errorf("test error")
err := req.Visit(func(_ *Info) error {
count++
if count > 1 {
return testErr
}
return nil
})
if err == nil {
t.Fatalf("unexpected error: %v", err)
}
if count != 3 {
t.Fatalf("did not visit all infos: %d", count)
}
agg, ok := err.(errors.Aggregate)
if !ok {
t.Fatalf("unexpected error: %v", err)
}
if len(agg.Errors()) != 2 || agg.Errors()[0] != testErr || agg.Errors()[1] != testErr {
t.Fatalf("unexpected error: %v", err)
}
}
func TestSingularObject(t *testing.T) {
obj, err := NewBuilder(latest.RESTMapper, api.Scheme, fakeClient()).
NamespaceParam("test").DefaultNamespace().

View File

@@ -350,6 +350,36 @@ func (v DecoratedVisitor) Visit(fn VisitorFunc) error {
})
}
// ContinueOnErrorVisitor visits each item and, if an error occurs on
// any individual item, returns an aggregate error after all items
// are visited.
type ContinueOnErrorVisitor struct {
Visitor
}
// Visit returns nil if no error occurs during traversal, a regular
// error if one occurs, or if multiple errors occur, an aggregate
// error. If the provided visitor fails on any individual item it
// will not prevent the remaining items from being visited. An error
// returned by the visitor directly may still result in some items
// not being visited.
func (v ContinueOnErrorVisitor) Visit(fn VisitorFunc) error {
errs := []error{}
err := v.Visitor.Visit(func(info *Info) error {
if err := fn(info); err != nil {
errs = append(errs, err)
}
return nil
})
if err != nil {
errs = append(errs, err)
}
if len(errs) == 1 {
return errs[0]
}
return errors.NewAggregate(errs)
}
// FlattenListVisitor flattens any objects that runtime.ExtractList recognizes as a list
// - has an "Items" public field that is a slice of runtime.Objects or objects satisfying
// that interface - into multiple Infos. An error on any sub item (for instance, if a List