From c37284a58efa492a79591e3978efc59d120cc339 Mon Sep 17 00:00:00 2001 From: Mayank Shah Date: Mon, 5 Oct 2020 13:09:49 +0530 Subject: [PATCH] CI: Add MacOS unit test workflow Signed-off-by: Mayank Shah --- .github/workflows/darwin.yaml | 28 ++++++ .../workflows/{build-test.yml => linux.yml} | 8 +- .github/workflows/windows.yml | 7 +- Makefile | 4 + pkg/azuredisk/azure_common_test.go | 2 +- pkg/azuredisk/nodeserver_test.go | 98 +++++++++++++------ test/utils/testutil/testutil.go | 6 ++ 7 files changed, 111 insertions(+), 42 deletions(-) create mode 100644 .github/workflows/darwin.yaml rename .github/workflows/{build-test.yml => linux.yml} (92%) diff --git a/.github/workflows/darwin.yaml b/.github/workflows/darwin.yaml new file mode 100644 index 0000000000..3035e680ec --- /dev/null +++ b/.github/workflows/darwin.yaml @@ -0,0 +1,28 @@ +name: MacOS Build & Unit Test +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + + build: + name: Build + runs-on: macos-latest + steps: + + - name: Set up Go 1.x + uses: actions/setup-go@v2 + with: + go-version: ^1.13 + id: go + + - name: Check out code into the Go module directory + uses: actions/checkout@v2 + + - name: Build Test + run: | + make azuredisk-darwin + - name: Run unit tests on MacOS + run: go test -v -race ./pkg/... \ No newline at end of file diff --git a/.github/workflows/build-test.yml b/.github/workflows/linux.yml similarity index 92% rename from .github/workflows/build-test.yml rename to .github/workflows/linux.yml index 8a6a4c06ab..2fc20acb57 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/linux.yml @@ -1,13 +1,10 @@ -name: Go - +name: Linux Build & Unit Tests on: push: branches: [ master ] pull_request: branches: [ master ] - jobs: - build: name: Build runs-on: ubuntu-latest @@ -22,9 +19,8 @@ jobs: - name: Check out code into the Go module directory uses: actions/checkout@v2 - - name: Test + - name: Build Test run: sudo go test -covermode=count -coverprofile=profile.cov ./pkg/... - - name: Send coverage env: COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d8336cf84e..da808a48b2 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -1,5 +1,4 @@ -name: Go - +name: Windows Build & Unit Tests on: push: branches: [ master ] @@ -20,9 +19,9 @@ jobs: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@v2 - - name: Build + - name: Build Test run: | - go build -a -o _output/azurediskplugin.exe ./pkg/azurediskplugin + make azuredisk-windows - name: Run Windows Unit Tests run: | # start the CSI Proxy before running tests on windows diff --git a/Makefile b/Makefile index d00d712777..cb5d0490b6 100644 --- a/Makefile +++ b/Makefile @@ -100,6 +100,10 @@ azuredisk: azuredisk-windows: CGO_ENABLED=0 GOOS=windows go build -a -ldflags ${LDFLAGS} -o _output/azurediskplugin.exe ./pkg/azurediskplugin +.PHONY: azuredisk-darwin +azuredisk-darwin: + CGO_ENABLED=0 GOOS=darwin go build -a -ldflags ${LDFLAGS} -o _output/azurediskplugin ./pkg/azurediskplugin + .PHONY: container container: azuredisk docker build --no-cache -t $(IMAGE_TAG) -f ./pkg/azurediskplugin/dev.Dockerfile . diff --git a/pkg/azuredisk/azure_common_test.go b/pkg/azuredisk/azure_common_test.go index 138dee51af..dfb8df8a44 100644 --- a/pkg/azuredisk/azure_common_test.go +++ b/pkg/azuredisk/azure_common_test.go @@ -123,7 +123,7 @@ func (handler *fakeIOHandler) ReadFile(filename string) ([]byte, error) { } func TestIoHandler(t *testing.T) { - if runtime.GOOS == "windows" { + if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { t.Skipf("skip test on GOOS=%s", runtime.GOOS) } disk, err := findDiskByLun(lun, &fakeIOHandler{}, nil) diff --git a/pkg/azuredisk/nodeserver_test.go b/pkg/azuredisk/nodeserver_test.go index 21bd01df50..ffe53302cb 100644 --- a/pkg/azuredisk/nodeserver_test.go +++ b/pkg/azuredisk/nodeserver_test.go @@ -215,9 +215,10 @@ func TestNodeGetVolumeStats(t *testing.T) { nonexistedPath := "/not/a/real/directory" fakePath := "/tmp/fake-volume-path" tests := []struct { - desc string - req csi.NodeGetVolumeStatsRequest - expectedErr error + desc string + req csi.NodeGetVolumeStatsRequest + expectedErr error + skipOnDarwin bool }{ { desc: "Volume ID missing", @@ -235,9 +236,10 @@ func TestNodeGetVolumeStats(t *testing.T) { expectedErr: status.Errorf(codes.NotFound, "path /not/a/real/directory does not exist"), }, { - desc: "standard success", - req: csi.NodeGetVolumeStatsRequest{VolumePath: fakePath, VolumeId: "vol_1"}, - expectedErr: nil, + desc: "standard success", + req: csi.NodeGetVolumeStatsRequest{VolumePath: fakePath, VolumeId: "vol_1"}, + skipOnDarwin: true, + expectedErr: nil, }, } @@ -246,9 +248,11 @@ func TestNodeGetVolumeStats(t *testing.T) { d, _ := NewFakeDriver(t) for _, test := range tests { - _, err := d.NodeGetVolumeStats(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.skipOnDarwin && runtime.GOOS == "darwin") { + _, err := d.NodeGetVolumeStats(context.Background(), &test.req) + if !reflect.DeepEqual(err, test.expectedErr) { + t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr) + } } } @@ -276,9 +280,10 @@ func TestNodeStageVolume(t *testing.T) { } tests := []struct { - desc string - req csi.NodeStageVolumeRequest - expectedErr error + desc string + req csi.NodeStageVolumeRequest + expectedErr error + skipOnDarwin bool }{ { desc: "Volume ID missing", @@ -313,7 +318,8 @@ func TestNodeStageVolume(t *testing.T) { expectedErr: status.Error(codes.InvalidArgument, "lun not provided"), }, { - desc: "Invalid Lun", + desc: "Invalid Lun", + skipOnDarwin: true, req: csi.NodeStageVolumeRequest{VolumeId: "vol_1", StagingTargetPath: sourceTest, VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap, AccessType: stdVolCap}, @@ -331,11 +337,13 @@ func TestNodeStageVolume(t *testing.T) { d, _ := NewFakeDriver(t) d.mounter, _ = mounter.NewSafeMounter() for _, test := range tests { - _, err := d.NodeStageVolume(context.Background(), &test.req) - if test.desc == "Failed volume mount" { - assert.Error(t, err) - } else if !reflect.DeepEqual(err, test.expectedErr) { - t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr) + if !(test.skipOnDarwin && runtime.GOOS == "darwin") { + _, err := d.NodeStageVolume(context.Background(), &test.req) + if test.desc == "Failed volume mount" { + assert.Error(t, err) + } else if !reflect.DeepEqual(err, test.expectedErr) { + t.Errorf("desc: %s\n actualErr: (%v), expectedErr: (%v)", test.desc, err, test.expectedErr) + } } } @@ -356,6 +364,7 @@ func TestNodeUnstageVolume(t *testing.T) { desc string req csi.NodeUnstageVolumeRequest skipOnWindows bool + skipOnDarwin bool expectedErr testutil.TestError }{ { @@ -376,6 +385,7 @@ func TestNodeUnstageVolume(t *testing.T) { desc: "[Error] CleanupMountPoint error mocked by IsLikelyNotMountPoint", req: csi.NodeUnstageVolumeRequest{StagingTargetPath: errorTarget, VolumeId: "vol_1"}, skipOnWindows: true, // no error reported in windows + skipOnDarwin: true, expectedErr: testutil.TestError{ DefaultError: status.Error(codes.Internal, fmt.Sprintf("failed to unmount staging target \"%s\": "+ "fake IsLikelyNotMountPoint: fake error", errorTarget)), @@ -396,7 +406,8 @@ func TestNodeUnstageVolume(t *testing.T) { d.mounter = fakeMounter for _, test := range tests { - if !(runtime.GOOS == "windows" && test.skipOnWindows) { + if !(runtime.GOOS == "windows" && test.skipOnWindows) && + !(runtime.GOOS == "darwin" && test.skipOnDarwin) { _, err := d.NodeUnstageVolume(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()) @@ -577,6 +588,7 @@ func TestNodeUnpublishVolume(t *testing.T) { desc string req csi.NodeUnpublishVolumeRequest skipOnWindows bool + skipOnDarwin bool expectedErr testutil.TestError }{ { @@ -597,6 +609,7 @@ func TestNodeUnpublishVolume(t *testing.T) { desc: "[Error] Unmount error mocked by IsLikelyNotMountPoint", req: csi.NodeUnpublishVolumeRequest{TargetPath: errorTarget, VolumeId: "vol_1"}, skipOnWindows: true, // no error reported in windows + skipOnDarwin: true, // no error reported in darwin expectedErr: testutil.TestError{ DefaultError: status.Error(codes.Internal, fmt.Sprintf("failed to unmount target \"%s\": fake IsLikelyNotMountPoint: fake error", errorTarget)), }, @@ -616,9 +629,12 @@ func TestNodeUnpublishVolume(t *testing.T) { d.mounter = fakeMounter for _, test := range tests { - _, err := d.NodeUnpublishVolume(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()) + if !(test.skipOnWindows && runtime.GOOS == "windows") && + !(test.skipOnDarwin && runtime.GOOS == "darwin") { + _, err := d.NodeUnpublishVolume(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()) + } } } @@ -633,6 +649,15 @@ func TestNodeExpandVolume(t *testing.T) { RequiredBytes: volumehelper.GiBToBytes(15), LimitBytes: volumehelper.GiBToBytes(10), } + + invalidPathErr := testutil.TestError{ + DefaultError: status.Error(codes.Internal, "Could not determine device path: exit status 1"), + WindowsError: status.Error(codes.Internal, "Could not determine device path: executable file not found in %PATH%"), + } + + if runtime.GOOS == "darwin" { + invalidPathErr.DefaultError = status.Error(codes.Internal, "Could not determine device path: executable file not found in $PATH") + } tests := []struct { desc string req csi.NodeExpandVolumeRequest @@ -652,10 +677,7 @@ func TestNodeExpandVolume(t *testing.T) { VolumePath: "./test", VolumeId: "test", }, - expectedErr: testutil.TestError{ - DefaultError: status.Error(codes.Internal, "Could not determine device path: exit status 1"), - WindowsError: status.Error(codes.Internal, "Could not determine device path: executable file not found in %PATH%"), - }, + expectedErr: invalidPathErr, }, } for _, test := range tests { @@ -671,6 +693,12 @@ func TestGetBlockSizeBytes(t *testing.T) { testTarget, err := testutil.GetWorkDirPath("test") assert.NoError(t, err) + notFoundErr := "exit status 1" + // exception in darwin + if runtime.GOOS == "darwin" { + notFoundErr = "executable file not found in $PATH" + } + tests := []struct { desc string req string @@ -680,16 +708,18 @@ func TestGetBlockSizeBytes(t *testing.T) { desc: "no exist path", req: "testpath", expectedErr: testutil.TestError{ - DefaultError: 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%"), + DefaultError: fmt.Errorf("error when getting size of block volume at path testpath: output: , err: %s", notFoundErr), + WindowsError: fmt.Errorf("error when getting size of block volume at path testpath: output: , err: %s", notFoundErr), }, }, { desc: "invalid path", req: testTarget, expectedErr: testutil.TestError{ - DefaultError: 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), + DefaultError: fmt.Errorf("error when getting size of block volume at path %s: "+ + "output: , err: %s", testTarget, notFoundErr), + WindowsError: fmt.Errorf("error when getting size of block volume at path %s: "+ + "output: , err: %s", testTarget, notFoundErr), }, }, } @@ -707,11 +737,17 @@ func TestGetBlockSizeBytes(t *testing.T) { } func TestEnsureBlockTargetFile(t *testing.T) { + // sip this test because `util/mount` not supported + // on darwin + if runtime.GOOS == "darwin" { + t.Skip("Skipping tests on darwin") + } 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) + d, err := NewFakeDriver(t) + assert.NoError(t, err) tests := []struct { desc string diff --git a/test/utils/testutil/testutil.go b/test/utils/testutil/testutil.go index f5aae27da6..201e95accb 100644 --- a/test/utils/testutil/testutil.go +++ b/test/utils/testutil/testutil.go @@ -38,8 +38,14 @@ type TestError struct { // Error returns the error on the basis of the platform func (t TestError) Error() string { if t.WindowsError == nil || !isWindows() { + if t.DefaultError == nil { + return "" + } return t.DefaultError.Error() } + if t.WindowsError == nil { + return "" + } return t.WindowsError.Error() }