Skip to content

Commit 7b7278c

Browse files
authored
Adding unit tests for StoragePolicyReservation code in metadatasyncer (#3602)
1 parent 8e6a853 commit 7b7278c

File tree

2 files changed

+217
-1
lines changed

2 files changed

+217
-1
lines changed

pkg/syncer/metadatasyncer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1550,7 +1550,7 @@ func fetchPVs(ctx context.Context, metadataSyncer *metadataSyncInformer) (map[st
15501550
}
15511551

15521552
// fetchStorageClassToStoragePolicyMapping will fetch storageclass and returns mapping with storagepolicy id
1553-
func fetchStorageClassToStoragePolicyMapping(ctx context.Context) (map[string]string, error) {
1553+
var fetchStorageClassToStoragePolicyMapping = func(ctx context.Context) (map[string]string, error) {
15541554
log := logger.GetLogger(ctx)
15551555
log.Debug("fetchStorageClassToStoragePolicyMapping: Fetching StorageClass and create mapping for storageclass" +
15561556
"and storagepolicyid")

pkg/syncer/metadatasyncer_test.go

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/*
2+
Copyright 2025 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 syncer
18+
19+
import (
20+
"context"
21+
"errors"
22+
"testing"
23+
24+
"k8s.io/apimachinery/pkg/api/resource"
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
storagepolicyv1alpha2 "sigs.k8s.io/vsphere-csi-driver/v3/pkg/apis/cnsoperator/storagepolicy/v1alpha2"
27+
)
28+
29+
// fake implementation for fetchStorageClassToStoragePolicyMapping
30+
var fakeStorageClassToStoragePolicy = map[string]string{
31+
"sc1": "policy1",
32+
"sc2": "policy2",
33+
}
34+
35+
func fakeFetchStorageClassToStoragePolicyMapping(ctx context.Context) (map[string]string, error) {
36+
return fakeStorageClassToStoragePolicy, nil
37+
}
38+
39+
func fakeErrorFetchStorageClassToStoragePolicyMapping(ctx context.Context) (map[string]string, error) {
40+
return nil, errors.New("fake error")
41+
}
42+
43+
func TestGetExpectedReservedCapacityForSPR(t *testing.T) {
44+
// Replace the function fetchStorageClassToStoragePolicyMapping with fake function call to isolate testing
45+
orig := fetchStorageClassToStoragePolicyMapping
46+
fetchStorageClassToStoragePolicyMapping = fakeFetchStorageClassToStoragePolicyMapping
47+
48+
ctx := context.Background()
49+
50+
tenGi := resource.MustParse("10Gi")
51+
fiveGi := resource.MustParse("5Gi")
52+
sevenGi := resource.MustParse("7Gi")
53+
zero := resource.MustParse("0Gi")
54+
threeGi := resource.MustParse("3Gi")
55+
56+
// Requested: sc1=10Gi, sc2=5Gi; Approved: sc1=7Gi, sc2=0Gi
57+
spr := storagepolicyv1alpha2.StoragePolicyReservation{
58+
ObjectMeta: metav1.ObjectMeta{
59+
Name: "spr-test",
60+
Namespace: "default",
61+
},
62+
Spec: storagepolicyv1alpha2.StoragePolicyReservationSpec{
63+
Requested: []storagepolicyv1alpha2.Requested{
64+
{
65+
ReservationRequests: []storagepolicyv1alpha2.ReservationRequest{
66+
{
67+
StorageClassName: "sc1",
68+
Request: &tenGi,
69+
},
70+
{
71+
StorageClassName: "sc2",
72+
Request: &fiveGi,
73+
},
74+
},
75+
},
76+
},
77+
},
78+
Status: storagepolicyv1alpha2.StoragePolicyReservationStatus{
79+
Approved: []storagepolicyv1alpha2.StorageObject{
80+
{
81+
StorageClassName: "sc1",
82+
Request: &sevenGi,
83+
},
84+
{
85+
StorageClassName: "sc2",
86+
Request: &zero,
87+
},
88+
},
89+
},
90+
}
91+
92+
expected := map[string]*resource.Quantity{
93+
"policy1": resource.NewQuantity(threeGi.Value(), resource.BinarySI),
94+
"policy2": resource.NewQuantity(fiveGi.Value(), resource.BinarySI),
95+
}
96+
97+
result, err := getExpectedReservedCapacityForSPR(ctx, spr)
98+
if err != nil {
99+
t.Errorf("getExpectedReservedCapacityForSPR() returned error: %v", err)
100+
}
101+
if !quantitiesEqual(result, expected) {
102+
t.Errorf("getExpectedReservedCapacityForSPR() result = %v; want %v", result, expected)
103+
}
104+
// Replace with the original function call
105+
fetchStorageClassToStoragePolicyMapping = orig
106+
}
107+
108+
func TestGetExpectedReservedCapacityForSPR2(t *testing.T) {
109+
// Replace the function fetchStorageClassToStoragePolicyMapping with fake function call to isolate testing
110+
orig := fetchStorageClassToStoragePolicyMapping
111+
fetchStorageClassToStoragePolicyMapping = fakeFetchStorageClassToStoragePolicyMapping
112+
113+
ctx := context.Background()
114+
115+
tenGi := resource.MustParse("10Gi")
116+
fiveGi := resource.MustParse("5Gi")
117+
118+
// Requested: sc1=10Gi, sc2=5Gi; Approved: sc1=10Gi
119+
spr := storagepolicyv1alpha2.StoragePolicyReservation{
120+
ObjectMeta: metav1.ObjectMeta{
121+
Name: "spr-test",
122+
Namespace: "default",
123+
},
124+
Spec: storagepolicyv1alpha2.StoragePolicyReservationSpec{
125+
Requested: []storagepolicyv1alpha2.Requested{
126+
{
127+
ReservationRequests: []storagepolicyv1alpha2.ReservationRequest{
128+
{
129+
StorageClassName: "sc1",
130+
Request: &tenGi,
131+
},
132+
{
133+
StorageClassName: "sc2",
134+
Request: &fiveGi,
135+
},
136+
},
137+
},
138+
},
139+
},
140+
Status: storagepolicyv1alpha2.StoragePolicyReservationStatus{
141+
Approved: []storagepolicyv1alpha2.StorageObject{
142+
{
143+
StorageClassName: "sc1",
144+
Request: &tenGi,
145+
},
146+
},
147+
},
148+
}
149+
150+
expected := map[string]*resource.Quantity{
151+
"policy2": resource.NewQuantity(fiveGi.Value(), resource.BinarySI),
152+
}
153+
154+
result, err := getExpectedReservedCapacityForSPR(ctx, spr)
155+
if err != nil {
156+
t.Errorf("getExpectedReservedCapacityForSPR() returned error: %v", err)
157+
}
158+
if !quantitiesEqual(result, expected) {
159+
t.Errorf("getExpectedReservedCapacityForSPR() result = %v; want %v", result, expected)
160+
}
161+
// Replace with the original function call
162+
fetchStorageClassToStoragePolicyMapping = orig
163+
}
164+
165+
func TestGetExpectedReservedCapacityForSPRError(t *testing.T) {
166+
// Replace the function fetchStorageClassToStoragePolicyMapping with fake function call which
167+
// returns error
168+
orig := fetchStorageClassToStoragePolicyMapping
169+
fetchStorageClassToStoragePolicyMapping = fakeErrorFetchStorageClassToStoragePolicyMapping
170+
171+
ctx := context.Background()
172+
173+
tenGi := resource.MustParse("10Gi")
174+
fiveGi := resource.MustParse("5Gi")
175+
spr := storagepolicyv1alpha2.StoragePolicyReservation{
176+
ObjectMeta: metav1.ObjectMeta{
177+
Name: "spr-test",
178+
Namespace: "default",
179+
},
180+
Spec: storagepolicyv1alpha2.StoragePolicyReservationSpec{
181+
Requested: []storagepolicyv1alpha2.Requested{
182+
{
183+
ReservationRequests: []storagepolicyv1alpha2.ReservationRequest{
184+
{
185+
StorageClassName: "sc1",
186+
Request: &tenGi,
187+
},
188+
{
189+
StorageClassName: "sc2",
190+
Request: &fiveGi,
191+
},
192+
},
193+
},
194+
},
195+
},
196+
}
197+
_, err := getExpectedReservedCapacityForSPR(ctx, spr)
198+
if err == nil {
199+
t.Error("getExpectedReservedCapacityForSPR() expected error but got nil")
200+
}
201+
// Replace with the original function call
202+
fetchStorageClassToStoragePolicyMapping = orig
203+
}
204+
205+
// Helper to compare resource.Quantity maps
206+
func quantitiesEqual(a, b map[string]*resource.Quantity) bool {
207+
if len(a) != len(b) {
208+
return false
209+
}
210+
for k, v := range a {
211+
if bv, ok := b[k]; !ok || v.Cmp(*bv) != 0 {
212+
return false
213+
}
214+
}
215+
return true
216+
}

0 commit comments

Comments
 (0)