1 package conditions
2
3 import (
4 "testing"
5 "time"
6
7 . "github.com/onsi/gomega"
8 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9
10 "edge-infra.dev/pkg/k8s/object/fobject"
11 )
12
13 func TestNewPatch(t *testing.T) {
14 fooTrue := TrueCondition("foo", "reason true", "message true")
15 fooFalse := FalseCondition("foo", "reason false", "message false")
16
17 tests := []struct {
18 name string
19 before Getter
20 after Getter
21 want Patch
22 }{
23 {
24 name: "No changes return empty patch",
25 before: getterWithConditions(),
26 after: getterWithConditions(),
27 want: nil,
28 },
29 {
30 name: "No changes return empty patch",
31 before: getterWithConditions(fooTrue),
32 after: getterWithConditions(fooTrue),
33 want: nil,
34 },
35 {
36 name: "Detects AddConditionPatch",
37 before: getterWithConditions(),
38 after: getterWithConditions(fooTrue),
39 want: Patch{
40 {
41 Before: nil,
42 After: fooTrue,
43 Op: AddConditionPatch,
44 },
45 },
46 },
47 {
48 name: "Detects ChangeConditionPatch",
49 before: getterWithConditions(fooTrue),
50 after: getterWithConditions(fooFalse),
51 want: Patch{
52 {
53 Before: fooTrue,
54 After: fooFalse,
55 Op: ChangeConditionPatch,
56 },
57 },
58 },
59 {
60 name: "Detects RemoveConditionPatch",
61 before: getterWithConditions(fooTrue),
62 after: getterWithConditions(),
63 want: Patch{
64 {
65 Before: fooTrue,
66 After: nil,
67 Op: RemoveConditionPatch,
68 },
69 },
70 },
71 }
72
73 for _, tt := range tests {
74 t.Run(tt.name, func(t *testing.T) {
75 g := NewWithT(t)
76
77 got := NewPatch(tt.before, tt.after)
78
79 g.Expect(got).To(Equal(tt.want))
80 })
81 }
82 }
83
84 func TestApply(t *testing.T) {
85 fooTrue := TrueCondition("foo", "reason true", "message true")
86 fooFalse := FalseCondition("foo", "reason false", "message false")
87 fooUnknown := UnknownCondition("foo", "reason unknown", "message unknown")
88
89 tests := []struct {
90 name string
91 before Getter
92 after Getter
93 latest Setter
94 options []ApplyOption
95 want []metav1.Condition
96 wantErr bool
97 }{
98 {
99 name: "No patch return same list",
100 before: getterWithConditions(fooTrue),
101 after: getterWithConditions(fooTrue),
102 latest: setterWithConditions(fooTrue),
103 want: conditionList(fooTrue),
104 wantErr: false,
105 },
106 {
107 name: "Add: When a condition does not exists, it should add",
108 before: getterWithConditions(),
109 after: getterWithConditions(fooTrue),
110 latest: setterWithConditions(),
111 want: conditionList(fooTrue),
112 wantErr: false,
113 },
114 {
115 name: "Add: When a condition already exists but without conflicts, it should add",
116 before: getterWithConditions(),
117 after: getterWithConditions(fooTrue),
118 latest: setterWithConditions(fooTrue),
119 want: conditionList(fooTrue),
120 wantErr: false,
121 },
122 {
123 name: "Add: When a condition already exists but with conflicts, it should error",
124 before: getterWithConditions(),
125 after: getterWithConditions(fooTrue),
126 latest: setterWithConditions(fooFalse),
127 want: nil,
128 wantErr: true,
129 },
130 {
131 name: "Add: When a condition already exists but with conflicts, it should not error if the condition is owned",
132 before: getterWithConditions(),
133 after: getterWithConditions(fooTrue),
134 latest: setterWithConditions(fooFalse),
135 options: []ApplyOption{WithOwnedConditions("foo")},
136 want: conditionList(fooTrue),
137 wantErr: false,
138 },
139 {
140 name: "Remove: When a condition was already deleted, it should pass",
141 before: getterWithConditions(fooTrue),
142 after: getterWithConditions(),
143 latest: setterWithConditions(),
144 want: conditionList(),
145 wantErr: false,
146 },
147 {
148 name: "Remove: When a condition already exists but without conflicts, it should delete",
149 before: getterWithConditions(fooTrue),
150 after: getterWithConditions(),
151 latest: setterWithConditions(fooTrue),
152 want: conditionList(),
153 wantErr: false,
154 },
155 {
156 name: "Remove: When a condition already exists but with conflicts, it should error",
157 before: getterWithConditions(fooTrue),
158 after: getterWithConditions(),
159 latest: setterWithConditions(fooFalse),
160 want: nil,
161 wantErr: true,
162 },
163 {
164 name: "Remove: When a condition already exists but with conflicts, it should not error if the condition is owned",
165 before: getterWithConditions(fooTrue),
166 after: getterWithConditions(),
167 latest: setterWithConditions(fooFalse),
168 options: []ApplyOption{WithOwnedConditions("foo")},
169 want: conditionList(),
170 wantErr: false,
171 },
172 {
173 name: "Change: When a condition exists without conflicts, it should change",
174 before: getterWithConditions(fooTrue),
175 after: getterWithConditions(fooFalse),
176 latest: setterWithConditions(fooTrue),
177 want: conditionList(fooFalse),
178 wantErr: false,
179 },
180 {
181 name: "Change: When a condition exists with conflicts but there is agreement on the final state, it should change",
182 before: getterWithConditions(fooFalse),
183 after: getterWithConditions(fooTrue),
184 latest: setterWithConditions(fooTrue),
185 want: conditionList(fooTrue),
186 wantErr: false,
187 },
188 {
189 name: "Change: When a condition exists with conflicts but there is no agreement on the final state, it should error",
190 before: getterWithConditions(fooUnknown),
191 after: getterWithConditions(fooFalse),
192 latest: setterWithConditions(fooTrue),
193 want: nil,
194 wantErr: true,
195 },
196 {
197 name: "Change: When a condition exists with conflicts but there is no agreement on the final state, it should not error if the condition is owned",
198 before: getterWithConditions(fooUnknown),
199 after: getterWithConditions(fooFalse),
200 latest: setterWithConditions(fooTrue),
201 options: []ApplyOption{WithOwnedConditions("foo")},
202 want: conditionList(fooFalse),
203 wantErr: false,
204 },
205 {
206 name: "Change: When a condition was deleted, it should error",
207 before: getterWithConditions(fooTrue),
208 after: getterWithConditions(fooFalse),
209 latest: setterWithConditions(),
210 want: nil,
211 wantErr: true,
212 },
213 {
214 name: "Change: When a condition was deleted, it should not error if the condition is owned",
215 before: getterWithConditions(fooTrue),
216 after: getterWithConditions(fooFalse),
217 latest: setterWithConditions(),
218 options: []ApplyOption{WithOwnedConditions("foo")},
219 want: conditionList(fooFalse),
220 wantErr: false,
221 },
222 }
223
224 for _, tt := range tests {
225 t.Run(tt.name, func(t *testing.T) {
226 g := NewWithT(t)
227
228 patch := NewPatch(tt.before, tt.after)
229
230 err := patch.Apply(tt.latest, tt.options...)
231 if tt.wantErr {
232 g.Expect(err).To(HaveOccurred())
233 return
234 }
235 g.Expect(err).ToNot(HaveOccurred())
236
237 g.Expect(tt.latest.GetConditions()).To(haveSameConditionsOf(tt.want))
238 })
239 }
240 }
241
242 func TestApplyDoesNotAlterLastTransitionTime(t *testing.T) {
243 g := NewWithT(t)
244
245 before := &fobject.Fake{}
246 after := &fobject.Fake{
247 Status: fobject.FakeStatus{
248 Conditions: []metav1.Condition{
249 {
250 Type: "foo",
251 Status: metav1.ConditionTrue,
252 LastTransitionTime: metav1.NewTime(time.Now().UTC().Truncate(time.Second)),
253 },
254 },
255 },
256 }
257 latest := &fobject.Fake{}
258
259
260
261
262
263 diff := NewPatch(before, after)
264 err := diff.Apply(latest)
265
266 g.Expect(err).ToNot(HaveOccurred())
267 g.Expect(latest.GetConditions()).To(Equal(after.GetConditions()))
268 }
269
View as plain text