From 14b2fa10eaf35c1bc5d59f67a07dc571f247e9ef Mon Sep 17 00:00:00 2001 From: Mayank Shah Date: Wed, 30 Sep 2020 12:23:41 +0530 Subject: [PATCH] fix: Windows unit tests and enable csi-proxy.exe in workflow Signed-off-by: Mayank Shah --- .github/workflows/windows.yml | 9 + pkg/azuredisk/azure_test.go | 1 + pkg/azuredisk/azuredisk_test.go | 1 + pkg/azuredisk/fake_mounter.go | 13 ++ pkg/azuredisk/nodeserver_test.go | 377 +++++++++++++++++++------------ test/utils/testutil/testutil.go | 59 ++++- 6 files changed, 317 insertions(+), 143 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 1d1bc83ae1..d8336cf84e 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -25,4 +25,13 @@ jobs: go build -a -o _output/azurediskplugin.exe ./pkg/azurediskplugin - name: Run Windows Unit Tests run: | + # start the CSI Proxy before running tests on windows + Start-Job -Name CSIProxy -ScriptBlock { + Invoke-WebRequest https://kubernetesartifacts.azureedge.net/csi-proxy/v0.2.1/binaries/csi-proxy.tar.gz -OutFile csi-proxy.tar.gz; + tar -xvf csi-proxy.tar.gz + .\bin\csi-proxy.exe --kubelet-csi-plugins-path $pwd --kubelet-pod-path $pwd + }; + Start-Sleep -Seconds 30; + Write-Output "getting named pipes" + [System.IO.Directory]::GetFiles("\\.\\pipe\\") go test -v -race ./pkg/... diff --git a/pkg/azuredisk/azure_test.go b/pkg/azuredisk/azure_test.go index 8308e5c0bf..db31011180 100644 --- a/pkg/azuredisk/azure_test.go +++ b/pkg/azuredisk/azure_test.go @@ -32,6 +32,7 @@ func skipIfTestingOnWindows(t *testing.T) { } func TestGetCloudProvider(t *testing.T) { + // skip for now as this is very flaky on Windows skipIfTestingOnWindows(t) fakeCredFile := "fake-cred-file.json" fakeKubeConfig := "fake-kube-config" diff --git a/pkg/azuredisk/azuredisk_test.go b/pkg/azuredisk/azuredisk_test.go index e8a8dcc9de..ea14867820 100644 --- a/pkg/azuredisk/azuredisk_test.go +++ b/pkg/azuredisk/azuredisk_test.go @@ -588,6 +588,7 @@ func TestIsAvailabilityZone(t *testing.T) { } func TestIsCorruptedDir(t *testing.T) { + // skip due to permission issues skipIfTestingOnWindows(t) existingMountPath, err := ioutil.TempDir(os.TempDir(), "csi-mount-test") if err != nil { diff --git a/pkg/azuredisk/fake_mounter.go b/pkg/azuredisk/fake_mounter.go index c0973f9bfa..be876294ed 100644 --- a/pkg/azuredisk/fake_mounter.go +++ b/pkg/azuredisk/fake_mounter.go @@ -18,6 +18,9 @@ package azuredisk import ( "fmt" + testingexec "k8s.io/utils/exec/testing" + "runtime" + "sigs.k8s.io/azuredisk-csi-driver/pkg/mounter" "strings" "k8s.io/utils/mount" @@ -59,3 +62,13 @@ func (f *fakeMounter) IsLikelyNotMountPoint(file string) (bool, error) { } return true, nil } + +func NewFakeMounter() (*mount.SafeFormatAndMount, error) { + if runtime.GOOS == "windows" { + return mounter.NewSafeMounter() + } + return &mount.SafeFormatAndMount{ + Interface: &fakeMounter{}, + Exec: &testingexec.FakeExec{ExactOrder: true}, + }, nil +} diff --git a/pkg/azuredisk/nodeserver_test.go b/pkg/azuredisk/nodeserver_test.go index f4ae0ec507..0c733e02d0 100644 --- a/pkg/azuredisk/nodeserver_test.go +++ b/pkg/azuredisk/nodeserver_test.go @@ -20,9 +20,11 @@ import ( "context" "errors" "fmt" + "log" "os" "reflect" "runtime" + "sigs.k8s.io/azuredisk-csi-driver/test/utils/testutil" "syscall" "testing" @@ -31,18 +33,32 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - testingexec "k8s.io/utils/exec/testing" - "k8s.io/utils/mount" - "sigs.k8s.io/azuredisk-csi-driver/pkg/mounter" volumehelper "sigs.k8s.io/azuredisk-csi-driver/pkg/util" ) -const ( - sourceTest = "./source_test" - targetTest = "./target_test" +var ( + sourceTest string + targetTest string ) +func TestMain(m *testing.M) { + var err error + sourceTest, err = testutil.GetWorkDirPath("source_test") + if err != nil { + log.Printf("failed to get source test path: %v\n", err) + os.Exit(1) + } + targetTest, err = testutil.GetWorkDirPath("target_test") + if err != nil { + log.Printf("failed to get target test path: %v\n", err) + os.Exit(1) + } + + _ = m.Run() + +} + func TestNodeGetCapabilities(t *testing.T) { d, _ := NewFakeDriver(t) capType := &csi.NodeServiceCapability_Rpc{ @@ -131,57 +147,62 @@ func TestGetMaxDataDiskCount(t *testing.T) { } func TestEnsureMountPoint(t *testing.T) { - skipIfTestingOnWindows(t) - errorTarget := "./error_is_likely_target" - alreadyExistTarget := "./false_is_likely_exist_target" - azuredisk := "./azure.go" + errorTarget, err := testutil.GetWorkDirPath("error_is_likely_target") + assert.NoError(t, err) + alreadyExistTarget, err := testutil.GetWorkDirPath("false_is_likely_exist_target") + assert.NoError(t, err) + azuredisk, err := testutil.GetWorkDirPath("azure.go") + assert.NoError(t, err) tests := []struct { desc string target string - expectedErr error + expectedErr testutil.TestError }{ { - desc: "[Error] Mocked by IsLikelyNotMountPoint", - target: errorTarget, - expectedErr: fmt.Errorf("fake IsLikelyNotMountPoint: fake error"), + desc: "[Error] Mocked by IsLikelyNotMountPoint", + target: errorTarget, + expectedErr: testutil.TestError{ + LinuxError: errors.New("fake IsLikelyNotMountPoint: fake error"), + WindowsError: nil, // different mount behaviour on windows, + }, }, { - desc: "[Error] Not a directory", - target: azuredisk, - expectedErr: &os.PathError{Op: "mkdir", Path: "./azure.go", Err: syscall.ENOTDIR}, + desc: "[Error] Not a directory", + target: azuredisk, + expectedErr: testutil.TestError{ + LinuxError: &os.PathError{Op: "mkdir", Path: azuredisk, Err: syscall.ENOTDIR}, + WindowsError: nil, // different mount behaviour on windows), + }, }, { desc: "[Success] Successful run", target: targetTest, - expectedErr: nil, + expectedErr: testutil.TestError{}, }, { desc: "[Success] Already existing mount", target: alreadyExistTarget, - expectedErr: nil, + expectedErr: testutil.TestError{}, }, } // Setup _ = makeDir(alreadyExistTarget) d, _ := NewFakeDriver(t) - fakeMounter := &fakeMounter{} - fakeExec := &testingexec.FakeExec{ExactOrder: true} - d.mounter = &mount.SafeFormatAndMount{ - Interface: fakeMounter, - Exec: fakeExec, - } + fakeMounter, err := NewFakeMounter() + assert.NoError(t, err) + d.mounter = fakeMounter for _, test := range tests { err := d.ensureMountPoint(test.target) - if !reflect.DeepEqual(err, test.expectedErr) { - t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr) + if !testutil.AssertError(&test.expectedErr, err) { + t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr.Error()) } } // Clean up - err := os.RemoveAll(alreadyExistTarget) + err = os.RemoveAll(alreadyExistTarget) assert.NoError(t, err) err = os.RemoveAll(targetTest) assert.NoError(t, err) @@ -234,10 +255,6 @@ func TestNodeGetVolumeStats(t *testing.T) { } func TestNodeStageVolume(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skipf("skip test on GOOS=%s", runtime.GOOS) - } - stdVolCap := &csi.VolumeCapability_Mount{ Mount: &csi.VolumeCapability_MountVolume{ FsType: defaultLinuxFsType, @@ -327,68 +344,86 @@ func TestNodeStageVolume(t *testing.T) { } func TestNodeUnstageVolume(t *testing.T) { - skipIfTestingOnWindows(t) - errorTarget := "./error_is_likely_target" - targetFile := "./abc.go" + errorTarget, err := testutil.GetWorkDirPath("error_is_likely_target") + assert.NoError(t, err) + targetFile, err := testutil.GetWorkDirPath("abc.go") + assert.NoError(t, err) + tests := []struct { desc string req csi.NodeUnstageVolumeRequest - expectedErr error + expectedErr testutil.TestError }{ { - desc: "Volume ID missing", - req: csi.NodeUnstageVolumeRequest{StagingTargetPath: targetTest}, - expectedErr: status.Error(codes.InvalidArgument, "Volume ID not provided"), + desc: "Volume ID missing", + req: csi.NodeUnstageVolumeRequest{StagingTargetPath: targetTest}, + expectedErr: testutil.TestError{ + LinuxError: status.Error(codes.InvalidArgument, "Volume ID not provided"), + WindowsError: status.Error(codes.InvalidArgument, "Volume ID not provided"), + }, }, { - desc: "Staging target missing ", - req: csi.NodeUnstageVolumeRequest{VolumeId: "vol_1"}, - expectedErr: status.Error(codes.InvalidArgument, "Staging target not provided"), + desc: "Staging target missing ", + req: csi.NodeUnstageVolumeRequest{VolumeId: "vol_1"}, + expectedErr: testutil.TestError{ + LinuxError: status.Error(codes.InvalidArgument, "Staging target not provided"), + WindowsError: status.Error(codes.InvalidArgument, "Staging target not provided"), + }, }, { - desc: "[Error] CleanupMountPoint error mocked by IsLikelyNotMountPoint", - req: csi.NodeUnstageVolumeRequest{StagingTargetPath: errorTarget, VolumeId: "vol_1"}, - expectedErr: status.Error(codes.Internal, "failed to unmount staging target \"./error_is_likely_target\": fake IsLikelyNotMountPoint: fake error"), + desc: "[Error] CleanupMountPoint error mocked by IsLikelyNotMountPoint", + req: csi.NodeUnstageVolumeRequest{StagingTargetPath: errorTarget, VolumeId: "vol_1"}, + expectedErr: testutil.TestError{ + LinuxError: status.Error(codes.Internal, fmt.Sprintf("failed to unmount staging target \"%s\": "+ + "fake IsLikelyNotMountPoint: fake error", errorTarget)), + WindowsError: nil, // different mount behaviour on windows + }, }, { desc: "[Success] Valid request", req: csi.NodeUnstageVolumeRequest{StagingTargetPath: targetFile, VolumeId: "vol_1"}, - expectedErr: nil, + expectedErr: testutil.TestError{}, }, } //Setup _ = makeDir(errorTarget) d, _ := NewFakeDriver(t) - fakeMounter := &fakeMounter{} - fakeExec := &testingexec.FakeExec{ExactOrder: true} - d.mounter = &mount.SafeFormatAndMount{ - Interface: fakeMounter, - Exec: fakeExec, - } + fakeMounter, err := NewFakeMounter() + assert.NoError(t, err) + d.mounter = fakeMounter for _, test := range tests { _, err := d.NodeUnstageVolume(context.Background(), &test.req) - - if !reflect.DeepEqual(err, test.expectedErr) { - t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr) + if !testutil.AssertError(&test.expectedErr, err) { + t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr.Error()) } } // Clean up - err := os.RemoveAll(errorTarget) + err = os.RemoveAll(errorTarget) assert.NoError(t, err) } func TestNodePublishVolume(t *testing.T) { - skipIfTestingOnWindows(t) volumeCap := csi.VolumeCapability_AccessMode{Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER} publishContext := map[string]string{ LUN: "/dev/01", } - errorMountSource := "./error_mount_source" - alreadyMountedTarget := "./false_is_likely_exist_target" - azuredisk := "./azure.go" + errorMountSource, err := testutil.GetWorkDirPath("error_mount_source") + assert.NoError(t, err) + alreadyMountedTarget, err := testutil.GetWorkDirPath("false_is_likely_exist_target") + assert.NoError(t, err) + + azurediskPath := "azure.go" + + // ".\azure.go will get deleted on Windows" + if runtime.GOOS == "windows" { + azurediskPath = "testfiles\\azure.go" + } + azuredisk, err := testutil.GetWorkDirPath(azurediskPath) + assert.NoError(t, err) + stdVolCap := &csi.VolumeCapability_Mount{ Mount: &csi.VolumeCapability_MountVolume{}, } @@ -397,32 +432,45 @@ func TestNodePublishVolume(t *testing.T) { } tests := []struct { - desc string - req csi.NodePublishVolumeRequest - expectedErr error + desc string + req csi.NodePublishVolumeRequest + skipOnWindows bool + expectedErr testutil.TestError }{ { - desc: "Volume capabilities missing", - req: csi.NodePublishVolumeRequest{}, - expectedErr: status.Error(codes.InvalidArgument, "Volume capability missing in request"), + desc: "Volume capabilities missing", + req: csi.NodePublishVolumeRequest{}, + expectedErr: testutil.TestError{ + LinuxError: status.Error(codes.InvalidArgument, "Volume capability missing in request"), + WindowsError: status.Error(codes.InvalidArgument, "Volume capability missing in request"), + }, }, { - desc: "Volume ID missing", - req: csi.NodePublishVolumeRequest{VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap}}, - expectedErr: status.Error(codes.InvalidArgument, "Volume ID missing in request"), + desc: "Volume ID missing", + req: csi.NodePublishVolumeRequest{VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap}}, + expectedErr: testutil.TestError{ + LinuxError: status.Error(codes.InvalidArgument, "Volume ID missing in request"), + WindowsError: status.Error(codes.InvalidArgument, "Volume ID missing in request"), + }, }, { desc: "Staging target path missing", req: csi.NodePublishVolumeRequest{VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap}, VolumeId: "vol_1"}, - expectedErr: status.Error(codes.InvalidArgument, "Staging target not provided"), + expectedErr: testutil.TestError{ + LinuxError: status.Error(codes.InvalidArgument, "Staging target not provided"), + WindowsError: status.Error(codes.InvalidArgument, "Staging target not provided"), + }, }, { desc: "Target path missing", req: csi.NodePublishVolumeRequest{VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap}, VolumeId: "vol_1", StagingTargetPath: sourceTest}, - expectedErr: status.Error(codes.InvalidArgument, "Target path not provided"), + expectedErr: testutil.TestError{ + LinuxError: status.Error(codes.InvalidArgument, "Target path not provided"), + WindowsError: status.Error(codes.InvalidArgument, "Target path not provided"), + }, }, { desc: "[Error] Not a directory", @@ -431,7 +479,13 @@ func TestNodePublishVolume(t *testing.T) { TargetPath: azuredisk, StagingTargetPath: sourceTest, Readonly: true}, - expectedErr: status.Errorf(codes.Internal, "Could not mount target \"./azure.go\": mkdir ./azure.go: not a directory"), + skipOnWindows: true, // permission issues + expectedErr: testutil.TestError{ + LinuxError: status.Errorf(codes.Internal, fmt.Sprintf("Could not mount target \"%s\": "+ + "mkdir %s: not a directory", azuredisk, azuredisk)), + WindowsError: status.Errorf(codes.Internal, fmt.Sprintf("Could not mount target \"%s\": "+ + "mkdir %s: not a directory", azuredisk, azuredisk)), + }, }, { desc: "[Error] Lun not provided", @@ -440,7 +494,10 @@ func TestNodePublishVolume(t *testing.T) { TargetPath: azuredisk, StagingTargetPath: sourceTest, Readonly: true}, - expectedErr: status.Error(codes.InvalidArgument, "lun not provided"), + expectedErr: testutil.TestError{ + LinuxError: status.Error(codes.InvalidArgument, "lun not provided"), + WindowsError: status.Error(codes.InvalidArgument, "lun not provided"), + }, }, { desc: "[Error] Lun not valid", @@ -450,7 +507,10 @@ func TestNodePublishVolume(t *testing.T) { StagingTargetPath: sourceTest, PublishContext: publishContext, Readonly: true}, - expectedErr: status.Error(codes.Internal, "Failed to find device path with lun /dev/01. cannot parse deviceInfo: /dev/01"), + expectedErr: testutil.TestError{ + LinuxError: status.Error(codes.Internal, "Failed to find device path with lun /dev/01. cannot parse deviceInfo: /dev/01"), + WindowsError: status.Error(codes.Internal, "Failed to find device path with lun /dev/01. cannot parse deviceInfo: /dev/01"), + }, }, { desc: "[Error] Mount error mocked by Mount", @@ -459,7 +519,13 @@ func TestNodePublishVolume(t *testing.T) { TargetPath: targetTest, StagingTargetPath: errorMountSource, Readonly: true}, - expectedErr: status.Errorf(codes.Internal, "Could not mount \"./error_mount_source\" at \"./target_test\": fake Mount: source error"), + skipOnWindows: true, // permission issues + expectedErr: testutil.TestError{ + LinuxError: status.Errorf(codes.Internal, fmt.Sprintf("Could not mount \"%s\" at \"%s\": "+ + "fake Mount: source error", errorMountSource, targetTest)), + WindowsError: status.Errorf(codes.Internal, fmt.Sprintf("Could not mount \"%s\" at \"%s\": "+ + "fake Mount: source error", errorMountSource, targetTest)), + }, }, { desc: "[Success] Valid request already mounted", @@ -468,7 +534,8 @@ func TestNodePublishVolume(t *testing.T) { TargetPath: alreadyMountedTarget, StagingTargetPath: sourceTest, Readonly: true}, - expectedErr: nil, + skipOnWindows: true, // permission issues + expectedErr: testutil.TestError{}, }, { desc: "[Success] Valid request", @@ -477,90 +544,97 @@ func TestNodePublishVolume(t *testing.T) { TargetPath: targetTest, StagingTargetPath: sourceTest, Readonly: true}, - expectedErr: nil, + skipOnWindows: true, // permission issues + expectedErr: testutil.TestError{}, }, } // Setup _ = makeDir(alreadyMountedTarget) d, _ := NewFakeDriver(t) - fakeMounter := &fakeMounter{} - fakeExec := &testingexec.FakeExec{ExactOrder: true} - d.mounter = &mount.SafeFormatAndMount{ - Interface: fakeMounter, - Exec: fakeExec, - } + assert.NoError(t, err) + fakeMounter, err := NewFakeMounter() + assert.NoError(t, err) + d.mounter = fakeMounter for _, test := range tests { - _, err := d.NodePublishVolume(context.Background(), &test.req) - - if !reflect.DeepEqual(err, test.expectedErr) { - t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr) + if !(test.skipOnWindows && runtime.GOOS == "windows") { + _, err := d.NodePublishVolume(context.Background(), &test.req) + if !testutil.AssertError(&test.expectedErr, err) { + t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr.Error()) + } } } // Clean up - err := os.RemoveAll(targetTest) + err = os.RemoveAll(targetTest) assert.NoError(t, err) err = os.RemoveAll(alreadyMountedTarget) assert.NoError(t, err) } func TestNodeUnpublishVolume(t *testing.T) { - skipIfTestingOnWindows(t) - errorTarget := "./error_is_likely_target" - targetFile := "./abc.go" + errorTarget, err := testutil.GetWorkDirPath("error_is_likely_target") + assert.NoError(t, err) + targetFile, err := testutil.GetWorkDirPath("abc.go") + assert.NoError(t, err) + tests := []struct { desc string req csi.NodeUnpublishVolumeRequest - expectedErr error + expectedErr testutil.TestError }{ { - desc: "Volume ID missing", - req: csi.NodeUnpublishVolumeRequest{TargetPath: targetTest}, - expectedErr: status.Error(codes.InvalidArgument, "Volume ID missing in request"), + desc: "Volume ID missing", + req: csi.NodeUnpublishVolumeRequest{TargetPath: targetTest}, + expectedErr: testutil.TestError{ + LinuxError: status.Error(codes.InvalidArgument, "Volume ID missing in request"), + WindowsError: status.Error(codes.InvalidArgument, "Volume ID missing in request"), + }, }, { - desc: "Target missing", - req: csi.NodeUnpublishVolumeRequest{VolumeId: "vol_1"}, - expectedErr: status.Error(codes.InvalidArgument, "Target path missing in request"), + desc: "Target missing", + req: csi.NodeUnpublishVolumeRequest{VolumeId: "vol_1"}, + expectedErr: testutil.TestError{ + LinuxError: status.Error(codes.InvalidArgument, "Target path missing in request"), + WindowsError: status.Error(codes.InvalidArgument, "Target path missing in request"), + }, }, { - desc: "[Error] Unmount error mocked by IsLikelyNotMountPoint", - req: csi.NodeUnpublishVolumeRequest{TargetPath: errorTarget, VolumeId: "vol_1"}, - expectedErr: status.Error(codes.Internal, "failed to unmount target \"./error_is_likely_target\": fake IsLikelyNotMountPoint: fake error"), + desc: "[Error] Unmount error mocked by IsLikelyNotMountPoint", + req: csi.NodeUnpublishVolumeRequest{TargetPath: errorTarget, VolumeId: "vol_1"}, + expectedErr: testutil.TestError{ + LinuxError: status.Error(codes.Internal, fmt.Sprintf("failed to unmount target \"%s\": fake IsLikelyNotMountPoint: fake error", errorTarget)), + WindowsError: nil, // different mount behaviour on windows + }, }, { desc: "[Success] Valid request", req: csi.NodeUnpublishVolumeRequest{TargetPath: targetFile, VolumeId: "vol_1"}, - expectedErr: nil, + expectedErr: testutil.TestError{}, }, } // Setup _ = makeDir(errorTarget) d, _ := NewFakeDriver(t) - fakeMounter := &fakeMounter{} - fakeExec := &testingexec.FakeExec{ExactOrder: true} - d.mounter = &mount.SafeFormatAndMount{ - Interface: fakeMounter, - Exec: fakeExec, - } + fakeMounter, err := NewFakeMounter() + assert.NoError(t, err) + d.mounter = fakeMounter for _, test := range tests { _, err := d.NodeUnpublishVolume(context.Background(), &test.req) - if !reflect.DeepEqual(err, test.expectedErr) { - t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr) + if !testutil.AssertError(&test.expectedErr, err) { + t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr.Error()) } } // Clean up - err := os.RemoveAll(errorTarget) + err = os.RemoveAll(errorTarget) assert.NoError(t, err) } func TestNodeExpandVolume(t *testing.T) { - skipIfTestingOnWindows(t) d, _ := NewFakeDriver(t) stdCapacityRange = &csi.CapacityRange{ RequiredBytes: volumehelper.GiBToBytes(15), @@ -569,91 +643,110 @@ func TestNodeExpandVolume(t *testing.T) { tests := []struct { desc string req csi.NodeExpandVolumeRequest - expectedErr error + expectedErr testutil.TestError }{ { - desc: "Volume ID missing", - req: csi.NodeExpandVolumeRequest{}, - expectedErr: status.Error(codes.InvalidArgument, "Volume ID not provided"), + desc: "Volume ID missing", + req: csi.NodeExpandVolumeRequest{}, + expectedErr: testutil.TestError{ + LinuxError: status.Error(codes.InvalidArgument, "Volume ID not provided"), + WindowsError: status.Error(codes.InvalidArgument, "Volume ID not provided"), + }, }, { - desc: "cound not find path", + desc: "could not find path", req: csi.NodeExpandVolumeRequest{ CapacityRange: stdCapacityRange, VolumePath: "./test", VolumeId: "test", }, - expectedErr: status.Error(codes.Internal, "Could not determine device path: exit status 1"), + expectedErr: testutil.TestError{ + WindowsError: status.Error(codes.Internal, "Could not determine device path: exit status 1"), + LinuxError: status.Error(codes.Internal, "Could not determine device path: executable file not found in %PATH%"), + }, }, } for _, test := range tests { _, err := d.NodeExpandVolume(context.Background(), &test.req) - if !reflect.DeepEqual(err, test.expectedErr) { - t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr) + if !testutil.AssertError(&test.expectedErr, err) { + t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr.Error()) } } } func TestGetBlockSizeBytes(t *testing.T) { - skipIfTestingOnWindows(t) d, _ := NewFakeDriver(t) - testTarget := "./test" + testTarget, err := testutil.GetWorkDirPath("test") + assert.NoError(t, err) + tests := []struct { desc string req string - expectedErr error + expectedErr testutil.TestError }{ { - desc: "no exist path", - req: "testpath", - expectedErr: fmt.Errorf("error when getting size of block volume at path testpath: output: , err: exit status 1"), + desc: "no exist path", + req: "testpath", + expectedErr: testutil.TestError{ + LinuxError: errors.New("error when getting size of block volume at path testpath: output: , err: exit status 1"), + WindowsError: errors.New("error when getting size of block volume at path testpath: output: , err: executable file not found in %PATH%"), + }, }, { - desc: "invalid path", - req: testTarget, - expectedErr: fmt.Errorf("error when getting size of block volume at path ./test: output: , err: exit status 1"), + desc: "invalid path", + req: testTarget, + expectedErr: testutil.TestError{ + LinuxError: fmt.Errorf("error when getting size of block volume at path %s: output: , err: exit status 1", testTarget), + WindowsError: fmt.Errorf("error when getting size of block volume at path %s: output: , err: executable file not found in %%PATH%%", testTarget), + }, }, } for _, test := range tests { _, err := d.getBlockSizeBytes(test.req) - if !reflect.DeepEqual(err, test.expectedErr) { - t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr) + if !testutil.AssertError(&test.expectedErr, err) { + t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr.Error()) } } //Setup _ = makeDir(testTarget) - err := os.RemoveAll(testTarget) + err = os.RemoveAll(testTarget) assert.NoError(t, err) } func TestEnsureBlockTargetFile(t *testing.T) { - skipIfTestingOnWindows(t) - testTarget := "./test" + testTarget, err := testutil.GetWorkDirPath("test") + assert.NoError(t, err) + testPath, err := testutil.GetWorkDirPath(fmt.Sprintf("test%ctest", os.PathSeparator)) + assert.NoError(t, err) d, _ := NewFakeDriver(t) + tests := []struct { desc string req string - expectedErr error + expectedErr testutil.TestError }{ { desc: "valid test", req: testTarget, - expectedErr: nil, + expectedErr: testutil.TestError{}, }, { - desc: "test if file exists", - req: "./test/test", - expectedErr: status.Error(codes.Internal, "Could not mount target \"test\": mkdir test: not a directory"), + desc: "test if file exists", + req: testPath, + expectedErr: testutil.TestError{ + WindowsError: status.Error(codes.Internal, fmt.Sprintf("Could not mount target \"%s\": mkdir %s: not a directory", testTarget, testTarget)), + LinuxError: status.Error(codes.Internal, fmt.Sprintf("Could not remove mount target %#v: remove %s: The system cannot find the path specified.", testPath, testPath)), + }, }, } for _, test := range tests { err := d.ensureBlockTargetFile(test.req) - if !reflect.DeepEqual(err, test.expectedErr) { - t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr) + if !testutil.AssertError(&test.expectedErr, err) { + t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr.Error()) } } - err := os.RemoveAll(testTarget) + err = os.RemoveAll(testTarget) assert.NoError(t, err) } diff --git a/test/utils/testutil/testutil.go b/test/utils/testutil/testutil.go index aeacfc68ec..f6861aaa2a 100644 --- a/test/utils/testutil/testutil.go +++ b/test/utils/testutil/testutil.go @@ -16,9 +16,66 @@ limitations under the License. package testutil -import "os" +import ( + "fmt" + "os" + "reflect" + "runtime" +) func IsRunningInProw() bool { _, ok := os.LookupEnv("AZURE_CREDENTIALS") return ok } + +// TestError is used to define the errors given by different kinds of OS +// Implements the `error` interface +type TestError struct { + LinuxError error + WindowsError error +} + +// Error returns the error on the basis of the platform +func (t TestError) Error() string { + switch runtime.GOOS { + case linux: + if t.LinuxError == nil { + return "" + } + return t.LinuxError.Error() + case windows: + if t.WindowsError == nil { + return "" + } + return t.WindowsError.Error() + default: + return fmt.Sprintf("could not find error for ARCH: %s", runtime.GOOS) + } +} + +const ( + windows = "windows" + linux = "linux" +) + +// AssertError checks if the TestError matches with the actual error +// on the basis of the platform on which it is running +func AssertError(expected *TestError, actual error) bool { + switch runtime.GOOS { + case linux: + return reflect.DeepEqual(expected.LinuxError, actual) + case windows: + return reflect.DeepEqual(expected.WindowsError, actual) + default: + return false + } +} + +// GetWorkDirPath returns the path to the current working directory +func GetWorkDirPath(dir string) (string, error) { + path, err := os.Getwd() + if err != nil { + return "", err + } + return fmt.Sprintf("%s%c%s", path, os.PathSeparator, dir), nil +}