Skip to content

Commit fe3a142

Browse files
authored
Merge pull request #1980 from Zhupku/mengzezhu/ut2
test: add UT coverage for blob/nodeserver.go
2 parents 81590cc + 91cdc85 commit fe3a142

File tree

2 files changed

+174
-1
lines changed

2 files changed

+174
-1
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ require (
1818
github.com/container-storage-interface/spec v1.11.0
1919
github.com/go-ini/ini v1.67.0
2020
github.com/golang/protobuf v1.5.4
21+
github.com/google/uuid v1.6.0
2122
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1
2223
github.com/kubernetes-csi/csi-lib-utils v0.16.0
2324
github.com/onsi/ginkgo/v2 v2.23.4
@@ -107,7 +108,6 @@ require (
107108
github.com/google/go-cmp v0.7.0 // indirect
108109
github.com/google/gofuzz v1.2.0 // indirect
109110
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
110-
github.com/google/uuid v1.6.0 // indirect
111111
github.com/gorilla/websocket v1.5.0 // indirect
112112
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
113113
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect

pkg/blob/nodeserver_test.go

+173
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636

3737
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage"
3838
"github.com/container-storage-interface/spec/lib/go/csi"
39+
"github.com/google/uuid"
3940
"github.com/stretchr/testify/assert"
4041
"go.uber.org/mock/gomock"
4142

@@ -234,6 +235,113 @@ func TestNodePublishVolume(t *testing.T) {
234235
},
235236
expectedErr: status.Error(codes.InvalidArgument, fmt.Sprintf("invalid mountPermissions %s", "07ab")),
236237
},
238+
{
239+
desc: "Valid request with service account token and clientID",
240+
setup: func(d *Driver) {
241+
// Mock NodeStageVolume to return success
242+
d.cloud.ResourceGroup = "rg"
243+
d.enableBlobMockMount = true
244+
},
245+
req: &csi.NodePublishVolumeRequest{
246+
VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap},
247+
VolumeId: "vol_1",
248+
TargetPath: targetTest,
249+
StagingTargetPath: sourceTest,
250+
VolumeContext: map[string]string{
251+
serviceAccountTokenField: `{"api://AzureADTokenExchange":{"token":"test-token","expirationTimestamp":"2023-01-01T00:00:00Z"}}`,
252+
clientIDField: "client-id-value",
253+
},
254+
},
255+
expectedErr: nil,
256+
},
257+
{
258+
desc: "Valid request with ephemeral volume",
259+
setup: func(d *Driver) {
260+
// Mock NodeStageVolume to return success
261+
d.cloud.ResourceGroup = "rg"
262+
d.enableBlobMockMount = true
263+
},
264+
req: &csi.NodePublishVolumeRequest{
265+
VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap},
266+
VolumeId: "vol_1",
267+
TargetPath: targetTest,
268+
StagingTargetPath: sourceTest,
269+
VolumeContext: map[string]string{
270+
"csi.storage.k8s.io/ephemeral": "true",
271+
"csi.storage.k8s.io/pod.namespace": "test-namespace",
272+
"containername": "test-container", // Add container name to avoid error
273+
},
274+
},
275+
expectedErr: nil,
276+
},
277+
{
278+
desc: "Volume already mounted",
279+
setup: func(_ *Driver) {
280+
// Create the directory and ensure it's seen as already mounted
281+
_ = makeDir("./false_is_likely")
282+
},
283+
req: &csi.NodePublishVolumeRequest{
284+
VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap},
285+
VolumeId: "vol_1",
286+
TargetPath: "./false_is_likely", // This path will make IsLikelyNotMountPoint return false
287+
StagingTargetPath: sourceTest,
288+
},
289+
expectedErr: nil,
290+
cleanup: func(_ *Driver) {
291+
// Clean up the directory
292+
_ = os.RemoveAll("./false_is_likely")
293+
},
294+
},
295+
{
296+
desc: "enableBlobMockMount enabled",
297+
setup: func(d *Driver) {
298+
// Enable mock mount
299+
d.enableBlobMockMount = true
300+
301+
// Create a temporary directory for the test
302+
_ = makeDir("./mock_mount_test")
303+
},
304+
req: &csi.NodePublishVolumeRequest{
305+
VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap},
306+
VolumeId: "vol_1",
307+
TargetPath: "./mock_mount_test",
308+
StagingTargetPath: sourceTest,
309+
VolumeContext: map[string]string{
310+
mountPermissionsField: "0755",
311+
},
312+
},
313+
expectedErr: nil,
314+
cleanup: func(d *Driver) {
315+
// Disable mock mount
316+
d.enableBlobMockMount = false
317+
318+
// Clean up the directory
319+
_ = os.RemoveAll("./mock_mount_test")
320+
},
321+
},
322+
{
323+
desc: "enableBlobMockMount enabled - MakeDir fails",
324+
setup: func(d *Driver) {
325+
// Enable mock mount
326+
d.enableBlobMockMount = true
327+
},
328+
req: &csi.NodePublishVolumeRequest{
329+
VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap},
330+
VolumeId: "vol_1",
331+
TargetPath: "./azure.go", // This will fail because it's a file, not a directory
332+
StagingTargetPath: sourceTest,
333+
VolumeContext: map[string]string{
334+
mountPermissionsField: "0755",
335+
},
336+
},
337+
expectedErr: func() error {
338+
if runtime.GOOS == "windows" {
339+
t.Skip("Skipping test on ", runtime.GOOS)
340+
return nil
341+
}
342+
return status.Errorf(codes.Internal, "Could not mount target \"./azure.go\": mkdir ./azure.go: not a directory")
343+
}(),
344+
},
237345
}
238346

239347
// Setup
@@ -273,6 +381,71 @@ func TestNodePublishVolume(t *testing.T) {
273381
assert.NoError(t, err)
274382
}
275383

384+
func TestNodePublishVolumeMountError(t *testing.T) {
385+
d := NewFakeDriver()
386+
fakeMounter := &fakeMounter{}
387+
fakeExec := &testingexec.FakeExec{ExactOrder: true}
388+
d.mounter = &mount.SafeFormatAndMount{
389+
Interface: fakeMounter,
390+
Exec: fakeExec,
391+
}
392+
393+
volumeCap := csi.VolumeCapability_AccessMode{
394+
Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
395+
}
396+
397+
// Test case 1: Mount fails with source error
398+
targetPath := "./mount_test_target"
399+
_ = makeDir(targetPath)
400+
401+
req := &csi.NodePublishVolumeRequest{
402+
VolumeId: "vol_1",
403+
TargetPath: targetPath,
404+
StagingTargetPath: "error_mount", // This will trigger an error in Mount
405+
VolumeCapability: &csi.VolumeCapability{
406+
AccessMode: &volumeCap,
407+
},
408+
}
409+
410+
// Run the test
411+
_, err := d.NodePublishVolume(context.Background(), req)
412+
expectedErr := status.Errorf(codes.Internal, "Could not mount \"error_mount\" at \"./mount_test_target\": fake Mount: source error")
413+
if err == nil || err.Error() != expectedErr.Error() {
414+
t.Errorf("Expected error: %v, got: %v", expectedErr, err)
415+
}
416+
417+
// Clean up
418+
_ = os.RemoveAll(targetPath)
419+
420+
// Let's try a different approach
421+
// Let's create a custom fakeMounter that returns a specific error for Mount
422+
423+
// We'll continue to use the same fakeMounter
424+
// It's already configured to return an error for paths containing "error_mount"
425+
426+
// Create a test directory that doesn't exist
427+
nonExistentPath := "/tmp/non-existent-path-" + uuid.NewString()
428+
429+
req = &csi.NodePublishVolumeRequest{
430+
VolumeId: "vol_1",
431+
TargetPath: nonExistentPath,
432+
StagingTargetPath: "error_mount", // This will trigger an error in Mount
433+
VolumeCapability: &csi.VolumeCapability{
434+
AccessMode: &volumeCap,
435+
},
436+
}
437+
438+
// Run the test
439+
_, err = d.NodePublishVolume(context.Background(), req)
440+
441+
// The error should be about failing to mount, not about removing the target
442+
// because the target doesn't exist
443+
expectedErr = status.Errorf(codes.Internal, "Could not mount \"error_mount\" at \"%s\": fake Mount: source error", nonExistentPath)
444+
if err == nil || err.Error() != expectedErr.Error() {
445+
t.Errorf("Expected error: %v, got: %v", expectedErr, err)
446+
}
447+
}
448+
276449
func TestNodePublishVolumeIdempotentMount(t *testing.T) {
277450
if runtime.GOOS != "linux" || os.Getuid() != 0 {
278451
return

0 commit comments

Comments
 (0)