Skip to content

Commit b5465da

Browse files
committed
add StatusUpdater
1 parent bd2574f commit b5465da

File tree

8 files changed

+991
-103
lines changed

8 files changed

+991
-103
lines changed

pkg/conditions/updater.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ import (
1111
// conditionUpdater is a helper struct for updating a list of Conditions.
1212
// Use the ConditionUpdater constructor for initializing.
1313
type conditionUpdater[T comparable] struct {
14-
Now time.Time
15-
conditions map[string]Condition[T]
16-
updated sets.Set[string]
17-
constructor func() Condition[T]
18-
changed bool
14+
Now time.Time
15+
conditions map[string]Condition[T]
16+
updated sets.Set[string]
17+
construct func() Condition[T]
18+
changed bool
1919
}
2020

2121
// ConditionUpdater creates a builder-like helper struct for updating a list of Conditions.
@@ -30,12 +30,12 @@ type conditionUpdater[T comparable] struct {
3030
//
3131
// Usage example:
3232
// status.conditions = ConditionUpdater(status.conditions, true).UpdateCondition(...).UpdateCondition(...).Conditions()
33-
func ConditionUpdater[T comparable](constructor func() Condition[T], conditions []Condition[T], removeUntouched bool) *conditionUpdater[T] {
33+
func ConditionUpdater[T comparable](construct func() Condition[T], conditions []Condition[T], removeUntouched bool) *conditionUpdater[T] {
3434
res := &conditionUpdater[T]{
35-
Now: time.Now(),
36-
conditions: make(map[string]Condition[T], len(conditions)),
37-
constructor: constructor,
38-
changed: false,
35+
Now: time.Now(),
36+
conditions: make(map[string]Condition[T], len(conditions)),
37+
construct: construct,
38+
changed: false,
3939
}
4040
for _, con := range conditions {
4141
res.conditions[con.GetType()] = con
@@ -50,7 +50,7 @@ func ConditionUpdater[T comparable](constructor func() Condition[T], conditions
5050
// All fields of the condition are updated with the values given in the arguments, but the condition's LastTransitionTime is only updated (with the timestamp contained in the receiver struct) if the status changed.
5151
// Returns the receiver for easy chaining.
5252
func (c *conditionUpdater[T]) UpdateCondition(conType string, status T, reason, message string) *conditionUpdater[T] {
53-
con := c.constructor()
53+
con := c.construct()
5454
con.SetType(conType)
5555
con.SetStatus(status)
5656
con.SetReason(reason)
@@ -103,6 +103,7 @@ func (c *conditionUpdater[T]) RemoveCondition(conType string) *conditionUpdater[
103103
// If the condition updater was initialized with removeUntouched=true, this list will only contain the conditions which have been updated
104104
// in between the condition updater creation and this method call. Otherwise, it will potentially also contain old conditions.
105105
// The conditions are returned sorted by their type.
106+
// The second return value indicates whether the condition list has actually changed.
106107
func (c *conditionUpdater[T]) Conditions() ([]Condition[T], bool) {
107108
res := make([]Condition[T], 0, len(c.conditions))
108109
for _, con := range c.conditions {

pkg/conditions/updater_test.go

Lines changed: 18 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -7,76 +7,17 @@ import (
77

88
. "github.com/onsi/ginkgo/v2"
99
. "github.com/onsi/gomega"
10+
. "github.com/openmcp-project/controller-utils/pkg/testing/matchers"
1011

1112
"github.com/openmcp-project/controller-utils/pkg/conditions"
1213
)
1314

14-
type conImpl struct {
15-
status bool
16-
conType string
17-
reason string
18-
message string
19-
lastTransitionTime time.Time
20-
}
21-
22-
func newConImplWithValues(conType string, status bool, reason, message string, lastTransitionTime time.Time) *conImpl {
23-
return &conImpl{
24-
conType: conType,
25-
status: status,
26-
reason: reason,
27-
message: message,
28-
lastTransitionTime: lastTransitionTime,
29-
}
30-
}
31-
32-
var _ conditions.Condition[bool] = &conImpl{}
33-
34-
func (c *conImpl) GetLastTransitionTime() time.Time {
35-
return c.lastTransitionTime
36-
}
37-
38-
func (c *conImpl) GetType() string {
39-
return c.conType
40-
}
41-
42-
func (c *conImpl) GetStatus() bool {
43-
return c.status
44-
}
45-
46-
func (c *conImpl) GetReason() string {
47-
return c.reason
48-
}
49-
50-
func (c *conImpl) GetMessage() string {
51-
return c.message
52-
}
53-
54-
func (c *conImpl) SetStatus(status bool) {
55-
c.status = status
56-
}
57-
58-
func (c *conImpl) SetType(conType string) {
59-
c.conType = conType
60-
}
61-
62-
func (c *conImpl) SetLastTransitionTime(timestamp time.Time) {
63-
c.lastTransitionTime = timestamp
64-
}
65-
66-
func (c *conImpl) SetReason(reason string) {
67-
c.reason = reason
68-
}
69-
70-
func (c *conImpl) SetMessage(message string) {
71-
c.message = message
72-
}
73-
7415
func testConditionSet() []conditions.Condition[bool] {
7516
now := time.Now().Add((-24) * time.Hour)
7617
return []conditions.Condition[bool]{
77-
newConImplWithValues("true", true, "reason", "message", now),
78-
newConImplWithValues("false", false, "reason", "message", now),
79-
newConImplWithValues("alsoTrue", true, "alsoReason", "alsoMessage", now),
18+
NewConditionImplFromValues("true", true, "reason", "message", now),
19+
NewConditionImplFromValues("false", false, "reason", "message", now),
20+
NewConditionImplFromValues("alsoTrue", true, "alsoReason", "alsoMessage", now),
8021
}
8122
}
8223

@@ -134,7 +75,7 @@ var _ = Describe("Conditions", func() {
13475
It("should update the condition (same value, keep other cons)", func() {
13576
cons := testConditionSet()
13677
oldCon := conditions.GetCondition(cons, "true")
137-
updated, changed := conditions.ConditionUpdater(func() conditions.Condition[bool] { return &conImpl{} }, cons, false).UpdateCondition(oldCon.GetType(), oldCon.GetStatus(), "newReason", "newMessage").Conditions()
78+
updated, changed := conditions.ConditionUpdater(NewCondition[bool], cons, false).UpdateCondition(oldCon.GetType(), oldCon.GetStatus(), "newReason", "newMessage").Conditions()
13879
Expect(changed).To(BeTrue())
13980
newCon := conditions.GetCondition(updated, "true")
14081
Expect(updated).To(HaveLen(len(cons)))
@@ -151,7 +92,7 @@ var _ = Describe("Conditions", func() {
15192
It("should update the condition (different value, keep other cons)", func() {
15293
cons := testConditionSet()
15394
oldCon := conditions.GetCondition(cons, "true")
154-
updated, changed := conditions.ConditionUpdater(func() conditions.Condition[bool] { return &conImpl{} }, cons, false).UpdateCondition(oldCon.GetType(), !oldCon.GetStatus(), "newReason", "newMessage").Conditions()
95+
updated, changed := conditions.ConditionUpdater(NewCondition[bool], cons, false).UpdateCondition(oldCon.GetType(), !oldCon.GetStatus(), "newReason", "newMessage").Conditions()
15596
Expect(changed).To(BeTrue())
15697
newCon := conditions.GetCondition(updated, "true")
15798
Expect(updated).To(HaveLen(len(cons)))
@@ -169,7 +110,7 @@ var _ = Describe("Conditions", func() {
169110
It("should update the condition (same value, discard other cons)", func() {
170111
cons := testConditionSet()
171112
oldCon := conditions.GetCondition(cons, "true")
172-
updated, changed := conditions.ConditionUpdater(func() conditions.Condition[bool] { return &conImpl{} }, cons, true).UpdateCondition(oldCon.GetType(), oldCon.GetStatus(), "newReason", "newMessage").Conditions()
113+
updated, changed := conditions.ConditionUpdater(NewCondition[bool], cons, true).UpdateCondition(oldCon.GetType(), oldCon.GetStatus(), "newReason", "newMessage").Conditions()
173114
Expect(changed).To(BeTrue())
174115
newCon := conditions.GetCondition(updated, "true")
175116
Expect(updated).To(HaveLen(1))
@@ -186,7 +127,7 @@ var _ = Describe("Conditions", func() {
186127
It("should update the condition (different value, discard other cons)", func() {
187128
cons := testConditionSet()
188129
oldCon := conditions.GetCondition(cons, "true")
189-
updated, changed := conditions.ConditionUpdater(func() conditions.Condition[bool] { return &conImpl{} }, cons, true).UpdateCondition(oldCon.GetType(), !oldCon.GetStatus(), "newReason", "newMessage").Conditions()
130+
updated, changed := conditions.ConditionUpdater(NewCondition[bool], cons, true).UpdateCondition(oldCon.GetType(), !oldCon.GetStatus(), "newReason", "newMessage").Conditions()
190131
Expect(changed).To(BeTrue())
191132
newCon := conditions.GetCondition(updated, "true")
192133
Expect(updated).To(HaveLen(1))
@@ -203,16 +144,16 @@ var _ = Describe("Conditions", func() {
203144

204145
It("should sort the conditions by type", func() {
205146
cons := []conditions.Condition[bool]{
206-
newConImplWithValues("c", true, "reason", "message", time.Now()),
207-
newConImplWithValues("d", true, "reason", "message", time.Now()),
208-
newConImplWithValues("a", true, "reason", "message", time.Now()),
209-
newConImplWithValues("b", true, "reason", "message", time.Now()),
147+
NewConditionImplFromValues("c", true, "reason", "message", time.Now()),
148+
NewConditionImplFromValues("d", true, "reason", "message", time.Now()),
149+
NewConditionImplFromValues("a", true, "reason", "message", time.Now()),
150+
NewConditionImplFromValues("b", true, "reason", "message", time.Now()),
210151
}
211152
compareConditions := func(a, b conditions.Condition[bool]) int {
212153
return strings.Compare(a.GetType(), b.GetType())
213154
}
214155
Expect(slices.IsSortedFunc(cons, compareConditions)).To(BeFalse(), "conditions in the test object are already sorted, unable to test sorting")
215-
updated, changed := conditions.ConditionUpdater(func() conditions.Condition[bool] { return &conImpl{} }, cons, false).Conditions()
156+
updated, changed := conditions.ConditionUpdater(NewCondition[bool], cons, false).Conditions()
216157
Expect(changed).To(BeFalse())
217158
Expect(len(updated)).To(BeNumerically(">", 1), "test object does not contain enough conditions to test sorting")
218159
Expect(len(updated)).To(Equal(len(cons)))
@@ -221,32 +162,32 @@ var _ = Describe("Conditions", func() {
221162

222163
It("should remove a condition", func() {
223164
cons := testConditionSet()
224-
updated, changed := conditions.ConditionUpdater(func() conditions.Condition[bool] { return &conImpl{} }, cons, false).RemoveCondition("true").Conditions()
165+
updated, changed := conditions.ConditionUpdater(NewCondition[bool], cons, false).RemoveCondition("true").Conditions()
225166
Expect(changed).To(BeTrue())
226167
Expect(updated).To(HaveLen(len(cons) - 1))
227168
con := conditions.GetCondition(updated, "true")
228169
Expect(con).To(BeNil())
229170

230171
// removing a condition that does not exist should not change anything
231-
updated, changed = conditions.ConditionUpdater(func() conditions.Condition[bool] { return &conImpl{} }, cons, false).RemoveCondition("doesNotExist").Conditions()
172+
updated, changed = conditions.ConditionUpdater(NewCondition[bool], cons, false).RemoveCondition("doesNotExist").Conditions()
232173
Expect(changed).To(BeFalse())
233174
Expect(updated).To(HaveLen(len(cons)))
234175
})
235176

236177
It("should not mark a condition as changed if it has the same values as before", func() {
237178
cons := testConditionSet()
238179
con := conditions.GetCondition(cons, "true")
239-
updated, changed := conditions.ConditionUpdater(func() conditions.Condition[bool] { return &conImpl{} }, cons, false).UpdateCondition(con.GetType(), con.GetStatus(), con.GetReason(), con.GetMessage()).Conditions()
180+
updated, changed := conditions.ConditionUpdater(NewCondition[bool], cons, false).UpdateCondition(con.GetType(), con.GetStatus(), con.GetReason(), con.GetMessage()).Conditions()
240181
Expect(changed).To(BeFalse())
241182
Expect(updated).To(HaveLen(len(cons)))
242183
})
243184

244185
It("should return that a condition exists only if it will be contained in the returned list", func() {
245186
cons := testConditionSet()
246-
updater := conditions.ConditionUpdater(func() conditions.Condition[bool] { return &conImpl{} }, cons, false)
187+
updater := conditions.ConditionUpdater(NewCondition[bool], cons, false)
247188
Expect(updater.HasCondition("true")).To(BeTrue())
248189
Expect(updater.HasCondition("doesNotExist")).To(BeFalse())
249-
updater = conditions.ConditionUpdater(func() conditions.Condition[bool] { return &conImpl{} }, cons, true)
190+
updater = conditions.ConditionUpdater(NewCondition[bool], cons, true)
250191
Expect(updater.HasCondition("true")).To(BeFalse())
251192
Expect(updater.HasCondition("doesNotExist")).To(BeFalse())
252193
updater.UpdateCondition("true", true, "reason", "message")

pkg/controller/predicates.go

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -152,23 +152,10 @@ type StatusChangedPredicate struct {
152152
}
153153

154154
func (p StatusChangedPredicate) Update(e event.UpdateEvent) bool {
155-
oldStatus := getStatus(e.ObjectOld)
156-
newStatus := getStatus(e.ObjectNew)
155+
oldStatus := GetField(e.ObjectOld, "Status", false)
156+
newStatus := GetField(e.ObjectNew, "Status", false)
157157
if oldStatus == nil || newStatus == nil {
158158
return true
159159
}
160160
return !reflect.DeepEqual(oldStatus, newStatus)
161161
}
162-
163-
func getStatus(obj any) any {
164-
if obj == nil {
165-
return nil
166-
}
167-
val := reflect.ValueOf(obj).Elem()
168-
for i := 0; i < val.NumField(); i++ {
169-
if val.Type().Field(i).Name == "Status" {
170-
return val.Field(i).Interface()
171-
}
172-
}
173-
return nil
174-
}

0 commit comments

Comments
 (0)