Skip to content

Commit 9288f0b

Browse files
committed
make StatusUpdater work with condition implementations that are not pointers
1 parent 9d2c6e0 commit 9288f0b

File tree

3 files changed

+92
-17
lines changed

3 files changed

+92
-17
lines changed

pkg/controller/status_updater.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,23 @@ func (s *statusUpdater[Obj, PhType, ConType]) UpdateStatus(ctx context.Context,
227227
}
228228
newConsRaw, _ := cu.Conditions()
229229
conType := reflect.TypeOf(s.conConstruct())
230+
targetType := reflect.TypeOf(GetField(status, s.fieldNames[STATUS_FIELD_CONDITIONS], false))
231+
depointerize := false
232+
if !reflect.SliceOf(conType).AssignableTo(targetType) {
233+
// this can happen if the constructor returns a *ConditionImplementation, which creates a []*ConditionImplementation below,
234+
// but the condition list field is a []ConditionImplementation
235+
if conType.Kind() == reflect.Ptr {
236+
depointerize = true
237+
conType = conType.Elem()
238+
}
239+
}
230240
newCons := reflect.MakeSlice(reflect.SliceOf(conType), len(newConsRaw), len(newConsRaw)).Interface()
231241
for i := range newConsRaw {
232-
val := reflect.ValueOf(newConsRaw[i]).Convert(conType)
233-
reflect.ValueOf(newCons).Index(i).Set(val)
242+
val := reflect.ValueOf(newConsRaw[i])
243+
if depointerize {
244+
val = val.Elem()
245+
}
246+
reflect.ValueOf(newCons).Index(i).Set(val.Convert(conType))
234247
}
235248
SetField(status, s.fieldNames[STATUS_FIELD_CONDITIONS], newCons)
236249
}

pkg/controller/status_updater_test.go

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ func (c *Condition) SetLastTransitionTime(t time.Time) {
202202
}
203203

204204
// ConditionList is a list of Conditions.
205-
type ConditionList []*Condition
205+
type ConditionList []Condition
206206

207207
type CommonStatus struct {
208208
ObservedGeneration int64 `json:"observedGeneration"`
@@ -237,11 +237,7 @@ func (in *CommonStatus) DeepCopyInto(out *CommonStatus) {
237237
in, out := &in.Conditions, &out.Conditions
238238
*out = make(ConditionList, len(*in))
239239
for i := range *in {
240-
if (*in)[i] != nil {
241-
in, out := &(*in)[i], &(*out)[i]
242-
*out = new(Condition)
243-
(*in).DeepCopyInto(*out)
244-
}
240+
(*in)[i].DeepCopyInto(&(*out)[i])
245241
}
246242
}
247243
}
@@ -278,11 +274,7 @@ func (in ConditionList) DeepCopyInto(out *ConditionList) {
278274
in := &in
279275
*out = make(ConditionList, len(*in))
280276
for i := range *in {
281-
if (*in)[i] != nil {
282-
in, out := &(*in)[i], &(*out)[i]
283-
*out = new(Condition)
284-
(*in).DeepCopyInto(*out)
285-
}
277+
(*in)[i].DeepCopyInto(&(*out)[i])
286278
}
287279
}
288280
}

pkg/testing/matchers/conditions.go

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,50 @@ type conditionMatcher[T comparable] struct {
2020
expected *ConditionImpl[T]
2121
}
2222

23+
func (c *conditionMatcher[T]) GomegaString() string {
24+
if c == nil || c.expected == nil {
25+
return "<nil>"
26+
}
27+
return c.expected.String()
28+
}
29+
2330
var _ types.GomegaMatcher = &conditionMatcher[bool]{}
2431

2532
// Match implements types.GomegaMatcher.
26-
func (c *conditionMatcher[T]) Match(actualRaw interface{}) (success bool, err error) {
27-
actual, ok := actualRaw.(conditions.Condition[T])
28-
if !ok {
29-
return false, fmt.Errorf("expected actual to be of type Condition[%s], got %T", reflect.TypeFor[T]().Name(), actualRaw)
33+
func (c *conditionMatcher[T]) Match(actualRaw any) (success bool, err error) {
34+
actual, converted := actualRaw.(conditions.Condition[T])
35+
if !converted {
36+
// actualRaw doesn't implement conditions.Condition[T], check if a pointer to it does
37+
ptrValue := reflect.New(reflect.TypeOf(actualRaw))
38+
reflect.Indirect(ptrValue).Set(reflect.ValueOf(actualRaw))
39+
actual, converted = ptrValue.Interface().(conditions.Condition[T])
40+
}
41+
if !converted {
42+
return false, fmt.Errorf("expected actual (or &actual) to be of type Condition[%s], got %T", reflect.TypeFor[T]().Name(), actualRaw)
43+
}
44+
// if aVal.CanConvert(conImplType) {
45+
// actual = aVal.Convert(conImplType).Interface().(conditions.Condition[T])
46+
// } else if aVal.Kind() == reflect.Struct {
47+
// p := reflect.PointerTo()
48+
// actual = aVal.Addr().Convert(conImplType).Interface().(conditions.Condition[T])
49+
// } else {
50+
// return false, fmt.Errorf("expected actual to be of type Condition[%s], got %T", reflect.TypeFor[T]().Name(), actualRaw)
51+
// }
52+
// actual, ok := actualRaw.(conditions.Condition[T])
53+
// if !ok {
54+
// // check if actualRaw is a valid Condition if a pointer to it is used instead
55+
// tmp, ok := actualRaw.(*conditions.Condition[T])
56+
// if ok {
57+
// actual = *tmp
58+
// } else {
59+
// return false, fmt.Errorf("expected actual to be of type Condition[%s], got %T", reflect.TypeFor[T]().Name(), actualRaw)
60+
// }
61+
// }
62+
if actual == nil && c.expected == nil {
63+
return true, nil
64+
}
65+
if actual == nil || c.expected == nil {
66+
return false, nil
3067
}
3168
if c.expected.HasType() && c.expected.GetType() != actual.GetType() {
3269
return false, nil
@@ -86,6 +123,39 @@ type ConditionImpl[T comparable] struct {
86123
lastTransitionTime *time.Time
87124
}
88125

126+
func (c *ConditionImpl[T]) String() string {
127+
if c == nil {
128+
return "<nil>"
129+
}
130+
var status, conType, reason, message, lastTransitionTime string
131+
if c.status == nil {
132+
status = "<arbitrary>"
133+
} else {
134+
status = fmt.Sprintf("%v", *c.status)
135+
}
136+
if c.conType == nil {
137+
conType = "<arbitrary>"
138+
} else {
139+
conType = *c.conType
140+
}
141+
if c.reason == nil {
142+
reason = "<arbitrary>"
143+
} else {
144+
reason = *c.reason
145+
}
146+
if c.message == nil {
147+
message = "<arbitrary>"
148+
} else {
149+
message = *c.message
150+
}
151+
if c.lastTransitionTime == nil {
152+
lastTransitionTime = "<arbitrary>"
153+
} else {
154+
lastTransitionTime = c.lastTransitionTime.Format(time.RFC3339)
155+
}
156+
return fmt.Sprintf("Condition[%s]{\n\tType: %q,\n\tStatus: %s,\n\tReason: %q,\n\tMessage: %q,\n\tLastTransitionTime: %v,\n}", reflect.TypeFor[T]().Name(), conType, status, reason, message, lastTransitionTime)
157+
}
158+
89159
var _ conditions.Condition[bool] = &ConditionImpl[bool]{}
90160

91161
func (c *ConditionImpl[T]) GetLastTransitionTime() time.Time {

0 commit comments

Comments
 (0)