github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/lib/clientfake/decorator.go (about) 1 package clientfake 2 3 import ( 4 "k8s.io/apimachinery/pkg/runtime" 5 fake "k8s.io/client-go/kubernetes/fake" 6 "k8s.io/client-go/testing" 7 ) 8 9 // This is used to prepend reactors to the k8s fake client. should be removed when client go is updated. 10 // TODO: see if we can merge the OLM ClientsetDecorator and this one. 11 12 // ClientsetDecorator defines decorator methods for a Clientset. 13 type ClientsetDecorator interface { 14 // PrependReactor adds a reactor to the beginning of the chain. 15 PrependReactor(verb, resource string, reaction testing.ReactionFunc) 16 } 17 18 // ReactionForwardingClientsetDecorator wraps a Clientset and "forwards" Action object mutations 19 // from all successful non-handling Reactors along the chain to the first handling Reactor. This is 20 // is a stopgap until we can upgrade to client-go v11.0, where the behavior is the default 21 // (see https://github.com/kubernetes/client-go/blob/6ee68ca5fd8355d024d02f9db0b3b667e8357a0f/testing/fake.go#L130). 22 type ReactionForwardingClientsetDecorator struct { 23 fake.Clientset 24 ReactionChain []testing.Reactor // shadow embedded ReactionChain 25 actions []testing.Action // these may be castable to other types, but "Action" is the minimum 26 } 27 28 // NewReactionForwardingClientsetDecorator returns the ReactionForwardingClientsetDecorator wrapped Clientset result 29 // of calling NewSimpleClientset with the given objects. 30 func NewReactionForwardingClientsetDecorator(objects []runtime.Object, options ...Option) *ReactionForwardingClientsetDecorator { 31 decorator := &ReactionForwardingClientsetDecorator{ 32 Clientset: *fake.NewSimpleClientset(objects...), 33 } 34 35 // Swap out the embedded ReactionChain with a Reactor that reduces over the decorator's ReactionChain. 36 decorator.ReactionChain = decorator.Clientset.ReactionChain 37 decorator.Clientset.ReactionChain = []testing.Reactor{&testing.SimpleReactor{Verb: "*", Resource: "*", Reaction: decorator.reduceReactions}} 38 39 // Apply options 40 for _, option := range options { 41 option(decorator) 42 } 43 44 return decorator 45 } 46 47 // reduceReactions reduces over all reactions in the chain while "forwarding" Action object mutations 48 // from all successful non-handling Reactors along the chain to the first handling Reactor. 49 func (c *ReactionForwardingClientsetDecorator) reduceReactions(action testing.Action) (handled bool, ret runtime.Object, err error) { 50 // The embedded Client set is already locked, so there's no need to lock again 51 actionCopy := action.DeepCopy() 52 c.actions = append(c.actions, action.DeepCopy()) 53 for _, reactor := range c.ReactionChain { 54 if !reactor.Handles(actionCopy) { 55 continue 56 } 57 58 handled, ret, err = reactor.React(actionCopy) 59 if !handled { 60 continue 61 } 62 63 return 64 } 65 66 return 67 } 68 69 // PrependReactor adds a reactor to the beginning of the chain. 70 func (c *ReactionForwardingClientsetDecorator) PrependReactor(verb, resource string, reaction testing.ReactionFunc) { 71 c.ReactionChain = append([]testing.Reactor{&testing.SimpleReactor{Verb: verb, Resource: resource, Reaction: reaction}}, c.ReactionChain...) 72 }