-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
GetCondition and something like UpdateCondition have worked well in the OperatorPolicy. The fakepolicy tests have been updated to use conditions instead of the various special fields it was collecting in its status. Signed-off-by: Justin Kulikauskas <[email protected]>
- Loading branch information
1 parent
c4bb986
commit 7ea4fed
Showing
12 changed files
with
573 additions
and
131 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// Copyright Contributors to the Open Cluster Management project | ||
|
||
package v1beta1 | ||
|
||
import ( | ||
"sort" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
// GetCondition returns the existing index and condition on the status matching the given type. If | ||
// no condition of that type is found, it will return -1 as the index. | ||
func (status PolicyCoreStatus) GetCondition(condType string) (int, metav1.Condition) { | ||
for i, cond := range status.Conditions { | ||
if cond.Type == condType { | ||
return i, cond | ||
} | ||
} | ||
|
||
return -1, metav1.Condition{} | ||
} | ||
|
||
// UpdateCondition modifies the specified condition in the status or adds it if not present, | ||
// ensuring conditions remain sorted by Type. Returns true if the condition was updated or added. | ||
func (status *PolicyCoreStatus) UpdateCondition(newCond metav1.Condition) (changed bool) { | ||
idx, existingCond := status.GetCondition(newCond.Type) | ||
if idx == -1 { | ||
if newCond.LastTransitionTime.IsZero() { | ||
newCond.LastTransitionTime = metav1.Now() | ||
} | ||
|
||
status.Conditions = append(status.Conditions, newCond) | ||
|
||
sort.SliceStable(status.Conditions, func(i, j int) bool { | ||
return status.Conditions[i].Type < status.Conditions[j].Type | ||
}) | ||
|
||
return true | ||
} else if condSemanticallyChanged(newCond, existingCond) { | ||
if newCond.LastTransitionTime.IsZero() { | ||
newCond.LastTransitionTime = metav1.Now() | ||
} | ||
|
||
status.Conditions[idx] = newCond | ||
|
||
// Do not sort in this case, assume that they are in order. | ||
|
||
return true | ||
} | ||
|
||
return false | ||
} | ||
|
||
func condSemanticallyChanged(newCond, oldCond metav1.Condition) bool { | ||
return newCond.Message != oldCond.Message || | ||
newCond.Reason != oldCond.Reason || | ||
newCond.Status != oldCond.Status | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
// Copyright Contributors to the Open Cluster Management project | ||
|
||
package v1beta1 | ||
|
||
import ( | ||
"testing" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
func getSampleStatus() PolicyCoreStatus { | ||
return PolicyCoreStatus{ | ||
Conditions: []metav1.Condition{{ | ||
Type: "Apple", | ||
Status: metav1.ConditionTrue, | ||
Reason: "NoDoctor", | ||
Message: "an apple a day...", | ||
}, { | ||
Type: "Compliant", | ||
Status: metav1.ConditionTrue, | ||
Reason: "Compliant", | ||
Message: "everything is good", | ||
}, { | ||
Type: "Bonus", | ||
Status: metav1.ConditionFalse, | ||
Reason: "Compliant", | ||
Message: "this condition is out of order", | ||
}}, | ||
} | ||
} | ||
|
||
func TestGetCondition(t *testing.T) { | ||
t.Parallel() | ||
|
||
tests := map[string]struct { | ||
inputType string | ||
wantIdx int | ||
wantMsg string | ||
}{ | ||
"Apple is found": { | ||
inputType: "Apple", | ||
wantIdx: 0, | ||
wantMsg: "an apple a day...", | ||
}, | ||
"Compliant is found": { | ||
inputType: "Compliant", | ||
wantIdx: 1, | ||
wantMsg: "everything is good", | ||
}, | ||
"Imaginary is not found": { | ||
inputType: "Imaginary", | ||
wantIdx: -1, | ||
wantMsg: "", | ||
}, | ||
} | ||
|
||
for name, tcase := range tests { | ||
gotIdx, gotCond := getSampleStatus().GetCondition(tcase.inputType) | ||
|
||
if gotIdx != tcase.wantIdx { | ||
t.Errorf("Expected index %v in test %q, got %v", tcase.wantIdx, name, gotIdx) | ||
} | ||
|
||
if tcase.wantIdx == -1 { | ||
continue | ||
} | ||
|
||
if gotCond.Message != tcase.wantMsg { | ||
t.Errorf("Expected message %q in test %q, got %q", tcase.wantMsg, name, gotCond.Message) | ||
} | ||
} | ||
} | ||
|
||
func TestUpdateCondition(t *testing.T) { | ||
t.Parallel() | ||
|
||
baseLen := len(getSampleStatus().Conditions) | ||
|
||
tests := map[string]struct { | ||
newCond metav1.Condition | ||
wantChange bool | ||
wantLen int | ||
wantIdx int | ||
}{ | ||
"Imaginary should be added to the end": { | ||
newCond: metav1.Condition{ | ||
Type: "Imaginary", | ||
Status: metav1.ConditionFalse, | ||
Reason: "Existent", | ||
Message: "not just imaginary", | ||
}, | ||
wantChange: true, | ||
wantLen: baseLen + 1, | ||
wantIdx: baseLen, | ||
}, | ||
"Basic should be added in the middle": { | ||
newCond: metav1.Condition{ | ||
Type: "Basic", | ||
Status: metav1.ConditionTrue, | ||
Reason: "Easy", | ||
Message: "should be simple enough", | ||
}, | ||
wantChange: true, | ||
wantLen: baseLen + 1, | ||
wantIdx: 1, | ||
}, | ||
"Bonus should be updated but not moved": { | ||
newCond: metav1.Condition{ | ||
Type: "Bonus", | ||
Status: metav1.ConditionTrue, | ||
Reason: "Compliant", | ||
Message: "this condition is now in order", | ||
}, | ||
wantChange: true, | ||
wantLen: baseLen, | ||
wantIdx: baseLen - 1, | ||
}, | ||
"Apple should be updated if the message is different": { | ||
newCond: metav1.Condition{ | ||
Type: "Apple", | ||
Status: metav1.ConditionTrue, | ||
Reason: "NoDoctor", | ||
Message: "an apple a day keeps the doctor away", | ||
}, | ||
wantChange: true, | ||
wantLen: baseLen, | ||
wantIdx: 0, | ||
}, | ||
"Apple should not be updated if the message is the same": { | ||
newCond: metav1.Condition{ | ||
Type: "Apple", | ||
Status: metav1.ConditionTrue, | ||
Reason: "NoDoctor", | ||
Message: "an apple a day...", | ||
}, | ||
wantChange: false, | ||
wantLen: baseLen, | ||
wantIdx: 0, | ||
}, | ||
} | ||
|
||
for name, tcase := range tests { | ||
status := getSampleStatus() | ||
|
||
gotChanged := status.UpdateCondition(tcase.newCond) | ||
|
||
if tcase.wantChange && !gotChanged { | ||
t.Errorf("Expected test %q to change the conditions, but it didn't", name) | ||
} else if !tcase.wantChange && gotChanged { | ||
t.Errorf("Expected test %q not to change the conditions, but it did", name) | ||
} | ||
|
||
gotLen := len(status.Conditions) | ||
if gotLen != tcase.wantLen { | ||
t.Errorf("Expected conditions to be length %v after test %q, got length %v", | ||
tcase.wantLen, name, gotLen) | ||
} | ||
|
||
gotIdx, gotCond := status.GetCondition(tcase.newCond.Type) | ||
|
||
if gotIdx != tcase.wantIdx { | ||
t.Errorf("Expected condition to be at index %v after test %q, got index %v", | ||
tcase.wantIdx, name, gotIdx) | ||
} | ||
|
||
if gotCond.Message != tcase.newCond.Message { | ||
t.Errorf("Expected condition to have message %q after test %q, got %q", | ||
tcase.newCond.Message, name, gotCond.Message) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.