Repository: kubernetes-csi/csi-driver-nfs
Pull request #101 (2020-11-19 07:21:13)

test: Add unit tests for identityserver and nodeserver
Signed-off-by: Mayank Shah <mayankshah1614@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. Follow the instructions for writing a release note: https://git.k8s.io/community/contributors/guide/release-notes.md
3. 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

**What this PR does / why we need it**:
 Add unit tests for identityserver.go
**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 #

**Special notes for your reviewer**:

**Does this PR introduce a user-facing change?**:
<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->
```release-note
None
```


k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-csi/csi-driver-nfs/pull/101#" title="Author self-approved">mayankshah1607</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **msau42** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @msau42` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-csi%2Fcsi-driver-nfs).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes-csi/csi-driver-nfs/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["msau42"]} -->
k8s-ci-robot: @mayankshah1607: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-csi-driver-nfs-integration | 396273d81b3f0a71c5fc4995f7d95add67ad76e8 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-integration/1329323834519588865) | `/test pull-csi-driver-nfs-integration`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-nfs&pr=101). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Amayankshah1607). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-nfs/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
mayankshah1607: /retest
k8s-ci-robot: @mayankshah1607: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-csi-driver-nfs-integration | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-integration/1329745271982133248) | `/test pull-csi-driver-nfs-integration`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-nfs&pr=101). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Amayankshah1607). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-nfs/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @mayankshah1607: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-csi-driver-nfs-integration | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-integration/1329745271982133248) | `/test pull-csi-driver-nfs-integration`
pull-kubernetes-csi-csi-driver-nfs | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-kubernetes-csi-csi-driver-nfs/1329745271923412992) | `/test pull-kubernetes-csi-csi-driver-nfs`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-nfs&pr=101). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Amayankshah1607). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-nfs/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @mayankshah1607: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-csi-driver-nfs-integration | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-integration/1329745271982133248) | `/test pull-csi-driver-nfs-integration`
pull-kubernetes-csi-csi-driver-nfs | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-kubernetes-csi-csi-driver-nfs/1329745271923412992) | `/test pull-kubernetes-csi-csi-driver-nfs`
pull-csi-driver-nfs-sanity | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-sanity/1329745271973744640) | `/test pull-csi-driver-nfs-sanity`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-nfs&pr=101). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Amayankshah1607). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-nfs/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @mayankshah1607: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-csi-driver-nfs-integration | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-integration/1329745271982133248) | `/test pull-csi-driver-nfs-integration`
pull-kubernetes-csi-csi-driver-nfs | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-kubernetes-csi-csi-driver-nfs/1329745271923412992) | `/test pull-kubernetes-csi-csi-driver-nfs`
pull-csi-driver-nfs-sanity | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-sanity/1329745271973744640) | `/test pull-csi-driver-nfs-sanity`
pull-csi-driver-nfs-e2e | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-e2e/1329745272003104768) | `/test pull-csi-driver-nfs-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-nfs&pr=101). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Amayankshah1607). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-nfs/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @mayankshah1607: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-csi-driver-nfs-integration | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-integration/1329745271982133248) | `/test pull-csi-driver-nfs-integration`
pull-kubernetes-csi-csi-driver-nfs | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-kubernetes-csi-csi-driver-nfs/1329745271923412992) | `/test pull-kubernetes-csi-csi-driver-nfs`
pull-csi-driver-nfs-sanity | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-sanity/1329745271973744640) | `/test pull-csi-driver-nfs-sanity`
pull-csi-driver-nfs-e2e | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-e2e/1329745272003104768) | `/test pull-csi-driver-nfs-e2e`
pull-csi-driver-nfs-unit | d340377ed5211ca0e59748f451e87036a790b3f2 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-unit/1329753749408714752) | `/test pull-csi-driver-nfs-unit`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-nfs&pr=101). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Amayankshah1607). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-nfs/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @mayankshah1607: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-csi-driver-nfs-integration | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-integration/1329745271982133248) | `/test pull-csi-driver-nfs-integration`
pull-csi-driver-nfs-e2e | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-e2e/1329745272003104768) | `/test pull-csi-driver-nfs-e2e`
pull-csi-driver-nfs-unit | d340377ed5211ca0e59748f451e87036a790b3f2 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-unit/1329753749408714752) | `/test pull-csi-driver-nfs-unit`
pull-kubernetes-csi-csi-driver-nfs | d340377ed5211ca0e59748f451e87036a790b3f2 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-kubernetes-csi-csi-driver-nfs/1329753749362577408) | `/test pull-kubernetes-csi-csi-driver-nfs`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-nfs&pr=101). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Amayankshah1607). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-nfs/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @mayankshah1607: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-csi-driver-nfs-e2e | e5259417d4a5dd41ad611eec4c09c2d19eefdc9c | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-csi-driver-nfs-e2e/1329745272003104768) | `/test pull-csi-driver-nfs-e2e`
pull-kubernetes-csi-csi-driver-nfs | 7e2efc6842b30aab20280ff734aa681e6c00ed05 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-csi_csi-driver-nfs/101/pull-kubernetes-csi-csi-driver-nfs/1329755585020694528) | `/test pull-kubernetes-csi-csi-driver-nfs`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-csi&repo=csi-driver-nfs&pr=101). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Amayankshah1607). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-csi/csi-driver-nfs/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->

Patch:
diff --git a/Makefile b/Makefile
index 3f6205bb..5a05196a 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 CMDS=nfsplugin
-DEPLOY_FOLDER = ./deploy
+DEPLOY_FOLDER = ./deploy/kubernetes
 CMDS=nfsplugin
 PKG = github.com/kubernetes-csi/csi-driver-nfs
 GINKGO_FLAGS = -ginkgo.v
@@ -93,7 +93,7 @@ push:
 
 .PHONY: install-nfs-server
 install-nfs-server:
-	kubectl apply -f ./deploy/example/nfs-provisioner/nfs-server.yaml
+	kubectl apply -f ./examples/nfs-server.yaml
 
 .PHONY: install-helm
 install-helm:
@@ -117,6 +117,6 @@ e2e-test:
 
 .PHONY: create-example-deployment
 create-example-deployment:
-	kubectl apply -f ./deploy/example/storageclass-nfs.yaml
-	kubectl apply -f ./deploy/example/deployment.yaml
-	kubectl apply -f ./deploy/example/statefulset.yaml
+	kubectl apply -f ./examples/storageclass-nfs.yaml
+	kubectl apply -f ./examples/deployment.yaml
+	kubectl apply -f ./examples/statefulset.yaml
diff --git a/README.md b/README.md
index 12523ed3..d42bfc23 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # CSI NFS driver
 
-### Overview
+## Overview
 
 This is a repository for [NFS](https://en.wikipedia.org/wiki/Network_File_System) [CSI](https://kubernetes-csi.github.io/docs/) Driver.
 Currently it implements bare minimum of the [CSI spec](https://github.com/container-storage-interface/spec) and is in the alpha state 
@@ -10,34 +10,79 @@ of the development.
 
 | **nfs.csi.k8s.io** | K8s version compatibility | CSI versions compatibility | Dynamic Provisioning | Resize | Snapshots | Raw Block | AccessModes              | Status                                                                       |
 |--------------------|---------------------------|----------------------------|----------------------|--------|-----------|-----------|--------------------------|------------------------------------------------------------------------------|
-|master              | 1.14 +                    | v1.0 +                     |  yes                 |  no    |  no       |  no       | Read/Write Multiple Pods | Alpha                                                                        |
+|master              | 1.14 +                    | v1.0 +                     |  no                  |  no    |  no       |  no       | Read/Write Multiple Pods | Alpha                                                                        |
 |v2.0.0              | 1.14 +                    | v1.0 +                     |  no                  |  no    |  no       |  no       | Read/Write Multiple Pods | Alpha                                                                        |
 |v1.0.0              | 1.9 - 1.15                | v1.0                       |  no                  |  no    |  no       |  no       | Read/Write Multiple Pods | [deprecated](https://github.com/kubernetes-csi/drivers/tree/master/pkg/nfs)  |
 
-### Requirements
+## Requirements
 
 The CSI NFS driver requires Kubernetes cluster of version 1.14 or newer and 
 preexisting NFS server, whether it is deployed on cluster or provisioned 
 independently. The plugin itself provides only a communication layer between 
 resources in the cluser and the NFS server.
 
-### Install NFS CSI driver on a kubernetes cluster
-Please refer to [install NFS CSI driver](./docs/install-csi-driver.md).
+## Install NFS CSI driver on a kubernetes cluster
+Please refer to [install NFS CSI driver](https://github.com/kubernetes-csi/csi-driver-nfs/blob/master/docs/install-csi-driver.md).
 
-### Driver parameters
-Please refer to [`nfs.csi.k8s.io` driver parameters](./docs/driver-parameters.md)
+## Example
 
-### Examples
- - [Set up a NFS Server on a Kubernetes cluster](./deploy/example/nfs-provisioner/README.md)
- - [Basic usage](./deploy/example/README.md)
+There are multiple ways to create a kubernetes cluster, the NFS CSI plugin
+should work invariantly of your cluster setup. Very simple way of getting
+a local environment for testing can be achieved using for example
+[kind](https://github.com/kubernetes-sigs/kind).
 
-### Troubleshooting
- - [CSI driver troubleshooting guide](./docs/csi-debug.md) 
+There are also multiple different NFS servers you can use for testing of 
+the plugin, the major versions of the protocol v2, v3 and v4 should be supported
+by the current implementation.
 
-## Kubernetes Development
-Please refer to [development guide](./docs/csi-dev.md)
+The example assumes you have your cluster created (e.g. `kind create cluster`)
+and working NFS server (e.g. https://github.com/rootfs/nfs-ganesha-docker)
 
-### Community, discussion, contribution, and support
+#### Deploy
+
+Deploy the NFS plugin along with the `CSIDriver` info.
+```console
+kubectl create -f deploy/kubernetes
+```
+
+#### Example Nginx application
+
+The [/examples/kubernetes/nginx.yaml](/examples/kubernetes/nginx.yaml) contains a `PersistentVolume`,
+`PersistentVolumeClaim` and an nginx `Pod` mounting the NFS volume under `/var/www`.
+
+You will need to update the NFS Server IP and the share information under 
+`volumeAttributes` inside `PersistentVolume` in `nginx.yaml` file to match your
+NFS server public end point and configuration. You can also provide additional 
+`mountOptions`, such as protocol version, in the `PersistentVolume` `spec` 
+relevant for your NFS Server.
+
+```console
+kubectl create -f examples/kubernetes/nginx.yaml
+```
+
+## Running Kubernetes End To End tests on an NFS Driver
+
+First, stand up a local cluster `ALLOW_PRIVILEGED=1 hack/local-up-cluster.sh` (from your Kubernetes repo)
+For Fedora/RHEL clusters, the following might be required:
+```console
+sudo chown -R $USER:$USER /var/run/kubernetes/
+sudo chown -R $USER:$USER /var/lib/kubelet
+sudo chcon -R -t svirt_sandbox_file_t /var/lib/kubelet
+```
+If you are plannig to test using your own private image, you could either install your nfs driver using your own set of YAML files, or edit the existing YAML files to use that private image.
+
+When using the [existing set of YAML files](https://github.com/kubernetes-csi/csi-driver-nfs/tree/master/deploy/kubernetes), you would edit [csi-nfs-node.yaml](https://github.com/kubernetes-csi/csi-driver-nfs/blob/master/deploy/kubernetes/csi-nfs-node.yaml#L45) files to include your private image instead of the default one. After editing these files, skip to step 3 of the following steps.
+
+If you already have a driver installed, skip to step 4 of the following steps.
+
+1) Build the nfs driver by running `make`
+2) Create NFS Driver Image, where the image tag would be whatever that is required by your YAML deployment files        `docker build -t quay.io/k8scsi/nfsplugin:v2.0.0 .`
+3) Install the Driver: `kubectl create -f deploy/kubernetes`
+4) Build E2E test binary: `make build-tests`
+5) Run E2E Tests using the following command: `./bin/tests --ginkgo.v --ginkgo.progress --kubeconfig=/var/run/kubernetes/admin.kubeconfig`
+
+
+## Community, discussion, contribution, and support
 
 Learn how to engage with the Kubernetes community on the [community page](http://kubernetes.io/community/).
 
@@ -46,6 +91,7 @@ You can reach the maintainers of this project at:
 - [Slack channel](https://kubernetes.slack.com/messages/sig-storage)
 - [Mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-storage)
 
+
 ### Code of conduct
 
 Participation in the Kubernetes community is governed by the [Kubernetes Code of Conduct](code-of-conduct.md).
diff --git a/charts/README.md b/charts/README.md
index 05da3476..0828570b 100644
--- a/charts/README.md
+++ b/charts/README.md
@@ -37,21 +37,21 @@ The following table lists the configurable parameters of the latest NFS CSI Driv
 
 | Parameter                                         | Description                                                | Default                                                           |
 |---------------------------------------------------|------------------------------------------------------------|-------------------------------------------------------------------|
-| `image.nfs.repository`                            | csi-driver-nfs docker image                                | gcr.io/k8s-staging-sig-storage/nfsplugin                          |
-| `image.nfs.tag`                                   | csi-driver-nfs docker image tag                            | amd64-linux-canary                                                |
+| `image.nfs.repository`                            | csi-driver-nfs docker image                                | mcr.microsoft.com/k8s/csi/nfs-csi                                 |
+| `image.nfs.tag`                                   | csi-driver-nfs docker image tag                            | latest                                                            |
 | `image.nfs.pullPolicy`                            | csi-driver-nfs image pull policy                           | IfNotPresent                                                      |
-| `image.csiProvisioner.repository`                 | csi-provisioner docker image                               | k8s.gcr.io/sig-storage/csi-provisioner                            |
-| `image.csiProvisioner.tag`                        | csi-provisioner docker image tag                           | v2.0.4                                                            |
+| `image.csiProvisioner.repository`                 | csi-provisioner docker image                               | mcr.microsoft.com/oss/kubernetes-csi/csi-provisioner              |
+| `image.csiProvisioner.tag`                        | csi-provisioner docker image tag                           | v1.4.0                                                            |
 | `image.csiProvisioner.pullPolicy`                 | csi-provisioner image pull policy                          | IfNotPresent                                                      |
-| `image.livenessProbe.repository`                  | liveness-probe docker image                                | k8s.gcr.io/sig-storage/livenessprobe                              |
-| `image.livenessProbe.tag`                         | liveness-probe docker image tag                            | v2.1.0                                                            |
+| `image.livenessProbe.repository`                  | liveness-probe docker image                                | mcr.microsoft.com/oss/kubernetes-csi/livenessprobe                |
+| `image.livenessProbe.tag`                         | liveness-probe docker image tag                            | v1.1.0                                                            |
 | `image.livenessProbe.pullPolicy`                  | liveness-probe image pull policy                           | IfNotPresent                                                      |
-| `image.nodeDriverRegistrar.repository`            | csi-node-driver-registrar docker image                     | k8s.gcr.io/sig-storage/csi-node-driver-registrar                  |
-| `image.nodeDriverRegistrar.tag`                   | csi-node-driver-registrar docker image tag                 | v2.0.1                                                            |
+| `image.nodeDriverRegistrar.repository`            | csi-node-driver-registrar docker image                     | mcr.microsoft.com/oss/kubernetes-csi/csi-node-driver-registrar    |
+| `image.nodeDriverRegistrar.tag`                   | csi-node-driver-registrar docker image tag                 | v1.2.0                                                            |
 | `image.nodeDriverRegistrar.pullPolicy`            | csi-node-driver-registrar image pull policy                | IfNotPresent                                                      |
 | `serviceAccount.create`                           | whether create service account of csi-nfs-controller       | true                                                              |
 | `rbac.create`                                     | whether create rbac of csi-nfs-controller                  | true                                                              |
-| `controller.replicas`                             | the replicas of csi-nfs-controller                         | 2                                                                 |
+| `controller.replicas`                             | the replicas of csi-nfs-controller                                  | 2                                                   |
 
 ## Troubleshooting
 
diff --git a/deploy/example/README.md b/deploy/example/README.md
deleted file mode 100644
index dbbfbb08..00000000
--- a/deploy/example/README.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# CSI driver example
-
-After the NFS CSI Driver is deployed in your cluster, you can follow this documentation to quickly deploy some examples. 
-
-You can use NFS CSI Driver to provision Persistent Volumes statically or dynamically. Please read [Kubernetes Persistent Volumes documentation](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) for more information about Static and Dynamic provisioning.
-
-Please refer to [driver parameters](../../docs/driver-parameters.md) for more detailed usage.
-
-## Prerequisite
-
-- [Set up a NFS Server on a Kubernetes cluster](./nfs-provisioner/README.md)
-- [Install NFS CSI Driver](../../docs/install-csi-driver.md)
-
-## Storage Class Usage (Dynamic Provisioning)
-
-- Follow the folling command to create a `StorageClass`, and then `PersistentVolume` and `PersistentVolumeClaim` dynamically.
-
-```bash
-# create StorageClass
-kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/deploy/example/storageclass-nfs.yaml
-
-# create PVC
-kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/deploy/example/pvc-nfs-csi-dynamic.yaml
-```
-
-## PV/PVC Usage (Static Provisioning)
-
-- Follow the folling command to create `PersistentVolume` and `PersistentVolumeClaim` statically.
-
-```bash
-# create PV
-kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/deploy/example/pv-nfs-csi.yaml
-
-# create PVC
-kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/deploy/example/pvc-nfs-csi-static.yaml
-```
diff --git a/deploy/example/nfs-provisioner/README.md b/deploy/example/nfs-provisioner/README.md
deleted file mode 100644
index e1682d0d..00000000
--- a/deploy/example/nfs-provisioner/README.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# Set up a NFS Server on a Kubernetes cluster
-
-After the NFS CSI Driver is deployed in your cluster, you can follow this documentation to quickly deploy some example applications. You can use NFS CSI Driver to provision Persistent Volumes statically or dynamically. Please read Kubernetes Persistent Volumes for more information about Static and Dynamic provisioning.
-
-There are multiple different NFS servers you can use for testing of 
-the plugin, the major versions of the protocol v2, v3 and v4 should be supported
-by the current implementation. This page will show you how to set up a NFS Server deployment on a Kubernetes cluster.
-
-- To create a NFS provisioner on your Kubernetes cluster, run the following command.
-
-```bash
-kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/deploy/example/nfs-provisioner/nfs-server.yaml
-```
-
-- During the deployment, a new service `nfs-server` will be created which exposes the NFS server endpoint `nfs-server.default.svc.cluster.local` and the share path `/`. You can specify `PersistentVolume` or `StorageClass` using these information.
-
-- Deploy the NFS CSI driver, please refer to [install NFS CSI driver](../../../docs/install-csi-driver.md).
-
-- To check if the NFS server is working, we can statically create a PersistentVolume and a PersistentVolumeClaim, and mount it onto a sample pod:
-
-```bash
-kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/deploy/example/nfs-provisioner/nginx-pod.yaml
-```
-
- - Verify if the NFS server is functional, you can check the mount point from the example pod.
-
- ```bash
-kubectl exec nginx-nfs-example -- bash -c "findmnt /var/www -o TARGET,SOURCE,FSTYPE"
-```
-
- - The output should look like the following:
-
- ```bash
-TARGET   SOURCE                                 FSTYPE
-/var/www nfs-server.default.svc.cluster.local:/ nfs4
-```
diff --git a/deploy/example/nfs-provisioner/nginx-pod.yaml b/deploy/example/nfs-provisioner/nginx-pod.yaml
deleted file mode 100644
index ab52f22e..00000000
--- a/deploy/example/nfs-provisioner/nginx-pod.yaml
+++ /dev/null
@@ -1,53 +0,0 @@
----
-apiVersion: v1
-kind: PersistentVolume
-metadata:
-  name: pv-nginx
-spec:
-  capacity:
-    storage: 10Gi
-  accessModes:
-    - ReadWriteOnce
-  persistentVolumeReclaimPolicy: Delete
-  mountOptions:
-    - hard
-    - nfsvers=4.1
-  csi:
-    driver: nfs.csi.k8s.io
-    readOnly: false
-    volumeHandle: unique-volumeid  # make sure it's a unique id in the cluster
-    volumeAttributes:
-      server: nfs-server.default.svc.cluster.local
-      share: /
----
-kind: PersistentVolumeClaim
-apiVersion: v1
-metadata:
-  name: pvc-nginx
-spec:
-  accessModes:
-    - ReadWriteOnce
-  resources:
-    requests:
-      storage: 10Gi
-  volumeName: pv-nginx
-  storageClassName: ""
----
-apiVersion: v1
-kind: Pod
-metadata:
-  name: nginx-nfs-example
-spec:
-  containers:
-  - image: nginx
-    name: nginx
-    ports:
-    - containerPort: 80
-      protocol: TCP
-    volumeMounts:
-      - mountPath: /var/www
-        name: pvc-nginx
-  volumes:
-  - name: pvc-nginx
-    persistentVolumeClaim:
-      claimName: pvc-nginx
diff --git a/docs/csi-debug.md b/docs/csi-debug.md
deleted file mode 100644
index 0b870142..00000000
--- a/docs/csi-debug.md
+++ /dev/null
@@ -1,30 +0,0 @@
-## CSI driver debug tips
-
-### Case#1: volume create/delete failed
- - locate csi driver pod
-```console
-$ kubectl get pod -o wide -n kube-system | grep csi-nfs-controller
-NAME                                     READY   STATUS    RESTARTS   AGE     IP             NODE
-csi-nfs-controller-56bfddd689-dh5tk      5/5     Running   0          35s     10.240.0.19    k8s-agentpool-22533604-0
-csi-nfs-controller-56bfddd689-sl4ll      5/5     Running   0          35s     10.240.0.23    k8s-agentpool-22533604-1
-```
- - get csi driver logs
-```console
-$ kubectl logs csi-nfs-controller-56bfddd689-dh5tk -c nfs -n kube-system > csi-nfs-controller.log
-```
-> note: there could be multiple controller pods, if there are no helpful logs, try to get logs from other controller pods
-
-### Case#2: volume mount/unmount failed
- - locate csi driver pod and figure out which pod does tha actual volume mount/unmount
-
-```console
-$ kubectl get pod -o wide -n kube-system | grep csi-nfs-node
-NAME                                      READY   STATUS    RESTARTS   AGE     IP             NODE
-csi-nfs-node-cvgbs                        3/3     Running   0          7m4s    10.240.0.35    k8s-agentpool-22533604-1
-csi-nfs-node-dr4s4                        3/3     Running   0          7m4s    10.240.0.4     k8s-agentpool-22533604-0
-```
-
- - get csi driver logs
-```console
-$ kubectl logs csi-nfs-node-cvgbs -c nfs -n kube-system > csi-nfs-node.log
-```
diff --git a/docs/csi-dev.md b/docs/csi-dev.md
index e0b25768..8c58f362 100644
--- a/docs/csi-dev.md
+++ b/docs/csi-dev.md
@@ -1,114 +1,49 @@
-# NFS CSI driver development guide
+# CSI Driver Development Guide
 
-## How to build this project
- - Clone repo
-```console
-$ mkdir -p $GOPATH/src/sigs.k8s.io/
-$ git clone https://github.com/kubernetes-csi/csi-driver-nfs $GOPATH/src/github.com/kubernetes-csi/csi-driver-nfs
-```
+## Build this project
 
- - Build CSI driver
-```console
-$ cd $GOPATH/src/github.com/kubernetes-csi/csi-driver-nfs
-$ make
-```
+- Clone this repo
 
- - Run verification test before submitting code
-```console
-$ make verify
+```bash
+git clone https://github.com/kubernetes-csi/csi-driver-nfs
 ```
 
-## How to test CSI driver in local environment
+- Build CSI Driver
 
-Install `csc` tool according to https://github.com/rexray/gocsi/tree/master/csc
-```console
-$ mkdir -p $GOPATH/src/github.com
-$ cd $GOPATH/src/github.com
-$ git clone https://github.com/rexray/gocsi.git
-$ cd rexray/gocsi/csc
-$ make build
+```bash
+$ cd csi-driver-nfs
+$ make
 ```
 
-#### Start CSI driver locally
-```console
-$ cd $GOPATH/src/github.com/kubernetes-csi/csi-driver-nfs
-$ ./_output/nfsplugin --endpoint tcp://127.0.0.1:10000 --nodeid CSINode -v=5 &
-```
+- Verify code before submitting PRs
 
-#### 0. Set environmnet variables
-```console
-$ cap="1,mount,"
-$ volname="test-$(date +%s)"
-$ volsize="2147483648"
-$ endpoint="unix:///tmp/csi.sock"
-$ target_path="/tmp/targetpath"
-$ params="server=127.0.0.1,share=/"
+```bash
+make verify
 ```
+## Test CSI Driver locally
 
-#### 1. Get plugin info
-```console
-$ csc identity plugin-info --endpoint "$endpoint"
-"nfs.csi.k8s.io"    "v2.0.0"
-```
+> WIP
 
-#### 2. Create a new nfs volume
-```console
-$ value="$(csc controller new --endpoint "$endpoint" --cap "$cap" "$volname" --req-bytes "$volsize" --params "$params")"
-$ sleep 15
-$ volumeid="$(echo "$value" | awk '{print $1}' | sed 's/"//g')"
-$ echo "Got volume id: $volumeid"
-```
+## Test CSI Driver in a Kubernetes Cluster
 
-#### 3. Publish a nfs volume
-```
-$ csc node publish --endpoint "$endpoint" --cap "$cap" --vol-context "$params" --target-path "$target_path" "$volumeid"
-```
+- Build container image and push to DockerHub
 
-#### 4. Unpublish a nfs volume
-```
-$ csc node unpublish --endpoint "$endpoint" --target-path "$target_path" "$volumeid"
+```bash
+# Run `docker login` first
+$ export LOCAL_USER=<DockerHub Username>
+$ make local-build-push
 ```
 
-#### 6. Validate volume capabilities
-```console
-$ csc controller validate-volume-capabilities --endpoint "$endpoint" --cap "$cap" "$volumeid"
-```
+- Replace `quay.io/k8scsi/nfsplugin:v2.0.0` in `deploy/kubernetes/csi-nfs-controller.yaml` and `deploy/kubernetes/csi-nfs-node.yaml` with `<YOUR DOCKERHUB ID>/nfsplugin:latest`
 
-#### 7. Delete the nfs volume
-```console
-$ csc controller del --endpoint "$endpoint" "$volumeid" --timeout 10m
-```
+- Install driver locally
 
-#### 8. Get NodeID
-```console
-$ csc node get-info --endpoint "$endpoint"
-CSINode
+```bash
+make local-k8s-install 
 ```
 
-## How to test CSI driver in a Kubernetes cluster
-- Set environmnet variable
-```console
-export REGISTRY=<dockerhub-alias>
-export IMAGE_VERSION=latest
-```
-
-- Build continer image and push image to dockerhub
-```console
-# run `docker login` first
-# build docker image
-make container
-# push the docker image
-make push
-```
+- Uninstall driver
 
-- Deploy a Kubernetes cluster and make sure `kubectl get nodes` works on your dev box.
-
-- Run E2E test on the Kubernetes cluster.
-
-```console
-# install NFS CSI Driver on the Kubernetes cluster
-make e2e-bootstrap
-
-# run the E2E test
-make e2e-test
-```
+```bash
+make local-k8s-uninstall
+```
\ No newline at end of file
diff --git a/docs/driver-parameters.md b/docs/driver-parameters.md
deleted file mode 100644
index 2ebab081..00000000
--- a/docs/driver-parameters.md
+++ /dev/null
@@ -1,18 +0,0 @@
-## Driver Parameters
-> This plugin driver itself only provides a communication layer between resources in the cluser and the NFS server, you need to bring your own NFS server before using this driver.
-
-### Storage Class Usage (Dynamic Provisioning)
-> [`StorageClass` example](../deploy/example/storageclass-nfs.yaml)
-
-Name | Meaning | Example Value | Mandatory | Default value
---- | --- | --- | --- | ---
-server | NFS Server endpoint | Domain name `nfs-server.default.svc.cluster.local` <br>Or IP address `127.0.0.1` | Yes |
-share | NFS share path | `/` | Yes |
-
-### PV/PVC Usage (Static Provisioning)
-> [`PersistentVolume` example](../deploy/example/pv-nfs-csi.yaml)
-
-Name | Meaning | Example Value | Mandatory | Default value
---- | --- | --- | --- | ---
-volumeAttributes.source | NFS Server endpoint | Domain name `nfs-server.default.svc.cluster.local` <br>Or IP address `127.0.0.1` | Yes |
-volumeAttributes.share | NFS share path | `/` |  Yes  |
diff --git a/docs/install-csi-driver.md b/docs/install-csi-driver.md
index 25941177..f06a35be 100644
--- a/docs/install-csi-driver.md
+++ b/docs/install-csi-driver.md
@@ -5,14 +5,14 @@ If you have already installed Helm, you can also use it to install NFS CSI drive
 ## Install with kubectl
  - remote install
 ```console
-curl -skSL https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/deploy/install-driver.sh | bash -s master --
+curl -skSL https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/deploy/kubernetes/install-driver.sh | bash -s master --
 ```
 
  - local install
 ```console
 git clone https://github.com/kubernetes-csi/csi-driver-nfs.git
 cd csi-driver-nfs
-./deploy/install-driver.sh master local
+./deploy/kubernetes/install-driver.sh master local
 ```
 
 - check pods status:
@@ -33,5 +33,5 @@ csi-nfs-node-dr4s4                        3/3     Running   0          35s     1
 
 - clean up NFS CSI driver
 ```console
-curl -skSL https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/deploy/uninstall-driver.sh | bash -s master --
+curl -skSL https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/deploy/kubernetes/uninstall-driver.sh | bash -s master --
 ```
\ No newline at end of file
diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 00000000..2269cfb9
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,30 @@
+# Set up a NFS Server on a Kubernetes cluster
+
+> Note: This example is for development only. Because the NFS server is sticky to the node it is scheduled on, data shall be lost if the pod is rescheduled on another node.
+
+- To create a NFS provisioner on your Kubernetes cluster, run the following command
+
+```bash
+kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/examples/kubernetes/nfs-provisioner/nfs-server.yaml
+```
+
+- After deploying, a new service `nfs-server` is created, nfs share path is`nfs-server.default.svc.cluster.local:/`.
+
+- To check if the server is working, we can statically create a `PersistentVolume` and a `PersistentVolumeClaim`, and mount it onto a sample pod:
+
+```bash
+kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/examples/kubernetes/nfs-provisioner/app.yaml
+```
+
+Verify if the newly create deployment is Running:
+
+```bash
+# kubectl exec -it nfs-busybox-8cd8d9c5b-sf8mx sh
+/ # df -h
+Filesystem                Size      Used Available Use% Mounted on
+...
+nfs-server.default.svc.cluster.local:/
+                        123.9G     15.2G    108.6G  12% /mnt
+...
+```
+
diff --git a/deploy/example/deployment.yaml b/examples/deployment.yaml
similarity index 80%
rename from deploy/example/deployment.yaml
rename to examples/deployment.yaml
index 2f497a07..c1006b7b 100644
--- a/deploy/example/deployment.yaml
+++ b/examples/deployment.yaml
@@ -1,43 +1,43 @@
----
-apiVersion: v1
-kind: PersistentVolumeClaim
-metadata:
-  name: pvc-deployment-nfs
-spec:
-  accessModes:
-    - ReadWriteMany  # In this example, multiple Pods consume the same PVC.
-  resources:
-    requests:
-      storage: 10Gi
-  storageClassName: nfs-csi
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: deployment-nfs
-spec:
-  replicas: 3
-  selector:
-    matchLabels:
-        name: deployment-nfs
-  template:
-    metadata:
-        name: deployment-nfs
-        labels:
-            name: deployment-nfs
-    spec:
-      containers:
-      containers:
-      - name: deployment-nfs
-        image: mcr.microsoft.com/oss/nginx/nginx:1.17.3-alpine
-        command:
-          - "/bin/sh"
-          - "-c"
-          - while true; do echo $(hostname) $(date) >> /mnt/nfs/outfile; sleep 1; done
-        volumeMounts:
-          - name: nfs
-            mountPath: "/mnt/nfs"
-      volumes:
-      - name: nfs
-        persistentVolumeClaim:
-          claimName: pvc-deployment-nfs
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: pvc-deployment-nfs
+spec:
+  accessModes:
+    - ReadWriteMany  # In this example, multiple Pods consume the same PVC.
+  resources:
+    requests:
+      storage: 10Gi
+  storageClassName: nfs-csi
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: deployment-nfs-rwm
+spec:
+  replicas: 3
+  selector:
+    matchLabels:
+        name: deployment-nfs-rwm
+  template:
+    metadata:
+        name: deployment-nfs-rwm
+        labels:
+            name: deployment-nfs-rwm
+    spec:
+      containers:
+      containers:
+      - name: deployment-nfs-rwm
+        image: mcr.microsoft.com/oss/nginx/nginx:1.17.3-alpine
+        command:
+          - "/bin/sh"
+          - "-c"
+          - while true; do echo $(hostname) $(date) >> /mnt/nfs/outfile; sleep 1; done
+        volumeMounts:
+          - name: nfs
+            mountPath: "/mnt/nfs"
+      volumes:
+      - name: nfs
+        persistentVolumeClaim:
+          claimName: pvc-deployment-nfs
diff --git a/deploy/example/nfs-provisioner/nfs-server.yaml b/examples/nfs-server.yaml
similarity index 100%
rename from deploy/example/nfs-provisioner/nfs-server.yaml
rename to examples/nfs-server.yaml
diff --git a/examples/nginx-pod.yaml b/examples/nginx-pod.yaml
new file mode 100644
index 00000000..904f4e0e
--- /dev/null
+++ b/examples/nginx-pod.yaml
@@ -0,0 +1,31 @@
+---
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: pvc-nginx
+spec:
+  accessModes:
+  - ReadWriteMany
+  resources:
+    requests:
+      storage: 100Gi
+  storageClassName: nfs-csi
+---
+apiVersion: v1
+kind: Pod
+metadata:
+  name: nginx
+spec:
+  containers:
+  - image: nginx
+    name: nginx
+    ports:
+    - containerPort: 80
+      protocol: TCP
+    volumeMounts:
+      - mountPath: /var/www
+        name: pvc-nginx
+  volumes:
+  - name: pvc-nginx
+    persistentVolumeClaim:
+      claimName: pvc-nginx
diff --git a/deploy/example/pv-nfs-csi.yaml b/examples/pv-nfs-csi.yaml
similarity index 100%
rename from deploy/example/pv-nfs-csi.yaml
rename to examples/pv-nfs-csi.yaml
diff --git a/deploy/example/pvc-nfs-csi-dynamic.yaml b/examples/pvc-nfs-csi-dynamic.yaml
similarity index 100%
rename from deploy/example/pvc-nfs-csi-dynamic.yaml
rename to examples/pvc-nfs-csi-dynamic.yaml
diff --git a/deploy/example/pvc-nfs-csi-static.yaml b/examples/pvc-nfs-csi-static.yaml
similarity index 100%
rename from deploy/example/pvc-nfs-csi-static.yaml
rename to examples/pvc-nfs-csi-static.yaml
diff --git a/deploy/example/statefulset.yaml b/examples/statefulset.yaml
similarity index 100%
rename from deploy/example/statefulset.yaml
rename to examples/statefulset.yaml
diff --git a/deploy/example/storageclass-nfs.yaml b/examples/storageclass-nfs.yaml
similarity index 100%
rename from deploy/example/storageclass-nfs.yaml
rename to examples/storageclass-nfs.yaml
diff --git a/go.mod b/go.mod
index 24288978..f9410585 100644
--- a/go.mod
+++ b/go.mod
@@ -5,6 +5,7 @@ go 1.13
 require (
 	github.com/container-storage-interface/spec v1.3.0
 	github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
+	github.com/golang/protobuf v1.4.1
 	github.com/kubernetes-csi/csi-lib-utils v0.7.0
 	github.com/kubernetes-csi/external-snapshotter/v2 v2.0.0-20200617021606-4800ca72d403
 	github.com/onsi/ginkgo v1.11.0
@@ -12,7 +13,7 @@ require (
 	github.com/pborman/uuid v1.2.0
 	github.com/prometheus/client_golang v1.5.1 // indirect
 	github.com/spf13/cobra v0.0.5
-	github.com/stretchr/testify v1.5.1 // indirect
+	github.com/stretchr/testify v1.5.1
 	golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
 	golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
 	golang.org/x/text v0.3.3 // indirect
diff --git a/pkg/mounter/safe_mounter_unix.go b/pkg/mounter/safe_mounter_unix.go
new file mode 100644
index 00000000..678c2950
--- /dev/null
+++ b/pkg/mounter/safe_mounter_unix.go
@@ -0,0 +1,28 @@
+// +build linux darwin
+
+/*
+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 (
+	utilexec "k8s.io/utils/exec"
+	"k8s.io/utils/mount"
+)
+
+func NewSafeMounter() (*mount.SafeFormatAndMount, error) {
+	return &mount.SafeFormatAndMount{
+		Interface: mount.New(""),
+		Exec:      utilexec.New(),
+	}, nil
+}
diff --git a/pkg/nfs/fake_mounter.go b/pkg/nfs/fake_mounter.go
new file mode 100644
index 00000000..f052c61f
--- /dev/null
+++ b/pkg/nfs/fake_mounter.go
@@ -0,0 +1,73 @@
+/*
+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"
+	"runtime"
+	"strings"
+
+	"github.com/kubernetes-csi/csi-driver-nfs/pkg/mounter"
+
+	"k8s.io/utils/mount"
+)
+
+type fakeMounter struct {
+	mount.FakeMounter
+}
+
+// Mount overrides mount.FakeMounter.Mount.
+func (f *fakeMounter) Mount(source string, target string, fstype string, options []string) error {
+	if strings.Contains(source, "error_mount") {
+		return fmt.Errorf("fake Mount: source error")
+	} else if strings.Contains(target, "error_mount") {
+		return fmt.Errorf("fake Mount: target error")
+	}
+
+	return nil
+}
+
+// MountSensitive overrides mount.FakeMounter.MountSensitive.
+func (f *fakeMounter) MountSensitive(source string, target string, fstype string, options []string, sensitiveOptions []string) error {
+	if strings.Contains(source, "error_mount_sens") {
+		return fmt.Errorf("fake MountSensitive: source error")
+	} else if strings.Contains(target, "error_mount_sens") {
+		return fmt.Errorf("fake MountSensitive: target error")
+	}
+
+	return nil
+}
+
+//IsLikelyNotMountPoint overrides mount.FakeMounter.IsLikelyNotMountPoint.
+func (f *fakeMounter) IsLikelyNotMountPoint(file string) (bool, error) {
+	if strings.Contains(file, "error_is_likely") {
+		return false, fmt.Errorf("fake IsLikelyNotMountPoint: fake error")
+	}
+	if strings.Contains(file, "false_is_likely") {
+		return false, nil
+	}
+	return true, nil
+}
+
+func NewFakeMounter() (*mount.SafeFormatAndMount, error) {
+	if runtime.GOOS == "windows" {
+		return mounter.NewSafeMounter()
+	}
+	return &mount.SafeFormatAndMount{
+		Interface: &fakeMounter{},
+	}, nil
+}
diff --git a/pkg/nfs/indentityserver.go b/pkg/nfs/indentityserver.go
index 8f276bd1..9ee82bd3 100644
--- a/pkg/nfs/indentityserver.go
+++ b/pkg/nfs/indentityserver.go
@@ -19,6 +19,7 @@ package nfs
 import (
 	"github.com/container-storage-interface/spec/lib/go/csi"
 	"github.com/golang/glog"
+	"github.com/golang/protobuf/ptypes/wrappers"
 	"golang.org/x/net/context"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
@@ -45,8 +46,12 @@ func (ids *IdentityServer) GetPluginInfo(ctx context.Context, req *csi.GetPlugin
 	}, nil
 }
 
+// Probe check whether the plugin is running or not.
+// This method does not need to return anything.
+// Currently the spec does not dictate what you should return either.
+// Hence, return an empty response
 func (ids *IdentityServer) Probe(ctx context.Context, req *csi.ProbeRequest) (*csi.ProbeResponse, error) {
-	return &csi.ProbeResponse{}, nil
+	return &csi.ProbeResponse{Ready: &wrappers.BoolValue{Value: true}}, nil
 }
 
 func (ids *IdentityServer) GetPluginCapabilities(ctx context.Context, req *csi.GetPluginCapabilitiesRequest) (*csi.GetPluginCapabilitiesResponse, error) {
diff --git a/pkg/nfs/nodeserver.go b/pkg/nfs/nodeserver.go
index 91f18c34..ce5617c5 100644
--- a/pkg/nfs/nodeserver.go
+++ b/pkg/nfs/nodeserver.go
@@ -160,3 +160,13 @@ func (ns *NodeServer) NodeStageVolume(ctx context.Context, req *csi.NodeStageVol
 func (ns *NodeServer) NodeExpandVolume(ctx context.Context, req *csi.NodeExpandVolumeRequest) (*csi.NodeExpandVolumeResponse, error) {
 	return nil, status.Error(codes.Unimplemented, "")
 }
+
+func makeDir(pathname string) error {
+	err := os.MkdirAll(pathname, os.FileMode(0755))
+	if err != nil {
+		if !os.IsExist(err) {
+			return err
+		}
+	}
+	return nil
+}


Test patch:
diff --git a/pkg/nfs/identityserver_test.go b/pkg/nfs/identityserver_test.go
new file mode 100644
index 00000000..27759739
--- /dev/null
+++ b/pkg/nfs/identityserver_test.go
@@ -0,0 +1,102 @@
+/*
+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 (
+	"context"
+	"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"
+)
+
+func TestGetPluginInfo(t *testing.T) {
+	req := csi.GetPluginInfoRequest{}
+	emptyNameDriver := NewEmptyDriver("name")
+	emptyVersionDriver := NewEmptyDriver("version")
+	tests := []struct {
+		desc        string
+		driver      *Driver
+		expectedErr error
+	}{
+		{
+			desc:        "Successful Request",
+			driver:      NewEmptyDriver(""),
+			expectedErr: nil,
+		},
+		{
+			desc:        "Driver name missing",
+			driver:      emptyNameDriver,
+			expectedErr: status.Error(codes.Unavailable, "Driver name not configured"),
+		},
+		{
+			desc:        "Driver version missing",
+			driver:      emptyVersionDriver,
+			expectedErr: status.Error(codes.Unavailable, "Driver is missing version"),
+		},
+	}
+
+	for _, test := range tests {
+		fakeIdentityServer := IdentityServer{
+			Driver: test.driver,
+		}
+		_, err := fakeIdentityServer.GetPluginInfo(context.Background(), &req)
+		if !reflect.DeepEqual(err, test.expectedErr) {
+			t.Errorf("Unexpected error: %v\nExpected: %v", err, test.expectedErr)
+		}
+	}
+}
+
+func TestProbe(t *testing.T) {
+	d := NewEmptyDriver("")
+	req := csi.ProbeRequest{}
+	fakeIdentityServer := IdentityServer{
+		Driver: d,
+	}
+	resp, err := fakeIdentityServer.Probe(context.Background(), &req)
+	assert.NoError(t, err)
+	assert.NotNil(t, resp)
+	assert.Equal(t, resp.XXX_sizecache, int32(0))
+	assert.Equal(t, resp.Ready.Value, true)
+}
+
+func TestGetPluginCapabilities(t *testing.T) {
+	expectedCap := []*csi.PluginCapability{
+		{
+			Type: &csi.PluginCapability_Service_{
+				Service: &csi.PluginCapability_Service{
+					Type: csi.PluginCapability_Service_CONTROLLER_SERVICE,
+				},
+			},
+		},
+	}
+
+	d := NewEmptyDriver("")
+	fakeIdentityServer := IdentityServer{
+		Driver: d,
+	}
+	req := csi.GetPluginCapabilitiesRequest{}
+	resp, err := fakeIdentityServer.GetPluginCapabilities(context.Background(), &req)
+	assert.NoError(t, err)
+	assert.NotNil(t, resp)
+	assert.Equal(t, resp.XXX_sizecache, int32(0))
+	assert.Equal(t, resp.Capabilities, expectedCap)
+
+}
diff --git a/pkg/nfs/nfs_test.go b/pkg/nfs/nfs_test.go
new file mode 100644
index 00000000..440736bc
--- /dev/null
+++ b/pkg/nfs/nfs_test.go
@@ -0,0 +1,56 @@
+/*
+Copyright 2019 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 "github.com/container-storage-interface/spec/lib/go/csi"
+
+const (
+	fakeNodeID = "fakeNodeID"
+)
+
+func NewEmptyDriver(emptyField string) *Driver {
+	var d *Driver
+	var perm *uint32
+	switch emptyField {
+	case "version":
+		d = &Driver{
+			name:    DriverName,
+			version: "",
+			nodeID:  fakeNodeID,
+			cap:     map[csi.VolumeCapability_AccessMode_Mode]bool{},
+			perm:    perm,
+		}
+	case "name":
+		d = &Driver{
+			name:    "",
+			version: version,
+			nodeID:  fakeNodeID,
+			cap:     map[csi.VolumeCapability_AccessMode_Mode]bool{},
+			perm:    perm,
+		}
+	default:
+		d = &Driver{
+			name:    DriverName,
+			version: version,
+			nodeID:  fakeNodeID,
+			cap:     map[csi.VolumeCapability_AccessMode_Mode]bool{},
+			perm:    perm,
+		}
+	}
+
+	return d
+}
diff --git a/pkg/nfs/nodeserver_test.go b/pkg/nfs/nodeserver_test.go
new file mode 100644
index 00000000..7a31c957
--- /dev/null
+++ b/pkg/nfs/nodeserver_test.go
@@ -0,0 +1,213 @@
+/*
+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 (
+	"context"
+	"errors"
+	"os"
+	"reflect"
+	"testing"
+
+	"github.com/container-storage-interface/spec/lib/go/csi"
+	"github.com/kubernetes-csi/csi-driver-nfs/test/utils/testutil"
+	"github.com/stretchr/testify/assert"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+)
+
+func TestNodePublishVolume(t *testing.T) {
+	volumeCap := csi.VolumeCapability_AccessMode{Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER}
+	alreadyMountedTarget := testutil.GetWorkDirPath("false_is_likely_exist_target", t)
+	targetTest := testutil.GetWorkDirPath("target_test", t)
+
+	tests := []struct {
+		desc          string
+		req           csi.NodePublishVolumeRequest
+		skipOnWindows bool
+		expectedErr   error
+	}{
+		{
+			desc:        "[Error] Volume capabilities missing",
+			req:         csi.NodePublishVolumeRequest{},
+			expectedErr: status.Error(codes.InvalidArgument, "Volume capability missing in request"),
+		},
+		{
+			desc:        "[Error] Volume ID missing",
+			req:         csi.NodePublishVolumeRequest{VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap}},
+			expectedErr: status.Error(codes.InvalidArgument, "Volume ID missing in request"),
+		},
+		{
+			desc: "[Error] Target path missing",
+			req: csi.NodePublishVolumeRequest{VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap},
+				VolumeId: "vol_1"},
+			expectedErr: status.Error(codes.InvalidArgument, "Target path not provided"),
+		},
+		{
+			desc: "[Success] Stage target path missing",
+			req: csi.NodePublishVolumeRequest{VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap},
+				VolumeId:   "vol_1",
+				TargetPath: targetTest},
+			expectedErr: nil,
+		},
+		{
+			desc: "[Success] Valid request read only",
+			req: csi.NodePublishVolumeRequest{VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap},
+				VolumeId:   "vol_1",
+				TargetPath: targetTest,
+				Readonly:   true},
+			expectedErr: nil,
+		},
+		{
+			desc: "[Success] Valid request already mounted",
+			req: csi.NodePublishVolumeRequest{VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap},
+				VolumeId:   "vol_1",
+				TargetPath: alreadyMountedTarget,
+				Readonly:   true},
+			expectedErr: nil,
+		},
+		{
+			desc: "[Success] Valid request",
+			req: csi.NodePublishVolumeRequest{VolumeCapability: &csi.VolumeCapability{AccessMode: &volumeCap},
+				VolumeId:   "vol_1",
+				TargetPath: targetTest,
+				Readonly:   true},
+			expectedErr: nil,
+		},
+	}
+
+	// setup
+	_ = makeDir(alreadyMountedTarget)
+
+	ns, err := getTestNodeServer()
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	for _, tc := range tests {
+		_, err := ns.NodePublishVolume(context.Background(), &tc.req)
+		if !reflect.DeepEqual(err, tc.expectedErr) {
+			t.Errorf("Desc:%v\nUnexpected error: %v\nExpected: %v", tc.desc, err, tc.expectedErr)
+		}
+	}
+
+	// Clean up
+	err = os.RemoveAll(targetTest)
+	assert.NoError(t, err)
+	err = os.RemoveAll(alreadyMountedTarget)
+	assert.NoError(t, err)
+
+}
+
+func TestNodeUnpublishVolume(t *testing.T) {
+	errorTarget := testutil.GetWorkDirPath("error_is_likely_target", t)
+	targetTest := testutil.GetWorkDirPath("target_test", t)
+	targetFile := testutil.GetWorkDirPath("abc.go", t)
+
+	tests := []struct {
+		desc        string
+		req         csi.NodeUnpublishVolumeRequest
+		expectedErr error
+	}{
+		{
+			desc:        "[Error] Volume ID missing",
+			req:         csi.NodeUnpublishVolumeRequest{TargetPath: targetTest},
+			expectedErr: status.Error(codes.InvalidArgument, "Volume ID missing in request"),
+		},
+		{
+			desc:        "[Error] Target missing",
+			req:         csi.NodeUnpublishVolumeRequest{VolumeId: "vol_1"},
+			expectedErr: 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, "fake IsLikelyNotMountPoint: fake error"),
+		},
+		{
+			desc:        "[Error] Volume not mounted",
+			req:         csi.NodeUnpublishVolumeRequest{TargetPath: targetFile, VolumeId: "vol_1"},
+			expectedErr: status.Error(codes.NotFound, "Volume not mounted"),
+		},
+	}
+
+	// Setup
+	_ = makeDir(errorTarget)
+
+	ns, err := getTestNodeServer()
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	for _, tc := range tests {
+		_, err := ns.NodeUnpublishVolume(context.Background(), &tc.req)
+		if !reflect.DeepEqual(err, tc.expectedErr) {
+			t.Errorf("Desc:%v\nUnexpected error: %v\nExpected: %v", tc.desc, err, tc.expectedErr)
+		}
+	}
+
+	// Clean up
+	err = os.RemoveAll(errorTarget)
+	assert.NoError(t, err)
+}
+
+func TestNodeGetInfo(t *testing.T) {
+
+	ns, err := getTestNodeServer()
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	// Test valid request
+	req := csi.NodeGetInfoRequest{}
+	resp, err := ns.NodeGetInfo(context.Background(), &req)
+	assert.NoError(t, err)
+	assert.Equal(t, resp.GetNodeId(), fakeNodeID)
+}
+
+func TestNodeGetCapabilities(t *testing.T) {
+
+	ns, err := getTestNodeServer()
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	capType := &csi.NodeServiceCapability_Rpc{
+		Rpc: &csi.NodeServiceCapability_RPC{
+			Type: csi.NodeServiceCapability_RPC_UNKNOWN,
+		},
+	}
+
+	// Test valid request
+	req := csi.NodeGetCapabilitiesRequest{}
+	resp, err := ns.NodeGetCapabilities(context.Background(), &req)
+	assert.NotNil(t, resp)
+	assert.Equal(t, resp.Capabilities[0].GetType(), capType)
+	assert.NoError(t, err)
+}
+
+func getTestNodeServer() (NodeServer, error) {
+	d := NewEmptyDriver("")
+	mounter, err := NewFakeMounter()
+	if err != nil {
+		return NodeServer{}, errors.New("failed to get fake mounter")
+	}
+	return NodeServer{
+		Driver:  d,
+		mounter: mounter,
+	}, nil
+}
diff --git a/test/utils/testutil/testutil.go b/test/utils/testutil/testutil.go
new file mode 100644
index 00000000..cc2dd937
--- /dev/null
+++ b/test/utils/testutil/testutil.go
@@ -0,0 +1,32 @@
+/*
+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 testutil
+
+import (
+	"fmt"
+	"os"
+	"testing"
+)
+
+// GetWorkDirPath returns the path to the current working directory
+func GetWorkDirPath(dir string, t *testing.T) string {
+	path, err := os.Getwd()
+	if err != nil {
+		t.Fatalf("failed to get working directory: %s", err)
+	}
+	return fmt.Sprintf("%s%c%s", path, os.PathSeparator, dir)
+}