@@ -2,12 +2,17 @@ package pause
22
33import (
44 "context"
5+ "fmt"
6+ "testing"
57
8+ "github.com/stretchr/testify/require"
9+ "golang.org/x/exp/slices"
610 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
711
812 "github.com/authzed/controller-idioms/conditions"
913 "github.com/authzed/controller-idioms/handler"
1014 "github.com/authzed/controller-idioms/queue"
15+ "github.com/authzed/controller-idioms/queue/fake"
1116 "github.com/authzed/controller-idioms/typedctx"
1217)
1318
@@ -18,7 +23,7 @@ type MyObject struct {
1823 // this implements the conditions interface for MyObject, but note that
1924 // this is not supported by kube codegen at the moment (don't try to use
2025 // this in a real controller)
21- conditions.StatusWithConditions [MyObjectStatus ] `json:"-"`
26+ conditions.StatusWithConditions [* MyObjectStatus ] `json:"-"`
2227}
2328type MyObjectStatus struct {
2429 ObservedGeneration int64 `json:"observedGeneration,omitempty" protobuf:"varint,3,opt,name=observedGeneration"`
@@ -47,3 +52,170 @@ func ExampleNewPauseContextHandler() {
4752 pauseHandler .Handle (ctx )
4853 // Output:
4954}
55+
56+ func TestPauseHandler (t * testing.T ) {
57+ var nextKey handler.Key = "next"
58+ const PauseLabelKey = "com.my-controller/controller-paused"
59+ tests := []struct {
60+ name string
61+
62+ obj * MyObject
63+ patchError error
64+
65+ expectNext handler.Key
66+ expectEvents []string
67+ expectPatchStatus bool
68+ expectConditions []metav1.Condition
69+ expectRequeue bool
70+ expectDone bool
71+ }{
72+ {
73+ name : "pauses when label found" ,
74+ obj : & MyObject {
75+ ObjectMeta : metav1.ObjectMeta {
76+ Labels : map [string ]string {
77+ PauseLabelKey : "" ,
78+ },
79+ },
80+ StatusWithConditions : conditions.StatusWithConditions [* MyObjectStatus ]{
81+ Status : & MyObjectStatus {
82+ StatusConditions : conditions.StatusConditions {
83+ Conditions : []metav1.Condition {},
84+ },
85+ },
86+ },
87+ },
88+ expectPatchStatus : true ,
89+ expectConditions : []metav1.Condition {NewPausedCondition (PauseLabelKey )},
90+ expectDone : true ,
91+ },
92+ {
93+ name : "requeues on pause patch error" ,
94+ obj : & MyObject {
95+ ObjectMeta : metav1.ObjectMeta {
96+ Labels : map [string ]string {
97+ PauseLabelKey : "" ,
98+ },
99+ },
100+ StatusWithConditions : conditions.StatusWithConditions [* MyObjectStatus ]{
101+ Status : & MyObjectStatus {
102+ StatusConditions : conditions.StatusConditions {
103+ Conditions : []metav1.Condition {},
104+ },
105+ },
106+ },
107+ },
108+ patchError : fmt .Errorf ("error patching" ),
109+ expectPatchStatus : true ,
110+ expectRequeue : true ,
111+ },
112+ {
113+ name : "no-op when label found and status is already paused" ,
114+ obj : & MyObject {
115+ ObjectMeta : metav1.ObjectMeta {
116+ Labels : map [string ]string {
117+ PauseLabelKey : "" ,
118+ },
119+ },
120+ StatusWithConditions : conditions.StatusWithConditions [* MyObjectStatus ]{
121+ Status : & MyObjectStatus {
122+ StatusConditions : conditions.StatusConditions {
123+ Conditions : []metav1.Condition {NewPausedCondition (PauseLabelKey )},
124+ },
125+ },
126+ },
127+ },
128+ expectDone : true ,
129+ },
130+ {
131+ name : "removes condition when label is removed" ,
132+ obj : & MyObject {
133+ StatusWithConditions : conditions.StatusWithConditions [* MyObjectStatus ]{
134+ Status : & MyObjectStatus {
135+ StatusConditions : conditions.StatusConditions {
136+ Conditions : []metav1.Condition {NewPausedCondition (PauseLabelKey )},
137+ },
138+ },
139+ },
140+ },
141+ expectPatchStatus : true ,
142+ expectConditions : []metav1.Condition {},
143+ expectNext : nextKey ,
144+ },
145+ {
146+ name : "removes self-pause condition when label is removed" ,
147+ obj : & MyObject {
148+ StatusWithConditions : conditions.StatusWithConditions [* MyObjectStatus ]{
149+ Status : & MyObjectStatus {
150+ StatusConditions : conditions.StatusConditions {
151+ Conditions : []metav1.Condition {NewSelfPausedCondition (PauseLabelKey )},
152+ },
153+ },
154+ },
155+ },
156+ expectPatchStatus : true ,
157+ expectConditions : []metav1.Condition {},
158+ expectNext : nextKey ,
159+ },
160+ {
161+ name : "requeues on unpause patch error" ,
162+ obj : & MyObject {
163+ StatusWithConditions : conditions.StatusWithConditions [* MyObjectStatus ]{
164+ Status : & MyObjectStatus {
165+ StatusConditions : conditions.StatusConditions {
166+ Conditions : []metav1.Condition {NewPausedCondition (PauseLabelKey )},
167+ },
168+ },
169+ },
170+ },
171+ patchError : fmt .Errorf ("error patching" ),
172+ expectPatchStatus : true ,
173+ expectRequeue : true ,
174+ },
175+ {
176+ name : "no-op, no pause label, no pause status" ,
177+ obj : & MyObject {},
178+ expectNext : nextKey ,
179+ },
180+ }
181+ for _ , tt := range tests {
182+ t .Run (tt .name , func (t * testing.T ) {
183+ ctrls := & fake.FakeInterface {}
184+ patchCalled := false
185+
186+ patchStatus := func (ctx context.Context , patch * MyObject ) error {
187+ patchCalled = true
188+
189+ if tt .patchError != nil {
190+ return tt .patchError
191+ }
192+
193+ require .Truef (t , slices .EqualFunc (tt .expectConditions , patch .Status .Conditions , func (a , b metav1.Condition ) bool {
194+ return a .Type == b .Type &&
195+ a .Status == b .Status &&
196+ a .ObservedGeneration == b .ObservedGeneration &&
197+ a .Message == b .Message &&
198+ a .Reason == b .Reason
199+ }), "conditions not equal:\n a: %#v\n b: %#v" , tt .expectConditions , patch .Status .Conditions )
200+
201+ return nil
202+ }
203+ queueOps := queue .NewQueueOperationsCtx ()
204+ ctxMyObject := typedctx.WithDefault [* MyObject ](nil )
205+
206+ ctx := context .Background ()
207+ ctx = queueOps .WithValue (ctx , ctrls )
208+ ctx = ctxMyObject .WithValue (ctx , tt .obj )
209+ var called handler.Key
210+
211+ NewPauseContextHandler (queueOps .Key , PauseLabelKey , ctxMyObject , patchStatus , handler .ContextHandlerFunc (func (ctx context.Context ) {
212+ called = nextKey
213+ })).Handle (ctx )
214+
215+ require .Equal (t , tt .expectPatchStatus , patchCalled )
216+ require .Equal (t , tt .expectNext , called )
217+ require .Equal (t , tt .expectRequeue , ctrls .RequeueAPIErrCallCount () == 1 )
218+ require .Equal (t , tt .expectDone , ctrls .DoneCallCount () == 1 )
219+ })
220+ }
221+ }
0 commit comments