Repository: kubernetes-sigs/gcp-compute-persistent-disk-csi-driver
Pull request #816 (2021-08-07 00:05:50)

Update CSI sanity to v4.2.0
**What type of PR is this?**
/kind cleanup

**What this PR does / why we need it**:
This PR updates the CSI sanity library to the most recent release, v4.2.0.

This is important for asserting correct driver behavior and is a prerequisite for additional tests we will want to run against this driver, namely for the [new NodePublishVolume behavior tied to the new access modes](https://github.com/container-storage-interface/spec/blob/v1.5.0/spec.md#nodepublishvolume).

**Special notes for your reviewer**:
Please see #818 for more details on the skipped tests and possible solutions.

**Does this PR introduce a user-facing change?**:
```release-note
Updates the CSI sanity test suite to v4.2.0
```

/assign @msau42 
/assign @mattcary 

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

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/gcp-compute-persistent-disk-csi-driver/pull/816#" title="Author self-approved">chrishenzie</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **jingxu97** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @jingxu97` 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-sigs%2Fgcp-compute-persistent-disk-csi-driver).

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

- **[OWNERS](https://github.com/kubernetes-sigs/gcp-compute-persistent-disk-csi-driver/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":["jingxu97"]} -->
k8s-ci-robot: @chrishenzie: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-gcp-compute-persistent-disk-csi-driver-sanity | 9440b5c8c86f6fe7996851830cb3a228faf90d53 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/sigs.k8s.io_gcp-compute-persistent-disk-csi-driver/816/pull-gcp-compute-persistent-disk-csi-driver-sanity/1423797499373555712/) | `/test pull-gcp-compute-persistent-disk-csi-driver-sanity`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=gcp-compute-persistent-disk-csi-driver&pr=816). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Achrishenzie). 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-sigs/gcp-compute-persistent-disk-csi-driver/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/go.mod b/go.mod
index ad18777f..501db75d 100644
--- a/go.mod
+++ b/go.mod
@@ -9,9 +9,9 @@ require (
 	github.com/golang/protobuf v1.5.2
 	github.com/google/uuid v1.1.2
 	github.com/kubernetes-csi/csi-proxy/client v1.0.0
-	github.com/kubernetes-csi/csi-test/v3 v3.0.0
-	github.com/onsi/ginkgo v1.14.0
-	github.com/onsi/gomega v1.10.1
+	github.com/kubernetes-csi/csi-test/v4 v4.2.0
+	github.com/onsi/ginkgo v1.14.2
+	github.com/onsi/gomega v1.10.4
 	golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
 	golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
 	google.golang.org/api v0.34.0
diff --git a/go.sum b/go.sum
index 8748cfad..6ec1f4b3 100644
--- a/go.sum
+++ b/go.sum
@@ -134,11 +134,12 @@ github.com/clarketm/json v1.13.4/go.mod h1:ynr2LRfb0fQU34l07csRNBTcivjySLLiY1YzQ
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
 github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
 github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
-github.com/container-storage-interface/spec v1.2.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4=
+github.com/container-storage-interface/spec v1.3.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4=
 github.com/container-storage-interface/spec v1.5.0 h1:lvKxe3uLgqQeVQcrnL2CPQKISoKjTJxojEs9cBk+HXo=
 github.com/container-storage-interface/spec v1.5.0/go.mod h1:8K96oQNkJ7pFcC2R9Z1ynGGBB1I93kcS6PGg3SsOk8s=
 github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
@@ -204,6 +205,7 @@ github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
@@ -239,6 +241,7 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
 github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
 github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
 github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
 github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
 github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
@@ -462,8 +465,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/kubernetes-csi/csi-proxy/client v1.0.0 h1:jqxpu9VidCtxnjgiIjT1xsIndX1wVRGzOp7R0mCZ+gI=
 github.com/kubernetes-csi/csi-proxy/client v1.0.0/go.mod h1:URLOkEbRhOwKVvGvug6HSKRTpLSFuQ/Gt3xahDag8qc=
-github.com/kubernetes-csi/csi-test/v3 v3.0.0 h1:mVsfA4J67uNm8fdF/Pr84oMqL92qjIhjWbEUH8zv1fU=
-github.com/kubernetes-csi/csi-test/v3 v3.0.0/go.mod h1:VdIKGnDZHOjg4M5yd0OZICtsoEzdn64d0K33N6dm35Q=
+github.com/kubernetes-csi/csi-test/v4 v4.2.0 h1:uyFJMSN9vnOOuQwndB43Kp4Bi/dScuATdv4FMuGJJQ8=
+github.com/kubernetes-csi/csi-test/v4 v4.2.0/go.mod h1:HuWP7lCCJzehodzd4kO170soxqgzSQHZ5Jbp1pKPlmA=
 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc=
 github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
@@ -523,24 +526,26 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW
 github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.5 h1:obHEce3upls1IBn1gTw/o7bCv7OJb6Ib/o7wNO+4eKw=
+github.com/nxadm/tail v1.4.5/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
 github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
 github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
-github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
 github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
+github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M=
+github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
 github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
 github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
-github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
 github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.10.4 h1:NiTx7EEvBzu9sFOD1zORteLSt3o8gnlvZZwSE9TnY9U=
+github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ=
 github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
 github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
@@ -607,6 +612,7 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/quobyte/api v0.1.8/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI=
 github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
+github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
 github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
@@ -816,7 +822,6 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -835,6 +840,7 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE=
@@ -888,7 +894,6 @@ golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -919,6 +924,7 @@ golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1061,7 +1067,6 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98
 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
 google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
 google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
-google.golang.org/genproto v0.0.0-20191114150713-6bbd007550de/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
 google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
@@ -1088,6 +1093,7 @@ google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6D
 google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201209185603-f92720507ed4/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
 google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
 google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
@@ -1108,6 +1114,7 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
 google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
 google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
 google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
 google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
@@ -1146,6 +1153,7 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5/go.mod h1:hiOFpYm0ZJbusNj2ywpbrXowU3G8U6GIQzqn2mw1UIE=
+gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
 gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
@@ -1206,6 +1214,7 @@ k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
 k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
 k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
 k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
+k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
 k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM=
 k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
 k8s.io/kube-aggregator v0.22.0/go.mod h1:zHTepg0Q4tKzru7Pwg1QYHWrU/wrvIXM8hUdDAH66qg=
diff --git a/pkg/gce-cloud-provider/compute/fake-gce.go b/pkg/gce-cloud-provider/compute/fake-gce.go
index f59b63c0..4abd9a17 100644
--- a/pkg/gce-cloud-provider/compute/fake-gce.go
+++ b/pkg/gce-cloud-provider/compute/fake-gce.go
@@ -30,6 +30,7 @@ import (
 	"sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/common"
 
 	"k8s.io/apimachinery/pkg/util/sets"
+	"k8s.io/apimachinery/pkg/util/uuid"
 )
 
 const (
@@ -114,12 +115,43 @@ func (cloud *FakeCloudProvider) ListZones(ctx context.Context, region string) ([
 	return []string{cloud.zone, "country-region-fakesecondzone"}, nil
 }
 
-func (cloud *FakeCloudProvider) ListDisks(ctx context.Context) ([]*computev1.Disk, string, error) {
+func (cloud *FakeCloudProvider) ListDisks(ctx context.Context, maxEntries int64, pageToken string) ([]*computev1.Disk, string, error) {
+	// Ignore page tokens for now
+	var seen sets.String
+	var ok bool
+	var count int64 = 0
+	var newToken string
 	d := []*computev1.Disk{}
-	for _, cd := range cloud.disks {
-		d = append(d, cd.disk)
+
+	if pageToken != "" {
+		seen, ok = cloud.pageTokens[pageToken]
+		if !ok {
+			return nil, "", invalidError()
+		}
+	} else {
+		seen = sets.NewString()
 	}
-	return d, "", nil
+
+	if maxEntries == 0 {
+		maxEntries = 500
+	}
+
+	for name, cd := range cloud.disks {
+		// Only return v1 disks for simplicity
+		if !seen.Has(name) {
+			d = append(d, cd.disk)
+			seen.Insert(name)
+			count++
+		}
+
+		if count >= maxEntries {
+			newToken = string(uuid.NewUUID())
+			cloud.pageTokens[newToken] = seen
+			break
+		}
+	}
+
+	return d, newToken, nil
 }
 
 func (cloud *FakeCloudProvider) ListSnapshots(ctx context.Context, filter string, maxEntries int64, pageToken string) ([]*computev1.Snapshot, string, error) {
@@ -261,9 +293,6 @@ func (cloud *FakeCloudProvider) InsertDisk(ctx context.Context, project string,
 }
 
 func (cloud *FakeCloudProvider) DeleteDisk(ctx context.Context, project string, volKey *meta.Key) error {
-	if _, ok := cloud.disks[volKey.Name]; !ok {
-		return notFoundError()
-	}
 	delete(cloud.disks, volKey.Name)
 	return nil
 }
diff --git a/pkg/gce-cloud-provider/compute/gce-compute.go b/pkg/gce-cloud-provider/compute/gce-compute.go
index 73787c67..5d75acd3 100644
--- a/pkg/gce-cloud-provider/compute/gce-compute.go
+++ b/pkg/gce-cloud-provider/compute/gce-compute.go
@@ -64,7 +64,7 @@ type GCECompute interface {
 	GetDiskTypeURI(project string, volKey *meta.Key, diskType string) string
 	WaitForAttach(ctx context.Context, project string, volKey *meta.Key, instanceZone, instanceName string) error
 	ResizeDisk(ctx context.Context, project string, volKey *meta.Key, requestBytes int64) (int64, error)
-	ListDisks(ctx context.Context) ([]*computev1.Disk, string, error)
+	ListDisks(ctx context.Context, maxEntries int64, pageToken string) ([]*computev1.Disk, string, error)
 	// Regional Disk Methods
 	GetReplicaZoneURI(project string, zone string) string
 	// Instance Methods
@@ -89,31 +89,19 @@ func (cloud *CloudProvider) GetDefaultZone() string {
 
 // ListDisks lists disks based on maxEntries and pageToken only in the project
 // and zone that the driver is running in.
-func (cloud *CloudProvider) ListDisks(ctx context.Context) ([]*computev1.Disk, string, error) {
-	region, err := common.GetRegionFromZones([]string{cloud.zone})
-	if err != nil {
-		return nil, "", fmt.Errorf("failed to get region from zones: %v", err)
+func (cloud *CloudProvider) ListDisks(ctx context.Context, maxEntries int64, pageToken string) ([]*computev1.Disk, string, error) {
+	lCall := cloud.service.Disks.List(cloud.project, cloud.zone)
+	if maxEntries != 0 {
+		lCall = lCall.MaxResults(maxEntries)
 	}
-	zones, err := cloud.ListZones(ctx, region)
+	if len(pageToken) != 0 {
+		lCall = lCall.PageToken(pageToken)
+	}
+	diskList, err := lCall.Do()
 	if err != nil {
 		return nil, "", err
 	}
-	items := []*computev1.Disk{}
-
-	for _, zone := range zones {
-		lCall := cloud.service.Disks.List(cloud.project, zone)
-		nextPageToken := "pageToken"
-		for nextPageToken != "" {
-			diskList, err := lCall.Do()
-			if err != nil {
-				return nil, "", err
-			}
-			items = append(items, diskList.Items...)
-			nextPageToken = diskList.NextPageToken
-			lCall.PageToken(nextPageToken)
-		}
-	}
-	return items, "", nil
+	return diskList.Items, diskList.NextPageToken, nil
 }
 
 // RepairUnderspecifiedVolumeKey will query the cloud provider and check each zone for the disk specified
diff --git a/pkg/gce-pd-csi-driver/controller.go b/pkg/gce-pd-csi-driver/controller.go
index 7b143407..3b831fe4 100644
--- a/pkg/gce-pd-csi-driver/controller.go
+++ b/pkg/gce-pd-csi-driver/controller.go
@@ -29,7 +29,6 @@ import (
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 	"k8s.io/apimachinery/pkg/util/sets"
-	"k8s.io/apimachinery/pkg/util/uuid"
 	"k8s.io/klog"
 
 	"sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/common"
@@ -40,9 +39,6 @@ type GCEControllerServer struct {
 	Driver        *GCEDriver
 	CloudProvider gce.GCECompute
 
-	disks []*compute.Disk
-	seen  map[string]int
-
 	// A map storing all volumes with ongoing operations so that additional
 	// operations for that same volume (as defined by Volume Key) return an
 	// Aborted error
@@ -533,36 +529,22 @@ func (gceCS *GCEControllerServer) ListVolumes(ctx context.Context, req *csi.List
 	// https://cloud.google.com/compute/docs/reference/beta/disks/list
 	if req.MaxEntries < 0 {
 		return nil, status.Error(codes.InvalidArgument, fmt.Sprintf(
-			"ListVolumes got max entries request %v. GCE only supports values >0", req.MaxEntries))
+			"ListVolumes got max entries request %v. GCE only supports values between 0-500", req.MaxEntries))
 	}
-
-	offset := 0
-	var ok bool
-	if req.StartingToken == "" {
-		diskList, _, err := gceCS.CloudProvider.ListDisks(ctx)
-		if err != nil {
-			if gce.IsGCEInvalidError(err) {
-				return nil, status.Error(codes.Aborted, fmt.Sprintf("ListVolumes error with invalid request: %v", err))
-			}
-			return nil, status.Error(codes.Internal, fmt.Sprintf("Unknown list disk error: %v", err))
-		}
-		gceCS.disks = diskList
-		gceCS.seen = map[string]int{}
-	} else {
-		offset, ok = gceCS.seen[req.StartingToken]
-		if !ok {
-			return nil, status.Error(codes.Aborted, fmt.Sprintf("ListVolumes error with invalid startingToken: %s", req.StartingToken))
-		}
+	var maxEntries int64 = int64(req.MaxEntries)
+	if maxEntries > 500 {
+		klog.Warningf("ListVolumes requested max entries of %v, GCE only supports values <=500 so defaulting value back to 500", maxEntries)
+		maxEntries = 500
 	}
-
-	var maxEntries int = int(req.MaxEntries)
-	if maxEntries == 0 {
-		maxEntries = len(gceCS.disks)
+	diskList, nextToken, err := gceCS.CloudProvider.ListDisks(ctx, maxEntries, req.StartingToken)
+	if err != nil {
+		if gce.IsGCEInvalidError(err) {
+			return nil, status.Error(codes.Aborted, fmt.Sprintf("ListVolumes error with invalid request: %v", err))
+		}
+		return nil, status.Error(codes.Internal, fmt.Sprintf("Unknown list disk error: %v", err))
 	}
-
 	entries := []*csi.ListVolumesResponse_Entry{}
-	for i := 0; i+offset < len(gceCS.disks) && i < maxEntries; i++ {
-		d := gceCS.disks[i+offset]
+	for _, d := range diskList {
 		users := []string{}
 		for _, u := range d.Users {
 			users = append(users, cleanSelfLink(u))
@@ -577,12 +559,6 @@ func (gceCS *GCEControllerServer) ListVolumes(ctx context.Context, req *csi.List
 		})
 	}
 
-	nextToken := ""
-	if len(entries)+offset < len(gceCS.disks) {
-		nextToken = string(uuid.NewUUID())
-		gceCS.seen[nextToken] = len(entries) + offset
-	}
-
 	return &csi.ListVolumesResponse{
 		Entries:   entries,
 		NextToken: nextToken,
diff --git a/pkg/gce-pd-csi-driver/gce-pd-driver.go b/pkg/gce-pd-csi-driver/gce-pd-driver.go
index 62189861..60338368 100644
--- a/pkg/gce-pd-csi-driver/gce-pd-driver.go
+++ b/pkg/gce-pd-csi-driver/gce-pd-driver.go
@@ -151,7 +151,6 @@ func NewControllerServer(gceDriver *GCEDriver, cloudProvider gce.GCECompute) *GC
 	return &GCEControllerServer{
 		Driver:        gceDriver,
 		CloudProvider: cloudProvider,
-		seen:          map[string]int{},
 		volumeLocks:   common.NewVolumeLocks(),
 	}
 }
diff --git a/vendor/github.com/nxadm/tail/.travis.yml b/vendor/github.com/nxadm/tail/.travis.yml
index 95dd3bd7..adcb2613 100644
--- a/vendor/github.com/nxadm/tail/.travis.yml
+++ b/vendor/github.com/nxadm/tail/.travis.yml
@@ -3,13 +3,21 @@ language: go
 script:
   - go test -race -v ./...
 
+# For GOPATH build
+go_import_path: github.com/nxadm/tail
+
 go:
-  - "1.9"
-  - "1.10"
-  - "1.11"
-  - "1.12"
-  - "1.13"
+  # Keep the latest stable release at the top
+  # Keep 'tip' just under
+  # Because those two Go versions are the ones that interest us the most.
+  - "1.15.x"
   - tip
+  - "1.14.x"
+  - "1.13.x"
+  - "1.12.x"
+  - "1.11.x"
+  - "1.10.x"
+  - "1.9.x"
 
 matrix:
   allow_failures:
diff --git a/vendor/github.com/onsi/ginkgo/CHANGELOG.md b/vendor/github.com/onsi/ginkgo/CHANGELOG.md
index bdf18327..a733f95f 100644
--- a/vendor/github.com/onsi/ginkgo/CHANGELOG.md
+++ b/vendor/github.com/onsi/ginkgo/CHANGELOG.md
@@ -1,3 +1,14 @@
+## 1.14.2
+
+### Fixes
+- correct handling windows backslash in import path (#721) [97f3d51]
+- Add additional methods to GinkgoT() to improve compatibility with the testing.TB interface [b5fe44d]
+
+## 1.14.1
+
+### Fixes
+- Discard exported method declaration when running ginkgo bootstrap (#558) [f4b0240]
+
 ## 1.14.0
 
 ### Features
diff --git a/vendor/github.com/onsi/ginkgo/README.md b/vendor/github.com/onsi/ginkgo/README.md
index fab11458..475e0499 100644
--- a/vendor/github.com/onsi/ginkgo/README.md
+++ b/vendor/github.com/onsi/ginkgo/README.md
@@ -80,10 +80,11 @@ Agouti allows you run WebDriver integration tests.  Learn more about Agouti [her
 You'll need the Go command-line tools. Follow the [installation instructions](https://golang.org/doc/install) if you don't have it installed.
 
 ### Global installation
-To install the Ginkgo command line interface into the `$PATH` (actually to `$GOBIN`):
+To install the Ginkgo command line interface:
 ```bash
 go get -u github.com/onsi/ginkgo/ginkgo
 ```
+Note that this will install it to `$GOBIN`, which will need to be in the `$PATH` (or equivalent). Run `go help install` for more information.
 
 ### Go module ["tools package"](https://github.com/golang/go/issues/25922):
 Create (or update) a file called `tools/tools.go` with the following contents:
@@ -93,7 +94,7 @@ Create (or update) a file called `tools/tools.go` with the following contents:
 package tools
 
 import (
-	_ "github.com/onsi/ginkgo"
+	_ "github.com/onsi/ginkgo/ginkgo"
 )
 
 // This file imports packages that are used when running go generate, or used
diff --git a/vendor/github.com/onsi/ginkgo/config/config.go b/vendor/github.com/onsi/ginkgo/config/config.go
index 2ae48b80..3220c095 100644
--- a/vendor/github.com/onsi/ginkgo/config/config.go
+++ b/vendor/github.com/onsi/ginkgo/config/config.go
@@ -20,7 +20,7 @@ import (
 	"fmt"
 )
 
-const VERSION = "1.14.0"
+const VERSION = "1.14.2"
 
 type GinkgoConfigType struct {
 	RandomSeed         int64
diff --git a/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go b/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
index 30ff86f5..7e8a4870 100644
--- a/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
+++ b/vendor/github.com/onsi/ginkgo/ginkgo_dsl.go
@@ -93,26 +93,36 @@ func GinkgoT(optionalOffset ...int) GinkgoTInterface {
 	if len(optionalOffset) > 0 {
 		offset = optionalOffset[0]
 	}
-	return testingtproxy.New(GinkgoWriter, Fail, offset)
+	failedFunc := func() bool {
+		return CurrentGinkgoTestDescription().Failed
+	}
+	nameFunc := func() string {
+		return CurrentGinkgoTestDescription().FullTestText
+	}
+	return testingtproxy.New(GinkgoWriter, Fail, Skip, failedFunc, nameFunc, offset)
 }
 
 //The interface returned by GinkgoT().  This covers most of the methods
 //in the testing package's T.
 type GinkgoTInterface interface {
-	Fail()
+	Cleanup(func())
 	Error(args ...interface{})
 	Errorf(format string, args ...interface{})
+	Fail()
 	FailNow()
+	Failed() bool
 	Fatal(args ...interface{})
 	Fatalf(format string, args ...interface{})
+	Helper()
 	Log(args ...interface{})
 	Logf(format string, args ...interface{})
-	Failed() bool
+	Name() string
 	Parallel()
 	Skip(args ...interface{})
-	Skipf(format string, args ...interface{})
 	SkipNow()
+	Skipf(format string, args ...interface{})
 	Skipped() bool
+	TempDir() string
 }
 
 //Custom Ginkgo test reporters must implement the Reporter interface.
diff --git a/vendor/github.com/onsi/gomega/.travis.yml b/vendor/github.com/onsi/gomega/.travis.yml
index 072fdd2d..348e3014 100644
--- a/vendor/github.com/onsi/gomega/.travis.yml
+++ b/vendor/github.com/onsi/gomega/.travis.yml
@@ -1,8 +1,11 @@
 language: go
+arch:
+    - amd64
+    - ppc64le
 
 go:
-  - 1.13.x
   - 1.14.x
+  - 1.15.x
   - gotip
 
 env:
diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md
index 3aafdbcf..0f1765d8 100644
--- a/vendor/github.com/onsi/gomega/CHANGELOG.md
+++ b/vendor/github.com/onsi/gomega/CHANGELOG.md
@@ -1,3 +1,20 @@
+## 1.10.4
+
+### Fixes
+- update golang net library to more recent version without vulnerability (#406) [817a8b9]
+- Correct spelling: alloted -> allotted (#403) [0bae715]
+- fix a panic in MessageWithDiff with long message (#402) [ea06b9b]
+
+## 1.10.3
+
+### Fixes
+- updates golang/x/net to fix vulnerability detected by snyk (#394) [c479356]
+
+## 1.10.2
+
+### Fixes
+- Add ExpectWithOffset, EventuallyWithOffset and ConsistentlyWithOffset to WithT (#391) [990941a]
+
 ## 1.10.1
 
 ### Fixes
diff --git a/vendor/github.com/onsi/gomega/format/format.go b/vendor/github.com/onsi/gomega/format/format.go
index fae25adc..e59d7d75 100644
--- a/vendor/github.com/onsi/gomega/format/format.go
+++ b/vendor/github.com/onsi/gomega/format/format.go
@@ -105,7 +105,13 @@ func MessageWithDiff(actual, message, expected string) string {
 
 		tabLength := 4
 		spaceFromMessageToActual := tabLength + len("<string>: ") - len(message)
-		padding := strings.Repeat(" ", spaceFromMessageToActual+spacesBeforeFormattedMismatch) + "|"
+
+		paddingCount := spaceFromMessageToActual + spacesBeforeFormattedMismatch
+		if paddingCount < 0 {
+			return Message(formattedActual, message, formattedExpected)
+		}
+
+		padding := strings.Repeat(" ", paddingCount) + "|"
 		return Message(formattedActual, message+padding, formattedExpected)
 	}
 
diff --git a/vendor/github.com/onsi/gomega/go.mod b/vendor/github.com/onsi/gomega/go.mod
index 77893514..02b99ab6 100644
--- a/vendor/github.com/onsi/gomega/go.mod
+++ b/vendor/github.com/onsi/gomega/go.mod
@@ -1,9 +1,11 @@
 module github.com/onsi/gomega
 
+go 1.14
+
 require (
 	github.com/golang/protobuf v1.4.2
 	github.com/onsi/ginkgo v1.12.1
-	golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7
+	golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb
 	golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
 	gopkg.in/yaml.v2 v2.3.0
 )
diff --git a/vendor/github.com/onsi/gomega/go.sum b/vendor/github.com/onsi/gomega/go.sum
index 610b09be..fc230153 100644
--- a/vendor/github.com/onsi/gomega/go.sum
+++ b/vendor/github.com/onsi/gomega/go.sum
@@ -23,22 +23,34 @@ github.com/onsi/ginkgo v1.12.1 h1:mFwc4LvZ0xpSvDZ3E+k8Yte0hLOMxXUlP+yXtJqkYfQ=
 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
 github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
 golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M=
+golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA=
 golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
diff --git a/vendor/github.com/onsi/gomega/gomega_dsl.go b/vendor/github.com/onsi/gomega/gomega_dsl.go
index 8ff9611d..a8529f1c 100644
--- a/vendor/github.com/onsi/gomega/gomega_dsl.go
+++ b/vendor/github.com/onsi/gomega/gomega_dsl.go
@@ -24,7 +24,7 @@ import (
 	"github.com/onsi/gomega/types"
 )
 
-const GOMEGA_VERSION = "1.10.1"
+const GOMEGA_VERSION = "1.10.4"
 
 const nilFailHandlerPanic = `You are trying to make an assertion, but Gomega's fail handler is nil.
 If you're using Ginkgo then you probably forgot to put your assertion in an It().
@@ -376,13 +376,13 @@ func NewGomegaWithT(t types.GomegaTestingT) *GomegaWithT {
 	return NewWithT(t)
 }
 
-// Expect is used to make assertions. See documentation for Expect.
-func (g *WithT) Expect(actual interface{}, extra ...interface{}) Assertion {
-	return assertion.New(actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), 0, extra...)
+// ExpectWithOffset is used to make assertions. See documentation for ExpectWithOffset.
+func (g *WithT) ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) Assertion {
+	return assertion.New(actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), offset, extra...)
 }
 
-// Eventually is used to make asynchronous assertions. See documentation for Eventually.
-func (g *WithT) Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion {
+// EventuallyWithOffset is used to make asynchronous assertions. See documentation for EventuallyWithOffset.
+func (g *WithT) EventuallyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion {
 	timeoutInterval := defaultEventuallyTimeout
 	pollingInterval := defaultEventuallyPollingInterval
 	if len(intervals) > 0 {
@@ -391,11 +391,11 @@ func (g *WithT) Eventually(actual interface{}, intervals ...interface{}) AsyncAs
 	if len(intervals) > 1 {
 		pollingInterval = toDuration(intervals[1])
 	}
-	return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, 0)
+	return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, offset)
 }
 
-// Consistently is used to make asynchronous assertions. See documentation for Consistently.
-func (g *WithT) Consistently(actual interface{}, intervals ...interface{}) AsyncAssertion {
+// ConsistentlyWithOffset is used to make asynchronous assertions. See documentation for ConsistentlyWithOffset.
+func (g *WithT) ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion {
 	timeoutInterval := defaultConsistentlyDuration
 	pollingInterval := defaultConsistentlyPollingInterval
 	if len(intervals) > 0 {
@@ -404,7 +404,22 @@ func (g *WithT) Consistently(actual interface{}, intervals ...interface{}) Async
 	if len(intervals) > 1 {
 		pollingInterval = toDuration(intervals[1])
 	}
-	return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, 0)
+	return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, offset)
+}
+
+// Expect is used to make assertions. See documentation for Expect.
+func (g *WithT) Expect(actual interface{}, extra ...interface{}) Assertion {
+	return g.ExpectWithOffset(0, actual, extra...)
+}
+
+// Eventually is used to make asynchronous assertions. See documentation for Eventually.
+func (g *WithT) Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion {
+	return g.EventuallyWithOffset(0, actual, intervals...)
+}
+
+// Consistently is used to make asynchronous assertions. See documentation for Consistently.
+func (g *WithT) Consistently(actual interface{}, intervals ...interface{}) AsyncAssertion {
+	return g.ConsistentlyWithOffset(0, actual, intervals...)
 }
 
 func toDuration(input interface{}) time.Duration {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 79b0b937..b40a6c06 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -74,22 +74,22 @@ github.com/kubernetes-csi/csi-proxy/client/groups/filesystem/v1
 github.com/kubernetes-csi/csi-proxy/client/groups/filesystem/v1beta1
 github.com/kubernetes-csi/csi-proxy/client/groups/volume/v1
 github.com/kubernetes-csi/csi-proxy/client/groups/volume/v1beta1
-# github.com/kubernetes-csi/csi-test/v3 v3.0.0
-github.com/kubernetes-csi/csi-test/v3/pkg/sanity
-github.com/kubernetes-csi/csi-test/v3/utils
+# github.com/kubernetes-csi/csi-test/v4 v4.2.0
+github.com/kubernetes-csi/csi-test/v4/pkg/sanity
+github.com/kubernetes-csi/csi-test/v4/utils
 # github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369
 github.com/matttproud/golang_protobuf_extensions/pbutil
 # github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
 github.com/modern-go/concurrent
 # github.com/modern-go/reflect2 v1.0.1
 github.com/modern-go/reflect2
-# github.com/nxadm/tail v1.4.4
+# github.com/nxadm/tail v1.4.5
 github.com/nxadm/tail
 github.com/nxadm/tail/ratelimiter
 github.com/nxadm/tail/util
 github.com/nxadm/tail/watch
 github.com/nxadm/tail/winfile
-# github.com/onsi/ginkgo v1.14.0
+# github.com/onsi/ginkgo v1.14.2
 github.com/onsi/ginkgo
 github.com/onsi/ginkgo/config
 github.com/onsi/ginkgo/internal/codelocation
@@ -109,7 +109,7 @@ github.com/onsi/ginkgo/reporters/stenographer
 github.com/onsi/ginkgo/reporters/stenographer/support/go-colorable
 github.com/onsi/ginkgo/reporters/stenographer/support/go-isatty
 github.com/onsi/ginkgo/types
-# github.com/onsi/gomega v1.10.1
+# github.com/onsi/gomega v1.10.4
 github.com/onsi/gomega
 github.com/onsi/gomega/format
 github.com/onsi/gomega/internal/assertion


Test patch:
diff --git a/pkg/gce-pd-csi-driver/controller_test.go b/pkg/gce-pd-csi-driver/controller_test.go
index fe671ba7..dff1c412 100644
--- a/pkg/gce-pd-csi-driver/controller_test.go
+++ b/pkg/gce-pd-csi-driver/controller_test.go
@@ -771,7 +771,6 @@ func TestCreateVolumeArguments(t *testing.T) {
 }
 
 func TestListVolumeArgs(t *testing.T) {
-	diskCount := 600
 	testCases := []struct {
 		name            string
 		maxEntries      int32
@@ -780,13 +779,18 @@ func TestListVolumeArgs(t *testing.T) {
 	}{
 		{
 			name:            "normal",
-			expectedEntries: diskCount,
+			expectedEntries: 500,
 		},
 		{
 			name:            "fine amount of entries",
 			maxEntries:      420,
 			expectedEntries: 420,
 		},
+		{
+			name:            "too many entries, but defaults to 500",
+			maxEntries:      501,
+			expectedEntries: 500,
+		},
 		{
 			name:        "negative entries",
 			maxEntries:  -1,
@@ -798,7 +802,7 @@ func TestListVolumeArgs(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			// Setup new driver each time so no interference
 			var d []*gce.CloudDisk
-			for i := 0; i < diskCount; i++ {
+			for i := 0; i < 600; i++ {
 				// Create 600 dummy disks
 				d = append(d, gce.CloudDiskFromV1(&compute.Disk{Name: fmt.Sprintf("%v", i)}))
 			}
diff --git a/test/sanity/sanity_test.go b/test/sanity/sanity_test.go
index 45e94e30..d3ac9b36 100644
--- a/test/sanity/sanity_test.go
+++ b/test/sanity/sanity_test.go
@@ -15,15 +15,17 @@ limitations under the License.
 package sanitytest
 
 import (
+	"flag"
 	"fmt"
 	"os"
 	"path"
+	"strings"
 	"testing"
 
 	"github.com/google/uuid"
 	"google.golang.org/grpc"
 
-	sanity "github.com/kubernetes-csi/csi-test/v3/pkg/sanity"
+	sanity "github.com/kubernetes-csi/csi-test/v4/pkg/sanity"
 	compute "google.golang.org/api/compute/v1"
 	common "sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/common"
 	gce "sigs.k8s.io/gcp-compute-persistent-disk-csi-driver/pkg/gce-cloud-provider/compute"
@@ -43,6 +45,12 @@ func TestSanity(t *testing.T) {
 	endpoint := fmt.Sprintf("unix:%s/csi.sock", tmpDir)
 	mountPath := path.Join(tmpDir, "mount")
 	stagePath := path.Join(tmpDir, "stage")
+	skipTests := strings.Join([]string{
+		"NodeExpandVolume.*should work if node-expand is called after node-publish",
+		"NodeExpandVolume.*should fail when volume is not found",
+		"ListSnapshots.*should return snapshots that match the specified source volume id",
+	}, "|")
+
 	// Set up driver and env
 	gceDriver := driver.GetGCEDriver()
 
@@ -85,6 +93,9 @@ func TestSanity(t *testing.T) {
 		gceDriver.Run(endpoint)
 	}()
 
+	// TODO(#818): Fix failing tests and remove test skip flag.
+	flag.Set("ginkgo.skip", skipTests)
+
 	// Run test
 	config := sanity.TestConfig{
 		TargetPath:     mountPath,
diff --git a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/cleanup.go b/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/cleanup.go
deleted file mode 100644
index 0322233e..00000000
--- a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/cleanup.go
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
-Copyright 2018 Intel Corporation
-
-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 sanity
-
-import (
-	"context"
-	"log"
-	"sync"
-
-	"github.com/container-storage-interface/spec/lib/go/csi"
-
-	. "github.com/onsi/ginkgo"
-)
-
-// VolumeInfo keeps track of the information needed to delete a volume.
-type VolumeInfo struct {
-	// Node on which the volume was published, empty if none
-	// or publishing is not supported.
-	NodeID string
-
-	// Volume ID assigned by CreateVolume.
-	VolumeID string
-}
-
-// Cleanup keeps track of resources, in particular volumes, which need
-// to be freed when testing is done. All methods can be called concurrently.
-type Cleanup struct {
-	Context                    *TestContext
-	ControllerClient           csi.ControllerClient
-	NodeClient                 csi.NodeClient
-	ControllerPublishSupported bool
-	NodeStageSupported         bool
-
-	// Maps from volume name to the node ID for which the volume
-	// is published and the volume ID.
-	volumes map[string]VolumeInfo
-	mutex   sync.Mutex
-}
-
-// RegisterVolume adds or updates an entry for the volume with the
-// given name.
-func (cl *Cleanup) RegisterVolume(name string, info VolumeInfo) {
-	cl.mutex.Lock()
-	defer cl.mutex.Unlock()
-	if cl.volumes == nil {
-		cl.volumes = make(map[string]VolumeInfo)
-	}
-	cl.volumes[name] = info
-}
-
-// MaybeRegisterVolume adds or updates an entry for the volume with
-// the given name if CreateVolume was successful.
-func (cl *Cleanup) MaybeRegisterVolume(name string, vol *csi.CreateVolumeResponse, err error) {
-	if err == nil && vol.GetVolume().GetVolumeId() != "" {
-		cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-	}
-}
-
-// UnregisterVolume removes the entry for the volume with the
-// given name, thus preventing all cleanup operations for it.
-func (cl *Cleanup) UnregisterVolume(name string) {
-	cl.mutex.Lock()
-	defer cl.mutex.Unlock()
-	cl.unregisterVolume(name)
-}
-func (cl *Cleanup) unregisterVolume(name string) {
-	if cl.volumes != nil {
-		delete(cl.volumes, name)
-	}
-}
-
-// DeleteVolumes stops using the registered volumes and tries to delete all of them.
-func (cl *Cleanup) DeleteVolumes() {
-	cl.mutex.Lock()
-	defer cl.mutex.Unlock()
-	if cl.volumes == nil {
-		return
-	}
-	logger := log.New(GinkgoWriter, "cleanup: ", 0)
-	ctx := context.Background()
-
-	for name, info := range cl.volumes {
-		logger.Printf("deleting %s = %s", name, info.VolumeID)
-		if _, err := cl.NodeClient.NodeUnpublishVolume(
-			ctx,
-			&csi.NodeUnpublishVolumeRequest{
-				VolumeId:   info.VolumeID,
-				TargetPath: cl.Context.TargetPath + "/target",
-			},
-		); err != nil {
-			logger.Printf("warning: NodeUnpublishVolume: %s", err)
-		}
-
-		if cl.NodeStageSupported {
-			if _, err := cl.NodeClient.NodeUnstageVolume(
-				ctx,
-				&csi.NodeUnstageVolumeRequest{
-					VolumeId:          info.VolumeID,
-					StagingTargetPath: cl.Context.StagingPath,
-				},
-			); err != nil {
-				logger.Printf("warning: NodeUnstageVolume: %s", err)
-			}
-		}
-
-		if cl.ControllerPublishSupported && info.NodeID != "" {
-			if _, err := cl.ControllerClient.ControllerUnpublishVolume(
-				ctx,
-				&csi.ControllerUnpublishVolumeRequest{
-					VolumeId: info.VolumeID,
-					NodeId:   info.NodeID,
-					Secrets:  cl.Context.Secrets.ControllerUnpublishVolumeSecret,
-				},
-			); err != nil {
-				logger.Printf("warning: ControllerUnpublishVolume: %s", err)
-			}
-		}
-
-		if _, err := cl.ControllerClient.DeleteVolume(
-			ctx,
-			&csi.DeleteVolumeRequest{
-				VolumeId: info.VolumeID,
-				Secrets:  cl.Context.Secrets.DeleteVolumeSecret,
-			},
-		); err != nil {
-			logger.Printf("error: DeleteVolume: %s", err)
-		}
-
-		cl.unregisterVolume(name)
-	}
-}
diff --git a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/controller.go b/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/controller.go
deleted file mode 100644
index c404290c..00000000
--- a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/controller.go
+++ /dev/null
@@ -1,2306 +0,0 @@
-/*
-Copyright 2017 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 sanity
-
-import (
-	"context"
-	"fmt"
-	"strconv"
-
-	"google.golang.org/grpc/codes"
-	"google.golang.org/grpc/status"
-
-	"github.com/container-storage-interface/spec/lib/go/csi"
-
-	. "github.com/onsi/ginkgo"
-	. "github.com/onsi/gomega"
-)
-
-const (
-	// DefTestVolumeExpand defines the size increment for volume
-	// expansion. It can be overriden by setting an
-	// Config.TestVolumeExpandSize, which will be taken as absolute
-	// value.
-	DefTestExpandIncrement int64 = 1 * 1024 * 1024 * 1024
-
-	MaxNameLength int = 128
-)
-
-func TestVolumeSize(sc *TestContext) int64 {
-	return sc.Config.TestVolumeSize
-}
-
-func TestVolumeExpandSize(sc *TestContext) int64 {
-	if sc.Config.TestVolumeExpandSize > 0 {
-		return sc.Config.TestVolumeExpandSize
-	}
-	return TestVolumeSize(sc) + DefTestExpandIncrement
-}
-
-func verifyVolumeInfo(v *csi.Volume) {
-	Expect(v).NotTo(BeNil())
-	Expect(v.GetVolumeId()).NotTo(BeEmpty())
-}
-
-func verifySnapshotInfo(snapshot *csi.Snapshot) {
-	Expect(snapshot).NotTo(BeNil())
-	Expect(snapshot.GetSnapshotId()).NotTo(BeEmpty())
-	Expect(snapshot.GetSourceVolumeId()).NotTo(BeEmpty())
-	Expect(snapshot.GetCreationTime()).NotTo(BeZero())
-}
-
-func isControllerCapabilitySupported(
-	c csi.ControllerClient,
-	capType csi.ControllerServiceCapability_RPC_Type,
-) bool {
-
-	caps, err := c.ControllerGetCapabilities(
-		context.Background(),
-		&csi.ControllerGetCapabilitiesRequest{})
-	Expect(err).NotTo(HaveOccurred())
-	Expect(caps).NotTo(BeNil())
-	Expect(caps.GetCapabilities()).NotTo(BeNil())
-
-	for _, cap := range caps.GetCapabilities() {
-		Expect(cap.GetRpc()).NotTo(BeNil())
-		if cap.GetRpc().GetType() == capType {
-			return true
-		}
-	}
-	return false
-}
-
-var _ = DescribeSanity("Controller Service [Controller Server]", func(sc *TestContext) {
-	var (
-		c csi.ControllerClient
-		n csi.NodeClient
-
-		cl *Cleanup
-	)
-
-	BeforeEach(func() {
-		c = csi.NewControllerClient(sc.ControllerConn)
-		n = csi.NewNodeClient(sc.Conn)
-
-		cl = &Cleanup{
-			NodeClient:       n,
-			ControllerClient: c,
-			Context:          sc,
-		}
-	})
-
-	AfterEach(func() {
-		cl.DeleteVolumes()
-	})
-
-	Describe("ControllerGetCapabilities", func() {
-		It("should return appropriate capabilities", func() {
-			caps, err := c.ControllerGetCapabilities(
-				context.Background(),
-				&csi.ControllerGetCapabilitiesRequest{})
-
-			By("checking successful response")
-			Expect(err).NotTo(HaveOccurred())
-			Expect(caps).NotTo(BeNil())
-			Expect(caps.GetCapabilities()).NotTo(BeNil())
-
-			for _, cap := range caps.GetCapabilities() {
-				Expect(cap.GetRpc()).NotTo(BeNil())
-
-				switch cap.GetRpc().GetType() {
-				case csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME:
-				case csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME:
-				case csi.ControllerServiceCapability_RPC_LIST_VOLUMES:
-				case csi.ControllerServiceCapability_RPC_GET_CAPACITY:
-				case csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT:
-				case csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS:
-				case csi.ControllerServiceCapability_RPC_PUBLISH_READONLY:
-				case csi.ControllerServiceCapability_RPC_CLONE_VOLUME:
-				case csi.ControllerServiceCapability_RPC_EXPAND_VOLUME:
-				case csi.ControllerServiceCapability_RPC_LIST_VOLUMES_PUBLISHED_NODES:
-				default:
-					Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetRpc().GetType()))
-				}
-			}
-		})
-	})
-
-	Describe("GetCapacity", func() {
-		BeforeEach(func() {
-			if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_GET_CAPACITY) {
-				Skip("GetCapacity not supported")
-			}
-		})
-
-		It("should return capacity (no optional values added)", func() {
-			_, err := c.GetCapacity(
-				context.Background(),
-				&csi.GetCapacityRequest{})
-			Expect(err).NotTo(HaveOccurred())
-
-			// Since capacity is int64 we will not be checking it
-			// The value of zero is a possible value.
-		})
-	})
-	Describe("ListVolumes", func() {
-		BeforeEach(func() {
-			if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_LIST_VOLUMES) {
-				Skip("ListVolumes not supported")
-			}
-		})
-
-		It("should return appropriate values (no optional values added)", func() {
-			vols, err := c.ListVolumes(
-				context.Background(),
-				&csi.ListVolumesRequest{})
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vols).NotTo(BeNil())
-
-			for _, vol := range vols.GetEntries() {
-				verifyVolumeInfo(vol.GetVolume())
-			}
-		})
-
-		It("should fail when an invalid starting_token is passed", func() {
-			vols, err := c.ListVolumes(
-				context.Background(),
-				&csi.ListVolumesRequest{
-					StartingToken: "invalid-token",
-				},
-			)
-			Expect(err).To(HaveOccurred())
-			Expect(vols).To(BeNil())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.Aborted))
-		})
-
-		It("check the presence of new volumes and absence of deleted ones in the volume list", func() {
-			// List Volumes before creating new volume.
-			vols, err := c.ListVolumes(
-				context.Background(),
-				&csi.ListVolumesRequest{})
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vols).NotTo(BeNil())
-
-			totalVols := len(vols.GetEntries())
-
-			By("creating a volume")
-			name := "sanity"
-
-			// Create a new volume.
-			req := &csi.CreateVolumeRequest{
-				Name: name,
-				VolumeCapabilities: []*csi.VolumeCapability{
-					{
-						AccessType: &csi.VolumeCapability_Mount{
-							Mount: &csi.VolumeCapability_MountVolume{},
-						},
-						AccessMode: &csi.VolumeCapability_AccessMode{
-							Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-						},
-					},
-				},
-				Secrets: sc.Secrets.CreateVolumeSecret,
-			}
-
-			vol, err := c.CreateVolume(context.Background(), req)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol).NotTo(BeNil())
-			Expect(vol.GetVolume()).NotTo(BeNil())
-			Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-
-			// List volumes and check for the newly created volume.
-			vols, err = c.ListVolumes(
-				context.Background(),
-				&csi.ListVolumesRequest{})
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vols).NotTo(BeNil())
-			Expect(len(vols.GetEntries())).To(Equal(totalVols + 1))
-
-			By("cleaning up deleting the volume")
-
-			delReq := &csi.DeleteVolumeRequest{
-				VolumeId: vol.GetVolume().GetVolumeId(),
-				Secrets:  sc.Secrets.DeleteVolumeSecret,
-			}
-
-			_, err = c.DeleteVolume(context.Background(), delReq)
-			Expect(err).NotTo(HaveOccurred())
-
-			// List volumes and check if the deleted volume exists in the volume list.
-			vols, err = c.ListVolumes(
-				context.Background(),
-				&csi.ListVolumesRequest{})
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vols).NotTo(BeNil())
-			Expect(len(vols.GetEntries())).To(Equal(totalVols))
-		})
-
-		// Disabling this below case as it is fragile and results are inconsistent
-		// when no of volumes are different. The test might fail on a driver
-		// which implements the pagination based on index just by altering
-		// minVolCount := 4 and maxEntries := 3
-		// Related discussion links:
-		//  https://github.com/intel/pmem-csi/pull/424#issuecomment-540499938
-		//  https://github.com/kubernetes-csi/csi-test/issues/223
-		XIt("pagination should detect volumes added between pages and accept tokens when the last volume from a page is deleted", func() {
-			// minVolCount is the minimum number of volumes expected to exist,
-			// based on which paginated volume listing is performed.
-			minVolCount := 3
-			// maxEntries is the maximum entries in list volume request.
-			maxEntries := 2
-			// existing_vols to keep a record of the volumes that should exist
-			existing_vols := map[string]bool{}
-
-			// Get the number of existing volumes.
-			vols, err := c.ListVolumes(
-				context.Background(),
-				&csi.ListVolumesRequest{})
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vols).NotTo(BeNil())
-
-			initialTotalVols := len(vols.GetEntries())
-
-			for _, vol := range vols.GetEntries() {
-				existing_vols[vol.Volume.VolumeId] = true
-			}
-
-			if minVolCount <= initialTotalVols {
-				minVolCount = initialTotalVols
-			} else {
-				// Ensure minimum minVolCount volumes exist.
-				By("creating required new volumes")
-				for i := initialTotalVols; i < minVolCount; i++ {
-					name := "sanity" + strconv.Itoa(i)
-					req := &csi.CreateVolumeRequest{
-						Name: name,
-						VolumeCapabilities: []*csi.VolumeCapability{
-							{
-								AccessType: &csi.VolumeCapability_Mount{
-									Mount: &csi.VolumeCapability_MountVolume{},
-								},
-								AccessMode: &csi.VolumeCapability_AccessMode{
-									Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-								},
-							},
-						},
-						Secrets: sc.Secrets.CreateVolumeSecret,
-					}
-
-					vol, err := c.CreateVolume(context.Background(), req)
-					Expect(err).NotTo(HaveOccurred())
-					Expect(vol).NotTo(BeNil())
-					// Register the volume so it's automatically cleaned
-					cl.RegisterVolume(vol.Volume.VolumeId, VolumeInfo{VolumeID: vol.Volume.VolumeId})
-					existing_vols[vol.Volume.VolumeId] = true
-				}
-			}
-
-			// Request list volumes with max entries maxEntries.
-			vols, err = c.ListVolumes(
-				context.Background(),
-				&csi.ListVolumesRequest{
-					MaxEntries: int32(maxEntries),
-				})
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vols).NotTo(BeNil())
-			Expect(len(vols.GetEntries())).To(Equal(maxEntries))
-
-			nextToken := vols.GetNextToken()
-
-			By("removing all listed volumes")
-			for _, vol := range vols.GetEntries() {
-				Expect(existing_vols[vol.Volume.VolumeId]).To(BeTrue())
-				delReq := &csi.DeleteVolumeRequest{
-					VolumeId: vol.Volume.VolumeId,
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				}
-
-				_, err := c.DeleteVolume(context.Background(), delReq)
-				Expect(err).NotTo(HaveOccurred())
-				vol_id := vol.Volume.VolumeId
-				existing_vols[vol_id] = false
-				cl.UnregisterVolume(vol_id)
-			}
-
-			By("creating a new volume")
-			req := &csi.CreateVolumeRequest{
-				Name: "new-addition",
-				VolumeCapabilities: []*csi.VolumeCapability{
-					{
-						AccessType: &csi.VolumeCapability_Mount{
-							Mount: &csi.VolumeCapability_MountVolume{},
-						},
-						AccessMode: &csi.VolumeCapability_AccessMode{
-							Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-						},
-					},
-				},
-				Secrets: sc.Secrets.CreateVolumeSecret,
-			}
-			vol, err := c.CreateVolume(context.Background(), req)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol).NotTo(BeNil())
-			Expect(vol.Volume).NotTo(BeNil())
-			// Register the volume so it's automatically cleaned
-			cl.RegisterVolume(vol.Volume.VolumeId, VolumeInfo{VolumeID: vol.Volume.VolumeId})
-			existing_vols[vol.Volume.VolumeId] = true
-
-			vols, err = c.ListVolumes(
-				context.Background(),
-				&csi.ListVolumesRequest{
-					StartingToken: nextToken,
-				})
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vols).NotTo(BeNil())
-			expected_num_volumes := minVolCount - maxEntries + 1
-			// Depending on the plugin implementation we may be missing volumes, but should not get duplicates
-			Expect(len(vols.GetEntries()) <= expected_num_volumes).To(BeTrue())
-			for _, vol := range vols.GetEntries() {
-				Expect(existing_vols[vol.Volume.VolumeId]).To(BeTrue())
-				existing_vols[vol.Volume.VolumeId] = false
-			}
-		})
-	})
-
-	Describe("CreateVolume", func() {
-		BeforeEach(func() {
-			if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME) {
-				Skip("CreateVolume not supported")
-			}
-		})
-
-		It("should fail when no name is provided", func() {
-			vol, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			cl.MaybeRegisterVolume("", vol, err)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		It("should fail when no volume capabilities are provided", func() {
-			name := UniqueString("sanity-controller-create-no-volume-capabilities")
-			vol, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name:       name,
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			cl.MaybeRegisterVolume(name, vol, err)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		It("should return appropriate values SingleNodeWriter NoCapacity Type:Mount", func() {
-
-			By("creating a volume")
-			name := UniqueString("sanity-controller-create-single-no-capacity")
-
-			vol, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol).NotTo(BeNil())
-			Expect(vol.GetVolume()).NotTo(BeNil())
-			Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-
-			By("cleaning up deleting the volume")
-
-			_, err = c.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.UnregisterVolume(name)
-		})
-
-		It("should return appropriate values SingleNodeWriter WithCapacity 1Gi Type:Mount", func() {
-
-			By("creating a volume")
-			name := UniqueString("sanity-controller-create-single-with-capacity")
-
-			vol, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					CapacityRange: &csi.CapacityRange{
-						RequiredBytes: TestVolumeSize(sc),
-					},
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			if serverError, ok := status.FromError(err); ok &&
-				(serverError.Code() == codes.OutOfRange || serverError.Code() == codes.Unimplemented) {
-				Skip("Required bytes not supported")
-			}
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol).NotTo(BeNil())
-			Expect(vol.GetVolume()).NotTo(BeNil())
-			Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-			Expect(vol.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", TestVolumeSize(sc)))
-
-			By("cleaning up deleting the volume")
-
-			_, err = c.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.UnregisterVolume(name)
-		})
-		It("should not fail when requesting to create a volume with already existing name and same capacity.", func() {
-
-			By("creating a volume")
-			name := UniqueString("sanity-controller-create-twice")
-			size := TestVolumeSize(sc)
-
-			vol1, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					CapacityRange: &csi.CapacityRange{
-						RequiredBytes: size,
-					},
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol1).NotTo(BeNil())
-			Expect(vol1.GetVolume()).NotTo(BeNil())
-			Expect(vol1.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol1.GetVolume().GetVolumeId()})
-			Expect(vol1.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", size))
-
-			vol2, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					CapacityRange: &csi.CapacityRange{
-						RequiredBytes: size,
-					},
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol2).NotTo(BeNil())
-			Expect(vol2.GetVolume()).NotTo(BeNil())
-			Expect(vol2.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			Expect(vol2.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", size))
-			Expect(vol1.GetVolume().GetVolumeId()).To(Equal(vol2.GetVolume().GetVolumeId()))
-
-			By("cleaning up deleting the volume")
-
-			_, err = c.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: vol1.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.UnregisterVolume(name)
-		})
-		It("should fail when requesting to create a volume with already existing name and different capacity.", func() {
-
-			By("creating a volume")
-			name := UniqueString("sanity-controller-create-twice-different")
-			size1 := TestVolumeSize(sc)
-
-			vol1, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					CapacityRange: &csi.CapacityRange{
-						RequiredBytes: size1,
-						LimitBytes:    size1,
-					},
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			Expect(err).ToNot(HaveOccurred())
-			Expect(vol1).NotTo(BeNil())
-			Expect(vol1.GetVolume()).NotTo(BeNil())
-			Expect(vol1.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol1.GetVolume().GetVolumeId()})
-			size2 := 2 * TestVolumeSize(sc)
-
-			_, err = c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					CapacityRange: &csi.CapacityRange{
-						RequiredBytes: size2,
-						LimitBytes:    size2,
-					},
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.AlreadyExists))
-
-			By("cleaning up deleting the volume")
-
-			_, err = c.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: vol1.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.UnregisterVolume(name)
-		})
-
-		It("should not fail when creating volume with maximum-length name", func() {
-
-			nameBytes := make([]byte, MaxNameLength)
-			for i := 0; i < MaxNameLength; i++ {
-				nameBytes[i] = 'a'
-			}
-			name := string(nameBytes)
-			By("creating a volume")
-			size := TestVolumeSize(sc)
-
-			vol, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					CapacityRange: &csi.CapacityRange{
-						RequiredBytes: size,
-					},
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol).NotTo(BeNil())
-			Expect(vol.GetVolume()).NotTo(BeNil())
-			Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-			Expect(vol.GetVolume().GetCapacityBytes()).To(BeNumerically(">=", size))
-
-			By("cleaning up deleting the volume")
-
-			_, err = c.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.UnregisterVolume(name)
-		})
-
-		It("should create volume from an existing source snapshot", func() {
-			if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT) {
-				Skip("Snapshot not supported")
-			}
-
-			By("creating a volume")
-			vol1Name := UniqueString("sanity-controller-source-vol")
-			vol1Req := MakeCreateVolumeReq(sc, vol1Name)
-			volume1, err := c.CreateVolume(context.Background(), vol1Req)
-			Expect(err).NotTo(HaveOccurred())
-
-			By("creating a snapshot")
-			snapName := UniqueString("sanity-controller-snap-from-vol")
-			snapReq := MakeCreateSnapshotReq(sc, snapName, volume1.GetVolume().GetVolumeId())
-			snap, err := c.CreateSnapshot(context.Background(), snapReq)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(snap).NotTo(BeNil())
-			verifySnapshotInfo(snap.GetSnapshot())
-
-			By("creating a volume from source snapshot")
-			vol2Name := UniqueString("sanity-controller-vol-from-snap")
-			vol2Req := MakeCreateVolumeReq(sc, vol2Name)
-			vol2Req.VolumeContentSource = &csi.VolumeContentSource{
-				Type: &csi.VolumeContentSource_Snapshot{
-					Snapshot: &csi.VolumeContentSource_SnapshotSource{
-						SnapshotId: snap.GetSnapshot().GetSnapshotId(),
-					},
-				},
-			}
-			volume2, err := c.CreateVolume(context.Background(), vol2Req)
-			Expect(err).NotTo(HaveOccurred())
-
-			By("cleaning up deleting the volume created from snapshot")
-			delVol2Req := MakeDeleteVolumeReq(sc, volume2.GetVolume().GetVolumeId())
-			_, err = c.DeleteVolume(context.Background(), delVol2Req)
-			Expect(err).NotTo(HaveOccurred())
-
-			By("cleaning up deleting the snapshot")
-			delSnapReq := MakeDeleteSnapshotReq(sc, snap.GetSnapshot().GetSnapshotId())
-			_, err = c.DeleteSnapshot(context.Background(), delSnapReq)
-			Expect(err).NotTo(HaveOccurred())
-
-			By("cleaning up deleting the source volume")
-			delVol1Req := MakeDeleteVolumeReq(sc, volume1.GetVolume().GetVolumeId())
-			_, err = c.DeleteVolume(context.Background(), delVol1Req)
-			Expect(err).NotTo(HaveOccurred())
-		})
-
-		It("should fail when the volume source snapshot is not found", func() {
-			if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT) {
-				Skip("Snapshot not supported")
-			}
-
-			By("creating a volume from source snapshot")
-			volName := UniqueString("sanity-controller-vol-from-snap")
-			volReq := MakeCreateVolumeReq(sc, volName)
-			volReq.VolumeContentSource = &csi.VolumeContentSource{
-				Type: &csi.VolumeContentSource_Snapshot{
-					Snapshot: &csi.VolumeContentSource_SnapshotSource{
-						SnapshotId: "non-existing-snapshot-id",
-					},
-				},
-			}
-			_, err := c.CreateVolume(context.Background(), volReq)
-			Expect(err).To(HaveOccurred())
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.NotFound))
-		})
-
-		It("should create volume from an existing source volume", func() {
-			if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CLONE_VOLUME) {
-				Skip("Volume Cloning not supported")
-			}
-
-			By("creating a volume")
-			vol1Name := UniqueString("sanity-controller-source-vol")
-			vol1Req := MakeCreateVolumeReq(sc, vol1Name)
-			volume1, err := c.CreateVolume(context.Background(), vol1Req)
-			Expect(err).NotTo(HaveOccurred())
-
-			By("creating a volume from source volume")
-			vol2Name := UniqueString("sanity-controller-vol-from-vol")
-			vol2Req := MakeCreateVolumeReq(sc, vol2Name)
-			vol2Req.VolumeContentSource = &csi.VolumeContentSource{
-				Type: &csi.VolumeContentSource_Volume{
-					Volume: &csi.VolumeContentSource_VolumeSource{
-						VolumeId: volume1.GetVolume().GetVolumeId(),
-					},
-				},
-			}
-			volume2, err := c.CreateVolume(context.Background(), vol2Req)
-			Expect(err).NotTo(HaveOccurred())
-
-			By("cleaning up deleting the volume created from source volume")
-			delVol2Req := MakeDeleteVolumeReq(sc, volume2.GetVolume().GetVolumeId())
-			_, err = c.DeleteVolume(context.Background(), delVol2Req)
-			Expect(err).NotTo(HaveOccurred())
-
-			By("cleaning up deleting the source volume")
-			delVol1Req := MakeDeleteVolumeReq(sc, volume1.GetVolume().GetVolumeId())
-			_, err = c.DeleteVolume(context.Background(), delVol1Req)
-			Expect(err).NotTo(HaveOccurred())
-		})
-
-		It("should fail when the volume source volume is not found", func() {
-			if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CLONE_VOLUME) {
-				Skip("Volume Cloning not supported")
-			}
-
-			By("creating a volume from source snapshot")
-			volName := UniqueString("sanity-controller-vol-from-snap")
-			volReq := MakeCreateVolumeReq(sc, volName)
-			volReq.VolumeContentSource = &csi.VolumeContentSource{
-				Type: &csi.VolumeContentSource_Volume{
-					Volume: &csi.VolumeContentSource_VolumeSource{
-						VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
-					},
-				},
-			}
-			_, err := c.CreateVolume(context.Background(), volReq)
-			Expect(err).To(HaveOccurred())
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.NotFound))
-		})
-	})
-
-	Describe("DeleteVolume", func() {
-		BeforeEach(func() {
-			if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME) {
-				Skip("DeleteVolume not supported")
-			}
-		})
-
-		It("should fail when no volume id is provided", func() {
-
-			_, err := c.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					Secrets: sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		It("should succeed when an invalid volume id is used", func() {
-
-			_, err := c.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: sc.Config.IDGen.GenerateInvalidVolumeID(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-		})
-
-		It("should return appropriate values (no optional values added)", func() {
-
-			// Create Volume First
-			By("creating a volume")
-			name := UniqueString("sanity-controller-create-appropriate")
-
-			vol, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol).NotTo(BeNil())
-			Expect(vol.GetVolume()).NotTo(BeNil())
-			Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-
-			// Delete Volume
-			By("deleting a volume")
-
-			_, err = c.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.UnregisterVolume(name)
-		})
-	})
-
-	Describe("ValidateVolumeCapabilities", func() {
-		It("should fail when no volume id is provided", func() {
-
-			_, err := c.ValidateVolumeCapabilities(
-				context.Background(),
-				&csi.ValidateVolumeCapabilitiesRequest{
-					Secrets: sc.Secrets.ControllerValidateVolumeCapabilitiesSecret,
-				})
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		It("should fail when no volume capabilities are provided", func() {
-
-			// Create Volume First
-			By("creating a single node writer volume")
-			name := UniqueString("sanity-controller-validate-nocaps")
-
-			vol, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol).NotTo(BeNil())
-			Expect(vol.GetVolume()).NotTo(BeNil())
-			Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-
-			_, err = c.ValidateVolumeCapabilities(
-				context.Background(),
-				&csi.ValidateVolumeCapabilitiesRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.ControllerValidateVolumeCapabilitiesSecret,
-				})
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-
-			By("cleaning up deleting the volume")
-
-			_, err = c.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.UnregisterVolume(name)
-		})
-
-		It("should return appropriate values (no optional values added)", func() {
-
-			// Create Volume First
-			By("creating a single node writer volume")
-			name := UniqueString("sanity-controller-validate")
-
-			vol, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol).NotTo(BeNil())
-			Expect(vol.GetVolume()).NotTo(BeNil())
-			Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-
-			// ValidateVolumeCapabilities
-			By("validating volume capabilities")
-			valivolcap, err := c.ValidateVolumeCapabilities(
-				context.Background(),
-				&csi.ValidateVolumeCapabilitiesRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					Secrets: sc.Secrets.ControllerValidateVolumeCapabilitiesSecret,
-				})
-			Expect(err).NotTo(HaveOccurred())
-			Expect(valivolcap).NotTo(BeNil())
-
-			// If confirmation is provided then it is REQUIRED to provide
-			// the volume capabilities
-			if valivolcap.GetConfirmed() != nil {
-				Expect(valivolcap.GetConfirmed().GetVolumeCapabilities()).NotTo(BeEmpty())
-			}
-
-			By("cleaning up deleting the volume")
-
-			_, err = c.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.UnregisterVolume(name)
-		})
-
-		It("should fail when the requested volume does not exist", func() {
-
-			_, err := c.ValidateVolumeCapabilities(
-				context.Background(),
-				&csi.ValidateVolumeCapabilitiesRequest{
-					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					Secrets: sc.Secrets.ControllerValidateVolumeCapabilitiesSecret,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.NotFound))
-		})
-	})
-
-	Describe("ControllerPublishVolume", func() {
-		BeforeEach(func() {
-			if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME) {
-				Skip("ControllerPublishVolume not supported")
-			}
-		})
-
-		It("should fail when no volume id is provided", func() {
-
-			_, err := c.ControllerPublishVolume(
-				context.Background(),
-				&csi.ControllerPublishVolumeRequest{
-					Secrets: sc.Secrets.ControllerPublishVolumeSecret,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		It("should fail when no node id is provided", func() {
-
-			_, err := c.ControllerPublishVolume(
-				context.Background(),
-				&csi.ControllerPublishVolumeRequest{
-					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
-					Secrets:  sc.Secrets.ControllerPublishVolumeSecret,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		It("should fail when no volume capability is provided", func() {
-
-			_, err := c.ControllerPublishVolume(
-				context.Background(),
-				&csi.ControllerPublishVolumeRequest{
-					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
-					NodeId:   sc.Config.IDGen.GenerateUniqueValidNodeID(),
-					Secrets:  sc.Secrets.ControllerPublishVolumeSecret,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		// CSI spec poses no specific requirements for the cluster/storage setups that a SP MUST support. To perform
-		// meaningful checks the following test assumes that topology-aware provisioning on a single node setup is supported
-		It("should return appropriate values (no optional values added)", func() {
-
-			By("getting node information")
-			ni, err := n.NodeGetInfo(
-				context.Background(),
-				&csi.NodeGetInfoRequest{})
-			Expect(err).NotTo(HaveOccurred())
-			Expect(ni).NotTo(BeNil())
-			Expect(ni.GetNodeId()).NotTo(BeEmpty())
-
-			var accReqs *csi.TopologyRequirement
-			if ni.AccessibleTopology != nil {
-				// Topology requirements are honored if provided by the driver
-				accReqs = &csi.TopologyRequirement{
-					Requisite: []*csi.Topology{ni.AccessibleTopology},
-				}
-			}
-
-			// Create Volume First
-			By("creating a single node writer volume")
-			name := UniqueString("sanity-controller-publish")
-
-			vol, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					Secrets:                   sc.Secrets.CreateVolumeSecret,
-					Parameters:                sc.Config.TestVolumeParameters,
-					AccessibilityRequirements: accReqs,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol).NotTo(BeNil())
-			Expect(vol.GetVolume()).NotTo(BeNil())
-			Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-
-			// ControllerPublishVolume
-			By("calling controllerpublish on that volume")
-
-			conpubvol, err := c.ControllerPublishVolume(
-				context.Background(),
-				&csi.ControllerPublishVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					NodeId:   ni.GetNodeId(),
-					VolumeCapability: &csi.VolumeCapability{
-						AccessType: &csi.VolumeCapability_Mount{
-							Mount: &csi.VolumeCapability_MountVolume{},
-						},
-						AccessMode: &csi.VolumeCapability_AccessMode{
-							Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-						},
-					},
-					Readonly: false,
-					Secrets:  sc.Secrets.ControllerPublishVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId(), NodeID: ni.GetNodeId()})
-			Expect(conpubvol).NotTo(BeNil())
-
-			By("cleaning up unpublishing the volume")
-
-			conunpubvol, err := c.ControllerUnpublishVolume(
-				context.Background(),
-				&csi.ControllerUnpublishVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					// NodeID is optional in ControllerUnpublishVolume
-					NodeId:  ni.GetNodeId(),
-					Secrets: sc.Secrets.ControllerUnpublishVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(conunpubvol).NotTo(BeNil())
-
-			By("cleaning up deleting the volume")
-
-			_, err = c.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.UnregisterVolume(name)
-		})
-
-		It("should fail when publishing more volumes than the node max attach limit", func() {
-			if !sc.Config.TestNodeVolumeAttachLimit {
-				Skip("testnodevolumeattachlimit not enabled")
-			}
-
-			By("getting node info")
-			nodeInfo, err := n.NodeGetInfo(
-				context.Background(),
-				&csi.NodeGetInfoRequest{})
-			Expect(err).NotTo(HaveOccurred())
-			Expect(nodeInfo).NotTo(BeNil())
-
-			if nodeInfo.MaxVolumesPerNode <= 0 {
-				Skip("No MaxVolumesPerNode")
-			}
-
-			nid := nodeInfo.GetNodeId()
-			Expect(nid).NotTo(BeEmpty())
-
-			// Store the volume name and volume ID for later cleanup.
-			createdVols := map[string]string{}
-			By("creating volumes")
-			for i := int64(0); i < nodeInfo.MaxVolumesPerNode; i++ {
-				name := UniqueString(fmt.Sprintf("sanity-max-attach-limit-vol-%d", i))
-				volID, err := CreateAndControllerPublishVolume(sc, c, name, nid)
-				Expect(err).NotTo(HaveOccurred())
-				cl.RegisterVolume(name, VolumeInfo{VolumeID: volID, NodeID: nid})
-				createdVols[name] = volID
-			}
-
-			extraVolName := UniqueString("sanity-max-attach-limit-vol+1")
-			_, err = CreateAndControllerPublishVolume(sc, c, extraVolName, nid)
-			Expect(err).To(HaveOccurred())
-
-			By("cleaning up")
-			for volName, volID := range createdVols {
-				err = ControllerUnpublishAndDeleteVolume(sc, c, volID, nid)
-				Expect(err).NotTo(HaveOccurred())
-				cl.UnregisterVolume(volName)
-			}
-		})
-
-		It("should fail when the volume does not exist", func() {
-
-			By("calling controller publish on a non-existent volume")
-
-			conpubvol, err := c.ControllerPublishVolume(
-				context.Background(),
-				&csi.ControllerPublishVolumeRequest{
-					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
-					NodeId:   sc.Config.IDGen.GenerateUniqueValidNodeID(),
-					VolumeCapability: &csi.VolumeCapability{
-						AccessType: &csi.VolumeCapability_Mount{
-							Mount: &csi.VolumeCapability_MountVolume{},
-						},
-						AccessMode: &csi.VolumeCapability_AccessMode{
-							Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-						},
-					},
-					Readonly: false,
-					Secrets:  sc.Secrets.ControllerPublishVolumeSecret,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-			Expect(conpubvol).To(BeNil())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.NotFound))
-		})
-
-		It("should fail when the node does not exist", func() {
-
-			// Create Volume First
-			By("creating a single node writer volume")
-			name := UniqueString("sanity-controller-wrong-node")
-
-			vol, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol).NotTo(BeNil())
-			Expect(vol.GetVolume()).NotTo(BeNil())
-			Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-
-			// ControllerPublishVolume
-			By("calling controllerpublish on that volume")
-
-			conpubvol, err := c.ControllerPublishVolume(
-				context.Background(),
-				&csi.ControllerPublishVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					NodeId:   sc.Config.IDGen.GenerateUniqueValidNodeID(),
-					VolumeCapability: &csi.VolumeCapability{
-						AccessType: &csi.VolumeCapability_Mount{
-							Mount: &csi.VolumeCapability_MountVolume{},
-						},
-						AccessMode: &csi.VolumeCapability_AccessMode{
-							Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-						},
-					},
-					Readonly: false,
-					Secrets:  sc.Secrets.ControllerPublishVolumeSecret,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-			Expect(conpubvol).To(BeNil())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.NotFound))
-
-			By("cleaning up deleting the volume")
-
-			_, err = c.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.UnregisterVolume(name)
-		})
-
-		It("should fail when the volume is already published but is incompatible", func() {
-			if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_PUBLISH_READONLY) {
-				Skip("ControllerPublishVolume.readonly field not supported")
-			}
-
-			// Create Volume First
-			By("creating a single node writer volume")
-			name := UniqueString("sanity-controller-published-incompatible")
-
-			vol, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol).NotTo(BeNil())
-			Expect(vol.GetVolume()).NotTo(BeNil())
-			Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-
-			By("getting a node id")
-			nid, err := n.NodeGetInfo(
-				context.Background(),
-				&csi.NodeGetInfoRequest{})
-			Expect(err).NotTo(HaveOccurred())
-			Expect(nid).NotTo(BeNil())
-			Expect(nid.GetNodeId()).NotTo(BeEmpty())
-
-			// ControllerPublishVolume
-			By("calling controllerpublish on that volume")
-
-			pubReq := &csi.ControllerPublishVolumeRequest{
-				VolumeId: vol.GetVolume().GetVolumeId(),
-				NodeId:   nid.GetNodeId(),
-				VolumeCapability: &csi.VolumeCapability{
-					AccessType: &csi.VolumeCapability_Mount{
-						Mount: &csi.VolumeCapability_MountVolume{},
-					},
-					AccessMode: &csi.VolumeCapability_AccessMode{
-						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-					},
-				},
-				Readonly: false,
-				Secrets:  sc.Secrets.ControllerPublishVolumeSecret,
-			}
-
-			conpubvol, err := c.ControllerPublishVolume(context.Background(), pubReq)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(conpubvol).NotTo(BeNil())
-
-			// Publish again with different attributes.
-			pubReq.Readonly = true
-
-			conpubvol, err = c.ControllerPublishVolume(context.Background(), pubReq)
-			Expect(err).To(HaveOccurred())
-			Expect(conpubvol).To(BeNil())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.AlreadyExists))
-
-			By("cleaning up unpublishing the volume")
-
-			conunpubvol, err := c.ControllerUnpublishVolume(
-				context.Background(),
-				&csi.ControllerUnpublishVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					// NodeID is optional in ControllerUnpublishVolume
-					NodeId:  nid.GetNodeId(),
-					Secrets: sc.Secrets.ControllerUnpublishVolumeSecret,
-				},
-			)
-
-			Expect(err).NotTo(HaveOccurred())
-			Expect(conunpubvol).NotTo(BeNil())
-
-			By("cleaning up deleting the volume")
-
-			_, err = c.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.UnregisterVolume(name)
-		})
-	})
-
-	Describe("ControllerUnpublishVolume", func() {
-		BeforeEach(func() {
-			if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME) {
-				Skip("ControllerUnpublishVolume not supported")
-			}
-		})
-
-		It("should fail when no volume id is provided", func() {
-
-			_, err := c.ControllerUnpublishVolume(
-				context.Background(),
-				&csi.ControllerUnpublishVolumeRequest{
-					Secrets: sc.Secrets.ControllerUnpublishVolumeSecret,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		// CSI spec poses no specific requirements for the cluster/storage setups that a SP MUST support. To perform
-		// meaningful checks the following test assumes that topology-aware provisioning on a single node setup is supported
-		It("should return appropriate values (no optional values added)", func() {
-
-			// Create Volume First
-			By("creating a single node writer volume")
-			name := UniqueString("sanity-controller-unpublish")
-
-			By("getting node information")
-			ni, err := n.NodeGetInfo(
-				context.Background(),
-				&csi.NodeGetInfoRequest{})
-			Expect(err).NotTo(HaveOccurred())
-			Expect(ni).NotTo(BeNil())
-			Expect(ni.GetNodeId()).NotTo(BeEmpty())
-
-			var accReqs *csi.TopologyRequirement
-			if ni.AccessibleTopology != nil {
-				// Topology requirements are honored if provided by the driver
-				accReqs = &csi.TopologyRequirement{
-					Requisite: []*csi.Topology{ni.AccessibleTopology},
-				}
-			}
-
-			vol, err := c.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					Secrets:                   sc.Secrets.CreateVolumeSecret,
-					Parameters:                sc.Config.TestVolumeParameters,
-					AccessibilityRequirements: accReqs,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol).NotTo(BeNil())
-			Expect(vol.GetVolume()).NotTo(BeNil())
-			Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-
-			// ControllerPublishVolume
-			By("calling controllerpublish on that volume")
-
-			conpubvol, err := c.ControllerPublishVolume(
-				context.Background(),
-				&csi.ControllerPublishVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					NodeId:   ni.GetNodeId(),
-					VolumeCapability: &csi.VolumeCapability{
-						AccessType: &csi.VolumeCapability_Mount{
-							Mount: &csi.VolumeCapability_MountVolume{},
-						},
-						AccessMode: &csi.VolumeCapability_AccessMode{
-							Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-						},
-					},
-					Readonly: false,
-					Secrets:  sc.Secrets.ControllerPublishVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId(), NodeID: ni.GetNodeId()})
-			Expect(conpubvol).NotTo(BeNil())
-
-			// ControllerUnpublishVolume
-			By("calling controllerunpublish on that volume")
-
-			conunpubvol, err := c.ControllerUnpublishVolume(
-				context.Background(),
-				&csi.ControllerUnpublishVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					// NodeID is optional in ControllerUnpublishVolume
-					NodeId:  ni.GetNodeId(),
-					Secrets: sc.Secrets.ControllerUnpublishVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(conunpubvol).NotTo(BeNil())
-
-			By("cleaning up deleting the volume")
-
-			_, err = c.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.UnregisterVolume(name)
-		})
-	})
-})
-
-var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *TestContext) {
-	var (
-		c csi.ControllerClient
-	)
-
-	BeforeEach(func() {
-		c = csi.NewControllerClient(sc.ControllerConn)
-
-		if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS) {
-			Skip("ListSnapshots not supported")
-		}
-	})
-
-	It("should return appropriate values (no optional values added)", func() {
-		snapshots, err := c.ListSnapshots(
-			context.Background(),
-			&csi.ListSnapshotsRequest{})
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snapshots).NotTo(BeNil())
-
-		for _, snapshot := range snapshots.GetEntries() {
-			verifySnapshotInfo(snapshot.GetSnapshot())
-		}
-	})
-
-	It("should return snapshots that match the specified snapshot id", func() {
-
-		By("creating a volume")
-		volReq := MakeCreateVolumeReq(sc, "listSnapshots-volume-1")
-		volume, err := c.CreateVolume(context.Background(), volReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		By("creating a snapshot")
-		snapshotReq := MakeCreateSnapshotReq(sc, "listSnapshots-snapshot-1", volume.GetVolume().GetVolumeId())
-		snapshot, err := c.CreateSnapshot(context.Background(), snapshotReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		snapshots, err := c.ListSnapshots(
-			context.Background(),
-			&csi.ListSnapshotsRequest{SnapshotId: snapshot.GetSnapshot().GetSnapshotId()})
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snapshots).NotTo(BeNil())
-		Expect(len(snapshots.GetEntries())).To(BeNumerically("==", 1))
-		verifySnapshotInfo(snapshots.GetEntries()[0].GetSnapshot())
-		Expect(snapshots.GetEntries()[0].GetSnapshot().GetSnapshotId()).To(Equal(snapshot.GetSnapshot().GetSnapshotId()))
-
-		By("cleaning up deleting the snapshot")
-		delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetSnapshotId())
-		_, err = c.DeleteSnapshot(context.Background(), delSnapReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		By("cleaning up deleting the volume")
-		delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId())
-		_, err = c.DeleteVolume(context.Background(), delVolReq)
-		Expect(err).NotTo(HaveOccurred())
-	})
-
-	It("should return empty when the specified snapshot id does not exist", func() {
-
-		snapshots, err := c.ListSnapshots(
-			context.Background(),
-			&csi.ListSnapshotsRequest{SnapshotId: "none-exist-id"})
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snapshots).NotTo(BeNil())
-		Expect(snapshots.GetEntries()).To(BeEmpty())
-	})
-
-	It("should return snapshots that match the specified source volume id)", func() {
-
-		By("creating a volume")
-		volReq := MakeCreateVolumeReq(sc, "listSnapshots-volume-2")
-		volume, err := c.CreateVolume(context.Background(), volReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		By("creating a snapshot")
-		snapshotReq := MakeCreateSnapshotReq(sc, "listSnapshots-snapshot-2", volume.GetVolume().GetVolumeId())
-		snapshot, err := c.CreateSnapshot(context.Background(), snapshotReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		snapshots, err := c.ListSnapshots(
-			context.Background(),
-			&csi.ListSnapshotsRequest{SourceVolumeId: snapshot.GetSnapshot().GetSourceVolumeId()})
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snapshots).NotTo(BeNil())
-		for _, snap := range snapshots.GetEntries() {
-			verifySnapshotInfo(snap.GetSnapshot())
-			Expect(snap.GetSnapshot().GetSourceVolumeId()).To(Equal(snapshot.GetSnapshot().GetSourceVolumeId()))
-		}
-
-		By("cleaning up deleting the snapshot")
-		delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetSnapshotId())
-		_, err = c.DeleteSnapshot(context.Background(), delSnapReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		By("cleaning up deleting the volume")
-		delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId())
-		_, err = c.DeleteVolume(context.Background(), delVolReq)
-		Expect(err).NotTo(HaveOccurred())
-	})
-
-	It("should return empty when the specified source volume id does not exist", func() {
-
-		snapshots, err := c.ListSnapshots(
-			context.Background(),
-			&csi.ListSnapshotsRequest{SourceVolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID()})
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snapshots).NotTo(BeNil())
-		Expect(snapshots.GetEntries()).To(BeEmpty())
-	})
-
-	It("check the presence of new snapshots in the snapshot list", func() {
-		// List Snapshots before creating new snapshots.
-		snapshots, err := c.ListSnapshots(
-			context.Background(),
-			&csi.ListSnapshotsRequest{})
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snapshots).NotTo(BeNil())
-
-		totalSnapshots := len(snapshots.GetEntries())
-
-		By("creating a volume")
-		volReq := MakeCreateVolumeReq(sc, "listSnapshots-volume-3")
-		volume, err := c.CreateVolume(context.Background(), volReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		By("creating a snapshot")
-		snapReq := MakeCreateSnapshotReq(sc, "listSnapshots-snapshot-3", volume.GetVolume().GetVolumeId())
-		snapshot, err := c.CreateSnapshot(context.Background(), snapReq)
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snapshot).NotTo(BeNil())
-		verifySnapshotInfo(snapshot.GetSnapshot())
-
-		snapshots, err = c.ListSnapshots(
-			context.Background(),
-			&csi.ListSnapshotsRequest{})
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snapshots).NotTo(BeNil())
-		Expect(len(snapshots.GetEntries())).To(Equal(totalSnapshots + 1))
-
-		By("cleaning up deleting the snapshot")
-		delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetSnapshotId())
-		_, err = c.DeleteSnapshot(context.Background(), delSnapReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		By("cleaning up deleting the volume")
-		delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId())
-		_, err = c.DeleteVolume(context.Background(), delVolReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		// List snapshots and check if the deleted snapshot exists in the snapshot list.
-		snapshots, err = c.ListSnapshots(
-			context.Background(),
-			&csi.ListSnapshotsRequest{})
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snapshots).NotTo(BeNil())
-		Expect(len(snapshots.GetEntries())).To(Equal(totalSnapshots))
-	})
-
-	It("should return next token when a limited number of entries are requested", func() {
-		// minSnapshotCount is the minimum number of snapshots expected to exist,
-		// based on which paginated snapshot listing is performed.
-		minSnapshotCount := 5
-		// maxEntried is the maximum entries in list snapshot request.
-		maxEntries := 2
-		// currentTotalVols is the total number of volumes at a given time. It
-		// is used to verify that all the snapshots have been listed.
-		currentTotalSnapshots := 0
-
-		// Get the number of existing volumes.
-		snapshots, err := c.ListSnapshots(
-			context.Background(),
-			&csi.ListSnapshotsRequest{})
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snapshots).NotTo(BeNil())
-
-		initialTotalSnapshots := len(snapshots.GetEntries())
-		currentTotalSnapshots = initialTotalSnapshots
-
-		createVols := make([]*csi.Volume, 0)
-		createSnapshots := make([]*csi.Snapshot, 0)
-
-		// Ensure minimum minVolCount volumes exist.
-		if initialTotalSnapshots < minSnapshotCount {
-
-			By("creating required new volumes")
-			requiredSnapshots := minSnapshotCount - initialTotalSnapshots
-
-			for i := 1; i <= requiredSnapshots; i++ {
-				volReq := MakeCreateVolumeReq(sc, "volume"+strconv.Itoa(i))
-				volume, err := c.CreateVolume(context.Background(), volReq)
-				Expect(err).NotTo(HaveOccurred())
-				Expect(volume).NotTo(BeNil())
-				createVols = append(createVols, volume.GetVolume())
-
-				snapReq := MakeCreateSnapshotReq(sc, "snapshot"+strconv.Itoa(i), volume.GetVolume().GetVolumeId())
-				snapshot, err := c.CreateSnapshot(context.Background(), snapReq)
-				Expect(err).NotTo(HaveOccurred())
-				Expect(snapshot).NotTo(BeNil())
-				verifySnapshotInfo(snapshot.GetSnapshot())
-				createSnapshots = append(createSnapshots, snapshot.GetSnapshot())
-			}
-
-			// Update the current total snapshots count.
-			currentTotalSnapshots += requiredSnapshots
-		}
-
-		// Request list snapshots with max entries maxEntries.
-		snapshots, err = c.ListSnapshots(
-			context.Background(),
-			&csi.ListSnapshotsRequest{
-				MaxEntries: int32(maxEntries),
-			})
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snapshots).NotTo(BeNil())
-
-		nextToken := snapshots.GetNextToken()
-
-		Expect(len(snapshots.GetEntries())).To(Equal(maxEntries))
-
-		// Request list snapshots with starting_token and no max entries.
-		snapshots, err = c.ListSnapshots(
-			context.Background(),
-			&csi.ListSnapshotsRequest{
-				StartingToken: nextToken,
-			})
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snapshots).NotTo(BeNil())
-
-		// Ensure that all the remaining entries are returned at once.
-		Expect(len(snapshots.GetEntries())).To(Equal(currentTotalSnapshots - maxEntries))
-
-		if initialTotalSnapshots < minSnapshotCount {
-
-			By("cleaning up deleting the snapshots")
-
-			for _, snap := range createSnapshots {
-				delSnapReq := MakeDeleteSnapshotReq(sc, snap.GetSnapshotId())
-				_, err = c.DeleteSnapshot(context.Background(), delSnapReq)
-				Expect(err).NotTo(HaveOccurred())
-			}
-
-			By("cleaning up deleting the volumes")
-
-			for _, vol := range createVols {
-				delVolReq := MakeDeleteVolumeReq(sc, vol.GetVolumeId())
-				_, err = c.DeleteVolume(context.Background(), delVolReq)
-				Expect(err).NotTo(HaveOccurred())
-			}
-		}
-	})
-
-})
-
-var _ = DescribeSanity("DeleteSnapshot [Controller Server]", func(sc *TestContext) {
-	var (
-		c csi.ControllerClient
-	)
-
-	BeforeEach(func() {
-		c = csi.NewControllerClient(sc.ControllerConn)
-
-		if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT) {
-			Skip("DeleteSnapshot not supported")
-		}
-	})
-
-	It("should fail when no snapshot id is provided", func() {
-
-		req := &csi.DeleteSnapshotRequest{}
-
-		if sc.Secrets != nil {
-			req.Secrets = sc.Secrets.DeleteSnapshotSecret
-		}
-
-		_, err := c.DeleteSnapshot(context.Background(), req)
-		Expect(err).To(HaveOccurred())
-
-		serverError, ok := status.FromError(err)
-		Expect(ok).To(BeTrue())
-		Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-	})
-
-	It("should succeed when an invalid snapshot id is used", func() {
-
-		req := MakeDeleteSnapshotReq(sc, "reallyfakesnapshotid")
-		_, err := c.DeleteSnapshot(context.Background(), req)
-		Expect(err).NotTo(HaveOccurred())
-	})
-
-	It("should return appropriate values (no optional values added)", func() {
-
-		By("creating a volume")
-		volReq := MakeCreateVolumeReq(sc, "DeleteSnapshot-volume-1")
-		volume, err := c.CreateVolume(context.Background(), volReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		// Create Snapshot First
-		By("creating a snapshot")
-		snapshotReq := MakeCreateSnapshotReq(sc, "DeleteSnapshot-snapshot-1", volume.GetVolume().GetVolumeId())
-		snapshot, err := c.CreateSnapshot(context.Background(), snapshotReq)
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snapshot).NotTo(BeNil())
-		verifySnapshotInfo(snapshot.GetSnapshot())
-
-		By("cleaning up deleting the snapshot")
-		delSnapReq := MakeDeleteSnapshotReq(sc, snapshot.GetSnapshot().GetSnapshotId())
-		_, err = c.DeleteSnapshot(context.Background(), delSnapReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		By("cleaning up deleting the volume")
-		delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId())
-		_, err = c.DeleteVolume(context.Background(), delVolReq)
-		Expect(err).NotTo(HaveOccurred())
-	})
-})
-
-var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *TestContext) {
-	var (
-		c csi.ControllerClient
-	)
-
-	BeforeEach(func() {
-		c = csi.NewControllerClient(sc.ControllerConn)
-
-		if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT) {
-			Skip("CreateSnapshot not supported")
-		}
-	})
-
-	It("should fail when no name is provided", func() {
-
-		req := &csi.CreateSnapshotRequest{
-			SourceVolumeId: "testId",
-		}
-
-		if sc.Secrets != nil {
-			req.Secrets = sc.Secrets.CreateSnapshotSecret
-		}
-
-		_, err := c.CreateSnapshot(context.Background(), req)
-		Expect(err).To(HaveOccurred())
-		serverError, ok := status.FromError(err)
-		Expect(ok).To(BeTrue())
-		Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-	})
-
-	It("should fail when no source volume id is provided", func() {
-
-		req := &csi.CreateSnapshotRequest{
-			Name: "name",
-		}
-
-		if sc.Secrets != nil {
-			req.Secrets = sc.Secrets.CreateSnapshotSecret
-		}
-
-		_, err := c.CreateSnapshot(context.Background(), req)
-		Expect(err).To(HaveOccurred())
-		serverError, ok := status.FromError(err)
-		Expect(ok).To(BeTrue())
-		Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-	})
-
-	It("should not fail when requesting to create a snapshot with already existing name and same SourceVolumeId.", func() {
-
-		By("creating a volume")
-		volReq := MakeCreateVolumeReq(sc, "CreateSnapshot-volume-1")
-		volume, err := c.CreateVolume(context.Background(), volReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		By("creating a snapshot")
-		snapReq1 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-1", volume.GetVolume().GetVolumeId())
-		snap1, err := c.CreateSnapshot(context.Background(), snapReq1)
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snap1).NotTo(BeNil())
-		verifySnapshotInfo(snap1.GetSnapshot())
-
-		snap2, err := c.CreateSnapshot(context.Background(), snapReq1)
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snap2).NotTo(BeNil())
-		verifySnapshotInfo(snap2.GetSnapshot())
-
-		By("cleaning up deleting the snapshot")
-		delSnapReq := MakeDeleteSnapshotReq(sc, snap1.GetSnapshot().GetSnapshotId())
-		_, err = c.DeleteSnapshot(context.Background(), delSnapReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		By("cleaning up deleting the volume")
-		delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId())
-		_, err = c.DeleteVolume(context.Background(), delVolReq)
-		Expect(err).NotTo(HaveOccurred())
-	})
-
-	It("should fail when requesting to create a snapshot with already existing name and different SourceVolumeId.", func() {
-
-		By("creating a volume")
-		volume, err := c.CreateVolume(context.Background(), MakeCreateVolumeReq(sc, "CreateSnapshot-volume-2"))
-		Expect(err).ToNot(HaveOccurred())
-
-		By("creating a snapshot with the created volume source id")
-		req1 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-2", volume.GetVolume().GetVolumeId())
-		snap1, err := c.CreateSnapshot(context.Background(), req1)
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snap1).NotTo(BeNil())
-		verifySnapshotInfo(snap1.GetSnapshot())
-
-		volume2, err := c.CreateVolume(context.Background(), MakeCreateVolumeReq(sc, "CreateSnapshot-volume-3"))
-		Expect(err).ToNot(HaveOccurred())
-
-		By("creating a snapshot with the same name but different volume source id")
-		req2 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-2", volume2.GetVolume().GetVolumeId())
-		_, err = c.CreateSnapshot(context.Background(), req2)
-		Expect(err).To(HaveOccurred())
-		serverError, ok := status.FromError(err)
-		Expect(ok).To(BeTrue())
-		Expect(serverError.Code()).To(Equal(codes.AlreadyExists))
-
-		By("cleaning up deleting the snapshot")
-		delSnapReq := MakeDeleteSnapshotReq(sc, snap1.GetSnapshot().GetSnapshotId())
-		_, err = c.DeleteSnapshot(context.Background(), delSnapReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		By("cleaning up deleting the volume")
-		delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId())
-		_, err = c.DeleteVolume(context.Background(), delVolReq)
-		Expect(err).NotTo(HaveOccurred())
-	})
-
-	It("should not fail when creating snapshot with maximum-length name", func() {
-
-		By("creating a volume")
-		volReq := MakeCreateVolumeReq(sc, "CreateSnapshot-volume-3")
-		volume, err := c.CreateVolume(context.Background(), volReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		nameBytes := make([]byte, MaxNameLength)
-		for i := 0; i < MaxNameLength; i++ {
-			nameBytes[i] = 'a'
-		}
-		name := string(nameBytes)
-
-		By("creating a snapshot")
-		snapReq1 := MakeCreateSnapshotReq(sc, name, volume.GetVolume().GetVolumeId())
-		snap1, err := c.CreateSnapshot(context.Background(), snapReq1)
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snap1).NotTo(BeNil())
-		verifySnapshotInfo(snap1.GetSnapshot())
-
-		snap2, err := c.CreateSnapshot(context.Background(), snapReq1)
-		Expect(err).NotTo(HaveOccurred())
-		Expect(snap2).NotTo(BeNil())
-		verifySnapshotInfo(snap2.GetSnapshot())
-
-		By("cleaning up deleting the snapshot")
-		delSnapReq := MakeDeleteSnapshotReq(sc, snap1.GetSnapshot().GetSnapshotId())
-		_, err = c.DeleteSnapshot(context.Background(), delSnapReq)
-		Expect(err).NotTo(HaveOccurred())
-
-		By("cleaning up deleting the volume")
-		delVolReq := MakeDeleteVolumeReq(sc, volume.GetVolume().GetVolumeId())
-		_, err = c.DeleteVolume(context.Background(), delVolReq)
-		Expect(err).NotTo(HaveOccurred())
-	})
-})
-
-var _ = DescribeSanity("ExpandVolume [Controller Server]", func(sc *TestContext) {
-	var (
-		c  csi.ControllerClient
-		cl *Cleanup
-	)
-
-	BeforeEach(func() {
-		c = csi.NewControllerClient(sc.ControllerConn)
-		if !isControllerCapabilitySupported(c, csi.ControllerServiceCapability_RPC_EXPAND_VOLUME) {
-			Skip("ControllerExpandVolume not supported")
-		}
-		cl = &Cleanup{
-			ControllerClient: c,
-			Context:          sc,
-		}
-	})
-	AfterEach(func() {
-		cl.DeleteVolumes()
-	})
-	It("should fail if no volume id is given", func() {
-		expReq := &csi.ControllerExpandVolumeRequest{
-			VolumeId: "",
-			CapacityRange: &csi.CapacityRange{
-				RequiredBytes: TestVolumeExpandSize(sc),
-			},
-			Secrets: sc.Secrets.ControllerExpandVolumeSecret,
-		}
-		rsp, err := c.ControllerExpandVolume(context.Background(), expReq)
-		Expect(err).To(HaveOccurred())
-		Expect(rsp).To(BeNil())
-
-		serverError, ok := status.FromError(err)
-		Expect(ok).To(BeTrue())
-		Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-	})
-
-	It("should fail if no capacity range is given", func() {
-		expReq := &csi.ControllerExpandVolumeRequest{
-			VolumeId: "",
-			Secrets:  sc.Secrets.ControllerExpandVolumeSecret,
-		}
-		rsp, err := c.ControllerExpandVolume(context.Background(), expReq)
-		Expect(err).To(HaveOccurred())
-		Expect(rsp).To(BeNil())
-
-		serverError, ok := status.FromError(err)
-		Expect(ok).To(BeTrue())
-		Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-	})
-
-	It("should work", func() {
-
-		By("creating a new volume")
-		name := UniqueString("sanity-expand-volume")
-
-		// Create a new volume.
-		req := &csi.CreateVolumeRequest{
-			Name: name,
-			VolumeCapabilities: []*csi.VolumeCapability{
-				{
-					AccessType: &csi.VolumeCapability_Mount{
-						Mount: &csi.VolumeCapability_MountVolume{},
-					},
-					AccessMode: &csi.VolumeCapability_AccessMode{
-						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-					},
-				},
-			},
-			Secrets: sc.Secrets.CreateVolumeSecret,
-			CapacityRange: &csi.CapacityRange{
-				RequiredBytes: TestVolumeSize(sc),
-			},
-		}
-
-		vol, err := c.CreateVolume(context.Background(), req)
-		Expect(err).NotTo(HaveOccurred())
-		Expect(vol).NotTo(BeNil())
-		Expect(vol.GetVolume()).NotTo(BeNil())
-		Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-		cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-		By("expanding the volume")
-		expReq := &csi.ControllerExpandVolumeRequest{
-			VolumeId: vol.GetVolume().GetVolumeId(),
-			CapacityRange: &csi.CapacityRange{
-				RequiredBytes: TestVolumeExpandSize(sc),
-			},
-			Secrets: sc.Secrets.ControllerExpandVolumeSecret,
-		}
-		rsp, err := c.ControllerExpandVolume(context.Background(), expReq)
-		Expect(err).NotTo(HaveOccurred())
-		Expect(rsp).NotTo(BeNil())
-		Expect(rsp.GetCapacityBytes()).To(Equal(TestVolumeExpandSize(sc)))
-
-		By("cleaning up deleting the volume")
-		_, err = c.DeleteVolume(
-			context.Background(),
-			&csi.DeleteVolumeRequest{
-				VolumeId: vol.GetVolume().GetVolumeId(),
-				Secrets:  sc.Secrets.DeleteVolumeSecret,
-			},
-		)
-		Expect(err).NotTo(HaveOccurred())
-		cl.UnregisterVolume(name)
-	})
-})
-
-func MakeCreateVolumeReq(sc *TestContext, name string) *csi.CreateVolumeRequest {
-	size1 := TestVolumeSize(sc)
-
-	req := &csi.CreateVolumeRequest{
-		Name: name,
-		VolumeCapabilities: []*csi.VolumeCapability{
-			{
-				AccessType: &csi.VolumeCapability_Mount{
-					Mount: &csi.VolumeCapability_MountVolume{},
-				},
-				AccessMode: &csi.VolumeCapability_AccessMode{
-					Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-				},
-			},
-		},
-		CapacityRange: &csi.CapacityRange{
-			RequiredBytes: size1,
-			LimitBytes:    size1,
-		},
-		Parameters: sc.Config.TestVolumeParameters,
-	}
-
-	if sc.Secrets != nil {
-		req.Secrets = sc.Secrets.CreateVolumeSecret
-	}
-
-	return req
-}
-
-func MakeCreateSnapshotReq(sc *TestContext, name, sourceVolumeId string) *csi.CreateSnapshotRequest {
-	req := &csi.CreateSnapshotRequest{
-		Name:           name,
-		SourceVolumeId: sourceVolumeId,
-		Parameters:     sc.Config.TestSnapshotParameters,
-	}
-
-	if sc.Secrets != nil {
-		req.Secrets = sc.Secrets.CreateSnapshotSecret
-	}
-
-	return req
-}
-
-func MakeDeleteSnapshotReq(sc *TestContext, id string) *csi.DeleteSnapshotRequest {
-	delSnapReq := &csi.DeleteSnapshotRequest{
-		SnapshotId: id,
-	}
-
-	if sc.Secrets != nil {
-		delSnapReq.Secrets = sc.Secrets.DeleteSnapshotSecret
-	}
-
-	return delSnapReq
-}
-
-func MakeDeleteVolumeReq(sc *TestContext, id string) *csi.DeleteVolumeRequest {
-	delVolReq := &csi.DeleteVolumeRequest{
-		VolumeId: id,
-	}
-
-	if sc.Secrets != nil {
-		delVolReq.Secrets = sc.Secrets.DeleteVolumeSecret
-	}
-
-	return delVolReq
-}
-
-// MakeControllerPublishVolumeReq creates and returns a ControllerPublishVolumeRequest.
-func MakeControllerPublishVolumeReq(sc *TestContext, volID, nodeID string) *csi.ControllerPublishVolumeRequest {
-	return &csi.ControllerPublishVolumeRequest{
-		VolumeId: volID,
-		NodeId:   nodeID,
-		VolumeCapability: &csi.VolumeCapability{
-			AccessType: &csi.VolumeCapability_Mount{
-				Mount: &csi.VolumeCapability_MountVolume{},
-			},
-			AccessMode: &csi.VolumeCapability_AccessMode{
-				Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-			},
-		},
-		Readonly: false,
-		Secrets:  sc.Secrets.ControllerPublishVolumeSecret,
-	}
-}
-
-// MakeControllerUnpublishVolumeReq creates and returns a ControllerUnpublishVolumeRequest.
-func MakeControllerUnpublishVolumeReq(sc *TestContext, volID, nodeID string) *csi.ControllerUnpublishVolumeRequest {
-	return &csi.ControllerUnpublishVolumeRequest{
-		VolumeId: volID,
-		NodeId:   nodeID,
-		Secrets:  sc.Secrets.ControllerUnpublishVolumeSecret,
-	}
-}
-
-// CreateAndControllerPublishVolume creates and controller publishes a volume given a volume name and node ID.
-func CreateAndControllerPublishVolume(sc *TestContext, c csi.ControllerClient, volName, nodeID string) (volID string, err error) {
-	vol, err := c.CreateVolume(context.Background(), MakeCreateVolumeReq(sc, volName))
-	Expect(err).NotTo(HaveOccurred())
-	Expect(vol).NotTo(BeNil())
-	Expect(vol.GetVolume()).NotTo(BeNil())
-	Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-
-	_, err = c.ControllerPublishVolume(
-		context.Background(),
-		MakeControllerPublishVolumeReq(sc, vol.GetVolume().GetVolumeId(), nodeID),
-	)
-	return vol.GetVolume().GetVolumeId(), err
-}
-
-// ControllerUnpublishAndDeleteVolume controller unpublishes and deletes a volume, given volume ID and node ID.
-func ControllerUnpublishAndDeleteVolume(sc *TestContext, c csi.ControllerClient, volID, nodeID string) error {
-	_, err := c.ControllerUnpublishVolume(
-		context.Background(),
-		MakeControllerUnpublishVolumeReq(sc, volID, nodeID),
-	)
-	Expect(err).NotTo(HaveOccurred())
-
-	_, err = c.DeleteVolume(
-		context.Background(),
-		MakeDeleteVolumeReq(sc, volID),
-	)
-	Expect(err).NotTo(HaveOccurred())
-	return err
-}
diff --git a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/node.go b/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/node.go
deleted file mode 100644
index 5f36d862..00000000
--- a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/node.go
+++ /dev/null
@@ -1,835 +0,0 @@
-/*
-Copyright 2017 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 sanity
-
-import (
-	"context"
-	"fmt"
-
-	"google.golang.org/grpc/codes"
-	"google.golang.org/grpc/status"
-
-	"github.com/container-storage-interface/spec/lib/go/csi"
-
-	. "github.com/onsi/ginkgo"
-	. "github.com/onsi/gomega"
-)
-
-func isNodeCapabilitySupported(c csi.NodeClient,
-	capType csi.NodeServiceCapability_RPC_Type,
-) bool {
-
-	caps, err := c.NodeGetCapabilities(
-		context.Background(),
-		&csi.NodeGetCapabilitiesRequest{})
-	Expect(err).NotTo(HaveOccurred())
-	Expect(caps).NotTo(BeNil())
-
-	for _, cap := range caps.GetCapabilities() {
-		Expect(cap.GetRpc()).NotTo(BeNil())
-		if cap.GetRpc().GetType() == capType {
-			return true
-		}
-	}
-	return false
-}
-
-func isPluginCapabilitySupported(c csi.IdentityClient,
-	capType csi.PluginCapability_Service_Type,
-) bool {
-
-	caps, err := c.GetPluginCapabilities(
-		context.Background(),
-		&csi.GetPluginCapabilitiesRequest{})
-	Expect(err).NotTo(HaveOccurred())
-	Expect(caps).NotTo(BeNil())
-
-	for _, cap := range caps.GetCapabilities() {
-		if cap.GetService() != nil && cap.GetService().GetType() == capType {
-			return true
-		}
-	}
-	return false
-}
-
-var _ = DescribeSanity("Node Service", func(sc *TestContext) {
-	var (
-		cl *Cleanup
-		c  csi.NodeClient
-		s  csi.ControllerClient
-
-		providesControllerService  bool
-		controllerPublishSupported bool
-		nodeStageSupported         bool
-		nodeVolumeStatsSupported   bool
-	)
-
-	BeforeEach(func() {
-		c = csi.NewNodeClient(sc.Conn)
-		s = csi.NewControllerClient(sc.ControllerConn)
-
-		i := csi.NewIdentityClient(sc.Conn)
-		req := &csi.GetPluginCapabilitiesRequest{}
-		res, err := i.GetPluginCapabilities(context.Background(), req)
-		Expect(err).NotTo(HaveOccurred())
-		Expect(res).NotTo(BeNil())
-		for _, cap := range res.GetCapabilities() {
-			switch cap.GetType().(type) {
-			case *csi.PluginCapability_Service_:
-				switch cap.GetService().GetType() {
-				case csi.PluginCapability_Service_CONTROLLER_SERVICE:
-					providesControllerService = true
-				}
-			}
-		}
-		if providesControllerService {
-			controllerPublishSupported = isControllerCapabilitySupported(
-				s,
-				csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME)
-		}
-		nodeStageSupported = isNodeCapabilitySupported(c, csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME)
-		nodeVolumeStatsSupported = isNodeCapabilitySupported(c, csi.NodeServiceCapability_RPC_GET_VOLUME_STATS)
-		cl = &Cleanup{
-			Context:                    sc,
-			NodeClient:                 c,
-			ControllerClient:           s,
-			ControllerPublishSupported: controllerPublishSupported,
-			NodeStageSupported:         nodeStageSupported,
-		}
-	})
-
-	AfterEach(func() {
-		cl.DeleteVolumes()
-	})
-
-	Describe("NodeGetCapabilities", func() {
-		It("should return appropriate capabilities", func() {
-			caps, err := c.NodeGetCapabilities(
-				context.Background(),
-				&csi.NodeGetCapabilitiesRequest{})
-
-			By("checking successful response")
-			Expect(err).NotTo(HaveOccurred())
-			Expect(caps).NotTo(BeNil())
-
-			for _, cap := range caps.GetCapabilities() {
-				Expect(cap.GetRpc()).NotTo(BeNil())
-
-				switch cap.GetRpc().GetType() {
-				case csi.NodeServiceCapability_RPC_UNKNOWN:
-				case csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME:
-				case csi.NodeServiceCapability_RPC_GET_VOLUME_STATS:
-				case csi.NodeServiceCapability_RPC_EXPAND_VOLUME:
-				default:
-					Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetRpc().GetType()))
-				}
-			}
-		})
-	})
-
-	Describe("NodeGetInfo", func() {
-		var (
-			i                                csi.IdentityClient
-			accessibilityConstraintSupported bool
-		)
-
-		BeforeEach(func() {
-			i = csi.NewIdentityClient(sc.Conn)
-			accessibilityConstraintSupported = isPluginCapabilitySupported(i, csi.PluginCapability_Service_VOLUME_ACCESSIBILITY_CONSTRAINTS)
-		})
-
-		It("should return appropriate values", func() {
-			ninfo, err := c.NodeGetInfo(
-				context.Background(),
-				&csi.NodeGetInfoRequest{})
-
-			Expect(err).NotTo(HaveOccurred())
-			Expect(ninfo).NotTo(BeNil())
-			Expect(ninfo.GetNodeId()).NotTo(BeEmpty())
-			Expect(ninfo.GetMaxVolumesPerNode()).NotTo(BeNumerically("<", 0))
-
-			if accessibilityConstraintSupported {
-				Expect(ninfo.GetAccessibleTopology()).NotTo(BeNil())
-			}
-		})
-	})
-
-	Describe("NodePublishVolume", func() {
-		It("should fail when no volume id is provided", func() {
-			_, err := c.NodePublishVolume(
-				context.Background(),
-				&csi.NodePublishVolumeRequest{
-					Secrets: sc.Secrets.NodePublishVolumeSecret,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		It("should fail when no target path is provided", func() {
-			_, err := c.NodePublishVolume(
-				context.Background(),
-				&csi.NodePublishVolumeRequest{
-					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
-					Secrets:  sc.Secrets.NodePublishVolumeSecret,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		It("should fail when no volume capability is provided", func() {
-			_, err := c.NodePublishVolume(
-				context.Background(),
-				&csi.NodePublishVolumeRequest{
-					VolumeId:   sc.Config.IDGen.GenerateUniqueValidVolumeID(),
-					TargetPath: sc.TargetPath + "/target",
-					Secrets:    sc.Secrets.NodePublishVolumeSecret,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-	})
-
-	Describe("NodeUnpublishVolume", func() {
-		It("should fail when no volume id is provided", func() {
-
-			_, err := c.NodeUnpublishVolume(
-				context.Background(),
-				&csi.NodeUnpublishVolumeRequest{})
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		It("should fail when no target path is provided", func() {
-
-			_, err := c.NodeUnpublishVolume(
-				context.Background(),
-				&csi.NodeUnpublishVolumeRequest{
-					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
-				})
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-	})
-
-	Describe("NodeStageVolume", func() {
-		var (
-			device string
-		)
-
-		BeforeEach(func() {
-			if !nodeStageSupported {
-				Skip("NodeStageVolume not supported")
-			}
-
-			device = "/dev/mock"
-		})
-
-		It("should fail when no volume id is provided", func() {
-			_, err := c.NodeStageVolume(
-				context.Background(),
-				&csi.NodeStageVolumeRequest{
-					StagingTargetPath: sc.StagingPath,
-					VolumeCapability: &csi.VolumeCapability{
-						AccessType: &csi.VolumeCapability_Mount{
-							Mount: &csi.VolumeCapability_MountVolume{},
-						},
-						AccessMode: &csi.VolumeCapability_AccessMode{
-							Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-						},
-					},
-					PublishContext: map[string]string{
-						"device": device,
-					},
-					Secrets: sc.Secrets.NodeStageVolumeSecret,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		It("should fail when no staging target path is provided", func() {
-			_, err := c.NodeStageVolume(
-				context.Background(),
-				&csi.NodeStageVolumeRequest{
-					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
-					VolumeCapability: &csi.VolumeCapability{
-						AccessType: &csi.VolumeCapability_Mount{
-							Mount: &csi.VolumeCapability_MountVolume{},
-						},
-						AccessMode: &csi.VolumeCapability_AccessMode{
-							Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-						},
-					},
-					PublishContext: map[string]string{
-						"device": device,
-					},
-					Secrets: sc.Secrets.NodeStageVolumeSecret,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		It("should fail when no volume capability is provided", func() {
-
-			// Create Volume First
-			By("creating a single node writer volume")
-			name := UniqueString("sanity-node-stage-nocaps")
-
-			vol, err := s.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol).NotTo(BeNil())
-			Expect(vol.GetVolume()).NotTo(BeNil())
-			Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-
-			_, err = c.NodeStageVolume(
-				context.Background(),
-				&csi.NodeStageVolumeRequest{
-					VolumeId:          vol.GetVolume().GetVolumeId(),
-					StagingTargetPath: sc.StagingPath,
-					PublishContext: map[string]string{
-						"device": device,
-					},
-					Secrets: sc.Secrets.NodeStageVolumeSecret,
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-
-			By("cleaning up deleting the volume")
-
-			_, err = s.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.UnregisterVolume(name)
-		})
-	})
-
-	Describe("NodeUnstageVolume", func() {
-		BeforeEach(func() {
-			if !nodeStageSupported {
-				Skip("NodeUnstageVolume not supported")
-			}
-		})
-
-		It("should fail when no volume id is provided", func() {
-
-			_, err := c.NodeUnstageVolume(
-				context.Background(),
-				&csi.NodeUnstageVolumeRequest{
-					StagingTargetPath: sc.StagingPath,
-				})
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		It("should fail when no staging target path is provided", func() {
-
-			_, err := c.NodeUnstageVolume(
-				context.Background(),
-				&csi.NodeUnstageVolumeRequest{
-					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
-				})
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-	})
-
-	Describe("NodeGetVolumeStats", func() {
-		BeforeEach(func() {
-			if !nodeVolumeStatsSupported {
-				Skip("NodeGetVolume not supported")
-			}
-		})
-
-		It("should fail when no volume id is provided", func() {
-			_, err := c.NodeGetVolumeStats(
-				context.Background(),
-				&csi.NodeGetVolumeStatsRequest{
-					VolumePath: "some/path",
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		It("should fail when no volume path is provided", func() {
-			_, err := c.NodeGetVolumeStats(
-				context.Background(),
-				&csi.NodeGetVolumeStatsRequest{
-					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.InvalidArgument))
-		})
-
-		It("should fail when volume is not found", func() {
-			_, err := c.NodeGetVolumeStats(
-				context.Background(),
-				&csi.NodeGetVolumeStatsRequest{
-					VolumeId:   sc.Config.IDGen.GenerateUniqueValidVolumeID(),
-					VolumePath: "some/path",
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.NotFound))
-		})
-
-		It("should fail when volume does not exist on the specified path", func() {
-			name := UniqueString("sanity-node-get-volume-stats")
-
-			By("creating a single node writer volume")
-			vol, err := s.CreateVolume(
-				context.Background(),
-				&csi.CreateVolumeRequest{
-					Name: name,
-					VolumeCapabilities: []*csi.VolumeCapability{
-						{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-					},
-					Secrets:    sc.Secrets.CreateVolumeSecret,
-					Parameters: sc.Config.TestVolumeParameters,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(vol).NotTo(BeNil())
-			Expect(vol.GetVolume()).NotTo(BeNil())
-			Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-
-			By("getting a node id")
-			nid, err := c.NodeGetInfo(
-				context.Background(),
-				&csi.NodeGetInfoRequest{})
-			Expect(err).NotTo(HaveOccurred())
-			Expect(nid).NotTo(BeNil())
-			Expect(nid.GetNodeId()).NotTo(BeEmpty())
-
-			var conpubvol *csi.ControllerPublishVolumeResponse
-			if controllerPublishSupported {
-				By("controller publishing volume")
-
-				conpubvol, err = s.ControllerPublishVolume(
-					context.Background(),
-					&csi.ControllerPublishVolumeRequest{
-						VolumeId: vol.GetVolume().GetVolumeId(),
-						NodeId:   nid.GetNodeId(),
-						VolumeCapability: &csi.VolumeCapability{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-						VolumeContext: vol.GetVolume().GetVolumeContext(),
-						Readonly:      false,
-						Secrets:       sc.Secrets.ControllerPublishVolumeSecret,
-					},
-				)
-				Expect(err).NotTo(HaveOccurred())
-				cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId(), NodeID: nid.GetNodeId()})
-				Expect(conpubvol).NotTo(BeNil())
-			}
-			// NodeStageVolume
-			if nodeStageSupported {
-				By("node staging volume")
-				nodestagevol, err := c.NodeStageVolume(
-					context.Background(),
-					&csi.NodeStageVolumeRequest{
-						VolumeId: vol.GetVolume().GetVolumeId(),
-						VolumeCapability: &csi.VolumeCapability{
-							AccessType: &csi.VolumeCapability_Mount{
-								Mount: &csi.VolumeCapability_MountVolume{},
-							},
-							AccessMode: &csi.VolumeCapability_AccessMode{
-								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-							},
-						},
-						StagingTargetPath: sc.StagingPath,
-						VolumeContext:     vol.GetVolume().GetVolumeContext(),
-						PublishContext:    conpubvol.GetPublishContext(),
-						Secrets:           sc.Secrets.NodeStageVolumeSecret,
-					},
-				)
-				Expect(err).NotTo(HaveOccurred())
-				Expect(nodestagevol).NotTo(BeNil())
-			}
-			// NodePublishVolume
-			By("publishing the volume on a node")
-			var stagingPath string
-			if nodeStageSupported {
-				stagingPath = sc.StagingPath
-			}
-			nodepubvol, err := c.NodePublishVolume(
-				context.Background(),
-				&csi.NodePublishVolumeRequest{
-					VolumeId:          vol.GetVolume().GetVolumeId(),
-					TargetPath:        sc.TargetPath + "/target",
-					StagingTargetPath: stagingPath,
-					VolumeCapability: &csi.VolumeCapability{
-						AccessType: &csi.VolumeCapability_Mount{
-							Mount: &csi.VolumeCapability_MountVolume{},
-						},
-						AccessMode: &csi.VolumeCapability_AccessMode{
-							Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-						},
-					},
-					VolumeContext:  vol.GetVolume().GetVolumeContext(),
-					PublishContext: conpubvol.GetPublishContext(),
-					Secrets:        sc.Secrets.NodePublishVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(nodepubvol).NotTo(BeNil())
-
-			// NodeGetVolumeStats
-			By("Get node volume stats")
-			_, err = c.NodeGetVolumeStats(
-				context.Background(),
-				&csi.NodeGetVolumeStatsRequest{
-					VolumeId:   vol.GetVolume().GetVolumeId(),
-					VolumePath: "some/path",
-				},
-			)
-			Expect(err).To(HaveOccurred())
-
-			serverError, ok := status.FromError(err)
-			Expect(ok).To(BeTrue())
-			Expect(serverError.Code()).To(Equal(codes.NotFound))
-
-			// NodeUnpublishVolume
-			By("cleaning up calling nodeunpublish")
-			nodeunpubvol, err := c.NodeUnpublishVolume(
-				context.Background(),
-				&csi.NodeUnpublishVolumeRequest{
-					VolumeId:   vol.GetVolume().GetVolumeId(),
-					TargetPath: sc.TargetPath + "/target",
-				})
-			Expect(err).NotTo(HaveOccurred())
-			Expect(nodeunpubvol).NotTo(BeNil())
-
-			if nodeStageSupported {
-				By("cleaning up calling nodeunstage")
-				nodeunstagevol, err := c.NodeUnstageVolume(
-					context.Background(),
-					&csi.NodeUnstageVolumeRequest{
-						VolumeId:          vol.GetVolume().GetVolumeId(),
-						StagingTargetPath: sc.StagingPath,
-					},
-				)
-				Expect(err).NotTo(HaveOccurred())
-				Expect(nodeunstagevol).NotTo(BeNil())
-			}
-
-			if controllerPublishSupported {
-				By("cleaning up calling controllerunpublishing")
-
-				controllerunpubvol, err := s.ControllerUnpublishVolume(
-					context.Background(),
-					&csi.ControllerUnpublishVolumeRequest{
-						VolumeId: vol.GetVolume().GetVolumeId(),
-						NodeId:   nid.GetNodeId(),
-						Secrets:  sc.Secrets.ControllerUnpublishVolumeSecret,
-					},
-				)
-				Expect(err).NotTo(HaveOccurred())
-				Expect(controllerunpubvol).NotTo(BeNil())
-			}
-
-			By("cleaning up deleting the volume")
-
-			_, err = s.DeleteVolume(
-				context.Background(),
-				&csi.DeleteVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					Secrets:  sc.Secrets.DeleteVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-
-		})
-
-	})
-
-	// CSI spec poses no specific requirements for the cluster/storage setups that a SP MUST support. To perform
-	// meaningful checks the following test assumes that topology-aware provisioning on a single node setup is supported
-	It("should work", func() {
-		if !providesControllerService {
-			Skip("Controller Service not provided: CreateVolume not supported")
-		}
-
-		name := UniqueString("sanity-node-full")
-
-		By("getting node information")
-		ni, err := c.NodeGetInfo(
-			context.Background(),
-			&csi.NodeGetInfoRequest{})
-		Expect(err).NotTo(HaveOccurred())
-		Expect(ni).NotTo(BeNil())
-		Expect(ni.GetNodeId()).NotTo(BeEmpty())
-
-		var accReqs *csi.TopologyRequirement
-		if ni.AccessibleTopology != nil {
-			// Topology requirements are honored if provided by the driver
-			accReqs = &csi.TopologyRequirement{
-				Requisite: []*csi.Topology{ni.AccessibleTopology},
-			}
-		}
-
-		// Create Volume First
-		By("creating a single node writer volume")
-		vol, err := s.CreateVolume(
-			context.Background(),
-			&csi.CreateVolumeRequest{
-				Name: name,
-				VolumeCapabilities: []*csi.VolumeCapability{
-					{
-						AccessType: &csi.VolumeCapability_Mount{
-							Mount: &csi.VolumeCapability_MountVolume{},
-						},
-						AccessMode: &csi.VolumeCapability_AccessMode{
-							Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-						},
-					},
-				},
-				Secrets:                   sc.Secrets.CreateVolumeSecret,
-				Parameters:                sc.Config.TestVolumeParameters,
-				AccessibilityRequirements: accReqs,
-			},
-		)
-		Expect(err).NotTo(HaveOccurred())
-		Expect(vol).NotTo(BeNil())
-		Expect(vol.GetVolume()).NotTo(BeNil())
-		Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
-		cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId()})
-
-		var conpubvol *csi.ControllerPublishVolumeResponse
-		if controllerPublishSupported {
-			By("controller publishing volume")
-
-			conpubvol, err = s.ControllerPublishVolume(
-				context.Background(),
-				&csi.ControllerPublishVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					NodeId:   ni.GetNodeId(),
-					VolumeCapability: &csi.VolumeCapability{
-						AccessType: &csi.VolumeCapability_Mount{
-							Mount: &csi.VolumeCapability_MountVolume{},
-						},
-						AccessMode: &csi.VolumeCapability_AccessMode{
-							Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-						},
-					},
-					VolumeContext: vol.GetVolume().GetVolumeContext(),
-					Readonly:      false,
-					Secrets:       sc.Secrets.ControllerPublishVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			cl.RegisterVolume(name, VolumeInfo{VolumeID: vol.GetVolume().GetVolumeId(), NodeID: ni.GetNodeId()})
-			Expect(conpubvol).NotTo(BeNil())
-		}
-		// NodeStageVolume
-		if nodeStageSupported {
-			By("node staging volume")
-			nodestagevol, err := c.NodeStageVolume(
-				context.Background(),
-				&csi.NodeStageVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					VolumeCapability: &csi.VolumeCapability{
-						AccessType: &csi.VolumeCapability_Mount{
-							Mount: &csi.VolumeCapability_MountVolume{},
-						},
-						AccessMode: &csi.VolumeCapability_AccessMode{
-							Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-						},
-					},
-					StagingTargetPath: sc.StagingPath,
-					VolumeContext:     vol.GetVolume().GetVolumeContext(),
-					PublishContext:    conpubvol.GetPublishContext(),
-					Secrets:           sc.Secrets.NodeStageVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(nodestagevol).NotTo(BeNil())
-		}
-		// NodePublishVolume
-		By("publishing the volume on a node")
-		var stagingPath string
-		if nodeStageSupported {
-			stagingPath = sc.StagingPath
-		}
-		nodepubvol, err := c.NodePublishVolume(
-			context.Background(),
-			&csi.NodePublishVolumeRequest{
-				VolumeId:          vol.GetVolume().GetVolumeId(),
-				TargetPath:        sc.TargetPath + "/target",
-				StagingTargetPath: stagingPath,
-				VolumeCapability: &csi.VolumeCapability{
-					AccessType: &csi.VolumeCapability_Mount{
-						Mount: &csi.VolumeCapability_MountVolume{},
-					},
-					AccessMode: &csi.VolumeCapability_AccessMode{
-						Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
-					},
-				},
-				VolumeContext:  vol.GetVolume().GetVolumeContext(),
-				PublishContext: conpubvol.GetPublishContext(),
-				Secrets:        sc.Secrets.NodePublishVolumeSecret,
-			},
-		)
-		Expect(err).NotTo(HaveOccurred())
-		Expect(nodepubvol).NotTo(BeNil())
-
-		// NodeGetVolumeStats
-		if nodeVolumeStatsSupported {
-			By("Get node volume stats")
-			statsResp, err := c.NodeGetVolumeStats(
-				context.Background(),
-				&csi.NodeGetVolumeStatsRequest{
-					VolumeId:   vol.GetVolume().GetVolumeId(),
-					VolumePath: sc.TargetPath + "/target",
-				},
-			)
-			Expect(err).ToNot(HaveOccurred())
-			Expect(statsResp.GetUsage()).ToNot(BeNil())
-		}
-
-		// NodeUnpublishVolume
-		By("cleaning up calling nodeunpublish")
-		nodeunpubvol, err := c.NodeUnpublishVolume(
-			context.Background(),
-			&csi.NodeUnpublishVolumeRequest{
-				VolumeId:   vol.GetVolume().GetVolumeId(),
-				TargetPath: sc.TargetPath + "/target",
-			})
-		Expect(err).NotTo(HaveOccurred())
-		Expect(nodeunpubvol).NotTo(BeNil())
-
-		if nodeStageSupported {
-			By("cleaning up calling nodeunstage")
-			nodeunstagevol, err := c.NodeUnstageVolume(
-				context.Background(),
-				&csi.NodeUnstageVolumeRequest{
-					VolumeId:          vol.GetVolume().GetVolumeId(),
-					StagingTargetPath: sc.StagingPath,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(nodeunstagevol).NotTo(BeNil())
-		}
-
-		if controllerPublishSupported {
-			By("cleaning up calling controllerunpublishing")
-
-			controllerunpubvol, err := s.ControllerUnpublishVolume(
-				context.Background(),
-				&csi.ControllerUnpublishVolumeRequest{
-					VolumeId: vol.GetVolume().GetVolumeId(),
-					NodeId:   ni.GetNodeId(),
-					Secrets:  sc.Secrets.ControllerUnpublishVolumeSecret,
-				},
-			)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(controllerunpubvol).NotTo(BeNil())
-		}
-
-		By("cleaning up deleting the volume")
-
-		_, err = s.DeleteVolume(
-			context.Background(),
-			&csi.DeleteVolumeRequest{
-				VolumeId: vol.GetVolume().GetVolumeId(),
-				Secrets:  sc.Secrets.DeleteVolumeSecret,
-			},
-		)
-		Expect(err).NotTo(HaveOccurred())
-	})
-})
diff --git a/vendor/github.com/kubernetes-csi/csi-test/v3/LICENSE b/vendor/github.com/kubernetes-csi/csi-test/v4/LICENSE
similarity index 100%
rename from vendor/github.com/kubernetes-csi/csi-test/v3/LICENSE
rename to vendor/github.com/kubernetes-csi/csi-test/v4/LICENSE
diff --git a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/README.md b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/README.md
similarity index 94%
rename from vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/README.md
rename to vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/README.md
index fd30f192..773bf33c 100644
--- a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/README.md
+++ b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/README.md
@@ -15,12 +15,9 @@ Golang `TestXXX` functions. For example:
 func TestMyDriver(t *testing.T) {
 	// Setup the full driver and its environment
 	... setup driver ...
-	config := &sanity.Config{
-		TargetPath:     ...
-		StagingPath:    ...
-		Address:        endpoint,
-	}
-
+	config := sanity.NewTestConfig()
+	// Set configuration options as needed
+	cfg.Address = endpoint
 
 	// Now call the test suite
 	sanity.Test(t, config)
diff --git a/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/controller.go b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/controller.go
new file mode 100644
index 00000000..2b2d743c
--- /dev/null
+++ b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/controller.go
@@ -0,0 +1,1686 @@
+/*
+Copyright 2017 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 sanity
+
+import (
+	"context"
+	"fmt"
+	"strconv"
+	"strings"
+
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+
+	"github.com/container-storage-interface/spec/lib/go/csi"
+
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+const (
+	// DefTestVolumeExpand defines the size increment for volume
+	// expansion. It can be overriden by setting an
+	// Config.TestVolumeExpandSize, which will be taken as absolute
+	// value.
+	DefTestExpandIncrement int64 = 1 * 1024 * 1024 * 1024
+
+	MaxNameLength int = 128
+)
+
+func TestVolumeSize(sc *TestContext) int64 {
+	return sc.Config.TestVolumeSize
+}
+
+func TestVolumeCapabilityWithAccessType(sc *TestContext, m csi.VolumeCapability_AccessMode_Mode) *csi.VolumeCapability {
+	vc := &csi.VolumeCapability{
+		AccessMode: &csi.VolumeCapability_AccessMode{Mode: m},
+		AccessType: &csi.VolumeCapability_Mount{
+			Mount: &csi.VolumeCapability_MountVolume{},
+		},
+	}
+	if at := strings.TrimSpace(strings.ToLower(sc.Config.TestVolumeAccessType)); at == "block" {
+		vc.AccessType = &csi.VolumeCapability_Block{
+			Block: &csi.VolumeCapability_BlockVolume{},
+		}
+	}
+
+	return vc
+}
+
+func TestVolumeExpandSize(sc *TestContext) int64 {
+	if sc.Config.TestVolumeExpandSize > 0 {
+		return sc.Config.TestVolumeExpandSize
+	}
+	return TestVolumeSize(sc) + DefTestExpandIncrement
+}
+
+func verifyVolumeInfo(v *csi.Volume) {
+	Expect(v).NotTo(BeNil())
+	Expect(v.GetVolumeId()).NotTo(BeEmpty())
+}
+
+func verifySnapshotInfo(snapshot *csi.Snapshot) {
+	verifySnapshotInfoWithOffset(2, snapshot)
+}
+
+func verifySnapshotInfoWithOffset(offset int, snapshot *csi.Snapshot) {
+	ExpectWithOffset(offset, snapshot).NotTo(BeNil())
+	ExpectWithOffset(offset, snapshot.GetSnapshotId()).NotTo(BeEmpty())
+	ExpectWithOffset(offset, snapshot.GetSourceVolumeId()).NotTo(BeEmpty())
+	ExpectWithOffset(offset, snapshot.GetCreationTime()).NotTo(BeZero())
+}
+
+func isControllerCapabilitySupported(
+	c csi.ControllerClient,
+	capType csi.ControllerServiceCapability_RPC_Type,
+) bool {
+
+	caps, err := c.ControllerGetCapabilities(
+		context.Background(),
+		&csi.ControllerGetCapabilitiesRequest{})
+	Expect(err).NotTo(HaveOccurred())
+	Expect(caps).NotTo(BeNil())
+	Expect(caps.GetCapabilities()).NotTo(BeNil())
+
+	for _, cap := range caps.GetCapabilities() {
+		Expect(cap.GetRpc()).NotTo(BeNil())
+		if cap.GetRpc().GetType() == capType {
+			return true
+		}
+	}
+	return false
+}
+
+var _ = DescribeSanity("Controller Service [Controller Server]", func(sc *TestContext) {
+	var r *Resources
+
+	BeforeEach(func() {
+		r = &Resources{
+			Context:          sc,
+			ControllerClient: csi.NewControllerClient(sc.ControllerConn),
+			NodeClient:       csi.NewNodeClient(sc.Conn),
+		}
+	})
+
+	AfterEach(func() {
+		r.Cleanup()
+	})
+
+	Describe("ControllerGetCapabilities", func() {
+		It("should return appropriate capabilities", func() {
+			caps, err := r.ControllerGetCapabilities(
+				context.Background(),
+				&csi.ControllerGetCapabilitiesRequest{})
+
+			By("checking successful response")
+			Expect(err).NotTo(HaveOccurred())
+			Expect(caps).NotTo(BeNil())
+			Expect(caps.GetCapabilities()).NotTo(BeNil())
+
+			for _, cap := range caps.GetCapabilities() {
+				Expect(cap.GetRpc()).NotTo(BeNil())
+
+				switch cap.GetRpc().GetType() {
+				case csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME:
+				case csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME:
+				case csi.ControllerServiceCapability_RPC_LIST_VOLUMES:
+				case csi.ControllerServiceCapability_RPC_GET_CAPACITY:
+				case csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT:
+				case csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS:
+				case csi.ControllerServiceCapability_RPC_PUBLISH_READONLY:
+				case csi.ControllerServiceCapability_RPC_CLONE_VOLUME:
+				case csi.ControllerServiceCapability_RPC_EXPAND_VOLUME:
+				case csi.ControllerServiceCapability_RPC_LIST_VOLUMES_PUBLISHED_NODES:
+				case csi.ControllerServiceCapability_RPC_GET_VOLUME:
+				case csi.ControllerServiceCapability_RPC_VOLUME_CONDITION:
+				default:
+					Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetRpc().GetType()))
+				}
+			}
+		})
+	})
+
+	Describe("GetCapacity", func() {
+		BeforeEach(func() {
+			if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_GET_CAPACITY) {
+				Skip("GetCapacity not supported")
+			}
+		})
+
+		It("should return capacity (no optional values added)", func() {
+			_, err := r.GetCapacity(
+				context.Background(),
+				&csi.GetCapacityRequest{})
+			Expect(err).NotTo(HaveOccurred())
+
+			// Since capacity is int64 we will not be checking it
+			// The value of zero is a possible value.
+		})
+	})
+	Describe("ListVolumes", func() {
+		BeforeEach(func() {
+			if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_LIST_VOLUMES) {
+				Skip("ListVolumes not supported")
+			}
+		})
+
+		It("should return appropriate values (no optional values added)", func() {
+			vols, err := r.ListVolumes(
+				context.Background(),
+				&csi.ListVolumesRequest{})
+			Expect(err).NotTo(HaveOccurred())
+			Expect(vols).NotTo(BeNil())
+
+			for _, vol := range vols.GetEntries() {
+				verifyVolumeInfo(vol.GetVolume())
+			}
+		})
+
+		It("should fail when an invalid starting_token is passed", func() {
+			vols, err := r.ListVolumes(
+				context.Background(),
+				&csi.ListVolumesRequest{
+					StartingToken: "invalid-token",
+				},
+			)
+			Expect(err).To(HaveOccurred())
+			Expect(vols).To(BeNil())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.Aborted), "unexpected error: %s", serverError.Message())
+		})
+
+		It("check the presence of new volumes and absence of deleted ones in the volume list", func() {
+			// List Volumes before creating new volume.
+			vols, err := r.ListVolumes(
+				context.Background(),
+				&csi.ListVolumesRequest{})
+			Expect(err).NotTo(HaveOccurred())
+			Expect(vols).NotTo(BeNil())
+
+			totalVols := len(vols.GetEntries())
+
+			By("creating a volume")
+			name := "sanity"
+
+			// Create a new volume.
+			req := &csi.CreateVolumeRequest{
+				Name: name,
+				VolumeCapabilities: []*csi.VolumeCapability{
+					TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+				},
+				Secrets:    sc.Secrets.CreateVolumeSecret,
+				Parameters: sc.Config.TestVolumeParameters,
+			}
+
+			vol := r.MustCreateVolume(context.Background(), req)
+
+			// List volumes and check for the newly created volume.
+			vols, err = r.ListVolumes(
+				context.Background(),
+				&csi.ListVolumesRequest{})
+			Expect(err).NotTo(HaveOccurred())
+			Expect(vols).NotTo(BeNil())
+			Expect(len(vols.GetEntries())).To(Equal(totalVols + 1))
+
+			By("deleting the volume")
+
+			delReq := &csi.DeleteVolumeRequest{
+				VolumeId: vol.GetVolume().GetVolumeId(),
+				Secrets:  sc.Secrets.DeleteVolumeSecret,
+			}
+
+			_, err = r.DeleteVolume(context.Background(), delReq)
+			Expect(err).NotTo(HaveOccurred())
+
+			// List volumes and check if the deleted volume exists in the volume list.
+			vols, err = r.ListVolumes(
+				context.Background(),
+				&csi.ListVolumesRequest{})
+			Expect(err).NotTo(HaveOccurred())
+			Expect(vols).NotTo(BeNil())
+			Expect(len(vols.GetEntries())).To(Equal(totalVols))
+		})
+
+		// Disabling this below case as it is fragile and results are inconsistent
+		// when no of volumes are different. The test might fail on a driver
+		// which implements the pagination based on index just by altering
+		// minVolCount := 4 and maxEntries := 3
+		// Related discussion links:
+		//  https://github.com/intel/pmem-csi/pull/424#issuecomment-540499938
+		//  https://github.com/kubernetes-csi/csi-test/issues/223
+		XIt("pagination should detect volumes added between pages and accept tokens when the last volume from a page is deleted", func() {
+			// minVolCount is the minimum number of volumes expected to exist,
+			// based on which paginated volume listing is performed.
+			minVolCount := 3
+			// maxEntries is the maximum entries in list volume request.
+			maxEntries := 2
+			// existing_vols to keep a record of the volumes that should exist
+			existing_vols := map[string]bool{}
+
+			// Get the number of existing volumes.
+			vols, err := r.ListVolumes(
+				context.Background(),
+				&csi.ListVolumesRequest{})
+			Expect(err).NotTo(HaveOccurred())
+			Expect(vols).NotTo(BeNil())
+
+			initialTotalVols := len(vols.GetEntries())
+
+			for _, vol := range vols.GetEntries() {
+				existing_vols[vol.Volume.VolumeId] = true
+			}
+
+			if minVolCount <= initialTotalVols {
+				minVolCount = initialTotalVols
+			} else {
+				// Ensure minimum minVolCount volumes exist.
+				By("creating required new volumes")
+				for i := initialTotalVols; i < minVolCount; i++ {
+					name := "sanity" + strconv.Itoa(i)
+					req := &csi.CreateVolumeRequest{
+						Name: name,
+						VolumeCapabilities: []*csi.VolumeCapability{
+							TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+						},
+						Secrets:    sc.Secrets.CreateVolumeSecret,
+						Parameters: sc.Config.TestVolumeParameters,
+					}
+
+					vol, err := r.CreateVolume(context.Background(), req)
+					Expect(err).NotTo(HaveOccurred())
+					Expect(vol).NotTo(BeNil())
+					// Register the volume so it's automatically cleaned
+					existing_vols[vol.Volume.VolumeId] = true
+				}
+			}
+
+			// Request list volumes with max entries maxEntries.
+			vols, err = r.ListVolumes(
+				context.Background(),
+				&csi.ListVolumesRequest{
+					MaxEntries: int32(maxEntries),
+				})
+			Expect(err).NotTo(HaveOccurred())
+			Expect(vols).NotTo(BeNil())
+			Expect(len(vols.GetEntries())).To(Equal(maxEntries))
+
+			nextToken := vols.GetNextToken()
+
+			By("removing all listed volumes")
+			for _, vol := range vols.GetEntries() {
+				Expect(existing_vols[vol.Volume.VolumeId]).To(BeTrue())
+				delReq := &csi.DeleteVolumeRequest{
+					VolumeId: vol.Volume.VolumeId,
+					Secrets:  sc.Secrets.DeleteVolumeSecret,
+				}
+
+				_, err := r.DeleteVolume(context.Background(), delReq)
+				Expect(err).NotTo(HaveOccurred())
+				vol_id := vol.Volume.VolumeId
+				existing_vols[vol_id] = false
+			}
+
+			By("creating a new volume")
+			req := &csi.CreateVolumeRequest{
+				Name: "new-addition",
+				VolumeCapabilities: []*csi.VolumeCapability{
+					TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+				},
+				Secrets:    sc.Secrets.CreateVolumeSecret,
+				Parameters: sc.Config.TestVolumeParameters,
+			}
+			vol := r.MustCreateVolume(context.Background(), req)
+			existing_vols[vol.Volume.VolumeId] = true
+
+			vols, err = r.ListVolumes(
+				context.Background(),
+				&csi.ListVolumesRequest{
+					StartingToken: nextToken,
+				})
+			Expect(err).NotTo(HaveOccurred())
+			Expect(vols).NotTo(BeNil())
+			expected_num_volumes := minVolCount - maxEntries + 1
+			// Depending on the plugin implementation we may be missing volumes, but should not get duplicates
+			Expect(len(vols.GetEntries()) <= expected_num_volumes).To(BeTrue())
+			for _, vol := range vols.GetEntries() {
+				Expect(existing_vols[vol.Volume.VolumeId]).To(BeTrue())
+				existing_vols[vol.Volume.VolumeId] = false
+			}
+		})
+	})
+
+	Describe("CreateVolume", func() {
+		BeforeEach(func() {
+			if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME) {
+				Skip("CreateVolume not supported")
+			}
+		})
+
+		It("should fail when no name is provided", func() {
+			_, err := r.CreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when no volume capabilities are provided", func() {
+			name := UniqueString("sanity-controller-create-no-volume-capabilities")
+			_, err := r.CreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Name:       name,
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		// TODO: whether CreateVolume request with no capacity should fail or not depends on driver implementation
+		It("should return appropriate values SingleNodeWriter NoCapacity", func() {
+
+			By("creating a volume")
+			name := UniqueString("sanity-controller-create-single-no-capacity")
+
+			r.MustCreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Name: name,
+					VolumeCapabilities: []*csi.VolumeCapability{
+						TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					},
+					CapacityRange: &csi.CapacityRange{
+						RequiredBytes: TestVolumeSize(sc),
+					},
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+		})
+
+		It("should return appropriate values SingleNodeWriter WithCapacity 1Gi", func() {
+
+			By("creating a volume")
+			name := UniqueString("sanity-controller-create-single-with-capacity")
+
+			vol, err := r.CreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Name: name,
+					VolumeCapabilities: []*csi.VolumeCapability{
+						TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					},
+					CapacityRange: &csi.CapacityRange{
+						RequiredBytes: TestVolumeSize(sc),
+					},
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+			if serverError, ok := status.FromError(err); ok &&
+				(serverError.Code() == codes.OutOfRange || serverError.Code() == codes.Unimplemented) {
+				Skip("Required bytes not supported")
+			}
+			Expect(err).NotTo(HaveOccurred())
+			Expect(vol).NotTo(BeNil())
+			Expect(vol.GetVolume()).NotTo(BeNil())
+			Expect(vol.GetVolume().GetVolumeId()).NotTo(BeEmpty())
+			Expect(vol.GetVolume().GetCapacityBytes()).To(Or(BeNumerically(">=", TestVolumeSize(sc)), BeZero()))
+		})
+
+		It("should not fail when requesting to create a volume with already existing name and same capacity", func() {
+
+			By("creating a volume")
+			name := UniqueString("sanity-controller-create-twice")
+			size := TestVolumeSize(sc)
+
+			vol1 := r.MustCreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Name: name,
+					VolumeCapabilities: []*csi.VolumeCapability{
+						TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					},
+					CapacityRange: &csi.CapacityRange{
+						RequiredBytes: size,
+					},
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+
+			Expect(vol1.GetVolume().GetCapacityBytes()).To(Or(BeNumerically(">=", size), BeZero()))
+
+			vol2 := r.MustCreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Name: name,
+					VolumeCapabilities: []*csi.VolumeCapability{
+						TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					},
+					CapacityRange: &csi.CapacityRange{
+						RequiredBytes: size,
+					},
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+			Expect(vol2.GetVolume().GetCapacityBytes()).To(Or(BeNumerically(">=", size), BeZero()))
+			Expect(vol1.GetVolume().GetVolumeId()).To(Equal(vol2.GetVolume().GetVolumeId()))
+		})
+
+		It("should fail when requesting to create a volume with already existing name and different capacity", func() {
+
+			By("creating a volume")
+			name := UniqueString("sanity-controller-create-twice-different")
+			size1 := TestVolumeSize(sc)
+
+			r.MustCreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Name: name,
+					VolumeCapabilities: []*csi.VolumeCapability{
+						TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					},
+					CapacityRange: &csi.CapacityRange{
+						RequiredBytes: size1,
+						LimitBytes:    size1,
+					},
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+			size2 := 2 * TestVolumeSize(sc)
+
+			_, err := r.CreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Name: name,
+					VolumeCapabilities: []*csi.VolumeCapability{
+						TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					},
+					CapacityRange: &csi.CapacityRange{
+						RequiredBytes: size2,
+						LimitBytes:    size2,
+					},
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.AlreadyExists), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should not fail when creating volume with maximum-length name", func() {
+
+			nameBytes := make([]byte, MaxNameLength)
+			for i := 0; i < MaxNameLength; i++ {
+				nameBytes[i] = 'a'
+			}
+			name := string(nameBytes)
+			By("creating a volume")
+			size := TestVolumeSize(sc)
+
+			vol := r.MustCreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Name: name,
+					VolumeCapabilities: []*csi.VolumeCapability{
+						TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					},
+					CapacityRange: &csi.CapacityRange{
+						RequiredBytes: size,
+					},
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+			Expect(vol.GetVolume().GetCapacityBytes()).To(Or(BeNumerically(">=", size), BeZero()))
+		})
+
+		It("should create volume from an existing source snapshot", func() {
+			if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT) {
+				Skip("Snapshot not supported")
+			}
+
+			By("creating a snapshot")
+			vol1Req := MakeCreateVolumeReq(sc, UniqueString("sanity-controller-source-vol"))
+			snap, _ := r.MustCreateSnapshotFromVolumeRequest(context.Background(), vol1Req, UniqueString("sanity-controller-snap-from-vol"))
+
+			By("creating a volume from source snapshot")
+			vol2Name := UniqueString("sanity-controller-vol-from-snap")
+			vol2Req := MakeCreateVolumeReq(sc, vol2Name)
+			vol2Req.VolumeContentSource = &csi.VolumeContentSource{
+				Type: &csi.VolumeContentSource_Snapshot{
+					Snapshot: &csi.VolumeContentSource_SnapshotSource{
+						SnapshotId: snap.GetSnapshot().GetSnapshotId(),
+					},
+				},
+			}
+			_, err := r.CreateVolume(context.Background(), vol2Req)
+			Expect(err).NotTo(HaveOccurred())
+		})
+
+		It("should fail when the volume source snapshot is not found", func() {
+			if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT) {
+				Skip("Snapshot not supported")
+			}
+
+			By("creating a volume from source snapshot")
+			volName := UniqueString("sanity-controller-vol-from-snap")
+			volReq := MakeCreateVolumeReq(sc, volName)
+			volReq.VolumeContentSource = &csi.VolumeContentSource{
+				Type: &csi.VolumeContentSource_Snapshot{
+					Snapshot: &csi.VolumeContentSource_SnapshotSource{
+						SnapshotId: "non-existing-snapshot-id",
+					},
+				},
+			}
+			_, err := r.CreateVolume(context.Background(), volReq)
+			Expect(err).To(HaveOccurred())
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.NotFound), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should create volume from an existing source volume", func() {
+			if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_CLONE_VOLUME) {
+				Skip("Volume Cloning not supported")
+			}
+
+			By("creating a volume")
+			vol1Name := UniqueString("sanity-controller-source-vol")
+			vol1Req := MakeCreateVolumeReq(sc, vol1Name)
+			volume1 := r.MustCreateVolume(context.Background(), vol1Req)
+
+			By("creating a volume from source volume")
+			vol2Name := UniqueString("sanity-controller-vol-from-vol")
+			vol2Req := MakeCreateVolumeReq(sc, vol2Name)
+			vol2Req.VolumeContentSource = &csi.VolumeContentSource{
+				Type: &csi.VolumeContentSource_Volume{
+					Volume: &csi.VolumeContentSource_VolumeSource{
+						VolumeId: volume1.GetVolume().GetVolumeId(),
+					},
+				},
+			}
+			_, err := r.CreateVolume(context.Background(), vol2Req)
+			Expect(err).NotTo(HaveOccurred())
+		})
+
+		It("should fail when the volume source volume is not found", func() {
+			if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_CLONE_VOLUME) {
+				Skip("Volume Cloning not supported")
+			}
+
+			By("creating a volume from source snapshot")
+			volName := UniqueString("sanity-controller-vol-from-snap")
+			volReq := MakeCreateVolumeReq(sc, volName)
+			volReq.VolumeContentSource = &csi.VolumeContentSource{
+				Type: &csi.VolumeContentSource_Volume{
+					Volume: &csi.VolumeContentSource_VolumeSource{
+						VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
+					},
+				},
+			}
+			_, err := r.CreateVolume(context.Background(), volReq)
+			Expect(err).To(HaveOccurred())
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.NotFound), "unexpected error: %s", serverError.Message())
+		})
+	})
+
+	Describe("DeleteVolume", func() {
+		BeforeEach(func() {
+			if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME) {
+				Skip("DeleteVolume not supported")
+			}
+		})
+
+		It("should fail when no volume id is provided", func() {
+
+			_, err := r.DeleteVolume(
+				context.Background(),
+				&csi.DeleteVolumeRequest{
+					Secrets: sc.Secrets.DeleteVolumeSecret,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should succeed when an invalid volume id is used", func() {
+
+			_, err := r.DeleteVolume(
+				context.Background(),
+				&csi.DeleteVolumeRequest{
+					VolumeId: sc.Config.IDGen.GenerateInvalidVolumeID(),
+					Secrets:  sc.Secrets.DeleteVolumeSecret,
+				},
+			)
+			Expect(err).NotTo(HaveOccurred())
+		})
+
+		It("should return appropriate values (no optional values added)", func() {
+
+			// Create Volume First
+			By("creating a volume")
+			name := UniqueString("sanity-controller-create-appropriate")
+
+			vol := r.MustCreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Name: name,
+					VolumeCapabilities: []*csi.VolumeCapability{
+						TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					},
+					CapacityRange: &csi.CapacityRange{
+						RequiredBytes: TestVolumeSize(sc),
+					},
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+
+			// Delete Volume
+			By("deleting a volume")
+
+			_, err := r.DeleteVolume(
+				context.Background(),
+				&csi.DeleteVolumeRequest{
+					VolumeId: vol.GetVolume().GetVolumeId(),
+					Secrets:  sc.Secrets.DeleteVolumeSecret,
+				},
+			)
+			Expect(err).NotTo(HaveOccurred())
+		})
+	})
+
+	Describe("ValidateVolumeCapabilities", func() {
+		It("should fail when no volume id is provided", func() {
+
+			_, err := r.ValidateVolumeCapabilities(
+				context.Background(),
+				&csi.ValidateVolumeCapabilitiesRequest{
+					Secrets: sc.Secrets.ControllerValidateVolumeCapabilitiesSecret,
+				})
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when no volume capabilities are provided", func() {
+
+			// Create Volume First
+			By("creating a single node writer volume")
+			name := UniqueString("sanity-controller-validate-nocaps")
+
+			vol := r.MustCreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Name: name,
+					VolumeCapabilities: []*csi.VolumeCapability{
+						TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					},
+					CapacityRange: &csi.CapacityRange{
+						RequiredBytes: TestVolumeSize(sc),
+					},
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+
+			_, err := r.ValidateVolumeCapabilities(
+				context.Background(),
+				&csi.ValidateVolumeCapabilitiesRequest{
+					VolumeId:           vol.GetVolume().GetVolumeId(),
+					VolumeCapabilities: nil,
+					Secrets:            sc.Secrets.ControllerValidateVolumeCapabilitiesSecret,
+				})
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should return appropriate values (no optional values added)", func() {
+
+			// Create Volume First
+			By("creating a single node writer volume")
+			name := UniqueString("sanity-controller-validate")
+
+			vol := r.MustCreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Name: name,
+					VolumeCapabilities: []*csi.VolumeCapability{
+						TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					},
+					CapacityRange: &csi.CapacityRange{
+						RequiredBytes: TestVolumeSize(sc),
+					},
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+
+			// ValidateVolumeCapabilities
+			By("validating volume capabilities")
+			valivolcap, err := r.ValidateVolumeCapabilities(
+				context.Background(),
+				&csi.ValidateVolumeCapabilitiesRequest{
+					VolumeId: vol.GetVolume().GetVolumeId(),
+					VolumeCapabilities: []*csi.VolumeCapability{
+						TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					},
+					Secrets: sc.Secrets.ControllerValidateVolumeCapabilitiesSecret,
+				})
+			Expect(err).NotTo(HaveOccurred())
+			Expect(valivolcap).NotTo(BeNil())
+
+			// If confirmation is provided then it is REQUIRED to provide
+			// the volume capabilities
+			if valivolcap.GetConfirmed() != nil {
+				Expect(valivolcap.GetConfirmed().GetVolumeCapabilities()).NotTo(BeEmpty())
+			}
+		})
+
+		It("should fail when the requested volume does not exist", func() {
+
+			_, err := r.ValidateVolumeCapabilities(
+				context.Background(),
+				&csi.ValidateVolumeCapabilitiesRequest{
+					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
+					VolumeCapabilities: []*csi.VolumeCapability{
+						TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					},
+					Secrets: sc.Secrets.ControllerValidateVolumeCapabilitiesSecret,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.NotFound), "unexpected error: %s", serverError.Message())
+		})
+	})
+
+	Describe("ControllerPublishVolume", func() {
+		BeforeEach(func() {
+			if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME) {
+				Skip("ControllerPublishVolume not supported")
+			}
+		})
+
+		It("should fail when no volume id is provided", func() {
+
+			_, err := r.ControllerPublishVolume(
+				context.Background(),
+				&csi.ControllerPublishVolumeRequest{
+					Secrets: sc.Secrets.ControllerPublishVolumeSecret,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when no node id is provided", func() {
+
+			_, err := r.ControllerPublishVolume(
+				context.Background(),
+				&csi.ControllerPublishVolumeRequest{
+					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
+					Secrets:  sc.Secrets.ControllerPublishVolumeSecret,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when no volume capability is provided", func() {
+
+			_, err := r.ControllerPublishVolume(
+				context.Background(),
+				&csi.ControllerPublishVolumeRequest{
+					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
+					NodeId:   sc.Config.IDGen.GenerateUniqueValidNodeID(),
+					Secrets:  sc.Secrets.ControllerPublishVolumeSecret,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when publishing more volumes than the node max attach limit", func() {
+			if !sc.Config.TestNodeVolumeAttachLimit {
+				Skip("testnodevolumeattachlimit not enabled")
+			}
+
+			By("getting node info")
+			nodeInfo, err := r.NodeGetInfo(
+				context.Background(),
+				&csi.NodeGetInfoRequest{})
+			Expect(err).NotTo(HaveOccurred())
+			Expect(nodeInfo).NotTo(BeNil())
+
+			if nodeInfo.MaxVolumesPerNode <= 0 {
+				Skip("No MaxVolumesPerNode")
+			}
+
+			nid := nodeInfo.GetNodeId()
+			Expect(nid).NotTo(BeEmpty())
+
+			By("publishing volumes")
+			for i := int64(0); i < nodeInfo.MaxVolumesPerNode; i++ {
+				name := UniqueString(fmt.Sprintf("sanity-max-attach-limit-vol-%d", i))
+				vol := r.MustCreateVolume(context.Background(), MakeCreateVolumeReq(sc, name))
+				volID := vol.GetVolume().GetVolumeId()
+				r.MustControllerPublishVolume(
+					context.Background(),
+					MakeControllerPublishVolumeReq(sc, volID, nid),
+				)
+			}
+
+			extraVolName := UniqueString("sanity-max-attach-limit-vol+1")
+			vol := r.MustCreateVolume(context.Background(), MakeCreateVolumeReq(sc, extraVolName))
+
+			_, err = r.ControllerPublishVolume(
+				context.Background(),
+				MakeControllerPublishVolumeReq(sc, vol.Volume.VolumeId, nid),
+			)
+			Expect(err).To(HaveOccurred())
+		})
+
+		It("should fail when the volume does not exist", func() {
+
+			By("calling controller publish on a non-existent volume")
+
+			conpubvol, err := r.ControllerPublishVolume(
+				context.Background(),
+				&csi.ControllerPublishVolumeRequest{
+					VolumeId:         sc.Config.IDGen.GenerateUniqueValidVolumeID(),
+					NodeId:           sc.Config.IDGen.GenerateUniqueValidNodeID(),
+					VolumeCapability: TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					Readonly:         false,
+					Secrets:          sc.Secrets.ControllerPublishVolumeSecret,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+			Expect(conpubvol).To(BeNil())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.NotFound), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when the node does not exist", func() {
+
+			// Create Volume First
+			By("creating a single node writer volume")
+			name := UniqueString("sanity-controller-wrong-node")
+
+			vol := r.MustCreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Name: name,
+					VolumeCapabilities: []*csi.VolumeCapability{
+						TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					},
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+
+			// ControllerPublishVolume
+			By("calling controllerpublish on that volume")
+
+			conpubvol, err := r.ControllerPublishVolume(
+				context.Background(),
+				&csi.ControllerPublishVolumeRequest{
+					VolumeId:         vol.GetVolume().GetVolumeId(),
+					NodeId:           sc.Config.IDGen.GenerateUniqueValidNodeID(),
+					VolumeCapability: TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					Readonly:         false,
+					Secrets:          sc.Secrets.ControllerPublishVolumeSecret,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+			Expect(conpubvol).To(BeNil())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.NotFound), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when the volume is already published but is incompatible", func() {
+			if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_PUBLISH_READONLY) {
+				Skip("ControllerPublishVolume.readonly field not supported")
+			}
+
+			// Create Volume First
+			By("creating a single node writer volume")
+			name := UniqueString("sanity-controller-published-incompatible")
+
+			vol := r.MustCreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Name: name,
+					VolumeCapabilities: []*csi.VolumeCapability{
+						TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					},
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+
+			By("getting a node id")
+			nid, err := r.NodeGetInfo(
+				context.Background(),
+				&csi.NodeGetInfoRequest{})
+			Expect(err).NotTo(HaveOccurred())
+			Expect(nid).NotTo(BeNil())
+			Expect(nid.GetNodeId()).NotTo(BeEmpty())
+
+			// ControllerPublishVolume
+			By("calling controllerpublish on that volume")
+
+			pubReq := &csi.ControllerPublishVolumeRequest{
+				VolumeId:         vol.GetVolume().GetVolumeId(),
+				NodeId:           nid.GetNodeId(),
+				VolumeCapability: TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+				Readonly:         false,
+				Secrets:          sc.Secrets.ControllerPublishVolumeSecret,
+			}
+
+			conpubvol := r.MustControllerPublishVolume(context.Background(), pubReq)
+
+			// Publish again with different attributes.
+			pubReq.Readonly = true
+
+			conpubvol, err = r.ControllerPublishVolume(context.Background(), pubReq)
+			Expect(err).To(HaveOccurred())
+			Expect(conpubvol).To(BeNil())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.AlreadyExists), "unexpected error: %s", serverError.Message())
+		})
+	})
+
+	Describe("volume lifecycle", func() {
+		BeforeEach(func() {
+			if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME) {
+				Skip("Controller Publish, UnpublishVolume not supported")
+			}
+		})
+
+		It("should work", func() {
+			VolumeLifecycle(r, sc, 1)
+		})
+
+		It("should be idempotent", func() {
+			VolumeLifecycle(r, sc, sc.Config.IdempotentCount)
+		})
+	})
+
+	Describe("ControllerUnpublishVolume", func() {
+		BeforeEach(func() {
+			if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME) {
+				Skip("ControllerUnpublishVolume not supported")
+			}
+		})
+
+		It("should fail when no volume id is provided", func() {
+
+			_, err := r.ControllerUnpublishVolume(
+				context.Background(),
+				&csi.ControllerUnpublishVolumeRequest{
+					Secrets: sc.Secrets.ControllerUnpublishVolumeSecret,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+	})
+})
+
+var _ = DescribeSanity("ListSnapshots [Controller Server]", func(sc *TestContext) {
+	var r *Resources
+
+	BeforeEach(func() {
+		r = &Resources{
+			Context:          sc,
+			ControllerClient: csi.NewControllerClient(sc.ControllerConn),
+			NodeClient:       csi.NewNodeClient(sc.Conn),
+		}
+
+		if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS) {
+			Skip("ListSnapshots not supported")
+		}
+	})
+
+	AfterEach(func() {
+		r.Cleanup()
+	})
+
+	It("should return appropriate values (no optional values added)", func() {
+		snapshots, err := r.ListSnapshots(
+			context.Background(),
+			&csi.ListSnapshotsRequest{})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(snapshots).NotTo(BeNil())
+
+		for _, snapshot := range snapshots.GetEntries() {
+			verifySnapshotInfo(snapshot.GetSnapshot())
+		}
+	})
+
+	It("should return snapshots that match the specified snapshot id", func() {
+		// The test creates three snapshots: one that we intend to find by
+		// snapshot ID, and two unrelated ones that must not be returned by
+		// ListSnapshots.
+
+		By("creating first unrelated snapshot")
+		// Create volume source and afterwards the first unrelated snapshot.
+		volReq := MakeCreateVolumeReq(sc, "listSnapshots-volume-unrelated1")
+		r.MustCreateSnapshotFromVolumeRequest(context.Background(), volReq, "listSnapshots-snapshot-unrelated1")
+
+		By("creating target snapshot")
+		// Create volume source and afterwards the target snapshot.
+		volReq = MakeCreateVolumeReq(sc, "listSnapshots-volume-target")
+		snapshotTarget, _ := r.MustCreateSnapshotFromVolumeRequest(context.Background(), volReq, "listSnapshots-snapshot-target")
+
+		By("creating second unrelated snapshot")
+		// Create volume source and afterwards the second unrelated snapshot.
+		volReq = MakeCreateVolumeReq(sc, "listSnapshots-volume-unrelated2")
+		r.MustCreateSnapshotFromVolumeRequest(context.Background(), volReq, "listSnapshots-snapshot-unrelated2")
+
+		By("listing snapshots")
+		snapshots, err := r.ListSnapshots(
+			context.Background(),
+			&csi.ListSnapshotsRequest{SnapshotId: snapshotTarget.GetSnapshot().GetSnapshotId()})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(snapshots).NotTo(BeNil())
+		Expect(snapshots.GetEntries()).To(HaveLen(1))
+		verifySnapshotInfo(snapshots.GetEntries()[0].GetSnapshot())
+		Expect(snapshots.GetEntries()[0].GetSnapshot().GetSnapshotId()).To(Equal(snapshotTarget.GetSnapshot().GetSnapshotId()))
+	})
+
+	It("should return empty when the specified snapshot id does not exist", func() {
+
+		snapshots, err := r.ListSnapshots(
+			context.Background(),
+			&csi.ListSnapshotsRequest{SnapshotId: "none-exist-id"})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(snapshots).NotTo(BeNil())
+		Expect(snapshots.GetEntries()).To(BeEmpty())
+	})
+
+	It("should return snapshots that match the specified source volume id", func() {
+
+		// The test creates three snapshots: one that we intend to find by
+		// source volume ID, and two unrelated ones that must not be returned by
+		// ListSnapshots.
+
+		By("creating first unrelated snapshot")
+		// Create volume source and afterwards the first unrelated snapshot.
+		volReq := MakeCreateVolumeReq(sc, "listSnapshots-volume-unrelated1")
+		r.MustCreateSnapshotFromVolumeRequest(context.Background(), volReq, "listSnapshots-snapshot-unrelated1")
+
+		By("creating target snapshot")
+		// Create volume source and afterwards the target snapshot.
+		volReq = MakeCreateVolumeReq(sc, "listSnapshots-volume-target")
+		snapshotTarget, _ := r.MustCreateSnapshotFromVolumeRequest(context.Background(), volReq, "listSnapshots-snapshot-target")
+
+		By("creating second unrelated snapshot")
+		// Create volume source and afterwards the second unrelated snapshot.
+		volReq = MakeCreateVolumeReq(sc, "listSnapshots-volume-unrelated2")
+		r.MustCreateSnapshotFromVolumeRequest(context.Background(), volReq, "listSnapshots-snapshot-unrelated2")
+
+		By("listing snapshots")
+		snapshots, err := r.ListSnapshots(
+			context.Background(),
+			&csi.ListSnapshotsRequest{SourceVolumeId: snapshotTarget.GetSnapshot().GetSourceVolumeId()})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(snapshots).NotTo(BeNil())
+		Expect(snapshots.GetEntries()).To(HaveLen(1))
+		snapshot := snapshots.GetEntries()[0].GetSnapshot()
+		verifySnapshotInfo(snapshot)
+		Expect(snapshot.GetSourceVolumeId()).To(Equal(snapshotTarget.GetSnapshot().GetSourceVolumeId()))
+	})
+
+	It("should return empty when the specified source volume id does not exist", func() {
+
+		snapshots, err := r.ListSnapshots(
+			context.Background(),
+			&csi.ListSnapshotsRequest{SourceVolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID()})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(snapshots).NotTo(BeNil())
+		Expect(snapshots.GetEntries()).To(BeEmpty())
+	})
+
+	It("check the presence of new snapshots in the snapshot list", func() {
+		// List Snapshots before creating new snapshots.
+		snapshots, err := r.ListSnapshots(
+			context.Background(),
+			&csi.ListSnapshotsRequest{})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(snapshots).NotTo(BeNil())
+
+		totalSnapshots := len(snapshots.GetEntries())
+
+		By("creating a snapshot")
+		volReq := MakeCreateVolumeReq(sc, "listSnapshots-volume-3")
+		snapshot, _ := r.MustCreateSnapshotFromVolumeRequest(context.Background(), volReq, "listSnapshots-snapshot-3")
+		verifySnapshotInfo(snapshot.GetSnapshot())
+
+		snapshots, err = r.ListSnapshots(
+			context.Background(),
+			&csi.ListSnapshotsRequest{})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(snapshots).NotTo(BeNil())
+		Expect(snapshots.GetEntries()).To(HaveLen(totalSnapshots + 1))
+
+		By("deleting the snapshot")
+		_, err = r.DeleteSnapshot(context.Background(), &csi.DeleteSnapshotRequest{SnapshotId: snapshot.Snapshot.SnapshotId})
+		Expect(err).NotTo(HaveOccurred())
+
+		By("checking if deleted snapshot is omitted")
+		snapshots, err = r.ListSnapshots(
+			context.Background(),
+			&csi.ListSnapshotsRequest{})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(snapshots).NotTo(BeNil())
+		Expect(snapshots.GetEntries()).To(HaveLen(totalSnapshots))
+	})
+
+	It("should return next token when a limited number of entries are requested", func() {
+		// minSnapshotCount is the minimum number of snapshots expected to exist,
+		// based on which paginated snapshot listing is performed.
+		minSnapshotCount := 5
+		// maxEntried is the maximum entries in list snapshot request.
+		maxEntries := 2
+		// currentTotalVols is the total number of volumes at a given time. It
+		// is used to verify that all the snapshots have been listed.
+		currentTotalSnapshots := 0
+
+		// Get the number of existing volumes.
+		snapshots, err := r.ListSnapshots(
+			context.Background(),
+			&csi.ListSnapshotsRequest{})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(snapshots).NotTo(BeNil())
+
+		initialTotalSnapshots := len(snapshots.GetEntries())
+		currentTotalSnapshots = initialTotalSnapshots
+
+		// Ensure minimum minVolCount volumes exist.
+		if initialTotalSnapshots < minSnapshotCount {
+
+			By("creating required new volumes")
+			requiredSnapshots := minSnapshotCount - initialTotalSnapshots
+
+			for i := 1; i <= requiredSnapshots; i++ {
+				volReq := MakeCreateVolumeReq(sc, "volume"+strconv.Itoa(i))
+				snapshot, _ := r.MustCreateSnapshotFromVolumeRequest(context.Background(), volReq, "snapshot"+strconv.Itoa(i))
+				verifySnapshotInfo(snapshot.GetSnapshot())
+			}
+
+			// Update the current total snapshots count.
+			currentTotalSnapshots += requiredSnapshots
+		}
+
+		// Request list snapshots with max entries maxEntries.
+		snapshots, err = r.ListSnapshots(
+			context.Background(),
+			&csi.ListSnapshotsRequest{
+				MaxEntries: int32(maxEntries),
+			})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(snapshots).NotTo(BeNil())
+
+		nextToken := snapshots.GetNextToken()
+
+		Expect(snapshots.GetEntries()).To(HaveLen(maxEntries))
+
+		// Request list snapshots with starting_token and no max entries.
+		snapshots, err = r.ListSnapshots(
+			context.Background(),
+			&csi.ListSnapshotsRequest{
+				StartingToken: nextToken,
+			})
+		Expect(err).NotTo(HaveOccurred())
+		Expect(snapshots).NotTo(BeNil())
+
+		// Ensure that all the remaining entries are returned at once.
+		Expect(snapshots.GetEntries()).To(HaveLen(currentTotalSnapshots - maxEntries))
+	})
+})
+
+var _ = DescribeSanity("DeleteSnapshot [Controller Server]", func(sc *TestContext) {
+	var r *Resources
+
+	BeforeEach(func() {
+		r = &Resources{
+			Context:          sc,
+			ControllerClient: csi.NewControllerClient(sc.ControllerConn),
+			NodeClient:       csi.NewNodeClient(sc.Conn),
+		}
+
+		if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT) {
+			Skip("DeleteSnapshot not supported")
+		}
+	})
+
+	AfterEach(func() {
+		r.Cleanup()
+	})
+
+	It("should fail when no snapshot id is provided", func() {
+
+		req := &csi.DeleteSnapshotRequest{}
+
+		if sc.Secrets != nil {
+			req.Secrets = sc.Secrets.DeleteSnapshotSecret
+		}
+
+		_, err := r.DeleteSnapshot(context.Background(), req)
+		Expect(err).To(HaveOccurred())
+
+		serverError, ok := status.FromError(err)
+		Expect(ok).To(BeTrue())
+		Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+	})
+
+	It("should succeed when an invalid snapshot id is used", func() {
+
+		req := MakeDeleteSnapshotReq(sc, "reallyfakesnapshotid")
+		_, err := r.DeleteSnapshot(context.Background(), req)
+		Expect(err).NotTo(HaveOccurred())
+	})
+
+	It("should return appropriate values (no optional values added)", func() {
+
+		By("creating a volume")
+		volReq := MakeCreateVolumeReq(sc, "DeleteSnapshot-volume-1")
+		volume, err := r.CreateVolume(context.Background(), volReq)
+		Expect(err).NotTo(HaveOccurred())
+
+		// Create Snapshot First
+		By("creating a snapshot")
+		snapshotReq := MakeCreateSnapshotReq(sc, "DeleteSnapshot-snapshot-1", volume.GetVolume().GetVolumeId())
+		r.MustCreateSnapshot(context.Background(), snapshotReq)
+	})
+})
+
+var _ = DescribeSanity("CreateSnapshot [Controller Server]", func(sc *TestContext) {
+	var r *Resources
+
+	BeforeEach(func() {
+		r = &Resources{
+			Context:          sc,
+			ControllerClient: csi.NewControllerClient(sc.ControllerConn),
+			NodeClient:       csi.NewNodeClient(sc.Conn),
+		}
+
+		if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT) {
+			Skip("CreateSnapshot not supported")
+		}
+	})
+
+	AfterEach(func() {
+		r.Cleanup()
+	})
+
+	It("should fail when no name is provided", func() {
+
+		req := &csi.CreateSnapshotRequest{
+			SourceVolumeId: "testId",
+		}
+
+		if sc.Secrets != nil {
+			req.Secrets = sc.Secrets.CreateSnapshotSecret
+		}
+
+		_, err := r.CreateSnapshot(context.Background(), req)
+		Expect(err).To(HaveOccurred())
+		serverError, ok := status.FromError(err)
+		Expect(ok).To(BeTrue())
+		Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+	})
+
+	It("should fail when no source volume id is provided", func() {
+
+		req := &csi.CreateSnapshotRequest{
+			Name: "name",
+		}
+
+		if sc.Secrets != nil {
+			req.Secrets = sc.Secrets.CreateSnapshotSecret
+		}
+
+		_, err := r.CreateSnapshot(context.Background(), req)
+		Expect(err).To(HaveOccurred())
+		serverError, ok := status.FromError(err)
+		Expect(ok).To(BeTrue())
+		Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+	})
+
+	It("should succeed when requesting to create a snapshot with already existing name and same source volume ID", func() {
+
+		By("creating a volume")
+		volReq := MakeCreateVolumeReq(sc, "CreateSnapshot-volume-1")
+		volume := r.MustCreateVolume(context.Background(), volReq)
+
+		By("creating a snapshot")
+		snapReq1 := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-1", volume.GetVolume().GetVolumeId())
+		r.MustCreateSnapshot(context.Background(), snapReq1)
+
+		By("creating a snapshot with the same name and source volume ID")
+		r.MustCreateSnapshot(context.Background(), snapReq1)
+	})
+
+	It("should fail when requesting to create a snapshot with already existing name and different source volume ID", func() {
+
+		By("creating a snapshot")
+		volReq := MakeCreateVolumeReq(sc, "CreateSnapshot-volume-2")
+		r.MustCreateSnapshotFromVolumeRequest(context.Background(), volReq, "CreateSnapshot-snapshot-2")
+
+		By("creating a new source volume")
+		volReq = MakeCreateVolumeReq(sc, "CreateSnapshot-volume-3")
+		volume2 := r.MustCreateVolume(context.Background(), volReq)
+
+		By("creating a snapshot with the same name but different source volume ID")
+		req := MakeCreateSnapshotReq(sc, "CreateSnapshot-snapshot-2", volume2.GetVolume().GetVolumeId())
+		_, err := r.CreateSnapshot(context.Background(), req)
+		Expect(err).To(HaveOccurred())
+		serverError, ok := status.FromError(err)
+		Expect(ok).To(BeTrue())
+		Expect(serverError.Code()).To(Equal(codes.AlreadyExists), "unexpected error: %s", serverError.Message())
+	})
+
+	It("should succeed when creating snapshot with maximum-length name", func() {
+
+		By("creating a volume")
+		volReq := MakeCreateVolumeReq(sc, "CreateSnapshot-volume-3")
+		volume := r.MustCreateVolume(context.Background(), volReq)
+
+		nameBytes := make([]byte, MaxNameLength)
+		for i := 0; i < MaxNameLength; i++ {
+			nameBytes[i] = 'a'
+		}
+		name := string(nameBytes)
+
+		By("creating a snapshot")
+		snapReq1 := MakeCreateSnapshotReq(sc, name, volume.GetVolume().GetVolumeId())
+		r.MustCreateSnapshot(context.Background(), snapReq1)
+
+		// TODO: review if the second snapshot create is really necessary
+		r.MustCreateSnapshot(context.Background(), snapReq1)
+	})
+})
+
+var _ = DescribeSanity("ExpandVolume [Controller Server]", func(sc *TestContext) {
+	var r *Resources
+
+	BeforeEach(func() {
+		r = &Resources{
+			ControllerClient: csi.NewControllerClient(sc.ControllerConn),
+			Context:          sc,
+		}
+
+		if !isControllerCapabilitySupported(r, csi.ControllerServiceCapability_RPC_EXPAND_VOLUME) {
+			Skip("ControllerExpandVolume not supported")
+		}
+	})
+
+	AfterEach(func() {
+		r.Cleanup()
+	})
+
+	It("should fail if no volume id is given", func() {
+		expReq := &csi.ControllerExpandVolumeRequest{
+			VolumeId: "",
+			CapacityRange: &csi.CapacityRange{
+				RequiredBytes: TestVolumeExpandSize(sc),
+			},
+			Secrets: sc.Secrets.ControllerExpandVolumeSecret,
+		}
+		rsp, err := r.ControllerExpandVolume(context.Background(), expReq)
+		Expect(err).To(HaveOccurred())
+		Expect(rsp).To(BeNil())
+
+		serverError, ok := status.FromError(err)
+		Expect(ok).To(BeTrue())
+		Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+	})
+
+	It("should fail if no capacity range is given", func() {
+		expReq := &csi.ControllerExpandVolumeRequest{
+			VolumeId: "",
+			Secrets:  sc.Secrets.ControllerExpandVolumeSecret,
+		}
+		rsp, err := r.ControllerExpandVolume(context.Background(), expReq)
+		Expect(err).To(HaveOccurred())
+		Expect(rsp).To(BeNil())
+
+		serverError, ok := status.FromError(err)
+		Expect(ok).To(BeTrue())
+		Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+	})
+
+	It("should work", func() {
+
+		By("creating a new volume")
+		name := UniqueString("sanity-expand-volume")
+
+		// Create a new volume.
+		req := &csi.CreateVolumeRequest{
+			Name: name,
+			VolumeCapabilities: []*csi.VolumeCapability{
+				TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+			},
+			Parameters: sc.Config.TestVolumeParameters,
+			Secrets:    sc.Secrets.CreateVolumeSecret,
+			CapacityRange: &csi.CapacityRange{
+				RequiredBytes: TestVolumeSize(sc),
+			},
+		}
+		vol := r.MustCreateVolume(context.Background(), req)
+
+		By("expanding the volume")
+		expReq := &csi.ControllerExpandVolumeRequest{
+			VolumeId: vol.GetVolume().GetVolumeId(),
+			CapacityRange: &csi.CapacityRange{
+				RequiredBytes: TestVolumeExpandSize(sc),
+			},
+			Secrets:          sc.Secrets.ControllerExpandVolumeSecret,
+			VolumeCapability: TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+		}
+		rsp, err := r.ControllerExpandVolume(context.Background(), expReq)
+		Expect(err).NotTo(HaveOccurred())
+		Expect(rsp).NotTo(BeNil())
+		Expect(rsp.GetCapacityBytes()).To(Equal(TestVolumeExpandSize(sc)))
+	})
+})
+
+func MakeCreateVolumeReq(sc *TestContext, name string) *csi.CreateVolumeRequest {
+	size1 := TestVolumeSize(sc)
+
+	req := &csi.CreateVolumeRequest{
+		Name: name,
+		VolumeCapabilities: []*csi.VolumeCapability{
+			TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+		},
+		CapacityRange: &csi.CapacityRange{
+			RequiredBytes: size1,
+			LimitBytes:    size1,
+		},
+		Parameters: sc.Config.TestVolumeParameters,
+	}
+
+	if sc.Secrets != nil {
+		req.Secrets = sc.Secrets.CreateVolumeSecret
+	}
+
+	return req
+}
+
+func MakeCreateSnapshotReq(sc *TestContext, name, sourceVolumeId string) *csi.CreateSnapshotRequest {
+	req := &csi.CreateSnapshotRequest{
+		Name:           name,
+		SourceVolumeId: sourceVolumeId,
+		Parameters:     sc.Config.TestSnapshotParameters,
+	}
+
+	if sc.Secrets != nil {
+		req.Secrets = sc.Secrets.CreateSnapshotSecret
+	}
+
+	return req
+}
+
+func MakeDeleteSnapshotReq(sc *TestContext, id string) *csi.DeleteSnapshotRequest {
+	delSnapReq := &csi.DeleteSnapshotRequest{
+		SnapshotId: id,
+	}
+
+	if sc.Secrets != nil {
+		delSnapReq.Secrets = sc.Secrets.DeleteSnapshotSecret
+	}
+
+	return delSnapReq
+}
+
+func MakeDeleteVolumeReq(sc *TestContext, id string) *csi.DeleteVolumeRequest {
+	delVolReq := &csi.DeleteVolumeRequest{
+		VolumeId: id,
+	}
+
+	if sc.Secrets != nil {
+		delVolReq.Secrets = sc.Secrets.DeleteVolumeSecret
+	}
+
+	return delVolReq
+}
+
+// MakeControllerPublishVolumeReq creates and returns a ControllerPublishVolumeRequest.
+func MakeControllerPublishVolumeReq(sc *TestContext, volID, nodeID string) *csi.ControllerPublishVolumeRequest {
+	return &csi.ControllerPublishVolumeRequest{
+		VolumeId:         volID,
+		NodeId:           nodeID,
+		VolumeCapability: TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+		Readonly:         false,
+		Secrets:          sc.Secrets.ControllerPublishVolumeSecret,
+	}
+}
+
+// MakeControllerUnpublishVolumeReq creates and returns a ControllerUnpublishVolumeRequest.
+func MakeControllerUnpublishVolumeReq(sc *TestContext, volID, nodeID string) *csi.ControllerUnpublishVolumeRequest {
+	return &csi.ControllerUnpublishVolumeRequest{
+		VolumeId: volID,
+		NodeId:   nodeID,
+		Secrets:  sc.Secrets.ControllerUnpublishVolumeSecret,
+	}
+}
+
+// VolumeLifecycle performs Create-Publish-Unpublish-Delete, with optional repeat count to test idempotency.
+func VolumeLifecycle(r *Resources, sc *TestContext, count int) {
+	// CSI spec poses no specific requirements for the cluster/storage setups that a SP MUST support. To perform
+	// meaningful checks the following test assumes that topology-aware provisioning on a single node setup is supported
+	By("getting node information")
+	ni, err := r.NodeGetInfo(
+		context.Background(),
+		&csi.NodeGetInfoRequest{})
+	Expect(err).NotTo(HaveOccurred())
+	Expect(ni).NotTo(BeNil())
+	Expect(ni.GetNodeId()).NotTo(BeEmpty())
+
+	var accReqs *csi.TopologyRequirement
+	if ni.AccessibleTopology != nil {
+		// Topology requirements are honored if provided by the driver
+		accReqs = &csi.TopologyRequirement{
+			Requisite: []*csi.Topology{ni.AccessibleTopology},
+		}
+	}
+
+	// Create Volume First
+	By("creating a single node writer volume")
+	name := UniqueString("sanity-controller-publish")
+
+	vol := r.MustCreateVolume(
+		context.Background(),
+		&csi.CreateVolumeRequest{
+			Name: name,
+			VolumeCapabilities: []*csi.VolumeCapability{
+				TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+			},
+			Secrets:                   sc.Secrets.CreateVolumeSecret,
+			Parameters:                sc.Config.TestVolumeParameters,
+			AccessibilityRequirements: accReqs,
+		},
+	)
+
+	// ControllerPublishVolume
+	for i := 0; i < count; i++ {
+		By("calling controllerpublish on that volume")
+		r.MustControllerPublishVolume(
+			context.Background(),
+			&csi.ControllerPublishVolumeRequest{
+				VolumeId:         vol.GetVolume().GetVolumeId(),
+				NodeId:           ni.GetNodeId(),
+				VolumeCapability: TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+				Readonly:         false,
+				Secrets:          sc.Secrets.ControllerPublishVolumeSecret,
+			},
+		)
+	}
+}
diff --git a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/identity.go b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/identity.go
similarity index 95%
rename from vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/identity.go
rename to vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/identity.go
index 28b940ed..2a93a9ca 100644
--- a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/identity.go
+++ b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/identity.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2017 Luis Pabón luis@portworx.com
+Copyright 2021 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.
@@ -83,7 +83,7 @@ var _ = DescribeSanity("Identity Service", func(sc *TestContext) {
 			serverError, ok := status.FromError(err)
 			Expect(ok).To(BeTrue())
 			Expect(serverError.Code() == codes.FailedPrecondition ||
-				serverError.Code() == codes.OK).To(BeTrue())
+				serverError.Code() == codes.OK).To(BeTrue(), "unexpected error: %s", serverError.Message())
 
 			if res.GetReady() != nil {
 				Expect(res.GetReady().GetValue() == true ||
diff --git a/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/node.go b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/node.go
new file mode 100644
index 00000000..39545e81
--- /dev/null
+++ b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/node.go
@@ -0,0 +1,861 @@
+/*
+Copyright 2017 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 sanity
+
+import (
+	"context"
+	"fmt"
+
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+
+	"github.com/container-storage-interface/spec/lib/go/csi"
+
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+func isNodeCapabilitySupported(c csi.NodeClient,
+	capType csi.NodeServiceCapability_RPC_Type,
+) bool {
+
+	caps, err := c.NodeGetCapabilities(
+		context.Background(),
+		&csi.NodeGetCapabilitiesRequest{})
+	Expect(err).NotTo(HaveOccurred())
+	Expect(caps).NotTo(BeNil())
+
+	for _, cap := range caps.GetCapabilities() {
+		Expect(cap.GetRpc()).NotTo(BeNil())
+		if cap.GetRpc().GetType() == capType {
+			return true
+		}
+	}
+	return false
+}
+
+func isPluginCapabilitySupported(c csi.IdentityClient,
+	capType csi.PluginCapability_Service_Type,
+) bool {
+
+	caps, err := c.GetPluginCapabilities(
+		context.Background(),
+		&csi.GetPluginCapabilitiesRequest{})
+	Expect(err).NotTo(HaveOccurred())
+	Expect(caps).NotTo(BeNil())
+
+	for _, cap := range caps.GetCapabilities() {
+		if cap.GetService() != nil && cap.GetService().GetType() == capType {
+			return true
+		}
+	}
+	return false
+}
+
+func runControllerTest(sc *TestContext, r *Resources, controllerPublishSupported bool, nodeStageSupported bool, nodeVolumeStatsSupported bool, count int) {
+
+	name := UniqueString("sanity-node-full")
+
+	By("getting node information")
+	ni, err := r.NodeGetInfo(
+		context.Background(),
+		&csi.NodeGetInfoRequest{})
+	Expect(err).NotTo(HaveOccurred())
+	Expect(ni).NotTo(BeNil())
+	Expect(ni.GetNodeId()).NotTo(BeEmpty())
+
+	var accReqs *csi.TopologyRequirement
+	if ni.AccessibleTopology != nil {
+		// Topology requirements are honored if provided by the driver
+		accReqs = &csi.TopologyRequirement{
+			Requisite: []*csi.Topology{ni.AccessibleTopology},
+		}
+	}
+
+	// Create Volume First
+	By("creating a single node writer volume")
+	vol := r.MustCreateVolume(
+		context.Background(),
+		&csi.CreateVolumeRequest{
+			Name: name,
+			VolumeCapabilities: []*csi.VolumeCapability{
+				TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+			},
+			CapacityRange: &csi.CapacityRange{
+				RequiredBytes: TestVolumeSize(sc),
+			},
+			Secrets:                   sc.Secrets.CreateVolumeSecret,
+			Parameters:                sc.Config.TestVolumeParameters,
+			AccessibilityRequirements: accReqs,
+		},
+	)
+
+	var conpubvol *csi.ControllerPublishVolumeResponse
+	if controllerPublishSupported {
+		By("controller publishing volume")
+
+		conpubvol, err = r.ControllerPublishVolume(
+			context.Background(),
+			&csi.ControllerPublishVolumeRequest{
+				VolumeId:         vol.GetVolume().GetVolumeId(),
+				NodeId:           ni.GetNodeId(),
+				VolumeCapability: TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+				VolumeContext:    vol.GetVolume().GetVolumeContext(),
+				Readonly:         false,
+				Secrets:          sc.Secrets.ControllerPublishVolumeSecret,
+			},
+		)
+		Expect(err).NotTo(HaveOccurred())
+		Expect(conpubvol).NotTo(BeNil())
+	}
+	// NodeStageVolume
+	if nodeStageSupported {
+		for i := 0; i < count; i++ {
+			By("node staging volume")
+			nodestagevol, err := r.NodeStageVolume(
+				context.Background(),
+				&csi.NodeStageVolumeRequest{
+					VolumeId:          vol.GetVolume().GetVolumeId(),
+					VolumeCapability:  TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					StagingTargetPath: sc.StagingPath,
+					VolumeContext:     vol.GetVolume().GetVolumeContext(),
+					PublishContext:    conpubvol.GetPublishContext(),
+					Secrets:           sc.Secrets.NodeStageVolumeSecret,
+				},
+			)
+			Expect(err).NotTo(HaveOccurred())
+			Expect(nodestagevol).NotTo(BeNil())
+		}
+	}
+	// NodePublishVolume
+	var stagingPath string
+	if nodeStageSupported {
+		stagingPath = sc.StagingPath
+	}
+	for i := 0; i < count; i++ {
+		By("publishing the volume on a node")
+		nodepubvol, err := r.NodePublishVolume(
+			context.Background(),
+			&csi.NodePublishVolumeRequest{
+				VolumeId:          vol.GetVolume().GetVolumeId(),
+				TargetPath:        sc.TargetPath + "/target",
+				StagingTargetPath: stagingPath,
+				VolumeCapability:  TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+				VolumeContext:     vol.GetVolume().GetVolumeContext(),
+				PublishContext:    conpubvol.GetPublishContext(),
+				Secrets:           sc.Secrets.NodePublishVolumeSecret,
+			},
+		)
+		Expect(err).NotTo(HaveOccurred())
+		Expect(nodepubvol).NotTo(BeNil())
+	}
+
+	// NodeGetVolumeStats
+	if nodeVolumeStatsSupported {
+		By("Get node volume stats")
+		statsResp, err := r.NodeGetVolumeStats(
+			context.Background(),
+			&csi.NodeGetVolumeStatsRequest{
+				VolumeId:   vol.GetVolume().GetVolumeId(),
+				VolumePath: sc.TargetPath + "/target",
+			},
+		)
+		Expect(err).ToNot(HaveOccurred())
+		Expect(statsResp.GetUsage()).ToNot(BeNil())
+	}
+}
+
+var _ = DescribeSanity("Node Service", func(sc *TestContext) {
+	var (
+		r *Resources
+
+		providesControllerService    bool
+		controllerPublishSupported   bool
+		nodeStageSupported           bool
+		nodeVolumeStatsSupported     bool
+		nodeExpansionSupported       bool
+		controllerExpansionSupported bool
+	)
+
+	createVolume := func(volumeName string) *csi.CreateVolumeResponse {
+		By("creating a single node writer volume for expansion")
+		return r.MustCreateVolume(
+			context.Background(),
+			&csi.CreateVolumeRequest{
+				Name: volumeName,
+				VolumeCapabilities: []*csi.VolumeCapability{
+					TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+				},
+				CapacityRange: &csi.CapacityRange{
+					RequiredBytes: TestVolumeSize(sc),
+				},
+				Secrets:    sc.Secrets.CreateVolumeSecret,
+				Parameters: sc.Config.TestVolumeParameters,
+			},
+		)
+	}
+
+	controllerPublishVolume := func(volumeName string, vol *csi.CreateVolumeResponse, nid *csi.NodeGetInfoResponse) *csi.ControllerPublishVolumeResponse {
+		var conpubvol *csi.ControllerPublishVolumeResponse
+		if controllerPublishSupported {
+			By("controller publishing volume")
+
+			conpubvol = r.MustControllerPublishVolume(
+				context.Background(),
+				&csi.ControllerPublishVolumeRequest{
+					VolumeId:         vol.GetVolume().GetVolumeId(),
+					NodeId:           nid.GetNodeId(),
+					VolumeCapability: TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					VolumeContext:    vol.GetVolume().GetVolumeContext(),
+					Readonly:         false,
+					Secrets:          sc.Secrets.ControllerPublishVolumeSecret,
+				},
+			)
+		}
+		return conpubvol
+	}
+
+	nodeStageVolume := func(volumeName string, vol *csi.CreateVolumeResponse, conpubvol *csi.ControllerPublishVolumeResponse) *csi.NodeStageVolumeResponse {
+		// NodeStageVolume
+		if nodeStageSupported {
+			By("node staging volume")
+			nodeStageRequest := &csi.NodeStageVolumeRequest{
+				VolumeId:          vol.GetVolume().GetVolumeId(),
+				VolumeCapability:  TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+				StagingTargetPath: sc.StagingPath,
+				VolumeContext:     vol.GetVolume().GetVolumeContext(),
+				Secrets:           sc.Secrets.NodeStageVolumeSecret,
+			}
+			if conpubvol != nil {
+				nodeStageRequest.PublishContext = conpubvol.GetPublishContext()
+			}
+			nodestagevol, err := r.NodeStageVolume(
+				context.Background(),
+				nodeStageRequest,
+			)
+			Expect(err).NotTo(HaveOccurred())
+			Expect(nodestagevol).NotTo(BeNil())
+			return nodestagevol
+		}
+		return nil
+	}
+
+	nodePublishVolume := func(volumeName string, vol *csi.CreateVolumeResponse, conpubvol *csi.ControllerPublishVolumeResponse) *csi.NodePublishVolumeResponse {
+		By("publishing the volume on a node")
+		var stagingPath string
+		if nodeStageSupported {
+			stagingPath = sc.StagingPath
+		}
+		nodePublishRequest := &csi.NodePublishVolumeRequest{
+			VolumeId:          vol.GetVolume().GetVolumeId(),
+			TargetPath:        sc.TargetPath + "/target",
+			StagingTargetPath: stagingPath,
+			VolumeCapability:  TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+			VolumeContext:     vol.GetVolume().GetVolumeContext(),
+			Secrets:           sc.Secrets.NodePublishVolumeSecret,
+		}
+
+		if conpubvol != nil {
+			nodePublishRequest.PublishContext = conpubvol.GetPublishContext()
+		}
+
+		nodepubvol, err := r.NodePublishVolume(
+			context.Background(),
+			nodePublishRequest,
+		)
+		Expect(err).NotTo(HaveOccurred())
+		Expect(nodepubvol).NotTo(BeNil())
+		return nodepubvol
+	}
+
+	BeforeEach(func() {
+		cl := csi.NewControllerClient(sc.ControllerConn)
+		n := csi.NewNodeClient(sc.Conn)
+
+		i := csi.NewIdentityClient(sc.Conn)
+		req := &csi.GetPluginCapabilitiesRequest{}
+		res, err := i.GetPluginCapabilities(context.Background(), req)
+		Expect(err).NotTo(HaveOccurred())
+		Expect(res).NotTo(BeNil())
+		for _, cap := range res.GetCapabilities() {
+			switch cap.GetType().(type) {
+			case *csi.PluginCapability_Service_:
+				switch cap.GetService().GetType() {
+				case csi.PluginCapability_Service_CONTROLLER_SERVICE:
+					providesControllerService = true
+				}
+			}
+		}
+		if providesControllerService {
+			controllerPublishSupported = isControllerCapabilitySupported(
+				cl,
+				csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME)
+		}
+		nodeStageSupported = isNodeCapabilitySupported(n, csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME)
+		nodeVolumeStatsSupported = isNodeCapabilitySupported(n, csi.NodeServiceCapability_RPC_GET_VOLUME_STATS)
+		nodeExpansionSupported = isNodeCapabilitySupported(n, csi.NodeServiceCapability_RPC_EXPAND_VOLUME)
+		controllerExpansionSupported = isControllerCapabilitySupported(cl, csi.ControllerServiceCapability_RPC_EXPAND_VOLUME)
+		r = &Resources{
+			Context:                    sc,
+			ControllerClient:           cl,
+			NodeClient:                 n,
+			ControllerPublishSupported: controllerPublishSupported,
+			NodeStageSupported:         nodeStageSupported,
+		}
+	})
+
+	AfterEach(func() {
+		r.Cleanup()
+	})
+
+	Describe("NodeGetCapabilities", func() {
+		It("should return appropriate capabilities", func() {
+			caps, err := r.NodeGetCapabilities(
+				context.Background(),
+				&csi.NodeGetCapabilitiesRequest{})
+
+			By("checking successful response")
+			Expect(err).NotTo(HaveOccurred())
+			Expect(caps).NotTo(BeNil())
+
+			for _, cap := range caps.GetCapabilities() {
+				Expect(cap.GetRpc()).NotTo(BeNil())
+
+				switch cap.GetRpc().GetType() {
+				case csi.NodeServiceCapability_RPC_UNKNOWN:
+				case csi.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME:
+				case csi.NodeServiceCapability_RPC_GET_VOLUME_STATS:
+				case csi.NodeServiceCapability_RPC_EXPAND_VOLUME:
+				case csi.NodeServiceCapability_RPC_VOLUME_CONDITION:
+				default:
+					Fail(fmt.Sprintf("Unknown capability: %v\n", cap.GetRpc().GetType()))
+				}
+			}
+		})
+	})
+
+	Describe("NodeGetInfo", func() {
+		var (
+			i                                csi.IdentityClient
+			accessibilityConstraintSupported bool
+		)
+
+		BeforeEach(func() {
+			i = csi.NewIdentityClient(sc.Conn)
+			accessibilityConstraintSupported = isPluginCapabilitySupported(i, csi.PluginCapability_Service_VOLUME_ACCESSIBILITY_CONSTRAINTS)
+		})
+
+		It("should return appropriate values", func() {
+			ninfo, err := r.NodeGetInfo(
+				context.Background(),
+				&csi.NodeGetInfoRequest{})
+
+			Expect(err).NotTo(HaveOccurred())
+			Expect(ninfo).NotTo(BeNil())
+			Expect(ninfo.GetNodeId()).NotTo(BeEmpty())
+			Expect(ninfo.GetMaxVolumesPerNode()).NotTo(BeNumerically("<", 0))
+
+			if accessibilityConstraintSupported {
+				Expect(ninfo.GetAccessibleTopology()).NotTo(BeNil())
+			}
+		})
+	})
+
+	Describe("NodePublishVolume", func() {
+		It("should fail when no volume id is provided", func() {
+			_, err := r.NodePublishVolume(
+				context.Background(),
+				&csi.NodePublishVolumeRequest{
+					Secrets: sc.Secrets.NodePublishVolumeSecret,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when no target path is provided", func() {
+			_, err := r.NodePublishVolume(
+				context.Background(),
+				&csi.NodePublishVolumeRequest{
+					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
+					Secrets:  sc.Secrets.NodePublishVolumeSecret,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when no volume capability is provided", func() {
+			_, err := r.NodePublishVolume(
+				context.Background(),
+				&csi.NodePublishVolumeRequest{
+					VolumeId:         sc.Config.IDGen.GenerateUniqueValidVolumeID(),
+					VolumeCapability: nil,
+					TargetPath:       sc.TargetPath + "/target",
+					Secrets:          sc.Secrets.NodePublishVolumeSecret,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+	})
+
+	Describe("NodeUnpublishVolume", func() {
+		It("should fail when no volume id is provided", func() {
+
+			_, err := r.NodeUnpublishVolume(
+				context.Background(),
+				&csi.NodeUnpublishVolumeRequest{})
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when no target path is provided", func() {
+
+			_, err := r.NodeUnpublishVolume(
+				context.Background(),
+				&csi.NodeUnpublishVolumeRequest{
+					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
+				})
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should remove target path", func() {
+			// This test may break for consumers that are using
+			// custom target path functions if they have not yet
+			// implemented similar functionality to check if the
+			// path exists. Skip this test if there is a custom
+			// command or function provided to create the path,
+			// but not yet provided to check the path.
+			if sc.Config.CreateTargetPathCmd != "" && sc.Config.CheckPathCmd == "" {
+				Skip("CreateTargetPathCmd was set, but CheckPathCmd was not. Please update your testing configuration to enable CheckPathCmd.")
+			}
+			if sc.Config.CreateTargetDir != nil && sc.Config.CheckPath == nil {
+				Skip("CreateTargetDir was set, but CheckPath was not. Please update your testing configuration to enable CheckPath.")
+			}
+
+			name := UniqueString("sanity-node-unpublish-volume")
+			vol := createVolume(name)
+			volid := vol.GetVolume().GetVolumeId()
+			volpath := sc.TargetPath + "/target"
+
+			By("Getting a node id")
+			nid, err := r.NodeGetInfo(
+				context.Background(),
+				&csi.NodeGetInfoRequest{})
+			Expect(err).NotTo(HaveOccurred())
+			Expect(nid).NotTo(BeNil())
+			Expect(nid.GetNodeId()).NotTo(BeEmpty())
+
+			By("Staging and publishing a volume")
+			conpubvol := controllerPublishVolume(name, vol, nid)
+			_ = nodeStageVolume(name, vol, conpubvol)
+			_ = nodePublishVolume(name, vol, conpubvol)
+
+			// Verify that the path exists before calling
+			// NodeUnpublishVolume.
+			By("Checking the target path exists")
+			pa, err := CheckPath(volpath, sc.Config)
+			Expect(err).NotTo(HaveOccurred(), "checking path %q", volpath)
+			Expect(pa).NotTo(Equal(PathIsNotFound), "path %q should have been created by CSI driver and the test config should be enabling testing for that path", volpath)
+
+			By("Unpublishing the volume")
+			_, err = r.NodeUnpublishVolume(
+				context.Background(),
+				&csi.NodeUnpublishVolumeRequest{
+					VolumeId:   volid,
+					TargetPath: volpath,
+				},
+			)
+			Expect(err).NotTo(HaveOccurred())
+
+			// The CSI spec states that the SP MUST delete
+			// the file or directory it created at this path
+			// as part of NodeUnpublishVolume.
+			By("Checking the target path was removed")
+			pa, err = CheckPath(volpath, sc.Config)
+			Expect(err).NotTo(HaveOccurred(), "checking path %q", volpath)
+			Expect(pa).To(Equal(PathIsNotFound), "path %q should have been removed by the CSI driver during NodeUnpublishVolume", volpath)
+		})
+	})
+
+	Describe("NodeStageVolume", func() {
+		var (
+			device string
+		)
+
+		BeforeEach(func() {
+			if !nodeStageSupported {
+				Skip("NodeStageVolume not supported")
+			}
+
+			device = "/dev/mock"
+		})
+
+		It("should fail when no volume id is provided", func() {
+			_, err := r.NodeStageVolume(
+				context.Background(),
+				&csi.NodeStageVolumeRequest{
+					StagingTargetPath: sc.StagingPath,
+					VolumeCapability:  TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					PublishContext: map[string]string{
+						"device": device,
+					},
+					Secrets: sc.Secrets.NodeStageVolumeSecret,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when no staging target path is provided", func() {
+			_, err := r.NodeStageVolume(
+				context.Background(),
+				&csi.NodeStageVolumeRequest{
+					VolumeId:         sc.Config.IDGen.GenerateUniqueValidVolumeID(),
+					VolumeCapability: TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+					PublishContext: map[string]string{
+						"device": device,
+					},
+					Secrets: sc.Secrets.NodeStageVolumeSecret,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when no volume capability is provided", func() {
+
+			// Create Volume First
+			By("creating a single node writer volume")
+			name := UniqueString("sanity-node-stage-nocaps")
+
+			vol := r.MustCreateVolume(
+				context.Background(),
+				&csi.CreateVolumeRequest{
+					Name: name,
+					VolumeCapabilities: []*csi.VolumeCapability{
+						{
+							AccessType: &csi.VolumeCapability_Mount{
+								Mount: &csi.VolumeCapability_MountVolume{},
+							},
+							AccessMode: &csi.VolumeCapability_AccessMode{
+								Mode: csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER,
+							},
+						},
+					},
+					Secrets:    sc.Secrets.CreateVolumeSecret,
+					Parameters: sc.Config.TestVolumeParameters,
+				},
+			)
+
+			_, err := r.NodeStageVolume(
+				context.Background(),
+				&csi.NodeStageVolumeRequest{
+					VolumeId:          vol.GetVolume().GetVolumeId(),
+					StagingTargetPath: sc.StagingPath,
+					PublishContext: map[string]string{
+						"device": device,
+					},
+					Secrets: sc.Secrets.NodeStageVolumeSecret,
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+	})
+
+	Describe("NodeUnstageVolume", func() {
+		BeforeEach(func() {
+			if !nodeStageSupported {
+				Skip("NodeUnstageVolume not supported")
+			}
+		})
+
+		It("should fail when no volume id is provided", func() {
+
+			_, err := r.NodeUnstageVolume(
+				context.Background(),
+				&csi.NodeUnstageVolumeRequest{
+					StagingTargetPath: sc.StagingPath,
+				})
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when no staging target path is provided", func() {
+
+			_, err := r.NodeUnstageVolume(
+				context.Background(),
+				&csi.NodeUnstageVolumeRequest{
+					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
+				})
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+	})
+
+	Describe("NodeGetVolumeStats", func() {
+		BeforeEach(func() {
+			if !nodeVolumeStatsSupported {
+				Skip("NodeGetVolume not supported")
+			}
+		})
+
+		It("should fail when no volume id is provided", func() {
+			_, err := r.NodeGetVolumeStats(
+				context.Background(),
+				&csi.NodeGetVolumeStatsRequest{
+					VolumePath: "some/path",
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when no volume path is provided", func() {
+			_, err := r.NodeGetVolumeStats(
+				context.Background(),
+				&csi.NodeGetVolumeStatsRequest{
+					VolumeId: sc.Config.IDGen.GenerateUniqueValidVolumeID(),
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when volume is not found", func() {
+			_, err := r.NodeGetVolumeStats(
+				context.Background(),
+				&csi.NodeGetVolumeStatsRequest{
+					VolumeId:   sc.Config.IDGen.GenerateUniqueValidVolumeID(),
+					VolumePath: "some/path",
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.NotFound), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when volume does not exist on the specified path", func() {
+			name := UniqueString("sanity-node-get-volume-stats")
+
+			vol := createVolume(name)
+
+			By("getting a node id")
+			nid, err := r.NodeGetInfo(
+				context.Background(),
+				&csi.NodeGetInfoRequest{})
+			Expect(err).NotTo(HaveOccurred())
+			Expect(nid).NotTo(BeNil())
+			Expect(nid.GetNodeId()).NotTo(BeEmpty())
+
+			conpubvol := controllerPublishVolume(name, vol, nid)
+
+			// NodeStageVolume
+			_ = nodeStageVolume(name, vol, conpubvol)
+
+			// NodePublishVolume
+			_ = nodePublishVolume(name, vol, conpubvol)
+
+			// NodeGetVolumeStats
+			By("Get node volume stats")
+			_, err = r.NodeGetVolumeStats(
+				context.Background(),
+				&csi.NodeGetVolumeStatsRequest{
+					VolumeId:   vol.GetVolume().GetVolumeId(),
+					VolumePath: "some/path",
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.NotFound), "unexpected error: %s", serverError.Message())
+		})
+
+	})
+
+	Describe("NodeExpandVolume", func() {
+		BeforeEach(func() {
+			if !nodeExpansionSupported {
+				Skip("NodeExpandVolume not supported")
+			}
+
+		})
+
+		It("should fail when no volume id is provided", func() {
+			_, err := r.NodeExpandVolume(
+				context.Background(),
+				&csi.NodeExpandVolumeRequest{
+					VolumePath:       sc.TargetPath,
+					VolumeCapability: TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when no volume path is provided", func() {
+			name := UniqueString("sanity-node-expand-volume-valid-id")
+
+			vol := createVolume(name)
+
+			_, err := r.NodeExpandVolume(
+				context.Background(),
+				&csi.NodeExpandVolumeRequest{
+					VolumeId:         vol.GetVolume().VolumeId,
+					VolumeCapability: TestVolumeCapabilityWithAccessType(sc, csi.VolumeCapability_AccessMode_SINGLE_NODE_WRITER),
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.InvalidArgument), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should fail when volume is not found", func() {
+			_, err := r.NodeExpandVolume(
+				context.Background(),
+				&csi.NodeExpandVolumeRequest{
+					VolumeId:   sc.Config.IDGen.GenerateUniqueValidVolumeID(),
+					VolumePath: "some/path",
+				},
+			)
+			Expect(err).To(HaveOccurred())
+
+			serverError, ok := status.FromError(err)
+			Expect(ok).To(BeTrue())
+			Expect(serverError.Code()).To(Equal(codes.NotFound), "unexpected error: %s", serverError.Message())
+		})
+
+		It("should work if node-expand is called after node-publish", func() {
+			name := UniqueString("sanity-node-expand-volume")
+
+			// Created volumes are automatically cleaned up via cl.DeleteVolumes
+			vol := createVolume(name)
+
+			if controllerExpansionSupported {
+				By("controller expanding the volume")
+				expReq := &csi.ControllerExpandVolumeRequest{
+					VolumeId: vol.GetVolume().GetVolumeId(),
+					CapacityRange: &csi.CapacityRange{
+						RequiredBytes: TestVolumeExpandSize(sc),
+					},
+					Secrets: sc.Secrets.ControllerExpandVolumeSecret,
+				}
+				rsp, err := r.ControllerExpandVolume(context.Background(), expReq)
+				Expect(err).NotTo(HaveOccurred())
+				Expect(rsp).NotTo(BeNil())
+				Expect(rsp.GetCapacityBytes()).To(Equal(TestVolumeExpandSize(sc)))
+			}
+
+			By("getting a node id")
+			nid, err := r.NodeGetInfo(
+				context.Background(),
+				&csi.NodeGetInfoRequest{})
+			Expect(err).NotTo(HaveOccurred())
+			Expect(nid).NotTo(BeNil())
+			Expect(nid.GetNodeId()).NotTo(BeEmpty())
+
+			conpubvol := controllerPublishVolume(name, vol, nid)
+
+			// NodeStageVolume
+			_ = nodeStageVolume(name, vol, conpubvol)
+
+			// NodePublishVolume
+			_ = nodePublishVolume(name, vol, conpubvol)
+
+			By("expanding the volume on a node")
+			_, err = r.NodeExpandVolume(
+				context.Background(),
+				&csi.NodeExpandVolumeRequest{
+					VolumeId:   vol.GetVolume().GetVolumeId(),
+					VolumePath: sc.TargetPath + "/target",
+					CapacityRange: &csi.CapacityRange{
+						RequiredBytes: TestVolumeExpandSize(sc),
+					},
+				},
+			)
+			Expect(err).ToNot(HaveOccurred(), "while expanding volume on node")
+		})
+	})
+
+	// CSI spec poses no specific requirements for the cluster/storage setups that a SP MUST support. To perform
+	// meaningful checks the following test assumes that topology-aware provisioning on a single node setup is supported
+	It("should work", func() {
+		if !providesControllerService {
+			Skip("Controller Service not provided: CreateVolume not supported")
+		}
+		By("runControllerTest")
+		runControllerTest(sc, r, controllerPublishSupported, nodeStageSupported, nodeVolumeStatsSupported, 1)
+	})
+	It("should be idempotent", func() {
+		if !providesControllerService {
+			Skip("Controller Service not provided: CreateVolume not supported")
+		}
+		if sc.Config.IdempotentCount <= 0 {
+			Skip("Config.IdempotentCount is zero or negative, skip tests")
+		}
+		count := sc.Config.IdempotentCount
+		By("runControllerTest with Idempotent count")
+		runControllerTest(sc, r, controllerPublishSupported, nodeStageSupported, nodeVolumeStatsSupported, count)
+	})
+})
diff --git a/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/resources.go b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/resources.go
new file mode 100644
index 00000000..07659063
--- /dev/null
+++ b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/resources.go
@@ -0,0 +1,338 @@
+/*
+Copyright 2021 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 sanity
+
+import (
+	"context"
+	"fmt"
+	"sync"
+
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+
+	"github.com/container-storage-interface/spec/lib/go/csi"
+
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+
+	"k8s.io/klog/v2"
+)
+
+// resourceInfo represents a resource (i.e., a volume or a snapshot).
+type resourceInfo struct {
+	id   string
+	data interface{}
+}
+
+// volumeInfo keeps track of the information needed to delete a volume.
+type volumeInfo struct {
+	// Node on which the volume was published, empty if none
+	// or publishing is not supported.
+	NodeID string
+}
+
+// snapshotInfo keeps track of the information needed to delete a snapshot.
+type snapshotInfo struct{}
+
+// Resources keeps track of resources, in particular volumes and snapshots, that
+// need to be freed when testing is done. It implements both ControllerClient
+// and NodeClient and should be used as the only interaction point to either
+// APIs. That way, Resources can ensure that resources are marked for cleanup as
+// necessary.
+// All methods can be called concurrently.
+type Resources struct {
+	Context *TestContext
+	// ControllerClient is meant for struct-internal usage. It should only be
+	// invoked directly if automatic cleanup is not desired and cannot be
+	// avoided otherwise.
+	csi.ControllerClient
+	// NodeClient is meant for struct-internal usage. It should only be invoked
+	// directly if automatic cleanup is not desired and cannot be avoided
+	// otherwise.
+	csi.NodeClient
+	ControllerPublishSupported bool
+	NodeStageSupported         bool
+
+	// mutex protects access to managedResourceInfos.
+	mutex                sync.Mutex
+	managedResourceInfos []resourceInfo
+}
+
+// ControllerClient interface wrappers
+
+// CreateVolume proxies to a Controller service implementation and registers the
+// volume for cleanup.
+func (cl *Resources) CreateVolume(ctx context.Context, in *csi.CreateVolumeRequest, _ ...grpc.CallOption) (*csi.CreateVolumeResponse, error) {
+	return cl.createVolume(ctx, 2, in)
+}
+
+// DeleteVolume proxies to a Controller service implementation and unregisters
+// the volume from cleanup.
+func (cl *Resources) DeleteVolume(ctx context.Context, in *csi.DeleteVolumeRequest, _ ...grpc.CallOption) (*csi.DeleteVolumeResponse, error) {
+	return cl.deleteVolume(ctx, 2, in)
+}
+
+// ControllerPublishVolume proxies to a Controller service implementation and
+// adds the node ID to the corresponding volume for cleanup.
+func (cl *Resources) ControllerPublishVolume(ctx context.Context, in *csi.ControllerPublishVolumeRequest, _ ...grpc.CallOption) (*csi.ControllerPublishVolumeResponse, error) {
+	return cl.controllerPublishVolume(ctx, 2, in)
+}
+
+// CreateSnapshot proxies to a Controller service implementation and registers
+// the snapshot for cleanup.
+func (cl *Resources) CreateSnapshot(ctx context.Context, in *csi.CreateSnapshotRequest, _ ...grpc.CallOption) (*csi.CreateSnapshotResponse, error) {
+	return cl.createSnapshot(ctx, 2, in)
+}
+
+// DeleteSnapshot proxies to a Controller service implementation and unregisters
+// the snapshot from cleanup.
+func (cl *Resources) DeleteSnapshot(ctx context.Context, in *csi.DeleteSnapshotRequest, _ ...grpc.CallOption) (*csi.DeleteSnapshotResponse, error) {
+	return cl.deleteSnapshot(ctx, 2, in)
+}
+
+// MustCreateVolume is like CreateVolume but asserts that the volume was
+// successfully created.
+func (cl *Resources) MustCreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) *csi.CreateVolumeResponse {
+	return cl.mustCreateVolumeWithOffset(ctx, 2, req)
+}
+
+func (cl *Resources) mustCreateVolumeWithOffset(ctx context.Context, offset int, req *csi.CreateVolumeRequest) *csi.CreateVolumeResponse {
+	vol, err := cl.createVolume(ctx, offset+1, req)
+	ExpectWithOffset(offset, err).NotTo(HaveOccurred(), "volume create failed")
+	ExpectWithOffset(offset, vol).NotTo(BeNil(), "volume response is nil")
+	ExpectWithOffset(offset, vol.GetVolume()).NotTo(BeNil(), "volume in response is nil")
+	ExpectWithOffset(offset, vol.GetVolume().GetVolumeId()).NotTo(BeEmpty(), "volume ID in response is missing")
+	return vol
+}
+
+func (cl *Resources) createVolume(ctx context.Context, offset int, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) {
+	vol, err := cl.ControllerClient.CreateVolume(ctx, req)
+	if err == nil && vol != nil && vol.GetVolume().GetVolumeId() != "" {
+		cl.registerVolume(offset+1, vol.GetVolume().GetVolumeId(), volumeInfo{})
+	}
+	return vol, err
+}
+
+func (cl *Resources) deleteVolume(ctx context.Context, offset int, req *csi.DeleteVolumeRequest) (*csi.DeleteVolumeResponse, error) {
+	vol, err := cl.ControllerClient.DeleteVolume(ctx, req)
+	if err == nil {
+		cl.unregisterResource(offset+1, req.VolumeId)
+	}
+	return vol, err
+}
+
+// MustControllerPublishVolume is like ControllerPublishVolume but asserts that
+// the volume was successfully controller-published.
+func (cl *Resources) MustControllerPublishVolume(ctx context.Context, req *csi.ControllerPublishVolumeRequest) *csi.ControllerPublishVolumeResponse {
+	conpubvol, err := cl.controllerPublishVolume(ctx, 2, req)
+	ExpectWithOffset(1, err).NotTo(HaveOccurred(), "controller publish volume failed")
+	ExpectWithOffset(1, conpubvol).NotTo(BeNil(), "controller publish volume response is nil")
+	return conpubvol
+}
+
+func (cl *Resources) controllerPublishVolume(ctx context.Context, offset int, req *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) {
+	conpubvol, err := cl.ControllerClient.ControllerPublishVolume(ctx, req)
+	if err == nil && req.VolumeId != "" && req.NodeId != "" {
+		cl.registerVolume(offset+1, req.VolumeId, volumeInfo{NodeID: req.NodeId})
+	}
+	return conpubvol, err
+}
+
+// registerVolume adds or updates an entry for given volume.
+func (cl *Resources) registerVolume(offset int, id string, info volumeInfo) {
+	ExpectWithOffset(offset, id).NotTo(BeEmpty(), "volume ID is empty")
+	ExpectWithOffset(offset, info).NotTo(BeNil(), "volume info is nil")
+	cl.mutex.Lock()
+	defer cl.mutex.Unlock()
+	klog.V(4).Infof("registering volume ID %s", id)
+	cl.managedResourceInfos = append(cl.managedResourceInfos, resourceInfo{
+		id:   id,
+		data: info,
+	})
+}
+
+// MustCreateSnapshot is like CreateSnapshot but asserts that the snapshot was
+// successfully created.
+func (cl *Resources) MustCreateSnapshot(ctx context.Context, req *csi.CreateSnapshotRequest) *csi.CreateSnapshotResponse {
+	return cl.mustCreateSnapshotWithOffset(ctx, 2, req)
+}
+
+func (cl *Resources) mustCreateSnapshotWithOffset(ctx context.Context, offset int, req *csi.CreateSnapshotRequest) *csi.CreateSnapshotResponse {
+	snap, err := cl.createSnapshot(ctx, offset+1, req)
+	ExpectWithOffset(offset, err).NotTo(HaveOccurred(), "create snapshot failed")
+	ExpectWithOffset(offset, snap).NotTo(BeNil(), "create snasphot response is nil")
+	verifySnapshotInfoWithOffset(offset+1, snap.GetSnapshot())
+	return snap
+}
+
+// MustCreateSnapshotFromVolumeRequest creates a volume from the given
+// CreateVolumeRequest and a snapshot subsequently. It registers the volume and
+// snapshot and asserts that both were created successfully.
+func (cl *Resources) MustCreateSnapshotFromVolumeRequest(ctx context.Context, req *csi.CreateVolumeRequest, snapshotName string) (*csi.CreateSnapshotResponse, *csi.CreateVolumeResponse) {
+	vol := cl.mustCreateVolumeWithOffset(ctx, 2, req)
+	snap := cl.mustCreateSnapshotWithOffset(ctx, 2, MakeCreateSnapshotReq(cl.Context, snapshotName, vol.Volume.VolumeId))
+	return snap, vol
+}
+
+func (cl *Resources) createSnapshot(ctx context.Context, offset int, req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) {
+	snap, err := cl.ControllerClient.CreateSnapshot(ctx, req)
+	if err == nil && snap.GetSnapshot().GetSnapshotId() != "" {
+		cl.registerSnapshot(offset+1, snap.Snapshot.SnapshotId)
+	}
+	return snap, err
+}
+
+func (cl *Resources) deleteSnapshot(ctx context.Context, offset int, req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) {
+	snap, err := cl.ControllerClient.DeleteSnapshot(ctx, req)
+	if err == nil && req.SnapshotId != "" {
+		cl.unregisterResource(offset+1, req.SnapshotId)
+	}
+	return snap, err
+}
+
+func (cl *Resources) registerSnapshot(offset int, id string) {
+	cl.mutex.Lock()
+	defer cl.mutex.Unlock()
+	cl.registerSnapshotNoLock(offset+1, id)
+}
+
+func (cl *Resources) registerSnapshotNoLock(offset int, id string) {
+	ExpectWithOffset(offset, id).NotTo(BeEmpty(), "ID for register snapshot is missing")
+	klog.V(4).Infof("registering snapshot ID %s", id)
+	cl.managedResourceInfos = append(cl.managedResourceInfos, resourceInfo{
+		id:   id,
+		data: snapshotInfo{},
+	})
+}
+
+func (cl *Resources) unregisterResource(offset int, id string) {
+	cl.mutex.Lock()
+	defer cl.mutex.Unlock()
+	cl.unregisterResourceNoLock(offset+1, id)
+}
+
+func (cl *Resources) unregisterResourceNoLock(offset int, id string) {
+	ExpectWithOffset(offset, id).NotTo(BeEmpty(), "ID for unregister resource is missing")
+	// Find resource info with the given ID and remove it.
+	for i, resInfo := range cl.managedResourceInfos {
+		if resInfo.id == id {
+			klog.V(4).Infof("unregistering resource ID %s", id)
+			cl.managedResourceInfos = append(cl.managedResourceInfos[:i], cl.managedResourceInfos[i+1:]...)
+			return
+		}
+	}
+}
+
+// Cleanup calls unpublish methods as needed and deletes all managed resources.
+func (cl *Resources) Cleanup() {
+	klog.V(4).Info("cleaning up all registered resources")
+	cl.mutex.Lock()
+	defer cl.mutex.Unlock()
+	ctx := context.Background()
+
+	// Clean up resources in LIFO order to account for dependency order.
+	var errs []error
+	for i := len(cl.managedResourceInfos) - 1; i >= 0; i-- {
+		resInfo := cl.managedResourceInfos[i]
+		id := resInfo.id
+		switch resType := resInfo.data.(type) {
+		case volumeInfo:
+			errs = append(errs, cl.cleanupVolume(ctx, 2, id, resType)...)
+		case snapshotInfo:
+			errs = append(errs, cl.cleanupSnapshot(ctx, 2, id)...)
+		default:
+			Fail(fmt.Sprintf("unknown resource type: %T", resType), 1)
+		}
+	}
+
+	ExpectWithOffset(2, errs).To(BeEmpty(), "resource cleanup failed")
+
+	klog.V(4).Info("clearing managed resources list")
+	cl.managedResourceInfos = []resourceInfo{}
+}
+
+func (cl *Resources) cleanupVolume(ctx context.Context, offset int, volumeID string, info volumeInfo) (errs []error) {
+	klog.V(4).Infof("deleting volume ID %s", volumeID)
+	if cl.NodeClient != nil {
+		if _, err := cl.NodeUnpublishVolume(
+			ctx,
+			&csi.NodeUnpublishVolumeRequest{
+				VolumeId:   volumeID,
+				TargetPath: cl.Context.TargetPath + "/target",
+			},
+		); isRelevantError(err) {
+			errs = append(errs, fmt.Errorf("NodeUnpublishVolume for volume ID %s failed: %s", volumeID, err))
+		}
+
+		if cl.NodeStageSupported {
+			if _, err := cl.NodeUnstageVolume(
+				ctx,
+				&csi.NodeUnstageVolumeRequest{
+					VolumeId:          volumeID,
+					StagingTargetPath: cl.Context.StagingPath,
+				},
+			); isRelevantError(err) {
+				errs = append(errs, fmt.Errorf("NodeUnstageVolume for volume ID %s failed: %s", volumeID, err))
+			}
+		}
+	}
+
+	if cl.ControllerPublishSupported && info.NodeID != "" {
+		if _, err := cl.ControllerClient.ControllerUnpublishVolume(
+			ctx,
+			&csi.ControllerUnpublishVolumeRequest{
+				VolumeId: volumeID,
+				NodeId:   info.NodeID,
+				Secrets:  cl.Context.Secrets.ControllerUnpublishVolumeSecret,
+			},
+		); err != nil {
+			errs = append(errs, fmt.Errorf("ControllerUnpublishVolume for volume ID %s failed: %s", volumeID, err))
+		}
+	}
+
+	if _, err := cl.ControllerClient.DeleteVolume(
+		ctx,
+		&csi.DeleteVolumeRequest{
+			VolumeId: volumeID,
+			Secrets:  cl.Context.Secrets.DeleteVolumeSecret,
+		},
+	); err != nil {
+		errs = append(errs, fmt.Errorf("DeleteVolume for volume ID %s failed: %s", volumeID, err))
+	}
+
+	return errs
+}
+
+func (cl *Resources) cleanupSnapshot(ctx context.Context, offset int, snapshotID string) []error {
+	klog.Infof("deleting snapshot ID %s", snapshotID)
+	if _, err := cl.ControllerClient.DeleteSnapshot(
+		ctx,
+		&csi.DeleteSnapshotRequest{
+			SnapshotId: snapshotID,
+			Secrets:    cl.Context.Secrets.DeleteSnapshotSecret,
+		},
+	); err != nil {
+		return []error{fmt.Errorf("DeleteSnapshot for snapshot ID %s failed: %s", snapshotID, err)}
+	}
+
+	return nil
+}
+
+func isRelevantError(err error) bool {
+	return err != nil && status.Code(err) != codes.NotFound
+}
diff --git a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/sanity.go b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/sanity.go
similarity index 80%
rename from vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/sanity.go
rename to vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/sanity.go
index 6ee1dce0..78157301 100644
--- a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/sanity.go
+++ b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/sanity.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2017 Luis Pabón luis@portworx.com
+Copyright 2021 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.
@@ -26,7 +26,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/kubernetes-csi/csi-test/v3/utils"
+	"github.com/kubernetes-csi/csi-test/v4/utils"
 	yaml "gopkg.in/yaml.v2"
 
 	"google.golang.org/grpc"
@@ -95,6 +95,7 @@ type TestConfig struct {
 	TestVolumeParametersFile  string
 	TestVolumeParameters      map[string]string
 	TestNodeVolumeAttachLimit bool
+	TestVolumeAccessType      string
 
 	// JUnitFile is used by Test to store test results in JUnit
 	// format. When using GinkgoTest, the caller is responsible
@@ -155,6 +156,22 @@ type TestConfig struct {
 	// generator for valid Volume and Node IDs. Defaults to
 	// DefaultIDGenerator.
 	IDGen IDGenerator
+
+	// Repeat count for Volume operations to test idempotency requirements.
+	// some tests can optionally run repeated variants for those Volume operations
+	// that are required to be idempotent, based on this count value.
+	// <= 0: skip idempotency tests
+	// n > 0: repeat each call n times
+	// NewTestConfig() by default enables idempotency testing.
+	IdempotentCount int
+
+	// CheckPath is a callback function to check whether the given path exists.
+	// If this is not set, then defaultCheckPath will be used instead.
+	CheckPath func(path string) (PathKind, error)
+	// Command to be executed for a customized way to check a given path.
+	CheckPathCmd string
+	// Timeout for the executed command to check a given path.
+	CheckPathCmdTimeout time.Duration
 }
 
 // TestContext gets initialized by the sanity package before each test
@@ -182,17 +199,20 @@ func NewTestConfig() TestConfig {
 		CreatePathCmdTimeout: 10 * time.Second,
 		RemovePathCmdTimeout: 10 * time.Second,
 		TestVolumeSize:       10 * 1024 * 1024 * 1024, // 10 GiB
+		TestVolumeAccessType: "mount",
 		IDGen:                &DefaultIDGenerator{},
+		IdempotentCount:      10,
+		CheckPathCmdTimeout:  10 * time.Second,
 
 		DialOptions:           []grpc.DialOption{grpc.WithInsecure()},
 		ControllerDialOptions: []grpc.DialOption{grpc.WithInsecure()},
 	}
 }
 
-// newContext sets up sanity testing with a config supplied by the
+// NewContext sets up sanity testing with a config supplied by the
 // user of the sanity package. Ownership of that config is shared
 // between the sanity package and the caller.
-func newTestContext(config *TestConfig) *TestContext {
+func NewTestContext(config *TestConfig) *TestContext {
 	return &TestContext{
 		Config: config,
 	}
@@ -221,7 +241,7 @@ func Test(t GinkgoTestingT, config TestConfig) {
 // still be modified in a BeforeEach. The sanity package itself treats
 // it as read-only.
 func GinkgoTest(config *TestConfig) *TestContext {
-	sc := newTestContext(config)
+	sc := NewTestContext(config)
 	registerTestsInGinkgo(sc)
 	return sc
 }
@@ -438,3 +458,89 @@ func PseudoUUID() string {
 func UniqueString(prefix string) string {
 	return prefix + uniqueSuffix
 }
+
+// Return codes for CheckPath
+type PathKind string
+
+const (
+	PathIsFile     PathKind = "file"
+	PathIsDir      PathKind = "directory"
+	PathIsNotFound PathKind = "not_found"
+	PathIsOther    PathKind = "other"
+)
+
+// IsPathKind validates that the input string matches one of the defined
+// PathKind values above. If successful, it returns the corresponding
+// PathKind type. Otherwise, it returns an error.
+func IsPathKind(in string) (PathKind, error) {
+	pk := PathKind(in)
+	switch pk {
+	case PathIsFile, PathIsDir, PathIsNotFound, PathIsOther:
+		return pk, nil
+	default:
+		return pk, fmt.Errorf("invalid PathType: %s", pk)
+	}
+}
+
+// defaultCheckPath runs os.Stat against the provided path and returns
+// a code indicating whether it's a file, directory, not found, or other.
+// If an error occurs, it returns an empty string along with the error.
+func defaultCheckPath(path string) (PathKind, error) {
+	var pk PathKind
+	fi, err := os.Stat(path)
+	if err != nil {
+		if os.IsNotExist(err) {
+			return PathIsNotFound, nil
+		} else {
+			return "", err
+		}
+	}
+	switch mode := fi.Mode(); {
+	case mode.IsRegular():
+		pk = PathIsFile
+	case mode.IsDir():
+		pk = PathIsDir
+	default:
+		pk = PathIsOther
+	}
+	return pk, nil
+}
+
+// CheckPath takes a path parameter and returns a code indicating whether
+// it's a file, directory, not found, or other. This can be done using a
+// custom command, custom function, or by the defaultCheckPath function.
+// If an error occurs, it returns an empty string along with the error.
+func CheckPath(path string, config *TestConfig) (PathKind, error) {
+	if path == "" {
+		return "", fmt.Errorf("path argument must not be empty")
+	}
+	if config == nil {
+		return "", fmt.Errorf("config argument must not be nil")
+	}
+
+	if config.CheckPathCmd != "" {
+		// Check the provided path using the check path command.
+		ctx, cancel := context.WithTimeout(context.Background(), config.CheckPathCmdTimeout)
+		defer cancel()
+
+		cmd := exec.CommandContext(ctx, config.CheckPathCmd, path)
+		cmd.Stderr = os.Stderr
+		out, err := cmd.Output()
+		if err != nil {
+			return "", fmt.Errorf("check path command %s failed: %v", config.CheckPathCmd, err)
+		}
+		// The output of this command is expected to match the value for
+		// PathIsFile, PathIsDir, PathIsNotFound, or PathIsOther.
+		pk, err := IsPathKind(strings.TrimSpace(string(out)))
+		if err != nil {
+			return "", fmt.Errorf("check path command %s failed: %v", config.CheckPathCmd, err)
+		}
+		return pk, nil
+	} else if config.CheckPath != nil {
+		// Check the path using a custom callback function.
+		return config.CheckPath(path)
+	} else {
+		// Use defaultCheckPath if no custom function was provided.
+		return defaultCheckPath(path)
+	}
+}
diff --git a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/tests.go b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/tests.go
similarity index 96%
rename from vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/tests.go
rename to vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/tests.go
index 92f2fe57..95d8ba74 100644
--- a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/tests.go
+++ b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/tests.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2018 Intel Corporation
+Copyright 2021 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.
@@ -41,6 +41,7 @@ func DescribeSanity(text string, body func(*TestContext)) bool {
 // for the tests registered earlier with DescribeSanity.
 func registerTestsInGinkgo(sc *TestContext) {
 	for _, test := range tests {
+		test := test
 		Describe(test.text, func() {
 			BeforeEach(func() {
 				sc.Setup()
diff --git a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/util.go b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/util.go
similarity index 98%
rename from vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/util.go
rename to vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/util.go
index bca2f83f..dab2b100 100644
--- a/vendor/github.com/kubernetes-csi/csi-test/v3/pkg/sanity/util.go
+++ b/vendor/github.com/kubernetes-csi/csi-test/v4/pkg/sanity/util.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2019 Kubernetes Authors.
+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.
diff --git a/vendor/github.com/kubernetes-csi/csi-test/v3/utils/grpcutil.go b/vendor/github.com/kubernetes-csi/csi-test/v4/utils/grpcutil.go
similarity index 100%
rename from vendor/github.com/kubernetes-csi/csi-test/v3/utils/grpcutil.go
rename to vendor/github.com/kubernetes-csi/csi-test/v4/utils/grpcutil.go
diff --git a/vendor/github.com/kubernetes-csi/csi-test/v3/utils/safegoroutinetester.go b/vendor/github.com/kubernetes-csi/csi-test/v4/utils/safegoroutinetester.go
similarity index 96%
rename from vendor/github.com/kubernetes-csi/csi-test/v3/utils/safegoroutinetester.go
rename to vendor/github.com/kubernetes-csi/csi-test/v4/utils/safegoroutinetester.go
index 3baf9672..2450e937 100644
--- a/vendor/github.com/kubernetes-csi/csi-test/v3/utils/safegoroutinetester.go
+++ b/vendor/github.com/kubernetes-csi/csi-test/v4/utils/safegoroutinetester.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2017 Luis Pabón luis@portworx.com
+Copyright 2021 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.
diff --git a/vendor/github.com/onsi/ginkgo/internal/testingtproxy/testing_t_proxy.go b/vendor/github.com/onsi/ginkgo/internal/testingtproxy/testing_t_proxy.go
index 090445d0..d7bbb7a9 100644
--- a/vendor/github.com/onsi/ginkgo/internal/testingtproxy/testing_t_proxy.go
+++ b/vendor/github.com/onsi/ginkgo/internal/testingtproxy/testing_t_proxy.go
@@ -6,21 +6,34 @@ import (
 )
 
 type failFunc func(message string, callerSkip ...int)
+type skipFunc func(message string, callerSkip ...int)
+type failedFunc func() bool
+type nameFunc func() string
 
-func New(writer io.Writer, fail failFunc, offset int) *ginkgoTestingTProxy {
+func New(writer io.Writer, fail failFunc, skip skipFunc, failed failedFunc, name nameFunc, offset int) *ginkgoTestingTProxy {
 	return &ginkgoTestingTProxy{
 		fail:   fail,
 		offset: offset,
 		writer: writer,
+		skip:   skip,
+		failed: failed,
+		name:   name,
 	}
 }
 
 type ginkgoTestingTProxy struct {
 	fail   failFunc
+	skip   skipFunc
+	failed failedFunc
+	name   nameFunc
 	offset int
 	writer io.Writer
 }
 
+func (t *ginkgoTestingTProxy) Cleanup(func()) {
+	// No-op
+}
+
 func (t *ginkgoTestingTProxy) Error(args ...interface{}) {
 	t.fail(fmt.Sprintln(args...), t.offset)
 }
@@ -37,6 +50,10 @@ func (t *ginkgoTestingTProxy) FailNow() {
 	t.fail("failed", t.offset)
 }
 
+func (t *ginkgoTestingTProxy) Failed() bool {
+	return t.failed()
+}
+
 func (t *ginkgoTestingTProxy) Fatal(args ...interface{}) {
 	t.fail(fmt.Sprintln(args...), t.offset)
 }
@@ -45,6 +62,10 @@ func (t *ginkgoTestingTProxy) Fatalf(format string, args ...interface{}) {
 	t.fail(fmt.Sprintf(format, args...), t.offset)
 }
 
+func (t *ginkgoTestingTProxy) Helper() {
+	// No-op
+}
+
 func (t *ginkgoTestingTProxy) Log(args ...interface{}) {
 	fmt.Fprintln(t.writer, args...)
 }
@@ -53,24 +74,31 @@ func (t *ginkgoTestingTProxy) Logf(format string, args ...interface{}) {
 	t.Log(fmt.Sprintf(format, args...))
 }
 
-func (t *ginkgoTestingTProxy) Failed() bool {
-	return false
+func (t *ginkgoTestingTProxy) Name() string {
+	return t.name()
 }
 
 func (t *ginkgoTestingTProxy) Parallel() {
+	// No-op
 }
 
 func (t *ginkgoTestingTProxy) Skip(args ...interface{}) {
-	fmt.Println(args...)
+	t.skip(fmt.Sprintln(args...), t.offset)
 }
 
-func (t *ginkgoTestingTProxy) Skipf(format string, args ...interface{}) {
-	t.Skip(fmt.Sprintf(format, args...))
+func (t *ginkgoTestingTProxy) SkipNow() {
+	t.skip("skip", t.offset)
 }
 
-func (t *ginkgoTestingTProxy) SkipNow() {
+func (t *ginkgoTestingTProxy) Skipf(format string, args ...interface{}) {
+	t.skip(fmt.Sprintf(format, args...), t.offset)
 }
 
 func (t *ginkgoTestingTProxy) Skipped() bool {
 	return false
 }
+
+func (t *ginkgoTestingTProxy) TempDir() string {
+	// No-op
+	return ""
+}