@@ -2,12 +2,17 @@ package pause
2
2
3
3
import (
4
4
"context"
5
+ "fmt"
6
+ "testing"
5
7
8
+ "github.com/stretchr/testify/require"
9
+ "golang.org/x/exp/slices"
6
10
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7
11
8
12
"github.com/authzed/controller-idioms/conditions"
9
13
"github.com/authzed/controller-idioms/handler"
10
14
"github.com/authzed/controller-idioms/queue"
15
+ "github.com/authzed/controller-idioms/queue/fake"
11
16
"github.com/authzed/controller-idioms/typedctx"
12
17
)
13
18
@@ -18,7 +23,7 @@ type MyObject struct {
18
23
// this implements the conditions interface for MyObject, but note that
19
24
// this is not supported by kube codegen at the moment (don't try to use
20
25
// this in a real controller)
21
- conditions.StatusWithConditions [MyObjectStatus ] `json:"-"`
26
+ conditions.StatusWithConditions [* MyObjectStatus ] `json:"-"`
22
27
}
23
28
type MyObjectStatus struct {
24
29
ObservedGeneration int64 `json:"observedGeneration,omitempty" protobuf:"varint,3,opt,name=observedGeneration"`
@@ -47,3 +52,170 @@ func ExampleNewPauseContextHandler() {
47
52
pauseHandler .Handle (ctx )
48
53
// Output:
49
54
}
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