Repository: kubernetes-csi/csi-driver-smb
Pull request #50 (2020-07-02 00:06:33)

test: Add unit tests
This commit adds unit tests for csi-common,
mounter and smb.
A testMode parameter has been introduced in
server to enable running of unit tests.
Unit tests for unimplemented methods are also
added.

Signed-off-by: Animesh Kumar <animuz111@gmail.com>

<!--  Thanks for sending a pull request!  Here are some tips for you:

1. If this is your first time, please read our contributor guidelines: https://git.k8s.io/community/contributors/guide#your-first-contribution and developer guide https://git.k8s.io/community/contributors/devel/development.md#development-guide
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. For reference on required PR/issue labels, read here:
https://git.k8s.io/community/contributors/devel/release.md#issue-kind-label
3. Ensure you have added or ran the appropriate tests for your PR: https://git.k8s.io/community/contributors/devel/testing.md
4. If you want *faster* PR reviews, read how: https://git.k8s.io/community/contributors/guide/pull-requests.md#best-practices-for-faster-reviews
5. Follow the instructions for writing a release note: https://git.k8s.io/community/contributors/guide/release-notes.md
6. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests
-->

**What type of PR is this?**
> Uncomment only one ` /kind <>` line, hit enter to put that in a new line, and remove leading whitespaces from that line:
>
> /kind api-change
> /kind bug
> /kind cleanup
> /kind design
> /kind documentation

> /kind failing-test
> /kind feature
> /kind flake
 
/kind test

**What this PR does / why we need it**:

**Which issue(s) this PR fixes**:
<!-- 
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes #

**Requirements**:
- [x] uses [conventional commit messages](https://www.conventionalcommits.org/)
  <!-- Common commit types:
        build: Build 🏭
        chore: Maintenance 🔧
        ci: Continuous Integration 💜
        docs: Documentation 📘
        feat: Features 🌈
        fix: Bug Fixes 🐞
        perf: Performance Improvements 🚀
        refactor: Code Refactoring 💎
        revert: Revert Change ◀️
        style: Code Style 🎶
        security: Security Fix 🛡️
        test: Testing 💚 -->
- [ ] includes documentation
- [x] adds unit tests
- [ ] tested upgrade from previous version

**Special notes for your reviewer**:


**Release note**:
```
test: Add unit tests
```



Patch:
diff --git a/pkg/csi-common/server.go b/pkg/csi-common/server.go
index 41beeeb86..2e63f44de 100644
--- a/pkg/csi-common/server.go
+++ b/pkg/csi-common/server.go
@@ -21,6 +21,7 @@ import (
 	"os"
 	"runtime"
 	"sync"
+	"time"
 
 	"google.golang.org/grpc"
 	"k8s.io/klog"
@@ -31,7 +32,7 @@ import (
 // Defines Non blocking GRPC server interfaces
 type NonBlockingGRPCServer interface {
 	// Start services at the endpoint
-	Start(endpoint string, ids csi.IdentityServer, cs csi.ControllerServer, ns csi.NodeServer)
+	Start(endpoint string, ids csi.IdentityServer, cs csi.ControllerServer, ns csi.NodeServer, testMode bool)
 	// Waits for the service to stop
 	Wait()
 	// Stops the service gracefully
@@ -50,9 +51,9 @@ type nonBlockingGRPCServer struct {
 	server *grpc.Server
 }
 
-func (s *nonBlockingGRPCServer) Start(endpoint string, ids csi.IdentityServer, cs csi.ControllerServer, ns csi.NodeServer) {
+func (s *nonBlockingGRPCServer) Start(endpoint string, ids csi.IdentityServer, cs csi.ControllerServer, ns csi.NodeServer, testMode bool) {
 	s.wg.Add(1)
-	go s.serve(endpoint, ids, cs, ns)
+	go s.serve(endpoint, ids, cs, ns, testMode)
 }
 
 func (s *nonBlockingGRPCServer) Wait() {
@@ -67,7 +68,7 @@ func (s *nonBlockingGRPCServer) ForceStop() {
 	s.server.Stop()
 }
 
-func (s *nonBlockingGRPCServer) serve(endpoint string, ids csi.IdentityServer, cs csi.ControllerServer, ns csi.NodeServer) {
+func (s *nonBlockingGRPCServer) serve(endpoint string, ids csi.IdentityServer, cs csi.ControllerServer, ns csi.NodeServer, testMode bool) {
 
 	proto, addr, err := ParseEndpoint(endpoint)
 	if err != nil {
@@ -103,6 +104,16 @@ func (s *nonBlockingGRPCServer) serve(endpoint string, ids csi.IdentityServer, c
 	if ns != nil {
 		csi.RegisterNodeServer(server, ns)
 	}
+	// Used to stop the server while running tests
+	if testMode {
+		s.wg.Done()
+		go func() {
+			// make sure Serve() is called
+			s.wg.Wait()
+			time.Sleep(time.Millisecond * 1000)
+			s.server.GracefulStop()
+		}()
+	}
 
 	klog.Infof("Listening for connections on address: %#v", listener.Addr())
 	if err := server.Serve(listener); err != nil {
diff --git a/pkg/csi-common/utils.go b/pkg/csi-common/utils.go
index eb306abc1..351f5b6c9 100644
--- a/pkg/csi-common/utils.go
+++ b/pkg/csi-common/utils.go
@@ -78,27 +78,27 @@ func NewNodeServiceCapability(cap csi.NodeServiceCapability_RPC_Type) *csi.NodeS
 	}
 }
 
-func RunNodePublishServer(endpoint string, d *CSIDriver, ns csi.NodeServer) {
+func RunNodePublishServer(endpoint string, d *CSIDriver, ns csi.NodeServer, testMode bool) {
 	ids := NewDefaultIdentityServer(d)
 
 	s := NewNonBlockingGRPCServer()
-	s.Start(endpoint, ids, nil, ns)
+	s.Start(endpoint, ids, nil, ns, testMode)
 	s.Wait()
 }
 
-func RunControllerPublishServer(endpoint string, d *CSIDriver, cs csi.ControllerServer) {
+func RunControllerPublishServer(endpoint string, d *CSIDriver, cs csi.ControllerServer, testMode bool) {
 	ids := NewDefaultIdentityServer(d)
 
 	s := NewNonBlockingGRPCServer()
-	s.Start(endpoint, ids, cs, nil)
+	s.Start(endpoint, ids, cs, nil, testMode)
 	s.Wait()
 }
 
-func RunControllerandNodePublishServer(endpoint string, d *CSIDriver, cs csi.ControllerServer, ns csi.NodeServer) {
+func RunControllerandNodePublishServer(endpoint string, d *CSIDriver, cs csi.ControllerServer, ns csi.NodeServer, testMode bool) {
 	ids := NewDefaultIdentityServer(d)
 
 	s := NewNonBlockingGRPCServer()
-	s.Start(endpoint, ids, cs, ns)
+	s.Start(endpoint, ids, cs, ns, testMode)
 	s.Wait()
 }
 
diff --git a/pkg/smb/smb.go b/pkg/smb/smb.go
index c72029e71..cf566ec85 100644
--- a/pkg/smb/smb.go
+++ b/pkg/smb/smb.go
@@ -49,7 +49,7 @@ func NewDriver(nodeID string) *Driver {
 }
 
 // Run driver initialization
-func (d *Driver) Run(endpoint, kubeconfig string) {
+func (d *Driver) Run(endpoint, kubeconfig string, testMode bool) {
 	versionMeta, err := GetVersionYAML()
 	if err != nil {
 		klog.Fatalf("%v", err)
@@ -78,7 +78,7 @@ func (d *Driver) Run(endpoint, kubeconfig string) {
 
 	s := csicommon.NewNonBlockingGRPCServer()
 	// Driver d act as IdentityServer, ControllerServer and NodeServer
-	s.Start(endpoint, d, d, d)
+	s.Start(endpoint, d, d, d, testMode)
 	s.Wait()
 }
 
diff --git a/pkg/smbplugin/main.go b/pkg/smbplugin/main.go
index 818ebcf3a..25a9807cb 100644
--- a/pkg/smbplugin/main.go
+++ b/pkg/smbplugin/main.go
@@ -67,7 +67,7 @@ func handle() {
 	if driver == nil {
 		klog.Fatalln("Failed to initialize smb CSI Driver")
 	}
-	driver.Run(*endpoint, *kubeconfig)
+	driver.Run(*endpoint, *kubeconfig, false)
 }
 
 func exportMetrics() {


Test patch:
diff --git a/pkg/csi-common/controllerserver-default_test.go b/pkg/csi-common/controllerserver-default_test.go
index 51cccc395..e5d660f35 100644
--- a/pkg/csi-common/controllerserver-default_test.go
+++ b/pkg/csi-common/controllerserver-default_test.go
@@ -18,9 +18,13 @@ package csicommon
 
 import (
 	"context"
+	"reflect"
+	"testing"
+
 	"github.com/container-storage-interface/spec/lib/go/csi"
 	"github.com/stretchr/testify/assert"
-	"testing"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
 )
 
 func TestValidateVolumeCapabilities(t *testing.T) {
@@ -65,3 +69,113 @@ func TestControllerGetCapabilities(t *testing.T) {
 	assert.NoError(t, err)
 	assert.Equal(t, resp.XXX_sizecache, int32(0))
 }
+
+func TestCreateVolume(t *testing.T) {
+	d := NewFakeDriver()
+	ns := NewDefaultControllerServer(d)
+	req := csi.CreateVolumeRequest{}
+	resp, err := ns.CreateVolume(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestDeleteVolume(t *testing.T) {
+	d := NewFakeDriver()
+	ns := NewDefaultControllerServer(d)
+	req := csi.DeleteVolumeRequest{}
+	resp, err := ns.DeleteVolume(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestControllerPublishVolume(t *testing.T) {
+	d := NewFakeDriver()
+	ns := NewDefaultControllerServer(d)
+	req := csi.ControllerPublishVolumeRequest{}
+	resp, err := ns.ControllerPublishVolume(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestControllerUnpublishVolume(t *testing.T) {
+	d := NewFakeDriver()
+	ns := NewDefaultControllerServer(d)
+	req := csi.ControllerUnpublishVolumeRequest{}
+	resp, err := ns.ControllerUnpublishVolume(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestGetCapacity(t *testing.T) {
+	d := NewFakeDriver()
+	ns := NewDefaultControllerServer(d)
+	req := csi.GetCapacityRequest{}
+	resp, err := ns.GetCapacity(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestListVolumes(t *testing.T) {
+	d := NewFakeDriver()
+	ns := NewDefaultControllerServer(d)
+	req := csi.ListVolumesRequest{}
+	resp, err := ns.ListVolumes(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestCreateSnapshot(t *testing.T) {
+	d := NewFakeDriver()
+	ns := NewDefaultControllerServer(d)
+	req := csi.CreateSnapshotRequest{}
+	resp, err := ns.CreateSnapshot(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestDeleteSnapshot(t *testing.T) {
+	d := NewFakeDriver()
+	ns := NewDefaultControllerServer(d)
+	req := csi.DeleteSnapshotRequest{}
+	resp, err := ns.DeleteSnapshot(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestListSnapshots(t *testing.T) {
+	d := NewFakeDriver()
+	ns := NewDefaultControllerServer(d)
+	req := csi.ListSnapshotsRequest{}
+	resp, err := ns.ListSnapshots(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestControllerExpandVolume(t *testing.T) {
+	d := NewFakeDriver()
+	ns := NewDefaultControllerServer(d)
+	req := csi.ControllerExpandVolumeRequest{}
+	resp, err := ns.ControllerExpandVolume(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
diff --git a/pkg/csi-common/server_test.go b/pkg/csi-common/server_test.go
new file mode 100644
index 000000000..636bc7eef
--- /dev/null
+++ b/pkg/csi-common/server_test.go
@@ -0,0 +1,63 @@
+/*
+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 csicommon
+
+import (
+	"sync"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"google.golang.org/grpc"
+)
+
+func TestNewNonBlockingGRPCServer(t *testing.T) {
+	s := NewNonBlockingGRPCServer()
+	assert.NotNil(t, s)
+}
+
+func TestStart(t *testing.T) {
+	s := NewNonBlockingGRPCServer()
+	s.Start("tcp://127.0.0.1:0", nil, nil, nil, true)
+}
+
+func TestServe(t *testing.T) {
+	s := nonBlockingGRPCServer{}
+	s.server = grpc.NewServer()
+	s.wg = sync.WaitGroup{}
+	//need to add one here as the actual also requires one.
+	s.wg.Add(1)
+	s.serve("tcp://127.0.0.1:0", nil, nil, nil, true)
+}
+
+func TestWait(t *testing.T) {
+	s := nonBlockingGRPCServer{}
+	s.server = grpc.NewServer()
+	s.wg = sync.WaitGroup{}
+	s.Wait()
+}
+
+func TestStop(t *testing.T) {
+	s := nonBlockingGRPCServer{}
+	s.server = grpc.NewServer()
+	s.Stop()
+}
+
+func TestForceStop(t *testing.T) {
+	s := nonBlockingGRPCServer{}
+	s.server = grpc.NewServer()
+	s.ForceStop()
+}
diff --git a/pkg/mounter/safe_mounter_unix_test.go b/pkg/mounter/safe_mounter_unix_test.go
new file mode 100644
index 000000000..cac54b715
--- /dev/null
+++ b/pkg/mounter/safe_mounter_unix_test.go
@@ -0,0 +1,29 @@
+/*
+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 mounter
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewSafeMounter(t *testing.T) {
+	resp, err := NewSafeMounter()
+	assert.NotNil(t, resp)
+	assert.Nil(t, err)
+}
diff --git a/pkg/smb/controllerserver_test.go b/pkg/smb/controllerserver_test.go
index 5b1f6621a..135dd83d0 100644
--- a/pkg/smb/controllerserver_test.go
+++ b/pkg/smb/controllerserver_test.go
@@ -18,9 +18,13 @@ package smb
 
 import (
 	"context"
+	"reflect"
+	"testing"
+
 	"github.com/container-storage-interface/spec/lib/go/csi"
 	"github.com/stretchr/testify/assert"
-	"testing"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
 )
 
 func TestControllerGetCapabilities(t *testing.T) {
@@ -37,3 +41,197 @@ func TestControllerGetCapabilities(t *testing.T) {
 	assert.NotNil(t, resp)
 	assert.Equal(t, resp.Capabilities, controlCap)
 }
+
+func TestCreateVolume(t *testing.T) {
+	d := NewFakeDriver()
+	stdVolCap := []*csi.VolumeCapability{
+		{
+			AccessType: &csi.VolumeCapability_Mount{
+				Mount: &csi.VolumeCapability_MountVolume{},
+			},
+			AccessMode: &csi.VolumeCapability_AccessMode{
+				Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
+			},
+		},
+	}
+
+	tests := []struct {
+		desc        string
+		req         csi.CreateVolumeRequest
+		expectedErr error
+	}{
+		{
+			desc:        "Volume capabilities missing",
+			req:         csi.CreateVolumeRequest{},
+			expectedErr: status.Error(codes.InvalidArgument, "CreateVolume Volume capabilities must be provided"),
+		},
+		{
+			desc: "Valid request",
+			req: csi.CreateVolumeRequest{
+				VolumeCapabilities: stdVolCap,
+			},
+			expectedErr: nil,
+		},
+	}
+
+	for _, test := range tests {
+		_, err := d.CreateVolume(context.Background(), &test.req)
+		if !reflect.DeepEqual(err, test.expectedErr) {
+			t.Errorf("Unexpected error: %v", err)
+		}
+	}
+}
+
+func TestDeleteVolume(t *testing.T) {
+	d := NewFakeDriver()
+
+	tests := []struct {
+		desc        string
+		req         csi.DeleteVolumeRequest
+		expectedErr error
+	}{
+		{
+			desc:        "Volume ID missing",
+			req:         csi.DeleteVolumeRequest{},
+			expectedErr: status.Error(codes.InvalidArgument, "Volume ID missing in request"),
+		},
+		{
+			desc:        "Valid request",
+			req:         csi.DeleteVolumeRequest{VolumeId: "vol_1"},
+			expectedErr: nil,
+		},
+	}
+
+	for _, test := range tests {
+		_, err := d.DeleteVolume(context.Background(), &test.req)
+		if !reflect.DeepEqual(err, test.expectedErr) {
+			t.Errorf("Unexpected error: %v", err)
+		}
+	}
+}
+
+func TestValidateVolumeCapabilities(t *testing.T) {
+	d := NewFakeDriver()
+	stdVolCap := []*csi.VolumeCapability{
+		{
+			AccessType: &csi.VolumeCapability_Mount{
+				Mount: &csi.VolumeCapability_MountVolume{},
+			},
+			AccessMode: &csi.VolumeCapability_AccessMode{
+				Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
+			},
+		},
+	}
+
+	tests := []struct {
+		desc        string
+		req         csi.ValidateVolumeCapabilitiesRequest
+		expectedErr error
+	}{
+		{
+			desc:        "Volume ID missing",
+			req:         csi.ValidateVolumeCapabilitiesRequest{},
+			expectedErr: status.Error(codes.InvalidArgument, "Volume ID missing in request"),
+		},
+		{
+			desc:        "Volume capabilities missing",
+			req:         csi.ValidateVolumeCapabilitiesRequest{VolumeId: "vol_1"},
+			expectedErr: status.Error(codes.InvalidArgument, "Volume capabilities missing in request"),
+		},
+		{
+			desc: "Valid request",
+			req: csi.ValidateVolumeCapabilitiesRequest{
+				VolumeId:           "vol_1#f5713de20cde511e8ba4900#fileshare#diskname#",
+				VolumeCapabilities: stdVolCap,
+			},
+			expectedErr: nil,
+		},
+	}
+
+	for _, test := range tests {
+		_, err := d.ValidateVolumeCapabilities(context.Background(), &test.req)
+		if !reflect.DeepEqual(err, test.expectedErr) {
+			t.Errorf("Unexpected error: %v", err)
+		}
+	}
+}
+
+func TestControllerPublishVolume(t *testing.T) {
+	d := NewFakeDriver()
+	req := csi.ControllerPublishVolumeRequest{}
+	resp, err := d.ControllerPublishVolume(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestControllerUnpublishVolume(t *testing.T) {
+	d := NewFakeDriver()
+	req := csi.ControllerUnpublishVolumeRequest{}
+	resp, err := d.ControllerUnpublishVolume(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestGetCapacity(t *testing.T) {
+	d := NewFakeDriver()
+	req := csi.GetCapacityRequest{}
+	resp, err := d.GetCapacity(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestListVolumes(t *testing.T) {
+	d := NewFakeDriver()
+	req := csi.ListVolumesRequest{}
+	resp, err := d.ListVolumes(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestControllerExpandVolume(t *testing.T) {
+	d := NewFakeDriver()
+	req := csi.ControllerExpandVolumeRequest{}
+	resp, err := d.ControllerExpandVolume(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestCreateSnapshot(t *testing.T) {
+	d := NewFakeDriver()
+	req := csi.CreateSnapshotRequest{}
+	resp, err := d.CreateSnapshot(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestDeleteSnapshot(t *testing.T) {
+	d := NewFakeDriver()
+	req := csi.DeleteSnapshotRequest{}
+	resp, err := d.DeleteSnapshot(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestListSnapshots(t *testing.T) {
+	d := NewFakeDriver()
+	req := csi.ListSnapshotsRequest{}
+	resp, err := d.ListSnapshots(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
diff --git a/pkg/smb/nodeserver_test.go b/pkg/smb/nodeserver_test.go
index b4cc1ba43..a04cba2f6 100644
--- a/pkg/smb/nodeserver_test.go
+++ b/pkg/smb/nodeserver_test.go
@@ -20,14 +20,17 @@ import (
 	"bytes"
 	"context"
 	"flag"
+	"reflect"
+	"testing"
+
 	"github.com/container-storage-interface/spec/lib/go/csi"
 	"github.com/stretchr/testify/assert"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
 	"k8s.io/klog"
-	"testing"
 )
 
 func TestNodeStageVolume(t *testing.T) {
-
 	klog.InitFlags(nil)
 	if e := flag.Set("logtostderr", "false"); e != nil {
 		t.Error(e)
@@ -80,3 +83,52 @@ func TestNodeStageVolume(t *testing.T) {
 	}
 
 }
+
+func TestNodeGetInfo(t *testing.T) {
+	d := NewFakeDriver()
+
+	// Test valid request
+	req := csi.NodeGetInfoRequest{}
+	resp, err := d.NodeGetInfo(context.Background(), &req)
+	assert.NoError(t, err)
+	assert.Equal(t, resp.GetNodeId(), fakeNodeID)
+}
+
+func TestNodeGetCapabilities(t *testing.T) {
+	d := NewFakeDriver()
+	capType := &csi.NodeServiceCapability_Rpc{
+		Rpc: &csi.NodeServiceCapability_RPC{
+			Type: csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME,
+		},
+	}
+	capList := []*csi.NodeServiceCapability{{
+		Type: capType,
+	}}
+	d.NSCap = capList
+	// Test valid request
+	req := csi.NodeGetCapabilitiesRequest{}
+	resp, err := d.NodeGetCapabilities(context.Background(), &req)
+	assert.NotNil(t, resp)
+	assert.Equal(t, resp.Capabilities[0].GetType(), capType)
+	assert.NoError(t, err)
+}
+
+func TestNodeGetVolumeStats(t *testing.T) {
+	d := NewFakeDriver()
+	req := csi.NodeGetVolumeStatsRequest{}
+	resp, err := d.NodeGetVolumeStats(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
+
+func TestNodeExpandVolume(t *testing.T) {
+	d := NewFakeDriver()
+	req := csi.NodeExpandVolumeRequest{}
+	resp, err := d.NodeExpandVolume(context.Background(), &req)
+	assert.Nil(t, resp)
+	if !reflect.DeepEqual(err, status.Error(codes.Unimplemented, "")) {
+		t.Errorf("Unexpected error: %v", err)
+	}
+}
diff --git a/pkg/smb/smb_test.go b/pkg/smb/smb_test.go
index 77c0e618a..c01f30379 100644
--- a/pkg/smb/smb_test.go
+++ b/pkg/smb/smb_test.go
@@ -17,11 +17,12 @@ limitations under the License.
 package smb
 
 import (
-	"github.com/stretchr/testify/assert"
 	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )
 
 const (
@@ -75,3 +76,30 @@ func TestIsCorruptedDir(t *testing.T) {
 		assert.Equal(t, test.expectedResult, isCorruptedDir, "TestCase[%d]: %s", i, test.desc)
 	}
 }
+
+func TestRun(t *testing.T) {
+	testCases := []struct {
+		name     string
+		testFunc func(t *testing.T)
+	}{
+		{
+			name: "Successful run",
+			testFunc: func(t *testing.T) {
+				d := NewFakeDriver()
+				d.Run("tcp://127.0.0.1:0", "", true)
+			},
+		},
+		{
+			name: "Successful run with node ID missing",
+			testFunc: func(t *testing.T) {
+				d := NewFakeDriver()
+				d.NodeID = ""
+				d.Run("tcp://127.0.0.1:0", "", true)
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, tc.testFunc)
+	}
+}