Skip to content

Commit d0a213a

Browse files
committedMar 3, 2023
Handle AllAlpha and AllBeta in SetFeatureGateDuringTest
1 parent 3835c7a commit d0a213a

File tree

3 files changed

+145
-2
lines changed

3 files changed

+145
-2
lines changed
 

Diff for: ‎hack/verify-test-featuregates.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ cd "${KUBE_ROOT}"
3030
rc=0
3131

3232
# find test files accessing the mutable global feature gate or interface
33-
direct_sets=$(find -L . -name '*_test.go' -exec grep -Hn 'MutableFeatureGate' {} \; 2>/dev/null) || true
33+
direct_sets=$(git grep MutableFeatureGate -- '*_test.go') || true
3434
if [[ -n "${direct_sets}" ]]; then
3535
echo "Test files may not access mutable global feature gates directly:" >&2
3636
echo "${direct_sets}" >&2
@@ -42,7 +42,7 @@ if [[ -n "${direct_sets}" ]]; then
4242
fi
4343

4444
# find test files calling SetFeatureGateDuringTest and not calling the result
45-
missing_defers=$(find -L . -name '*_test.go' -exec grep -Hn 'SetFeatureGateDuringTest' {} \; 2>/dev/null | grep -E -v "defer .*\\)\\(\\)$") || true
45+
missing_defers=$(git grep "\\.SetFeatureGateDuringTest" -- '*_test.go' | grep -E -v "defer .*\\)\\(\\)$") || true
4646
if [[ -n "${missing_defers}" ]]; then
4747
echo "Invalid invocations of featuregatetesting.SetFeatureGateDuringTest():" >&2
4848
echo "${missing_defers}" >&2

Diff for: ‎staging/src/k8s.io/component-base/featuregate/testing/feature_gate.go

+17
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@ import (
3232
func SetFeatureGateDuringTest(tb testing.TB, gate featuregate.FeatureGate, f featuregate.Feature, value bool) func() {
3333
originalValue := gate.Enabled(f)
3434

35+
// Specially handle AllAlpha and AllBeta
36+
var cleanups []func()
37+
if f == "AllAlpha" || f == "AllBeta" {
38+
// Iterate over individual gates so their individual values get restored
39+
for k, v := range gate.(featuregate.MutableFeatureGate).GetAll() {
40+
if k == "AllAlpha" || k == "AllBeta" {
41+
continue
42+
}
43+
if (f == "AllAlpha" && v.PreRelease == featuregate.Alpha) || (f == "AllBeta" && v.PreRelease == featuregate.Beta) {
44+
cleanups = append(cleanups, SetFeatureGateDuringTest(tb, gate, k, value))
45+
}
46+
}
47+
}
48+
3549
if err := gate.(featuregate.MutableFeatureGate).Set(fmt.Sprintf("%s=%v", f, value)); err != nil {
3650
tb.Errorf("error setting %s=%v: %v", f, value, err)
3751
}
@@ -40,5 +54,8 @@ func SetFeatureGateDuringTest(tb testing.TB, gate featuregate.FeatureGate, f fea
4054
if err := gate.(featuregate.MutableFeatureGate).Set(fmt.Sprintf("%s=%v", f, originalValue)); err != nil {
4155
tb.Errorf("error restoring %s=%v: %v", f, originalValue, err)
4256
}
57+
for _, cleanup := range cleanups {
58+
cleanup()
59+
}
4360
}
4461
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package testing
18+
19+
import (
20+
gotest "testing"
21+
22+
"k8s.io/component-base/featuregate"
23+
)
24+
25+
func TestSpecialGates(t *gotest.T) {
26+
gate := featuregate.NewFeatureGate()
27+
gate.Add(map[featuregate.Feature]featuregate.FeatureSpec{
28+
"alpha_default_on": {PreRelease: featuregate.Alpha, Default: true},
29+
"alpha_default_on_set_off": {PreRelease: featuregate.Alpha, Default: true},
30+
"alpha_default_off": {PreRelease: featuregate.Alpha, Default: false},
31+
"alpha_default_off_set_on": {PreRelease: featuregate.Alpha, Default: false},
32+
33+
"beta_default_on": {PreRelease: featuregate.Beta, Default: true},
34+
"beta_default_on_set_off": {PreRelease: featuregate.Beta, Default: true},
35+
"beta_default_off": {PreRelease: featuregate.Beta, Default: false},
36+
"beta_default_off_set_on": {PreRelease: featuregate.Beta, Default: false},
37+
38+
"stable_default_on": {PreRelease: featuregate.GA, Default: true},
39+
"stable_default_on_set_off": {PreRelease: featuregate.GA, Default: true},
40+
"stable_default_off": {PreRelease: featuregate.GA, Default: false},
41+
"stable_default_off_set_on": {PreRelease: featuregate.GA, Default: false},
42+
})
43+
gate.Set("alpha_default_on_set_off=false")
44+
gate.Set("beta_default_on_set_off=false")
45+
gate.Set("stable_default_on_set_off=false")
46+
gate.Set("alpha_default_off_set_on=true")
47+
gate.Set("beta_default_off_set_on=true")
48+
gate.Set("stable_default_off_set_on=true")
49+
50+
before := map[featuregate.Feature]bool{
51+
"AllAlpha": false,
52+
"AllBeta": false,
53+
54+
"alpha_default_on": true,
55+
"alpha_default_on_set_off": false,
56+
"alpha_default_off": false,
57+
"alpha_default_off_set_on": true,
58+
59+
"beta_default_on": true,
60+
"beta_default_on_set_off": false,
61+
"beta_default_off": false,
62+
"beta_default_off_set_on": true,
63+
64+
"stable_default_on": true,
65+
"stable_default_on_set_off": false,
66+
"stable_default_off": false,
67+
"stable_default_off_set_on": true,
68+
}
69+
expect(t, gate, before)
70+
71+
cleanupAlpha := SetFeatureGateDuringTest(t, gate, "AllAlpha", true)
72+
expect(t, gate, map[featuregate.Feature]bool{
73+
"AllAlpha": true,
74+
"AllBeta": false,
75+
76+
"alpha_default_on": true,
77+
"alpha_default_on_set_off": true,
78+
"alpha_default_off": true,
79+
"alpha_default_off_set_on": true,
80+
81+
"beta_default_on": true,
82+
"beta_default_on_set_off": false,
83+
"beta_default_off": false,
84+
"beta_default_off_set_on": true,
85+
86+
"stable_default_on": true,
87+
"stable_default_on_set_off": false,
88+
"stable_default_off": false,
89+
"stable_default_off_set_on": true,
90+
})
91+
92+
cleanupBeta := SetFeatureGateDuringTest(t, gate, "AllBeta", true)
93+
expect(t, gate, map[featuregate.Feature]bool{
94+
"AllAlpha": true,
95+
"AllBeta": true,
96+
97+
"alpha_default_on": true,
98+
"alpha_default_on_set_off": true,
99+
"alpha_default_off": true,
100+
"alpha_default_off_set_on": true,
101+
102+
"beta_default_on": true,
103+
"beta_default_on_set_off": true,
104+
"beta_default_off": true,
105+
"beta_default_off_set_on": true,
106+
107+
"stable_default_on": true,
108+
"stable_default_on_set_off": false,
109+
"stable_default_off": false,
110+
"stable_default_off_set_on": true,
111+
})
112+
113+
// run cleanups in reverse order like defer would
114+
cleanupBeta()
115+
cleanupAlpha()
116+
expect(t, gate, before)
117+
}
118+
119+
func expect(t *gotest.T, gate featuregate.FeatureGate, expect map[featuregate.Feature]bool) {
120+
t.Helper()
121+
for k, v := range expect {
122+
if gate.Enabled(k) != v {
123+
t.Errorf("Expected %v=%v, got %v", k, v, gate.Enabled(k))
124+
}
125+
}
126+
}

0 commit comments

Comments
 (0)
Please sign in to comment.