Skip to content

Commit 2d95f7c

Browse files
authored
Merge pull request #5498 from mohamedawnallah/unitTestClusterResourceBindingWebhook
pkg/webhook: unit test cluster resource binding
2 parents 673a603 + 14c3030 commit 2d95f7c

File tree

1 file changed

+183
-0
lines changed

1 file changed

+183
-0
lines changed

Diff for: pkg/webhook/clusterresourcebinding/mutating_test.go

+183
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/*
2+
Copyright 2024 The Karmada 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 clusterresourcebinding
18+
19+
import (
20+
"context"
21+
"encoding/json"
22+
"errors"
23+
"net/http"
24+
"reflect"
25+
"testing"
26+
27+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28+
"k8s.io/apimachinery/pkg/runtime"
29+
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
30+
31+
workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2"
32+
)
33+
34+
type fakeMutationDecoder struct {
35+
err error
36+
obj runtime.Object
37+
}
38+
39+
// Decode mocks the Decode method of admission.Decoder.
40+
func (f *fakeMutationDecoder) Decode(_ admission.Request, obj runtime.Object) error {
41+
if f.err != nil {
42+
return f.err
43+
}
44+
if f.obj != nil {
45+
reflect.ValueOf(obj).Elem().Set(reflect.ValueOf(f.obj).Elem())
46+
}
47+
return nil
48+
}
49+
50+
// DecodeRaw mocks the DecodeRaw method of admission.Decoder.
51+
func (f *fakeMutationDecoder) DecodeRaw(_ runtime.RawExtension, obj runtime.Object) error {
52+
if f.err != nil {
53+
return f.err
54+
}
55+
if f.obj != nil {
56+
reflect.ValueOf(obj).Elem().Set(reflect.ValueOf(f.obj).Elem())
57+
}
58+
return nil
59+
}
60+
61+
func TestMutatingAdmission_Handle(t *testing.T) {
62+
tests := []struct {
63+
name string
64+
decoder admission.Decoder
65+
req admission.Request
66+
want admission.Response
67+
}{
68+
{
69+
name: "Handle_DecodeError_DeniesAdmission",
70+
decoder: &fakeMutationDecoder{
71+
err: errors.New("decode error"),
72+
},
73+
req: admission.Request{},
74+
want: admission.Errored(http.StatusBadRequest, errors.New("decode error")),
75+
},
76+
}
77+
78+
for _, tt := range tests {
79+
t.Run(tt.name, func(t *testing.T) {
80+
m := MutatingAdmission{
81+
Decoder: tt.decoder,
82+
}
83+
got := m.Handle(context.Background(), tt.req)
84+
if !reflect.DeepEqual(got, tt.want) {
85+
t.Errorf("Handle() = %v, want %v", got, tt.want)
86+
}
87+
})
88+
}
89+
}
90+
91+
func TestMutatingAdmission_Handle_FullCoverage(t *testing.T) {
92+
// Define the crb object name and namespace to be used in the test.
93+
name := "test-cluster-resource-binding"
94+
namespace := "test-namespace"
95+
podName := "test-pod"
96+
97+
// Mock an admission request.
98+
req := admission.Request{}
99+
100+
// Create the initial crb object with default values for testing.
101+
crb := &workv1alpha2.ClusterResourceBinding{
102+
ObjectMeta: metav1.ObjectMeta{
103+
Name: name,
104+
Namespace: namespace,
105+
},
106+
Spec: workv1alpha2.ResourceBindingSpec{
107+
Resource: workv1alpha2.ObjectReference{
108+
APIVersion: "v1",
109+
Kind: "Pod",
110+
Namespace: namespace,
111+
Name: podName,
112+
},
113+
Clusters: []workv1alpha2.TargetCluster{
114+
{
115+
Name: "member1",
116+
Replicas: 1,
117+
},
118+
},
119+
},
120+
}
121+
122+
// Define the expected crb object after mutations.
123+
wantCRB := &workv1alpha2.ClusterResourceBinding{
124+
ObjectMeta: metav1.ObjectMeta{
125+
Name: name,
126+
Namespace: namespace,
127+
Labels: map[string]string{
128+
workv1alpha2.ClusterResourceBindingPermanentIDLabel: "some-unique-uuid",
129+
},
130+
},
131+
Spec: workv1alpha2.ResourceBindingSpec{
132+
Resource: workv1alpha2.ObjectReference{
133+
APIVersion: "v1",
134+
Kind: "Pod",
135+
Namespace: namespace,
136+
Name: podName,
137+
},
138+
Clusters: []workv1alpha2.TargetCluster{
139+
{
140+
Name: "member1",
141+
Replicas: 1,
142+
},
143+
},
144+
},
145+
}
146+
147+
// Mock decoder that decodes the request into the crb object.
148+
decoder := &fakeMutationDecoder{
149+
obj: crb,
150+
}
151+
152+
// Marshal the expected crb object to simulate the final mutated object.
153+
wantBytes, err := json.Marshal(wantCRB)
154+
if err != nil {
155+
t.Fatalf("Failed to marshal expected crb object: %v", err)
156+
}
157+
req.Object.Raw = wantBytes
158+
159+
// Instantiate the mutating handler.
160+
mutatingHandler := MutatingAdmission{
161+
Decoder: decoder,
162+
}
163+
164+
// Call the Handle function.
165+
got := mutatingHandler.Handle(context.Background(), req)
166+
167+
// Check if exactly one patch is applied.
168+
if len(got.Patches) != 1 {
169+
t.Errorf("Handle() returned an unexpected number of patches. Expected one patch, received: %v", got.Patches)
170+
}
171+
172+
// Verify that the patches are for the UUID label.
173+
// If any other patches are present, it indicates that the crb object was not handled as expected.
174+
firstPatch := got.Patches[0]
175+
if firstPatch.Operation != "replace" || firstPatch.Path != "/metadata/labels/clusterresourcebinding.karmada.io~1permanent-id" {
176+
t.Errorf("Handle() returned unexpected patches. Only the UUID patch was expected. Received patches: %v", got.Patches)
177+
}
178+
179+
// Check if the admission request was allowed.
180+
if !got.Allowed {
181+
t.Errorf("Handle() got.Allowed = false, want true")
182+
}
183+
}

0 commit comments

Comments
 (0)