From d83f52d9168a6c73140df5b73fdf1fdf606c6f8d Mon Sep 17 00:00:00 2001 From: Saurav Tiwary Date: Sun, 3 Jan 2021 21:25:53 +0530 Subject: [PATCH] test: Add missing unit tests for controller server and utils --- pkg/nfs/controllerserver_test.go | 165 ++++++++++++++++++++++++++++++- pkg/nfs/utils_test.go | 85 ++++++++++++++++ 2 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 pkg/nfs/utils_test.go diff --git a/pkg/nfs/controllerserver_test.go b/pkg/nfs/controllerserver_test.go index 526090b9..99601472 100644 --- a/pkg/nfs/controllerserver_test.go +++ b/pkg/nfs/controllerserver_test.go @@ -26,6 +26,8 @@ import ( "github.com/container-storage-interface/spec/lib/go/csi" "golang.org/x/net/context" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "k8s.io/utils/mount" ) @@ -46,7 +48,9 @@ func initTestController(t *testing.T) *ControllerServer { mounter := &mount.FakeMounter{MountPoints: []mount.MountPoint{}} driver := NewNFSdriver("", "", perm) driver.ns = NewNodeServer(driver, mounter) - return NewControllerServer(driver) + cs := NewControllerServer(driver) + cs.workingMountDir = "/tmp" + return cs } func teardown() { @@ -193,3 +197,162 @@ func TestCreateVolume(t *testing.T) { }) } } + +func TestDeleteVolume(t *testing.T) { + cases := []struct { + desc string + req *csi.DeleteVolumeRequest + resp *csi.DeleteVolumeResponse + expectedErr error + }{ + { + desc: "Volume ID missing", + req: &csi.DeleteVolumeRequest{}, + resp: nil, + expectedErr: status.Error(codes.InvalidArgument, "Volume ID missing in request"), + }, + { + desc: "Valid request", + req: &csi.DeleteVolumeRequest{VolumeId: testVolumeID}, + resp: &csi.DeleteVolumeResponse{}, + expectedErr: nil, + }, + } + + for _, test := range cases { + test := test //pin + t.Run(test.desc, func(t *testing.T) { + // Setup + cs := initTestController(t) + _ = os.MkdirAll(filepath.Join(cs.workingMountDir, testCSIVolume), os.ModePerm) + _, _ = os.Create(filepath.Join(cs.workingMountDir, testCSIVolume, testCSIVolume)) + + // Run + resp, err := cs.DeleteVolume(context.TODO(), test.req) + + // Verify + if test.expectedErr == nil && err != nil { + t.Errorf("test %q failed: %v", test.desc, err) + } + if test.expectedErr != nil && err == nil { + t.Errorf("test %q failed; expected error %v, got success", test.desc, test.expectedErr) + } + if !reflect.DeepEqual(resp, test.resp) { + t.Errorf("test %q failed: got resp %+v, expected %+v", test.desc, resp, test.resp) + } + if _, err := os.Stat(filepath.Join(cs.workingMountDir, testCSIVolume, testCSIVolume)); test.expectedErr == nil && !os.IsNotExist(err) { + t.Errorf("test %q failed: expected volume subdirectory deleted, it still exists", test.desc) + } + }) + } +} + +func TestValidateVolumeCapabilities(t *testing.T) { + cases := []struct { + desc string + req *csi.ValidateVolumeCapabilitiesRequest + resp *csi.ValidateVolumeCapabilitiesResponse + expectedErr error + }{ + { + desc: "Volume ID missing", + req: &csi.ValidateVolumeCapabilitiesRequest{}, + resp: nil, + expectedErr: status.Error(codes.InvalidArgument, "Volume ID missing in request"), + }, + { + desc: "Volume capabilities missing", + req: &csi.ValidateVolumeCapabilitiesRequest{VolumeId: testVolumeID}, + resp: nil, + expectedErr: status.Error(codes.InvalidArgument, "Volume capabilities missing in request"), + }, + { + desc: "valid request", + req: &csi.ValidateVolumeCapabilitiesRequest{ + VolumeId: testVolumeID, + VolumeCapabilities: []*csi.VolumeCapability{ + { + AccessType: &csi.VolumeCapability_Mount{ + Mount: &csi.VolumeCapability_MountVolume{}, + }, + AccessMode: &csi.VolumeCapability_AccessMode{ + Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER, + }, + }, + }, + }, + resp: &csi.ValidateVolumeCapabilitiesResponse{Message: ""}, + expectedErr: nil, + }, + } + + for _, test := range cases { + test := test //pin + t.Run(test.desc, func(t *testing.T) { + // Setup + cs := initTestController(t) + + // Run + resp, err := cs.ValidateVolumeCapabilities(context.TODO(), test.req) + + // Verify + if test.expectedErr == nil && err != nil { + t.Errorf("test %q failed: %v", test.desc, err) + } + if test.expectedErr != nil && err == nil { + t.Errorf("test %q failed; expected error %v, got success", test.desc, test.expectedErr) + } + if !reflect.DeepEqual(resp, test.resp) { + t.Errorf("test %q failed: got resp %+v, expected %+v", test.desc, resp, test.resp) + } + }) + } +} + +func TestControllerGetCapabilities(t *testing.T) { + cases := []struct { + desc string + req *csi.ControllerGetCapabilitiesRequest + resp *csi.ControllerGetCapabilitiesResponse + expectedErr error + }{ + { + desc: "valid request", + req: &csi.ControllerGetCapabilitiesRequest{}, + resp: &csi.ControllerGetCapabilitiesResponse{ + Capabilities: []*csi.ControllerServiceCapability{ + { + Type: &csi.ControllerServiceCapability_Rpc{ + Rpc: &csi.ControllerServiceCapability_RPC{ + Type: csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME, + }, + }, + }, + }, + }, + expectedErr: nil, + }, + } + + for _, test := range cases { + test := test //pin + t.Run(test.desc, func(t *testing.T) { + // Setup + cs := initTestController(t) + + // Run + resp, err := cs.ControllerGetCapabilities(context.TODO(), test.req) + + // Verify + if test.expectedErr == nil && err != nil { + t.Errorf("test %q failed: %v", test.desc, err) + } + if test.expectedErr != nil && err == nil { + t.Errorf("test %q failed; expected error %v, got success", test.desc, test.expectedErr) + } + if !reflect.DeepEqual(resp, test.resp) { + t.Errorf("test %q failed: got resp %+v, expected %+v", test.desc, resp, test.resp) + } + }) + } +} diff --git a/pkg/nfs/utils_test.go b/pkg/nfs/utils_test.go new file mode 100644 index 00000000..536f8065 --- /dev/null +++ b/pkg/nfs/utils_test.go @@ -0,0 +1,85 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package nfs + +import ( + "fmt" + "testing" +) + +var ( + invalidEndpoint = "invalid-endpoint" + emptyAddr = "tcp://" +) + +func TestParseEndpoint(t *testing.T) { + cases := []struct { + desc string + endpoint string + resproto string + respaddr string + expectedErr error + }{ + { + desc: "invalid endpoint", + endpoint: invalidEndpoint, + expectedErr: fmt.Errorf("Invalid endpoint: %v", invalidEndpoint), + }, + { + desc: "empty address", + endpoint: emptyAddr, + expectedErr: fmt.Errorf("Invalid endpoint: %v", emptyAddr), + }, + { + desc: "valid tcp", + endpoint: "tcp://address", + resproto: "tcp", + respaddr: "address", + expectedErr: nil, + }, + { + desc: "valid unix", + endpoint: "unix://address", + resproto: "unix", + respaddr: "address", + expectedErr: nil, + }, + } + + for _, test := range cases { + test := test //pin + t.Run(test.desc, func(t *testing.T) { + proto, addr, err := ParseEndpoint(test.endpoint) + + // Verify + if test.expectedErr == nil && err != nil { + t.Errorf("test %q failed: %v", test.desc, err) + } + if test.expectedErr != nil && err == nil { + t.Errorf("test %q failed; expected error %v, got success", test.desc, test.expectedErr) + } + if test.expectedErr == nil { + if test.resproto != proto { + t.Errorf("test %q failed; expected proto %v, got proto %v", test.desc, test.resproto, proto) + } + if test.respaddr != addr { + t.Errorf("test %q failed; expected addr %v, got addr %v", test.desc, test.respaddr, addr) + } + } + }) + } +}