Skip to content

Commit a28e461

Browse files
authored
Implemented watch reaction functions (#1)
Adding watch reactor functions
1 parent 16e49a3 commit a28e461

4 files changed

Lines changed: 78 additions & 6 deletions

File tree

testing/client.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ import (
2323

2424
"k8s.io/apimachinery/pkg/api/meta"
2525
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2627
"k8s.io/apimachinery/pkg/runtime"
2728
"k8s.io/apimachinery/pkg/runtime/schema"
29+
"k8s.io/apimachinery/pkg/watch"
2830
clientgotesting "k8s.io/client-go/testing"
2931
ref "k8s.io/client-go/tools/reference"
32+
"reconciler.io/runtime/duck"
3033
"sigs.k8s.io/controller-runtime/pkg/client"
3134
)
3235

@@ -146,6 +149,20 @@ func (w *clientWrapper) react(action Action) error {
146149
return nil
147150
}
148151

152+
func (w *clientWrapper) reactWatcherFunc(action Action) error {
153+
for _, reactor := range w.watchReactionChain {
154+
if !reactor.Handles(action) {
155+
continue
156+
}
157+
handled, _, err := reactor.React(action)
158+
if !handled {
159+
continue
160+
}
161+
return err
162+
}
163+
return nil
164+
}
165+
149166
func (w *clientWrapper) Scheme() *runtime.Scheme {
150167
return w.client.Scheme()
151168
}
@@ -313,6 +330,55 @@ func (w *clientWrapper) DeleteAllOf(ctx context.Context, obj client.Object, opts
313330
return w.client.DeleteAllOf(ctx, obj, opts...)
314331
}
315332

333+
func (w *clientWrapper) Watch(ctx context.Context, list client.ObjectList, opts ...client.ListOption) (watch.Interface, error) {
334+
335+
ww, ok := w.client.(client.WithWatch)
336+
if !ok {
337+
panic(fmt.Errorf("unable to call Watch with wrapped client that does not implement client.WithWatch"))
338+
}
339+
340+
gvr, namespace, name, err := w.objmeta(list)
341+
if err != nil {
342+
return nil, err
343+
}
344+
345+
// call reactor chain
346+
err = w.reactWatcherFunc(clientgotesting.NewGetAction(gvr, namespace, name))
347+
if err != nil {
348+
return nil, err
349+
}
350+
err = w.reactWatcherFunc(clientgotesting.NewCreateAction(gvr, namespace, list))
351+
if err != nil {
352+
return nil, err
353+
}
354+
err = w.reactWatcherFunc(clientgotesting.NewDeleteAction(gvr, namespace, name))
355+
if err != nil {
356+
return nil, err
357+
}
358+
err = w.reactWatcherFunc(clientgotesting.NewUpdateAction(gvr, namespace, list))
359+
if err != nil {
360+
return nil, err
361+
}
362+
363+
if !duck.IsDuck(list, w.Scheme()) {
364+
return ww.Watch(ctx, list, opts...)
365+
}
366+
367+
uObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(list)
368+
if err != nil {
369+
return nil, err
370+
}
371+
u := &unstructured.UnstructuredList{Object: uObj}
372+
watcher, err := ww.Watch(ctx, u, opts...)
373+
if err != nil {
374+
return nil, err
375+
}
376+
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, list); err != nil {
377+
return nil, err
378+
}
379+
return watcher, nil
380+
}
381+
316382
func (w *clientWrapper) Status() client.StatusWriter {
317383
return &statusWriterWrapper{
318384
statusWriter: w.client.Status(),

testing/reconciler.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ type ReconcilerTestCase struct {
4848

4949
// Request identifies the object to be reconciled
5050
Request reconcilers.Request
51-
// WithReactors installs each ReactionFunc into each fake clientset. ReactionFuncs intercept
51+
// WithReactors and WithWatchReactors installs each ReactionFunc into each fake clientset. ReactionFuncs intercept
5252
// each call to the clientset providing the ability to mutate the resource or inject an error.
53-
WithReactors []ReactionFunc
53+
WithReactors []ReactionFunc
54+
WithWatchReactors []WatchReactionFunc
5455
// WithClientBuilder allows a test to modify the fake client initialization.
5556
WithClientBuilder func(*fake.ClientBuilder) *fake.ClientBuilder
5657
// StatusSubResourceTypes is a set of object types that support the status sub-resource. For
@@ -188,6 +189,7 @@ func (tc *ReconcilerTestCase) Run(t *testing.T, scheme *runtime.Scheme, factory
188189
APIGivenObjects: tc.APIGivenObjects,
189190
WithClientBuilder: tc.WithClientBuilder,
190191
WithReactors: tc.WithReactors,
192+
WithWatchReactors: tc.WithWatchReactors,
191193
GivenTracks: tc.GivenTracks,
192194
ExpectTracks: tc.ExpectTracks,
193195
ExpectEvents: tc.ExpectEvents,

testing/subreconciler.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,10 @@ type SubReconcilerTestCase[Type client.Object] struct {
5656
GivenStashedValues map[reconcilers.StashKey]interface{}
5757
// WithClientBuilder allows a test to modify the fake client initialization.
5858
WithClientBuilder func(*fake.ClientBuilder) *fake.ClientBuilder
59-
// WithReactors installs each ReactionFunc into each fake clientset. ReactionFuncs intercept
59+
// WithReactors and WithWatchReactors installs each ReactionFunc into each fake clientset. ReactionFuncs intercept
6060
// each call to the clientset providing the ability to mutate the resource or inject an error.
61-
WithReactors []ReactionFunc
61+
WithReactors []ReactionFunc
62+
WithWatchReactors []WatchReactionFunc
6263
// StatusSubResourceTypes is a set of object types that support the status sub-resource. For
6364
// these types, the only way to modify the resource's status is update or patch the status
6465
// sub-resource. Patching or updating the main resource will not mutated the status field.
@@ -216,6 +217,7 @@ func (tc *SubReconcilerTestCase[T]) Run(t *testing.T, scheme *runtime.Scheme, fa
216217
APIGivenObjects: append(tc.APIGivenObjects, givenResource),
217218
WithClientBuilder: tc.WithClientBuilder,
218219
WithReactors: tc.WithReactors,
220+
WithWatchReactors: tc.WithWatchReactors,
219221
GivenTracks: tc.GivenTracks,
220222
ExpectTracks: tc.ExpectTracks,
221223
ExpectEvents: tc.ExpectEvents,

testing/webhook.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,10 @@ type AdmissionWebhookTestCase struct {
5454
HTTPRequest *http.Request
5555
// WithClientBuilder allows a test to modify the fake client initialization.
5656
WithClientBuilder func(*fake.ClientBuilder) *fake.ClientBuilder
57-
// WithReactors installs each ReactionFunc into each fake clientset. ReactionFuncs intercept
57+
// WithReactors and WithWatchReactors installs each ReactionFunc into each fake clientset. ReactionFuncs intercept
5858
// each call to the clientset providing the ability to mutate the resource or inject an error.
59-
WithReactors []ReactionFunc
59+
WithReactors []ReactionFunc
60+
WithWatchReactors []WatchReactionFunc
6061
// StatusSubResourceTypes is a set of object types that support the status sub-resource. For
6162
// these types, the only way to modify the resource's status is update or patch the status
6263
// sub-resource. Patching or updating the main resource will not mutated the status field.
@@ -181,6 +182,7 @@ func (tc *AdmissionWebhookTestCase) Run(t *testing.T, scheme *runtime.Scheme, fa
181182
APIGivenObjects: tc.APIGivenObjects,
182183
WithClientBuilder: tc.WithClientBuilder,
183184
WithReactors: tc.WithReactors,
185+
WithWatchReactors: tc.WithWatchReactors,
184186
GivenTracks: tc.GivenTracks,
185187
ExpectTracks: tc.ExpectTracks,
186188
ExpectEvents: tc.ExpectEvents,

0 commit comments

Comments
 (0)