1 package kmp
2
3 import (
4 "fmt"
5 "strings"
6
7 gocmp "github.com/google/go-cmp/cmp"
8 "github.com/google/go-cmp/cmp/cmpopts"
9 "gotest.tools/v3/assert/cmp"
10 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11 kstatus "sigs.k8s.io/cli-utils/pkg/kstatus/status"
12 "sigs.k8s.io/controller-runtime/pkg/client"
13
14 "edge-infra.dev/pkg/k8s/meta/status"
15 "edge-infra.dev/pkg/k8s/object"
16 "edge-infra.dev/pkg/k8s/runtime/conditions"
17 "edge-infra.dev/pkg/k8s/unstructured"
18 )
19
20
21
22
23 func SameCondition(exp, actual *metav1.Condition) cmp.Comparison {
24 return cmp.DeepEqual(exp, actual, cmpopts.IgnoreFields(
25 metav1.Condition{},
26 "LastTransitionTime", "ObservedGeneration",
27 ))
28 }
29
30
31
32
33
34 func SameConditions(exp, actual []metav1.Condition) cmp.Comparison {
35 return cmp.DeepEqual(exp, actual, cmpopts.IgnoreFields(
36 metav1.Condition{},
37 "LastTransitionTime", "ObservedGeneration",
38 ))
39 }
40
41
42
43
44
45
46
47 func HasSameConditions(exp []metav1.Condition) Komparison {
48 return func(o client.Object) cmp.Result {
49 return SameConditions(exp, o.(conditions.Getter).GetConditions())()
50 }
51 }
52
53
54
55
56
57
58
59 func HasSameCondition(exp *metav1.Condition) Komparison {
60 return func(o client.Object) cmp.Result {
61 return SameCondition(exp, conditions.Get(o.(conditions.Getter), exp.Type))()
62 }
63 }
64
65
66
67
68 func EqualCondition(exp, actual *metav1.Condition) cmp.Comparison {
69 return cmp.DeepEqual(exp, actual, gocmp.Comparer(equalCondition))
70 }
71
72
73
74
75
76 func EqualConditions(exp, actual []metav1.Condition) cmp.Comparison {
77 return cmp.DeepEqual(exp, actual, gocmp.Comparer(func(x, y metav1.Condition) bool {
78 return equalCondition(&x, &y)
79 }))
80 }
81
82
83
84
85
86
87
88 func HasEqualConditions(exp []metav1.Condition) Komparison {
89 return func(o client.Object) cmp.Result {
90 return EqualConditions(exp, o.(conditions.Getter).GetConditions())()
91 }
92 }
93
94
95
96
97
98
99
100 func HasEqualCondition(exp *metav1.Condition) Komparison {
101 return func(o client.Object) cmp.Result {
102 return EqualCondition(exp, conditions.Get(o.(conditions.Getter), exp.Type))()
103 }
104 }
105
106 func equalCondition(x, y *metav1.Condition) bool {
107 if x == nil && y == nil {
108 return true
109 }
110
111 if x == nil || y == nil {
112 return false
113 }
114
115 if x.Type != y.Type || x.Status != y.Status ||
116 x.Reason != y.Reason {
117 return false
118 }
119 xmsg, ymsg := strings.ToLower(x.Message), strings.ToLower(y.Message)
120
121 return strings.Contains(xmsg, ymsg) ||
122 strings.Contains(ymsg, xmsg)
123 }
124
125
126
127
128
129 func IsReady() Komparison {
130 return func(o client.Object) cmp.Result {
131 if conditions.IsReady(o.(conditions.Getter)) {
132 return cmp.ResultSuccess
133 }
134 return cmp.ResultFailure(fmt.Sprintf(
135 "%s is not Ready: got:\n\t%s",
136 object.FmtObject(o),
137 conditions.Get(o.(conditions.Getter), status.ReadyCondition),
138 ))
139 }
140 }
141
142
143
144
145
146 func IsStalled() Komparison {
147 return func(o client.Object) cmp.Result {
148 if conditions.IsStalled(o.(conditions.Getter)) {
149 return cmp.ResultSuccess
150 }
151 return cmp.ResultFailure(fmt.Sprintf(
152 "%s is not Stalled: got:\n\t%s",
153 object.FmtObject(o),
154 conditions.Get(o.(conditions.Getter), status.StalledCondition),
155 ))
156 }
157 }
158
159
160
161
162
163 func IsReconciling() Komparison {
164 return func(o client.Object) cmp.Result {
165 if conditions.IsReconciling(o.(conditions.Getter)) {
166 return cmp.ResultSuccess
167 }
168 return cmp.ResultFailure(fmt.Sprintf(
169 "%s is not Reconciling: got:\n\t%s",
170 object.FmtObject(o),
171 conditions.Get(o.(conditions.Getter), status.ReconcilingCondition),
172 ))
173 }
174 }
175
176
177
178
179
180 func HasTrueCondition(t string) Komparison {
181 return func(o client.Object) cmp.Result {
182 if conditions.IsTrue(o.(conditions.Getter), t) {
183 return cmp.ResultSuccess
184 }
185 return cmp.ResultFailure(fmt.Sprintf(
186 "%s is not True: got:\n\t%s",
187 object.FmtObject(o),
188 conditions.Get(o.(conditions.Getter), t),
189 ))
190 }
191 }
192
193
194
195
196
197 func HasFalseCondition(t string) Komparison {
198 return func(o client.Object) cmp.Result {
199 if conditions.IsFalse(o.(conditions.Getter), t) {
200 return cmp.ResultSuccess
201 }
202 return cmp.ResultFailure(fmt.Sprintf(
203 "%s is not False: got:\n\t%s",
204 object.FmtObject(o),
205 conditions.Get(o.(conditions.Getter), t),
206 ))
207 }
208 }
209
210
211
212
213
214
215
216 func IsCurrent() Komparison {
217 return func(o client.Object) cmp.Result {
218 u, err := unstructured.ToUnstructured(o)
219 if err != nil {
220 return cmp.ResultFromError(err)
221 }
222 res, err := kstatus.Compute(u)
223 if err != nil {
224 return cmp.ResultFromError(err)
225 }
226 if res.Status != kstatus.CurrentStatus {
227 return cmp.ResultFailure(fmt.Sprintf(
228 "%s not Current:\n\t%s",
229 object.FmtObject(o), res,
230 ))
231 }
232 return cmp.ResultSuccess
233 }
234 }
235
View as plain text