From 33fc6a3889f606bb1d94707956f8f88d5c0caf9a Mon Sep 17 00:00:00 2001 From: santhoshatdell Date: Mon, 18 Nov 2024 22:10:15 +0000 Subject: [PATCH] Improved code coverage for pkg/controller to above 90% --- .mockery.yaml | 8 +- pkg/controller/controller_test.go | 476 +++++++++++++++++++++++++++--- 2 files changed, 438 insertions(+), 46 deletions(-) diff --git a/.mockery.yaml b/.mockery.yaml index ffb945c7..8be4c164 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -14,8 +14,8 @@ # # -quiet: False -all: True -inpackage: False +quiet: false +all: true +inpackage: false dir: ./pkg -disable-version-string: True +disable-version-string: true diff --git a/pkg/controller/controller_test.go b/pkg/controller/controller_test.go index a999abe5..0b079e0a 100644 --- a/pkg/controller/controller_test.go +++ b/pkg/controller/controller_test.go @@ -872,6 +872,46 @@ var _ = ginkgo.Describe("CSIControllerService", func() { })) }) + ginkgo.It("should continue metro replication on volume to support idempotency when metro was previously configured", func() { + delete(req.Parameters, ctrlSvc.WithRP(controller.KeyReplicationRPO)) + delete(req.Parameters, ctrlSvc.WithRP(controller.KeyReplicationIgnoreNamespaces)) + delete(req.Parameters, ctrlSvc.WithRP(controller.KeyReplicationVGPrefix)) + + clientMock.On("ConfigureMetroVolume", mock.Anything, validBaseVolID, configureMetroRequest). + Return(gopowerstore.MetroSessionResponse{}, gopowerstore.APIError{ + ErrorMsg: &api.ErrorMsg{StatusCode: http.StatusBadRequest}}) + clientMock.On("GetVolume", context.Background(), mock.Anything). + Return(gopowerstore.Volume{ApplianceID: validApplianceID, MetroReplicationSessionID: validSessionID}, nil) + clientMock.On("GetAppliance", context.Background(), mock.Anything).Return(gopowerstore.ApplianceInstance{ServiceTag: validServiceTag}, nil) + clientMock.On("GetReplicationSessionByLocalResourceID", mock.Anything, validBaseVolID).Return(gopowerstore.ReplicationSession{ + LocalResourceID: validBaseVolID, + RemoteResourceID: validRemoteVolID, + ResourceType: "volume", + }, nil) + + res, err := ctrlSvc.CreateVolume(context.Background(), req) + + gomega.Expect(err).To(gomega.BeNil()) + gomega.Expect(res).To(gomega.Equal(&csi.CreateVolumeResponse{ + Volume: &csi.Volume{ + CapacityBytes: validVolSize, + VolumeId: fmt.Sprintf("%s/%s/%s:%s/%s", validBaseVolID, firstValidID, "scsi", validRemoteVolID, secondValidID), + VolumeContext: map[string]string{ + common.KeyArrayVolumeName: "my-vol", + common.KeyProtocol: "scsi", + common.KeyArrayID: firstValidID, + common.KeyVolumeDescription: req.Name + "-" + validNamespaceName, + common.KeyServiceTag: validServiceTag, + controller.KeyCSIPVCName: req.Name, + controller.KeyCSIPVCNamespace: validNamespaceName, + ctrlSvc.WithRP(controller.KeyReplicationEnabled): "true", + ctrlSvc.WithRP(controller.KeyReplicationMode): "METRO", + ctrlSvc.WithRP(controller.KeyReplicationRemoteSystem): validRemoteSystemName, + }, + }, + })) + }) + ginkgo.It("should fail to configure metro replication on volume if the volume cannot be found", func() { // Return volume not found error when trying to configure a metro session for that volume clientMock.On("ConfigureMetroVolume", mock.Anything, validBaseVolID, configureMetroRequest). @@ -1791,6 +1831,21 @@ var _ = ginkgo.Describe("CSIControllerService", func() { gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(res).To(gomega.Equal(&csi.DeleteVolumeResponse{})) }) + + ginkgo.It("should fail to delete block volume", func() { + clientMock.On("GetSnapshotsByVolumeID", mock.Anything, validBaseVolID).Return([]gopowerstore.Volume{}, nil) + clientMock.On("GetVolumeGroupsByVolumeID", mock.Anything, validBaseVolID). + Return(gopowerstore.VolumeGroups{VolumeGroup: []gopowerstore.VolumeGroup{{ID: validGroupID, ProtectionPolicyID: validPolicyID}}}, nil) + clientMock.On("RemoveMembersFromVolumeGroup", mock.Anything, mock.AnythingOfType("*gopowerstore.VolumeGroupMembers"), validGroupID). + Return(gopowerstore.EmptyResponse(""), gopowerstore.NewNotFoundError()) + + req := &csi.DeleteVolumeRequest{VolumeId: validBlockVolumeID} + res, err := ctrlSvc.DeleteVolume(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).ToNot(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("failed to remove volume")) + }) }) ginkgo.When("delete block metro volume with replication props", func() { @@ -1858,6 +1913,17 @@ var _ = ginkgo.Describe("CSIControllerService", func() { }) }) + ginkgo.When("array id is not found", func() { + ginkgo.It("should fail", func() { + req := &csi.DeleteVolumeRequest{VolumeId: invalidBlockVolumeID} + res, err := ctrlSvc.DeleteVolume(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).ToNot(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("can't find array with provided id")) + }) + }) + ginkgo.When("there is no array ip in volume id", func() { ginkgo.It("should check storage using default array [no volume found]", func() { clientMock.On("GetVolume", context.Background(), validBaseVolID). @@ -1897,6 +1963,37 @@ var _ = ginkgo.Describe("CSIControllerService", func() { }) }) + ginkgo.When("get block API call fails", func() { + ginkgo.It("should fail [GetSnapshotsByVolumeID]", func() { + clientMock.On("GetVolumeGroupsByVolumeID", mock.Anything, validBaseVolID).Return(gopowerstore.VolumeGroups{}, nil) + clientMock.On("GetSnapshotsByVolumeID", mock.Anything, validBaseVolID).Return([]gopowerstore.Volume{}, gopowerstore.APIError{ + ErrorMsg: &api.ErrorMsg{StatusCode: http.StatusGatewayTimeout}, + }) + + req := &csi.DeleteVolumeRequest{VolumeId: validBlockVolumeID} + res, err := ctrlSvc.DeleteVolume(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).NotTo(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("failure getting snapshot")) + }) + + ginkgo.It("should fail [GetVolume]", func() { + clientMock.On("GetVolumeGroupsByVolumeID", mock.Anything, validBaseVolID).Return(gopowerstore.VolumeGroups{}, nil) + clientMock.On("GetSnapshotsByVolumeID", mock.Anything, validBaseVolID).Return([]gopowerstore.Volume{}, nil) + clientMock.On("GetVolume", mock.Anything, validBaseVolID).Return(gopowerstore.Volume{}, gopowerstore.APIError{ + ErrorMsg: &api.ErrorMsg{StatusCode: http.StatusGatewayTimeout}, + }) + + req := &csi.DeleteVolumeRequest{VolumeId: validBlockVolumeID} + res, err := ctrlSvc.DeleteVolume(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).NotTo(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("failure getting volume")) + }) + }) + ginkgo.When("when trying delete volume with existing snapshots", func() { ginkgo.It("should fail [NFS]", func() { clientMock.On("GetFsSnapshotsByVolumeID", mock.Anything, validBaseVolID). @@ -2139,7 +2236,7 @@ var _ = ginkgo.Describe("CSIControllerService", func() { ginkgo.When("the array ID could not found", func() { ginkgo.It("should return error", func() { req := &csi.CreateSnapshotRequest{ - SourceVolumeId: "39bb1b5f-5624-490d-9ece-18f7b28a904e/globalvolid123/scsi", + SourceVolumeId: invalidBlockVolumeID, Name: validSnapName, } @@ -2212,6 +2309,40 @@ var _ = ginkgo.Describe("CSIControllerService", func() { }) }) + ginkgo.When("there is an API error when retrieving the source", func() { + ginkgo.It("should fail [Block]", func() { + clientMock.On("GetVolume", mock.Anything, validBaseVolID).Return( + gopowerstore.Volume{}, gopowerstore.APIError{ + ErrorMsg: &api.ErrorMsg{StatusCode: http.StatusGatewayTimeout}, + }) + + req := &csi.CreateSnapshotRequest{ + SourceVolumeId: validBlockVolumeID, + Name: validSnapName, + } + _, err := ctrlSvc.CreateSnapshot(context.Background(), req) + + gomega.Expect(err).ToNot(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("can't find source volume")) + }) + + ginkgo.It("should fail [NFS]", func() { + clientMock.On("GetFS", mock.Anything, validBaseVolID).Return( + gopowerstore.FileSystem{}, gopowerstore.APIError{ + ErrorMsg: &api.ErrorMsg{StatusCode: http.StatusGatewayTimeout}, + }) + + req := &csi.CreateSnapshotRequest{ + SourceVolumeId: validNfsVolumeID, + Name: validSnapName, + } + _, err := ctrlSvc.CreateSnapshot(context.Background(), req) + + gomega.Expect(err).ToNot(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("can't find source volume")) + }) + }) + ginkgo.When("there is an API error when creating snapshot", func() { ginkgo.It("should return that error", func() { snapName := validSnapName @@ -2360,7 +2491,7 @@ var _ = ginkgo.Describe("CSIControllerService", func() { ginkgo.When("the array ID could not found", func() { ginkgo.It("should return error", func() { req := &csi.DeleteSnapshotRequest{ - SnapshotId: "39bb1b5f-5624-490d-9ece-18f7b28a904e/globalvolid123/scsi", + SnapshotId: invalidBlockVolumeID, } _, err := ctrlSvc.DeleteSnapshot(context.Background(), req) @@ -2420,6 +2551,18 @@ var _ = ginkgo.Describe("CSIControllerService", func() { })) }) + ginkgo.It("should return empty response when current size is already larger than requested size", func() { + clientMock.On("GetVolume", mock.Anything, validBaseVolID).Return(gopowerstore.Volume{ + Size: validVolSize * 3, + }, nil) + + req := getTypicalControllerExpandRequest(validBlockVolumeID, validVolSize*2) + res, err := ctrlSvc.ControllerExpandVolume(context.Background(), req) + + gomega.Expect(err).To(gomega.BeNil()) + gomega.Expect(res).To(gomega.Equal(&csi.ControllerExpandVolumeResponse{})) + }) + ginkgo.It("should fail to find array ID", func() { req := getTypicalControllerExpandRequest(invalidBlockVolumeID, validVolSize*2) _, err := ctrlSvc.ControllerExpandVolume(context.Background(), req) @@ -3897,6 +4040,20 @@ var _ = ginkgo.Describe("CSIControllerService", func() { gomega.Expect(err.Error()).To(gomega.ContainSubstring("startingToken=%d > len(volumes)=%d", tokenInt, 3)) }) }) + + ginkgo.When("get volumes return error", func() { + ginkgo.It("should fail]", func() { + clientMock.On("GetVolumes", mock.Anything). + Return([]gopowerstore.Volume{}, gopowerstore.NewNotFoundError()) + + req := &csi.ListVolumesRequest{} + res, err := ctrlSvc.ListVolumes(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).ToNot(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("unable to list volumes")) + }) + }) }) ginkgo.Describe("calling ListSnapshots()", func() { @@ -4066,6 +4223,68 @@ var _ = ginkgo.Describe("CSIControllerService", func() { gomega.Expect(res.Entries[0].Snapshot.SnapshotId).To(gomega.Equal(validNfsVolumeID)) }) + ginkgo.It("should return empty response", func() { + clientMock.On("GetSnapshot", mock.Anything, validBaseVolID). + Return(gopowerstore.Volume{}, gopowerstore.NewNotFoundError()) + + req := &csi.ListSnapshotsRequest{ + SnapshotId: validBlockVolumeID, + } + res, err := ctrlSvc.ListSnapshots(context.Background(), req) + + gomega.Expect(res).ToNot(gomega.BeNil()) + gomega.Expect(err).To(gomega.BeNil()) + gomega.Expect(len(res.Entries)).To(gomega.Equal(0)) + }) + + ginkgo.It("should return error when GetFsSnapshot call fails", func() { + clientMock.On("GetSnapshot", mock.Anything, validBaseVolID). + Return(gopowerstore.Volume{}, gopowerstore.APIError{ + ErrorMsg: &api.ErrorMsg{ + StatusCode: http.StatusBadRequest, + }}) + + req := &csi.ListSnapshotsRequest{ + SnapshotId: validBlockVolumeID, + } + res, err := ctrlSvc.ListSnapshots(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).ToNot(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("unable to get block snapshot")) + }) + + ginkgo.It("should return empty response [NFS]", func() { + clientMock.On("GetFsSnapshot", mock.Anything, validBaseVolID). + Return(gopowerstore.FileSystem{}, gopowerstore.NewNotFoundError()) + + req := &csi.ListSnapshotsRequest{ + SnapshotId: validNfsVolumeID, + } + res, err := ctrlSvc.ListSnapshots(context.Background(), req) + + gomega.Expect(res).ToNot(gomega.BeNil()) + gomega.Expect(err).To(gomega.BeNil()) + gomega.Expect(len(res.Entries)).To(gomega.Equal(0)) + }) + + ginkgo.It("should return error when GetFsSnapshot call fails [NFS]", func() { + clientMock.On("GetFsSnapshot", mock.Anything, validBaseVolID). + Return(gopowerstore.FileSystem{}, gopowerstore.APIError{ + ErrorMsg: &api.ErrorMsg{ + StatusCode: http.StatusBadRequest, + }}) + + req := &csi.ListSnapshotsRequest{ + SnapshotId: validNfsVolumeID, + } + res, err := ctrlSvc.ListSnapshots(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).ToNot(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("unable to get filesystem snapshot")) + }) + ginkgo.It("should fail [incorrect id]", func() { randomID := "something-random" @@ -4080,6 +4299,15 @@ var _ = ginkgo.Describe("CSIControllerService", func() { gomega.Expect(err).To(gomega.BeNil()) gomega.Expect(res).To(gomega.Equal(&csi.ListSnapshotsResponse{})) }) + + ginkgo.It("should fail [incorrect array id]", func() { + req := &csi.ListSnapshotsRequest{SnapshotId: invalidBlockVolumeID} + res, err := ctrlSvc.ListSnapshots(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).NotTo(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("unable to get array with arrayID")) + }) }) ginkgo.When("passing source volume id", func() { @@ -4125,6 +4353,78 @@ var _ = ginkgo.Describe("CSIControllerService", func() { gomega.Expect(res).To(gomega.Equal(&csi.ListSnapshotsResponse{})) gomega.Expect(err).To(gomega.BeNil()) }) + + ginkgo.It("should fail [incorrect array id]", func() { + req := &csi.ListSnapshotsRequest{SourceVolumeId: invalidBlockVolumeID} + res, err := ctrlSvc.ListSnapshots(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).NotTo(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("unable to get array with arrayID")) + }) + + ginkgo.It("should return error when GetFsSnapshotsByVolumeID call fails", func() { + clientMock.On("GetFsSnapshotsByVolumeID", mock.Anything, validBaseVolID). + Return([]gopowerstore.FileSystem{}, gopowerstore.NewNotFoundError()) + + req := &csi.ListSnapshotsRequest{ + SourceVolumeId: validNfsVolumeID, + } + res, err := ctrlSvc.ListSnapshots(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).ToNot(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("unable to list filesystem snapshots")) + }) + + ginkgo.It("should return error when GetSnapshotsByVolumeID call fails", func() { + clientMock.On("GetSnapshotsByVolumeID", mock.Anything, validBaseVolID). + Return([]gopowerstore.Volume{}, gopowerstore.NewNotFoundError()) + + req := &csi.ListSnapshotsRequest{ + SourceVolumeId: validBlockVolumeID, + } + res, err := ctrlSvc.ListSnapshots(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).ToNot(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("unable to list block snapshots")) + }) + }) + + ginkgo.When("get snapshots call fails", func() { + ginkgo.It("should fail [block]", func() { + clientMock.On("GetSnapshots", mock.Anything). + Return([]gopowerstore.Volume{}, gopowerstore.APIError{ + ErrorMsg: &api.ErrorMsg{ + StatusCode: http.StatusNotFound, + }, + }) + + req := &csi.ListSnapshotsRequest{} + res, err := ctrlSvc.ListSnapshots(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).NotTo(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("unable to list block snapshots")) + }) + + ginkgo.It("should fail [NFS]", func() { + clientMock.On("GetSnapshots", mock.Anything).Return([]gopowerstore.Volume{}, nil) + clientMock.On("GetFsSnapshots", mock.Anything). + Return([]gopowerstore.FileSystem{}, gopowerstore.APIError{ + ErrorMsg: &api.ErrorMsg{ + StatusCode: http.StatusNotFound, + }, + }) + + req := &csi.ListSnapshotsRequest{} + res, err := ctrlSvc.ListSnapshots(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).NotTo(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("unable to list filesystem snapshots")) + }) }) }) @@ -4965,19 +5265,12 @@ var _ = ginkgo.Describe("CSIControllerService", func() { clientMock.On("GetVolume", mock.Anything, validBaseVolID). Return(gopowerstore.Volume{ID: validBaseVolID, State: gopowerstore.VolumeStateEnumReady}, nil) - clientMock.On("GetHost", mock.Anything, validHostID).Return(gopowerstore.Host{ID: validHostID, Name: validHostName}, nil) - clientMock.On("GetHostVolumeMappingByVolumeID", mock.Anything, validBaseVolID). Return([]gopowerstore.HostVolumeMapping{{HostID: validHostID}}, nil).Once() - clientMock.On("GetFS", mock.Anything, validBaseVolID). - Return(gopowerstore.FileSystem{ID: validBaseVolID}, nil) - - clientMock.On("GetNFSExportByFileSystemID", mock.Anything, validBaseVolID). - Return(gopowerstore.NFSExport{}, nil) + clientMock.On("GetHost", mock.Anything, validHostID).Return(gopowerstore.Host{ID: validHostID, Name: validHostName}, nil) req := &csi.ControllerGetVolumeRequest{VolumeId: validBlockVolumeID} - res, err := ctrlSvc.ControllerGetVolume(context.Background(), req) gomega.Expect(err).To(gomega.BeNil()) @@ -4995,7 +5288,37 @@ var _ = ginkgo.Describe("CSIControllerService", func() { })) }) }) - ginkgo.When("normal block volume does not exists on array", func() { + + ginkgo.When("normal block volume exists on array with different state", func() { + ginkgo.It("should fail", func() { + clientMock.On("GetVolume", mock.Anything, validBaseVolID). + Return(gopowerstore.Volume{ID: validBaseVolID, State: gopowerstore.VolumeStateEnumInitializing}, nil) + + clientMock.On("GetHostVolumeMappingByVolumeID", mock.Anything, validBaseVolID). + Return([]gopowerstore.HostVolumeMapping{{HostID: validHostID}}, nil).Once() + + clientMock.On("GetHost", mock.Anything, validHostID).Return(gopowerstore.Host{ID: validHostID, Name: validHostName}, nil) + + req := &csi.ControllerGetVolumeRequest{VolumeId: validBlockVolumeID} + res, err := ctrlSvc.ControllerGetVolume(context.Background(), req) + + gomega.Expect(err).To(gomega.BeNil()) + gomega.Expect(res).To(gomega.Equal(&csi.ControllerGetVolumeResponse{ + Volume: &csi.Volume{ + VolumeId: validBaseVolID, + }, + Status: &csi.ControllerGetVolumeResponse_VolumeStatus{ + PublishedNodeIds: []string{validHostName}, + VolumeCondition: &csi.VolumeCondition{ + Abnormal: true, + Message: fmt.Sprintf("Volume %s is in Initializing state", validBaseVolID), + }, + }, + })) + }) + }) + + ginkgo.When("normal block volume does not exist on array", func() { ginkgo.It("should fail", func() { var hosts []string clientMock.On("GetVolume", mock.Anything, mock.Anything). @@ -5005,19 +5328,7 @@ var _ = ginkgo.Describe("CSIControllerService", func() { }, }) - clientMock.On("GetHost", mock.Anything, validHostID).Return(gopowerstore.Host{ID: validHostID, Name: validHostName}, nil) - - clientMock.On("GetHostVolumeMappingByVolumeID", mock.Anything, validBaseVolID). - Return([]gopowerstore.HostVolumeMapping{{HostID: validHostID}}, nil).Once() - - clientMock.On("GetFS", mock.Anything, validBaseVolID). - Return(gopowerstore.FileSystem{ID: validBaseVolID}, nil) - - clientMock.On("GetNFSExportByFileSystemID", mock.Anything, validBaseVolID). - Return(gopowerstore.NFSExport{}, nil) - req := &csi.ControllerGetVolumeRequest{VolumeId: validBlockVolumeID} - res, err := ctrlSvc.ControllerGetVolume(context.Background(), req) gomega.Expect(err).To(gomega.BeNil()) @@ -5035,17 +5346,10 @@ var _ = ginkgo.Describe("CSIControllerService", func() { })) }) }) + ginkgo.When("normal filesystem exists on array", func() { ginkgo.It("should successfully get the filesystem", func() { var hosts []string - clientMock.On("GetVolume", mock.Anything, validBaseVolID). - Return(gopowerstore.Volume{ID: validBaseVolID, State: gopowerstore.VolumeStateEnumReady}, nil) - - clientMock.On("GetHost", mock.Anything, validHostID).Return(gopowerstore.Host{ID: validHostID, Name: validHostName}, nil) - - clientMock.On("GetHostVolumeMappingByVolumeID", mock.Anything, validBaseVolID). - Return([]gopowerstore.HostVolumeMapping{{HostID: validHostID}}, nil).Once() - clientMock.On("GetFS", mock.Anything, validBaseVolID). Return(gopowerstore.FileSystem{ID: validBaseVolID}, nil) @@ -5053,7 +5357,6 @@ var _ = ginkgo.Describe("CSIControllerService", func() { Return(gopowerstore.NFSExport{}, nil) req := &csi.ControllerGetVolumeRequest{VolumeId: validNfsVolumeID} - res, err := ctrlSvc.ControllerGetVolume(context.Background(), req) gomega.Expect(err).To(gomega.BeNil()) @@ -5071,17 +5374,10 @@ var _ = ginkgo.Describe("CSIControllerService", func() { })) }) }) - ginkgo.When("filesystem does not exists on array", func() { + + ginkgo.When("filesystem does not exist on array", func() { ginkgo.It("should fail", func() { var hosts []string - clientMock.On("GetVolume", mock.Anything, validBaseVolID). - Return(gopowerstore.Volume{ID: validBaseVolID, State: gopowerstore.VolumeStateEnumReady}, nil) - - clientMock.On("GetHost", mock.Anything, validHostID).Return(gopowerstore.Host{ID: validHostID, Name: validHostName}, nil) - - clientMock.On("GetHostVolumeMappingByVolumeID", mock.Anything, validBaseVolID). - Return([]gopowerstore.HostVolumeMapping{{HostID: validHostID}}, nil).Once() - clientMock.On("GetFS", mock.Anything, validBaseVolID). Return(gopowerstore.FileSystem{}, gopowerstore.APIError{ ErrorMsg: &api.ErrorMsg{ @@ -5093,7 +5389,6 @@ var _ = ginkgo.Describe("CSIControllerService", func() { Return(gopowerstore.NFSExport{}, nil) req := &csi.ControllerGetVolumeRequest{VolumeId: validNfsVolumeID} - res, err := ctrlSvc.ControllerGetVolume(context.Background(), req) gomega.Expect(err).To(gomega.BeNil()) @@ -5111,6 +5406,103 @@ var _ = ginkgo.Describe("CSIControllerService", func() { })) }) }) + + ginkgo.When("volume id is empty", func() { + ginkgo.It("should fail", func() { + req := &csi.ControllerGetVolumeRequest{VolumeId: ""} + res, err := ctrlSvc.ControllerGetVolume(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).NotTo(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("unable to parse the volume id")) + }) + }) + + ginkgo.When("block API call fails", func() { + ginkgo.It("should fail [GetVolume]", func() { + clientMock.On("GetVolume", mock.Anything, mock.Anything). + Return(gopowerstore.Volume{}, gopowerstore.APIError{ + ErrorMsg: &api.ErrorMsg{StatusCode: http.StatusBadRequest}, + }) + + req := &csi.ControllerGetVolumeRequest{VolumeId: validBlockVolumeID} + res, err := ctrlSvc.ControllerGetVolume(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).NotTo(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("failed to find volume")) + }) + + ginkgo.It("should fail [GetHostVolumeMappingByVolumeID]", func() { + clientMock.On("GetVolume", mock.Anything, validBaseVolID). + Return(gopowerstore.Volume{ID: validBaseVolID, State: gopowerstore.VolumeStateEnumReady}, nil) + + clientMock.On("GetHostVolumeMappingByVolumeID", mock.Anything, validBaseVolID). + Return([]gopowerstore.HostVolumeMapping{}, gopowerstore.APIError{ + ErrorMsg: &api.ErrorMsg{StatusCode: http.StatusBadRequest}, + }) + + req := &csi.ControllerGetVolumeRequest{VolumeId: validBlockVolumeID} + res, err := ctrlSvc.ControllerGetVolume(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).NotTo(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("failed to get host volume mapping for volume")) + }) + + ginkgo.It("should fail [GetHost]", func() { + clientMock.On("GetVolume", mock.Anything, validBaseVolID). + Return(gopowerstore.Volume{ID: validBaseVolID, State: gopowerstore.VolumeStateEnumReady}, nil) + + clientMock.On("GetHostVolumeMappingByVolumeID", mock.Anything, validBaseVolID). + Return([]gopowerstore.HostVolumeMapping{{HostID: validHostID}}, nil).Once() + + clientMock.On("GetHost", mock.Anything, validHostID). + Return(gopowerstore.Host{}, gopowerstore.APIError{ + ErrorMsg: &api.ErrorMsg{StatusCode: http.StatusBadRequest}, + }) + + req := &csi.ControllerGetVolumeRequest{VolumeId: validBlockVolumeID} + res, err := ctrlSvc.ControllerGetVolume(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).NotTo(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("failed to get host")) + }) + }) + + ginkgo.When("filesystem API call fails", func() { + ginkgo.It("should fail [GetFS]", func() { + clientMock.On("GetFS", mock.Anything, validBaseVolID). + Return(gopowerstore.FileSystem{}, gopowerstore.APIError{ + ErrorMsg: &api.ErrorMsg{StatusCode: http.StatusBadRequest}, + }) + + req := &csi.ControllerGetVolumeRequest{VolumeId: validNfsVolumeID} + res, err := ctrlSvc.ControllerGetVolume(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).NotTo(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("failed to find filesystem")) + }) + + ginkgo.It("should fail [GetNFSExportByFileSystemID]", func() { + clientMock.On("GetFS", mock.Anything, validBaseVolID). + Return(gopowerstore.FileSystem{ID: validBaseVolID}, nil) + + clientMock.On("GetNFSExportByFileSystemID", mock.Anything, validBaseVolID). + Return(gopowerstore.NFSExport{}, gopowerstore.APIError{ + ErrorMsg: &api.ErrorMsg{StatusCode: http.StatusBadRequest}, + }) + + req := &csi.ControllerGetVolumeRequest{VolumeId: validNfsVolumeID} + res, err := ctrlSvc.ControllerGetVolume(context.Background(), req) + + gomega.Expect(res).To(gomega.BeNil()) + gomega.Expect(err).NotTo(gomega.BeNil()) + gomega.Expect(err.Error()).To(gomega.ContainSubstring("failed to find nfs export for filesystem")) + }) + }) }) })