@@ -40,6 +40,112 @@ func UntilObjectPhase(expectedPhase string, timeout time.Duration, objs ...clien
4040 untilObjectField ("status.phase" , expectedPhase , timeout , objs ... )
4141}
4242
43+ // UntilConditionReason waits for the specified conditionType in status.conditions to have the given reason value for all provided objects.
44+ func UntilConditionReason (conditionType , expectedReason string , timeout time.Duration , objs ... client.Object ) {
45+ UntilConditionState (conditionType , timeout , struct {
46+ Reason string
47+ Status string
48+ Message string
49+ CheckReason bool
50+ CheckStatus bool
51+ CheckMessage bool
52+ }{
53+ Reason : expectedReason ,
54+ CheckReason : true ,
55+ }, objs ... )
56+ }
57+
58+ // UntilConditionStatus waits for the specified conditionType in status.conditions to have the given status value for all provided objects.
59+ func UntilConditionStatus (conditionType , expectedStatus string , timeout time.Duration , objs ... client.Object ) {
60+ UntilConditionState (conditionType , timeout , struct {
61+ Reason string
62+ Status string
63+ Message string
64+ CheckReason bool
65+ CheckStatus bool
66+ CheckMessage bool
67+ }{
68+ Status : expectedStatus ,
69+ CheckStatus : true ,
70+ }, objs ... )
71+ }
72+
73+ // UntilConditionState generalizes condition field checks ("reason", "status", "message") for the specified conditionType.
74+ // You can specify which fields to check by setting the corresponding flags to true and providing their expected values.
75+ func UntilConditionState (
76+ conditionType string ,
77+ timeout time.Duration ,
78+ checkOptions struct {
79+ Reason string
80+ Status string
81+ Message string
82+ CheckReason bool
83+ CheckStatus bool
84+ CheckMessage bool
85+ },
86+ objs ... client.Object ,
87+ ) {
88+ GinkgoHelper ()
89+ Eventually (func (g Gomega ) {
90+ for _ , obj := range objs {
91+ key := client .ObjectKeyFromObject (obj )
92+ u := getTemplateUnstructured (obj ).DeepCopy ()
93+ err := framework .GetClients ().GenericClient ().Get (context .Background (), key , u )
94+ g .Expect (err ).ShouldNot (HaveOccurred ())
95+
96+ conditions , found , err := unstructured .NestedSlice (u .Object , "status" , "conditions" )
97+ g .Expect (err ).ShouldNot (HaveOccurred (), "failed to access status.conditions of %s/%s" , u .GetNamespace (), u .GetName ())
98+ g .Expect (found ).Should (BeTrue (), "no status.conditions found in %s/%s" , u .GetNamespace (), u .GetName ())
99+
100+ var actualReason , actualStatus , actualMessage string
101+ condFound := false
102+
103+ for _ , c := range conditions {
104+ m , ok := c .(map [string ]interface {})
105+ if ! ok {
106+ continue
107+ }
108+ if t , ok := m ["type" ].(string ); ok && t == conditionType {
109+ condFound = true
110+ if s , ok := m ["reason" ].(string ); ok {
111+ actualReason = s
112+ } else {
113+ actualReason = "Unknown"
114+ }
115+ if s , ok := m ["status" ].(string ); ok {
116+ actualStatus = s
117+ } else {
118+ actualStatus = "Unknown"
119+ }
120+ if s , ok := m ["message" ].(string ); ok {
121+ actualMessage = s
122+ } else {
123+ actualMessage = ""
124+ }
125+ break
126+ }
127+ }
128+ g .Expect (condFound ).To (BeTrue (), "object %s/%s: condition %s not found" , u .GetNamespace (), u .GetName (), conditionType )
129+
130+ if checkOptions .CheckReason {
131+ g .Expect (actualReason ).To (Equal (checkOptions .Reason ),
132+ "object %s/%s: condition %s reason is %q, expected %q" ,
133+ u .GetNamespace (), u .GetName (), conditionType , actualReason , checkOptions .Reason )
134+ }
135+ if checkOptions .CheckStatus {
136+ g .Expect (actualStatus ).To (Equal (checkOptions .Status ),
137+ "object %s/%s: condition %s status is %q, expected %q" ,
138+ u .GetNamespace (), u .GetName (), conditionType , actualStatus , checkOptions .Status )
139+ }
140+ if checkOptions .CheckMessage {
141+ g .Expect (actualMessage ).To (Equal (checkOptions .Message ),
142+ "object %s/%s: condition %s message is %q, expected %q" ,
143+ u .GetNamespace (), u .GetName (), conditionType , actualMessage , checkOptions .Message )
144+ }
145+ }
146+ }).WithTimeout (timeout ).WithPolling (time .Second ).Should (Succeed ())
147+ }
148+
43149// UntilObjectState waits for an object to reach the specified state.
44150// It accepts a runtime.Object (which serves as a template with name and namespace),
45151// expected state string, and timeout duration.
0 commit comments