csi_client_test.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package csi
  14. import (
  15. "context"
  16. "errors"
  17. "io"
  18. "reflect"
  19. "testing"
  20. csipbv1 "github.com/container-storage-interface/spec/lib/go/csi"
  21. api "k8s.io/api/core/v1"
  22. "k8s.io/apimachinery/pkg/api/resource"
  23. "k8s.io/kubernetes/pkg/volume"
  24. "k8s.io/kubernetes/pkg/volume/csi/fake"
  25. )
  26. type fakeCsiDriverClient struct {
  27. t *testing.T
  28. nodeClient *fake.NodeClient
  29. }
  30. func newFakeCsiDriverClient(t *testing.T, stagingCapable bool) *fakeCsiDriverClient {
  31. return &fakeCsiDriverClient{
  32. t: t,
  33. nodeClient: fake.NewNodeClient(stagingCapable),
  34. }
  35. }
  36. func newFakeCsiDriverClientWithExpansion(t *testing.T, stagingCapable bool, expansionSet bool) *fakeCsiDriverClient {
  37. return &fakeCsiDriverClient{
  38. t: t,
  39. nodeClient: fake.NewNodeClientWithExpansion(stagingCapable, expansionSet),
  40. }
  41. }
  42. func newFakeCsiDriverClientWithVolumeStats(t *testing.T, volumeStatsSet bool) *fakeCsiDriverClient {
  43. return &fakeCsiDriverClient{
  44. t: t,
  45. nodeClient: fake.NewNodeClientWithVolumeStats(volumeStatsSet),
  46. }
  47. }
  48. func (c *fakeCsiDriverClient) NodeGetInfo(ctx context.Context) (
  49. nodeID string,
  50. maxVolumePerNode int64,
  51. accessibleTopology map[string]string,
  52. err error) {
  53. resp, err := c.nodeClient.NodeGetInfo(ctx, &csipbv1.NodeGetInfoRequest{})
  54. topology := resp.GetAccessibleTopology()
  55. if topology != nil {
  56. accessibleTopology = topology.Segments
  57. }
  58. return resp.GetNodeId(), resp.GetMaxVolumesPerNode(), accessibleTopology, err
  59. }
  60. func (c *fakeCsiDriverClient) NodeGetVolumeStats(ctx context.Context, volID string, targetPath string) (
  61. usageCountMap *volume.Metrics, err error) {
  62. c.t.Log("calling fake.NodeGetVolumeStats...")
  63. req := &csipbv1.NodeGetVolumeStatsRequest{
  64. VolumeId: volID,
  65. VolumePath: targetPath,
  66. }
  67. resp, err := c.nodeClient.NodeGetVolumeStats(ctx, req)
  68. usages := resp.GetUsage()
  69. metrics := &volume.Metrics{}
  70. if usages == nil {
  71. return nil, nil
  72. }
  73. for _, usage := range usages {
  74. unit := usage.GetUnit()
  75. switch unit {
  76. case csipbv1.VolumeUsage_BYTES:
  77. metrics.Available = resource.NewQuantity(usage.GetAvailable(), resource.BinarySI)
  78. metrics.Capacity = resource.NewQuantity(usage.GetTotal(), resource.BinarySI)
  79. metrics.Used = resource.NewQuantity(usage.GetUsed(), resource.BinarySI)
  80. case csipbv1.VolumeUsage_INODES:
  81. metrics.InodesFree = resource.NewQuantity(usage.GetAvailable(), resource.BinarySI)
  82. metrics.Inodes = resource.NewQuantity(usage.GetTotal(), resource.BinarySI)
  83. metrics.InodesUsed = resource.NewQuantity(usage.GetUsed(), resource.BinarySI)
  84. }
  85. }
  86. return metrics, nil
  87. }
  88. func (c *fakeCsiDriverClient) NodeSupportsVolumeStats(ctx context.Context) (bool, error) {
  89. c.t.Log("calling fake.NodeSupportsVolumeStats...")
  90. req := &csipbv1.NodeGetCapabilitiesRequest{}
  91. resp, err := c.nodeClient.NodeGetCapabilities(ctx, req)
  92. if err != nil {
  93. return false, err
  94. }
  95. capabilities := resp.GetCapabilities()
  96. if capabilities == nil {
  97. return false, nil
  98. }
  99. for _, capability := range capabilities {
  100. if capability.GetRpc().GetType() == csipbv1.NodeServiceCapability_RPC_GET_VOLUME_STATS {
  101. return true, nil
  102. }
  103. }
  104. return false, nil
  105. }
  106. func (c *fakeCsiDriverClient) NodePublishVolume(
  107. ctx context.Context,
  108. volID string,
  109. readOnly bool,
  110. stagingTargetPath string,
  111. targetPath string,
  112. accessMode api.PersistentVolumeAccessMode,
  113. publishContext map[string]string,
  114. volumeContext map[string]string,
  115. secrets map[string]string,
  116. fsType string,
  117. mountOptions []string,
  118. ) error {
  119. c.t.Log("calling fake.NodePublishVolume...")
  120. req := &csipbv1.NodePublishVolumeRequest{
  121. VolumeId: volID,
  122. TargetPath: targetPath,
  123. StagingTargetPath: stagingTargetPath,
  124. Readonly: readOnly,
  125. PublishContext: publishContext,
  126. VolumeContext: volumeContext,
  127. Secrets: secrets,
  128. VolumeCapability: &csipbv1.VolumeCapability{
  129. AccessMode: &csipbv1.VolumeCapability_AccessMode{
  130. Mode: asCSIAccessModeV1(accessMode),
  131. },
  132. AccessType: &csipbv1.VolumeCapability_Mount{
  133. Mount: &csipbv1.VolumeCapability_MountVolume{
  134. FsType: fsType,
  135. MountFlags: mountOptions,
  136. },
  137. },
  138. },
  139. }
  140. _, err := c.nodeClient.NodePublishVolume(ctx, req)
  141. return err
  142. }
  143. func (c *fakeCsiDriverClient) NodeUnpublishVolume(ctx context.Context, volID string, targetPath string) error {
  144. c.t.Log("calling fake.NodeUnpublishVolume...")
  145. req := &csipbv1.NodeUnpublishVolumeRequest{
  146. VolumeId: volID,
  147. TargetPath: targetPath,
  148. }
  149. _, err := c.nodeClient.NodeUnpublishVolume(ctx, req)
  150. return err
  151. }
  152. func (c *fakeCsiDriverClient) NodeStageVolume(ctx context.Context,
  153. volID string,
  154. publishContext map[string]string,
  155. stagingTargetPath string,
  156. fsType string,
  157. accessMode api.PersistentVolumeAccessMode,
  158. secrets map[string]string,
  159. volumeContext map[string]string,
  160. mountOptions []string,
  161. ) error {
  162. c.t.Log("calling fake.NodeStageVolume...")
  163. req := &csipbv1.NodeStageVolumeRequest{
  164. VolumeId: volID,
  165. PublishContext: publishContext,
  166. StagingTargetPath: stagingTargetPath,
  167. VolumeCapability: &csipbv1.VolumeCapability{
  168. AccessMode: &csipbv1.VolumeCapability_AccessMode{
  169. Mode: asCSIAccessModeV1(accessMode),
  170. },
  171. AccessType: &csipbv1.VolumeCapability_Mount{
  172. Mount: &csipbv1.VolumeCapability_MountVolume{
  173. FsType: fsType,
  174. MountFlags: mountOptions,
  175. },
  176. },
  177. },
  178. Secrets: secrets,
  179. VolumeContext: volumeContext,
  180. }
  181. _, err := c.nodeClient.NodeStageVolume(ctx, req)
  182. return err
  183. }
  184. func (c *fakeCsiDriverClient) NodeUnstageVolume(ctx context.Context, volID, stagingTargetPath string) error {
  185. c.t.Log("calling fake.NodeUnstageVolume...")
  186. req := &csipbv1.NodeUnstageVolumeRequest{
  187. VolumeId: volID,
  188. StagingTargetPath: stagingTargetPath,
  189. }
  190. _, err := c.nodeClient.NodeUnstageVolume(ctx, req)
  191. return err
  192. }
  193. func (c *fakeCsiDriverClient) NodeSupportsNodeExpand(ctx context.Context) (bool, error) {
  194. c.t.Log("calling fake.NodeSupportsNodeExpand...")
  195. req := &csipbv1.NodeGetCapabilitiesRequest{}
  196. resp, err := c.nodeClient.NodeGetCapabilities(ctx, req)
  197. if err != nil {
  198. return false, err
  199. }
  200. capabilities := resp.GetCapabilities()
  201. if capabilities == nil {
  202. return false, nil
  203. }
  204. for _, capability := range capabilities {
  205. if capability.GetRpc().GetType() == csipbv1.NodeServiceCapability_RPC_EXPAND_VOLUME {
  206. return true, nil
  207. }
  208. }
  209. return false, nil
  210. }
  211. func (c *fakeCsiDriverClient) NodeSupportsStageUnstage(ctx context.Context) (bool, error) {
  212. c.t.Log("calling fake.NodeGetCapabilities for NodeSupportsStageUnstage...")
  213. req := &csipbv1.NodeGetCapabilitiesRequest{}
  214. resp, err := c.nodeClient.NodeGetCapabilities(ctx, req)
  215. if err != nil {
  216. return false, err
  217. }
  218. capabilities := resp.GetCapabilities()
  219. stageUnstageSet := false
  220. if capabilities == nil {
  221. return false, nil
  222. }
  223. for _, capability := range capabilities {
  224. if capability.GetRpc().GetType() == csipbv1.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME {
  225. stageUnstageSet = true
  226. }
  227. }
  228. return stageUnstageSet, nil
  229. }
  230. func (c *fakeCsiDriverClient) NodeExpandVolume(ctx context.Context, volumeid, volumePath string, newSize resource.Quantity) (resource.Quantity, error) {
  231. c.t.Log("calling fake.NodeExpandVolume")
  232. req := &csipbv1.NodeExpandVolumeRequest{
  233. VolumeId: volumeid,
  234. VolumePath: volumePath,
  235. CapacityRange: &csipbv1.CapacityRange{RequiredBytes: newSize.Value()},
  236. }
  237. resp, err := c.nodeClient.NodeExpandVolume(ctx, req)
  238. if err != nil {
  239. return newSize, err
  240. }
  241. updatedQuantity := resource.NewQuantity(resp.CapacityBytes, resource.BinarySI)
  242. return *updatedQuantity, nil
  243. }
  244. func setupClient(t *testing.T, stageUnstageSet bool) csiClient {
  245. return newFakeCsiDriverClient(t, stageUnstageSet)
  246. }
  247. func setupClientWithExpansion(t *testing.T, stageUnstageSet bool, expansionSet bool) csiClient {
  248. return newFakeCsiDriverClientWithExpansion(t, stageUnstageSet, expansionSet)
  249. }
  250. func setupClientWithVolumeStats(t *testing.T, volumeStatsSet bool) csiClient {
  251. return newFakeCsiDriverClientWithVolumeStats(t, volumeStatsSet)
  252. }
  253. func checkErr(t *testing.T, expectedAnError bool, actualError error) {
  254. t.Helper()
  255. errOccurred := actualError != nil
  256. if expectedAnError && !errOccurred {
  257. t.Error("expected an error")
  258. }
  259. if !expectedAnError && errOccurred {
  260. t.Errorf("expected no error, got: %v", actualError)
  261. }
  262. }
  263. func TestClientNodeGetInfo(t *testing.T) {
  264. testCases := []struct {
  265. name string
  266. expectedNodeID string
  267. expectedMaxVolumePerNode int64
  268. expectedAccessibleTopology map[string]string
  269. mustFail bool
  270. err error
  271. }{
  272. {
  273. name: "test ok",
  274. expectedNodeID: "node1",
  275. expectedMaxVolumePerNode: 16,
  276. expectedAccessibleTopology: map[string]string{"com.example.csi-topology/zone": "zone1"},
  277. },
  278. {
  279. name: "grpc error",
  280. mustFail: true,
  281. err: errors.New("grpc error"),
  282. },
  283. }
  284. for _, tc := range testCases {
  285. t.Logf("test case: %s", tc.name)
  286. fakeCloser := fake.NewCloser(t)
  287. client := &csiDriverClient{
  288. driverName: "Fake Driver Name",
  289. nodeV1ClientCreator: func(addr csiAddr) (csipbv1.NodeClient, io.Closer, error) {
  290. nodeClient := fake.NewNodeClient(false /* stagingCapable */)
  291. nodeClient.SetNextError(tc.err)
  292. nodeClient.SetNodeGetInfoResp(&csipbv1.NodeGetInfoResponse{
  293. NodeId: tc.expectedNodeID,
  294. MaxVolumesPerNode: tc.expectedMaxVolumePerNode,
  295. AccessibleTopology: &csipbv1.Topology{
  296. Segments: tc.expectedAccessibleTopology,
  297. },
  298. })
  299. return nodeClient, fakeCloser, nil
  300. },
  301. }
  302. nodeID, maxVolumePerNode, accessibleTopology, err := client.NodeGetInfo(context.Background())
  303. checkErr(t, tc.mustFail, err)
  304. if nodeID != tc.expectedNodeID {
  305. t.Errorf("expected nodeID: %v; got: %v", tc.expectedNodeID, nodeID)
  306. }
  307. if maxVolumePerNode != tc.expectedMaxVolumePerNode {
  308. t.Errorf("expected maxVolumePerNode: %v; got: %v", tc.expectedMaxVolumePerNode, maxVolumePerNode)
  309. }
  310. if !reflect.DeepEqual(accessibleTopology, tc.expectedAccessibleTopology) {
  311. t.Errorf("expected accessibleTopology: %v; got: %v", tc.expectedAccessibleTopology, accessibleTopology)
  312. }
  313. if !tc.mustFail {
  314. fakeCloser.Check()
  315. }
  316. }
  317. }
  318. func TestClientNodePublishVolume(t *testing.T) {
  319. testCases := []struct {
  320. name string
  321. volID string
  322. targetPath string
  323. fsType string
  324. mustFail bool
  325. err error
  326. }{
  327. {name: "test ok", volID: "vol-test", targetPath: "/test/path"},
  328. {name: "missing volID", targetPath: "/test/path", mustFail: true},
  329. {name: "missing target path", volID: "vol-test", mustFail: true},
  330. {name: "bad fs", volID: "vol-test", targetPath: "/test/path", fsType: "badfs", mustFail: true},
  331. {name: "grpc error", volID: "vol-test", targetPath: "/test/path", mustFail: true, err: errors.New("grpc error")},
  332. }
  333. for _, tc := range testCases {
  334. t.Logf("test case: %s", tc.name)
  335. fakeCloser := fake.NewCloser(t)
  336. client := &csiDriverClient{
  337. driverName: "Fake Driver Name",
  338. nodeV1ClientCreator: func(addr csiAddr) (csipbv1.NodeClient, io.Closer, error) {
  339. nodeClient := fake.NewNodeClient(false /* stagingCapable */)
  340. nodeClient.SetNextError(tc.err)
  341. return nodeClient, fakeCloser, nil
  342. },
  343. }
  344. err := client.NodePublishVolume(
  345. context.Background(),
  346. tc.volID,
  347. false,
  348. "",
  349. tc.targetPath,
  350. api.ReadWriteOnce,
  351. map[string]string{"device": "/dev/null"},
  352. map[string]string{"attr0": "val0"},
  353. map[string]string{},
  354. tc.fsType,
  355. []string{},
  356. )
  357. checkErr(t, tc.mustFail, err)
  358. if !tc.mustFail {
  359. fakeCloser.Check()
  360. }
  361. }
  362. }
  363. func TestClientNodeUnpublishVolume(t *testing.T) {
  364. testCases := []struct {
  365. name string
  366. volID string
  367. targetPath string
  368. mustFail bool
  369. err error
  370. }{
  371. {name: "test ok", volID: "vol-test", targetPath: "/test/path"},
  372. {name: "missing volID", targetPath: "/test/path", mustFail: true},
  373. {name: "missing target path", volID: "vol-test", mustFail: true},
  374. {name: "grpc error", volID: "vol-test", targetPath: "/test/path", mustFail: true, err: errors.New("grpc error")},
  375. }
  376. for _, tc := range testCases {
  377. t.Logf("test case: %s", tc.name)
  378. fakeCloser := fake.NewCloser(t)
  379. client := &csiDriverClient{
  380. driverName: "Fake Driver Name",
  381. nodeV1ClientCreator: func(addr csiAddr) (csipbv1.NodeClient, io.Closer, error) {
  382. nodeClient := fake.NewNodeClient(false /* stagingCapable */)
  383. nodeClient.SetNextError(tc.err)
  384. return nodeClient, fakeCloser, nil
  385. },
  386. }
  387. err := client.NodeUnpublishVolume(context.Background(), tc.volID, tc.targetPath)
  388. checkErr(t, tc.mustFail, err)
  389. if !tc.mustFail {
  390. fakeCloser.Check()
  391. }
  392. }
  393. }
  394. func TestClientNodeStageVolume(t *testing.T) {
  395. testCases := []struct {
  396. name string
  397. volID string
  398. stagingTargetPath string
  399. fsType string
  400. secrets map[string]string
  401. mountOptions []string
  402. mustFail bool
  403. err error
  404. }{
  405. {name: "test ok", volID: "vol-test", stagingTargetPath: "/test/path", fsType: "ext4", mountOptions: []string{"unvalidated"}},
  406. {name: "missing volID", stagingTargetPath: "/test/path", mustFail: true},
  407. {name: "missing target path", volID: "vol-test", mustFail: true},
  408. {name: "bad fs", volID: "vol-test", stagingTargetPath: "/test/path", fsType: "badfs", mustFail: true},
  409. {name: "grpc error", volID: "vol-test", stagingTargetPath: "/test/path", mustFail: true, err: errors.New("grpc error")},
  410. }
  411. for _, tc := range testCases {
  412. t.Logf("Running test case: %s", tc.name)
  413. fakeCloser := fake.NewCloser(t)
  414. client := &csiDriverClient{
  415. driverName: "Fake Driver Name",
  416. nodeV1ClientCreator: func(addr csiAddr) (csipbv1.NodeClient, io.Closer, error) {
  417. nodeClient := fake.NewNodeClient(false /* stagingCapable */)
  418. nodeClient.SetNextError(tc.err)
  419. return nodeClient, fakeCloser, nil
  420. },
  421. }
  422. err := client.NodeStageVolume(
  423. context.Background(),
  424. tc.volID,
  425. map[string]string{"device": "/dev/null"},
  426. tc.stagingTargetPath,
  427. tc.fsType,
  428. api.ReadWriteOnce,
  429. tc.secrets,
  430. map[string]string{"attr0": "val0"},
  431. tc.mountOptions,
  432. )
  433. checkErr(t, tc.mustFail, err)
  434. if !tc.mustFail {
  435. fakeCloser.Check()
  436. }
  437. }
  438. }
  439. func TestClientNodeUnstageVolume(t *testing.T) {
  440. testCases := []struct {
  441. name string
  442. volID string
  443. stagingTargetPath string
  444. mustFail bool
  445. err error
  446. }{
  447. {name: "test ok", volID: "vol-test", stagingTargetPath: "/test/path"},
  448. {name: "missing volID", stagingTargetPath: "/test/path", mustFail: true},
  449. {name: "missing target path", volID: "vol-test", mustFail: true},
  450. {name: "grpc error", volID: "vol-test", stagingTargetPath: "/test/path", mustFail: true, err: errors.New("grpc error")},
  451. }
  452. for _, tc := range testCases {
  453. t.Logf("Running test case: %s", tc.name)
  454. fakeCloser := fake.NewCloser(t)
  455. client := &csiDriverClient{
  456. driverName: "Fake Driver Name",
  457. nodeV1ClientCreator: func(addr csiAddr) (csipbv1.NodeClient, io.Closer, error) {
  458. nodeClient := fake.NewNodeClient(false /* stagingCapable */)
  459. nodeClient.SetNextError(tc.err)
  460. return nodeClient, fakeCloser, nil
  461. },
  462. }
  463. err := client.NodeUnstageVolume(
  464. context.Background(),
  465. tc.volID, tc.stagingTargetPath,
  466. )
  467. checkErr(t, tc.mustFail, err)
  468. if !tc.mustFail {
  469. fakeCloser.Check()
  470. }
  471. }
  472. }
  473. func TestNodeExpandVolume(t *testing.T) {
  474. testCases := []struct {
  475. name string
  476. volID string
  477. volumePath string
  478. newSize resource.Quantity
  479. mustFail bool
  480. err error
  481. }{
  482. {
  483. name: "with all correct values",
  484. volID: "vol-abcde",
  485. volumePath: "/foo/bar",
  486. newSize: resource.MustParse("10Gi"),
  487. mustFail: false,
  488. },
  489. {
  490. name: "with missing volume-id",
  491. volumePath: "/foo/bar",
  492. newSize: resource.MustParse("10Gi"),
  493. mustFail: true,
  494. },
  495. {
  496. name: "with missing volume path",
  497. volID: "vol-1234",
  498. newSize: resource.MustParse("10Gi"),
  499. mustFail: true,
  500. },
  501. {
  502. name: "with invalid quantity",
  503. volID: "vol-1234",
  504. volumePath: "/foo/bar",
  505. newSize: *resource.NewQuantity(-10, resource.DecimalSI),
  506. mustFail: true,
  507. },
  508. }
  509. for _, tc := range testCases {
  510. t.Logf("Running test cases : %s", tc.name)
  511. fakeCloser := fake.NewCloser(t)
  512. client := &csiDriverClient{
  513. driverName: "Fake Driver Name",
  514. nodeV1ClientCreator: func(addr csiAddr) (csipbv1.NodeClient, io.Closer, error) {
  515. nodeClient := fake.NewNodeClient(false /* stagingCapable */)
  516. nodeClient.SetNextError(tc.err)
  517. return nodeClient, fakeCloser, nil
  518. },
  519. }
  520. _, err := client.NodeExpandVolume(context.Background(), tc.volID, tc.volumePath, tc.newSize)
  521. checkErr(t, tc.mustFail, err)
  522. if !tc.mustFail {
  523. fakeCloser.Check()
  524. }
  525. }
  526. }
  527. type VolumeStatsOptions struct {
  528. VolumeSpec *volume.Spec
  529. // this just could be volumeID
  530. VolumeID string
  531. // DeviceMountPath location where device is mounted on the node. If volume type
  532. // is attachable - this would be global mount path otherwise
  533. // it would be location where volume was mounted for the pod
  534. DeviceMountPath string
  535. }
  536. func TestVolumeStats(t *testing.T) {
  537. spec := volume.NewSpecFromPersistentVolume(makeTestPV("test-pv", 10, "metrics", "test-vol"), false)
  538. tests := []struct {
  539. name string
  540. volumeStatsSet bool
  541. volumeData VolumeStatsOptions
  542. success bool
  543. }{
  544. {
  545. name: "when nodeVolumeStats=on, VolumeID=on, DeviceMountPath=on",
  546. volumeStatsSet: true,
  547. volumeData: VolumeStatsOptions{
  548. VolumeSpec: spec,
  549. VolumeID: "volume1",
  550. DeviceMountPath: "/foo/bar",
  551. },
  552. success: true,
  553. },
  554. {
  555. name: "when nodeVolumeStats=off, VolumeID=on, DeviceMountPath=on",
  556. volumeStatsSet: false,
  557. volumeData: VolumeStatsOptions{
  558. VolumeSpec: spec,
  559. VolumeID: "volume1",
  560. DeviceMountPath: "/foo/bar",
  561. },
  562. success: false,
  563. },
  564. {
  565. name: "when nodeVolumeStats=on, VolumeID=off, DeviceMountPath=on",
  566. volumeStatsSet: true,
  567. volumeData: VolumeStatsOptions{
  568. VolumeSpec: spec,
  569. VolumeID: "",
  570. DeviceMountPath: "/foo/bar",
  571. },
  572. success: false,
  573. },
  574. {
  575. name: "when nodeVolumeStats=on, VolumeID=on, DeviceMountPath=off",
  576. volumeStatsSet: true,
  577. volumeData: VolumeStatsOptions{
  578. VolumeSpec: spec,
  579. VolumeID: "volume1",
  580. DeviceMountPath: "",
  581. },
  582. success: false,
  583. },
  584. {
  585. name: "when nodeVolumeStats=on, VolumeID=on, DeviceMountPath=off",
  586. volumeStatsSet: true,
  587. volumeData: VolumeStatsOptions{
  588. VolumeSpec: spec,
  589. VolumeID: "",
  590. DeviceMountPath: "",
  591. },
  592. success: false,
  593. },
  594. }
  595. for _, tc := range tests {
  596. ctx, cancel := context.WithTimeout(context.Background(), csiTimeout)
  597. defer cancel()
  598. csiSource, _ := getCSISourceFromSpec(tc.volumeData.VolumeSpec)
  599. csClient := setupClientWithVolumeStats(t, tc.volumeStatsSet)
  600. _, err := csClient.NodeGetVolumeStats(ctx, csiSource.VolumeHandle, tc.volumeData.DeviceMountPath)
  601. if err != nil && tc.success {
  602. t.Errorf("For %s : expected %v got %v", tc.name, tc.success, err)
  603. }
  604. }
  605. }