Skip to content

Commit c4082b2

Browse files
authored
Merge pull request #4452 from randomvariable/automated-cherry-pick-of-#4448-release-0.3
🐛 Adds a test helper to all mutating webhooks to ensure defaulting passes validation (0.3 backport)
2 parents 4232d5d + 03f1869 commit c4082b2

File tree

10 files changed

+102
-16
lines changed

10 files changed

+102
-16
lines changed

api/v1alpha3/cluster_webhook_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
corev1 "k8s.io/api/core/v1"
2525
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
utildefaulting "sigs.k8s.io/cluster-api/util/defaulting"
2627
)
2728

2829
func TestClusterDefault(t *testing.T) {
@@ -37,6 +38,8 @@ func TestClusterDefault(t *testing.T) {
3738
ControlPlaneRef: &corev1.ObjectReference{},
3839
},
3940
}
41+
42+
t.Run("for Cluster", utildefaulting.DefaultValidateTest(c))
4043
c.Default()
4144

4245
g.Expect(c.Spec.InfrastructureRef.Namespace).To(Equal(c.Namespace))

api/v1alpha3/machine_webhook_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"testing"
2121

2222
. "github.com/onsi/gomega"
23+
utildefaulting "sigs.k8s.io/cluster-api/util/defaulting"
2324

2425
corev1 "k8s.io/api/core/v1"
2526
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -38,7 +39,7 @@ func TestMachineDefault(t *testing.T) {
3839
Version: pointer.StringPtr("1.17.5"),
3940
},
4041
}
41-
42+
t.Run("for Machine", utildefaulting.DefaultValidateTest(m))
4243
m.Default()
4344

4445
g.Expect(m.Labels[ClusterLabelName]).To(Equal(m.Spec.ClusterName))

api/v1alpha3/machinedeployment_webhook_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2525
"k8s.io/utils/pointer"
26+
utildefaulting "sigs.k8s.io/cluster-api/util/defaulting"
2627
)
2728

2829
func TestMachineDeploymentDefault(t *testing.T) {
@@ -32,7 +33,7 @@ func TestMachineDeploymentDefault(t *testing.T) {
3233
Name: "test-md",
3334
},
3435
}
35-
36+
t.Run("for MachineDeployment", utildefaulting.DefaultValidateTest(md))
3637
md.Default()
3738

3839
g.Expect(md.Labels[ClusterLabelName]).To(Equal(md.Spec.ClusterName))

api/v1alpha3/machinehealthcheck_webhook_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,19 @@ import (
2424

2525
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2626
"k8s.io/apimachinery/pkg/util/intstr"
27+
utildefaulting "sigs.k8s.io/cluster-api/util/defaulting"
2728
)
2829

2930
func TestMachineHealthCheckDefault(t *testing.T) {
3031
g := NewWithT(t)
31-
mhc := &MachineHealthCheck{}
32-
32+
mhc := &MachineHealthCheck{
33+
Spec: MachineHealthCheckSpec{
34+
Selector: metav1.LabelSelector{
35+
MatchLabels: map[string]string{"foo": "bar"},
36+
},
37+
},
38+
}
39+
t.Run("for MachineHealthCheck", utildefaulting.DefaultValidateTest(mhc))
3340
mhc.Default()
3441

3542
g.Expect(mhc.Labels[ClusterLabelName]).To(Equal(mhc.Spec.ClusterName))

api/v1alpha3/machineset_webhook_test.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,23 @@ import (
2222
. "github.com/onsi/gomega"
2323

2424
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25-
"k8s.io/utils/pointer"
25+
utildefaulting "sigs.k8s.io/cluster-api/util/defaulting"
2626
)
2727

2828
func TestMachineSetDefault(t *testing.T) {
2929
g := NewWithT(t)
30-
md := &MachineSet{
30+
ms := &MachineSet{
3131
ObjectMeta: metav1.ObjectMeta{
3232
Name: "test-ms",
3333
},
3434
}
35+
t.Run("for MachineSet", utildefaulting.DefaultValidateTest(ms))
36+
ms.Default()
3537

36-
md.Default()
37-
38-
g.Expect(md.Labels[ClusterLabelName]).To(Equal(md.Spec.ClusterName))
39-
g.Expect(md.Spec.Replicas).To(Equal(pointer.Int32Ptr(1)))
40-
g.Expect(md.Spec.DeletePolicy).To(Equal(string(RandomMachineSetDeletePolicy)))
41-
g.Expect(md.Spec.Selector.MatchLabels).To(HaveKeyWithValue(MachineSetLabelName, "test-ms"))
42-
g.Expect(md.Spec.Template.Labels).To(HaveKeyWithValue(MachineSetLabelName, "test-ms"))
38+
g.Expect(ms.Labels[ClusterLabelName]).To(Equal(ms.Spec.ClusterName))
39+
g.Expect(ms.Spec.DeletePolicy).To(Equal(string(RandomMachineSetDeletePolicy)))
40+
g.Expect(ms.Spec.Selector.MatchLabels).To(HaveKeyWithValue(MachineSetLabelName, "test-ms"))
41+
g.Expect(ms.Spec.Template.Labels).To(HaveKeyWithValue(MachineSetLabelName, "test-ms"))
4342
}
4443

4544
func TestMachineSetLabelSelectorMatchValidation(t *testing.T) {

controlplane/kubeadm/api/v1alpha3/kubeadm_control_plane_webhook_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"k8s.io/utils/pointer"
2929
bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha3"
3030
kubeadmv1beta1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/v1beta1"
31+
utildefaulting "sigs.k8s.io/cluster-api/util/defaulting"
3132
)
3233

3334
func TestKubeadmControlPlaneDefault(t *testing.T) {
@@ -43,6 +44,12 @@ func TestKubeadmControlPlaneDefault(t *testing.T) {
4344
RolloutStrategy: &RolloutStrategy{},
4445
},
4546
}
47+
updateDefaultingValidationKCP := kcp.DeepCopy()
48+
updateDefaultingValidationKCP.Spec.Version = "v1.18.3"
49+
updateDefaultingValidationKCP.Spec.InfrastructureTemplate = corev1.ObjectReference{
50+
Namespace: "foo",
51+
}
52+
t.Run("for KubeadmControlPLane", utildefaulting.DefaultValidateTest(updateDefaultingValidationKCP))
4653
kcp.Default()
4754

4855
g.Expect(kcp.Spec.InfrastructureTemplate.Namespace).To(Equal(kcp.Namespace))

exp/addons/api/v1alpha3/clusterresourceset_webhook.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func (m *ClusterResourceSet) validate(old *ClusterResourceSet) error {
8787
)
8888
}
8989

90-
if old != nil && old.Spec.Strategy != m.Spec.Strategy {
90+
if old != nil && old.Spec.Strategy != "" && old.Spec.Strategy != m.Spec.Strategy {
9191
allErrs = append(
9292
allErrs,
9393
field.Invalid(field.NewPath("spec", "strategy"), m.Spec.Strategy, "field is immutable"),

exp/addons/api/v1alpha3/clusterresourceset_webhook_test.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,17 @@ import (
2222
. "github.com/onsi/gomega"
2323

2424
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25+
utildefaulting "sigs.k8s.io/cluster-api/util/defaulting"
2526
)
2627

2728
func TestClusterResourcesetDefault(t *testing.T) {
2829
g := NewWithT(t)
2930
clusterResourceSet := &ClusterResourceSet{}
30-
31+
defaultingValidationCRS := clusterResourceSet.DeepCopy()
32+
defaultingValidationCRS.Spec.ClusterSelector = metav1.LabelSelector{
33+
MatchLabels: map[string]string{"foo": "bar"},
34+
}
35+
t.Run("for ClusterResourceSet", utildefaulting.DefaultValidateTest(defaultingValidationCRS))
3136
clusterResourceSet.Default()
3237

3338
g.Expect(clusterResourceSet.Spec.Strategy).To(Equal(string(ClusterResourceSetStrategyApplyOnce)))

exp/api/v1alpha3/machinepool_webhook_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2626
"k8s.io/utils/pointer"
2727
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
28+
utildefaulting "sigs.k8s.io/cluster-api/util/defaulting"
2829
)
2930

3031
func TestMachinePoolDefault(t *testing.T) {
@@ -42,7 +43,7 @@ func TestMachinePoolDefault(t *testing.T) {
4243
},
4344
},
4445
}
45-
46+
t.Run("for MachinePool", utildefaulting.DefaultValidateTest(m))
4647
m.Default()
4748

4849
g.Expect(m.Labels[clusterv1.ClusterLabelName]).To(Equal(m.Spec.ClusterName))

util/defaulting/defaulting.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
Copyright 2021 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 defaulting
18+
19+
import (
20+
"testing"
21+
22+
"github.com/onsi/gomega"
23+
"k8s.io/apimachinery/pkg/runtime"
24+
)
25+
26+
// DefaultingValidator interface is for objects that define both defaulting
27+
// and validating webhooks.
28+
type DefaultingValidator interface {
29+
runtime.Object
30+
Default()
31+
ValidateCreate() error
32+
ValidateUpdate(old runtime.Object) error
33+
ValidateDelete() error
34+
}
35+
36+
// DefaultValidateTest returns a new testing function to be used in tests to
37+
// make sure defaulting webhooks also pass validation tests on create,
38+
// update and delete.
39+
func DefaultValidateTest(object DefaultingValidator) func(*testing.T) {
40+
return func(t *testing.T) {
41+
createCopy := object.DeepCopyObject().(DefaultingValidator)
42+
updateCopy := object.DeepCopyObject().(DefaultingValidator)
43+
deleteCopy := object.DeepCopyObject().(DefaultingValidator)
44+
defaultingUpdateCopy := updateCopy.DeepCopyObject().(DefaultingValidator)
45+
46+
t.Run("validate-on-create", func(t *testing.T) {
47+
g := gomega.NewWithT(t)
48+
createCopy.Default()
49+
g.Expect(createCopy.ValidateCreate()).To(gomega.Succeed())
50+
})
51+
t.Run("validate-on-update", func(t *testing.T) {
52+
g := gomega.NewWithT(t)
53+
defaultingUpdateCopy.Default()
54+
g.Expect(defaultingUpdateCopy.ValidateUpdate(updateCopy)).To(gomega.Succeed())
55+
})
56+
t.Run("validate-on-delete", func(t *testing.T) {
57+
g := gomega.NewWithT(t)
58+
deleteCopy.Default()
59+
g.Expect(deleteCopy.ValidateDelete()).To(gomega.Succeed())
60+
})
61+
}
62+
}

0 commit comments

Comments
 (0)