attacher_test.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. Copyright 2016 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 vsphere_volume
  14. import (
  15. "errors"
  16. "testing"
  17. "k8s.io/api/core/v1"
  18. "k8s.io/apimachinery/pkg/types"
  19. "k8s.io/kubernetes/pkg/volume"
  20. volumetest "k8s.io/kubernetes/pkg/volume/testing"
  21. "k8s.io/legacy-cloud-providers/vsphere/vclib"
  22. "k8s.io/klog"
  23. )
  24. func TestGetDeviceName_Volume(t *testing.T) {
  25. plugin := newPlugin()
  26. volPath := "[local] volumes/test"
  27. spec := createVolSpec(volPath)
  28. deviceName, err := plugin.GetVolumeName(spec)
  29. if err != nil {
  30. t.Errorf("GetDeviceName error: %v", err)
  31. }
  32. if deviceName != volPath {
  33. t.Errorf("GetDeviceName error: expected %s, got %s", volPath, deviceName)
  34. }
  35. }
  36. func TestGetDeviceName_PersistentVolume(t *testing.T) {
  37. plugin := newPlugin()
  38. volPath := "[local] volumes/test"
  39. spec := createPVSpec(volPath)
  40. deviceName, err := plugin.GetVolumeName(spec)
  41. if err != nil {
  42. t.Errorf("GetDeviceName error: %v", err)
  43. }
  44. if deviceName != volPath {
  45. t.Errorf("GetDeviceName error: expected %s, got %s", volPath, deviceName)
  46. }
  47. }
  48. // One testcase for TestAttachDetach table test below
  49. type testcase struct {
  50. name string
  51. // For fake vSphere:
  52. attach attachCall
  53. detach detachCall
  54. diskIsAttached diskIsAttachedCall
  55. t *testing.T
  56. // Actual test to run
  57. test func(test *testcase) (string, error)
  58. // Expected return of the test
  59. expectedDevice string
  60. expectedError error
  61. }
  62. func TestAttachDetach(t *testing.T) {
  63. uuid := "00000000000000"
  64. diskName := "[local] volumes/test"
  65. nodeName := types.NodeName("host")
  66. spec := createVolSpec(diskName)
  67. attachError := errors.New("Fake attach error")
  68. detachError := errors.New("Fake detach error")
  69. diskCheckError := errors.New("Fake DiskIsAttached error")
  70. tests := []testcase{
  71. // Successful Attach call
  72. {
  73. name: "Attach_Positive",
  74. attach: attachCall{diskName, nodeName, uuid, nil},
  75. test: func(testcase *testcase) (string, error) {
  76. attacher := newAttacher(testcase)
  77. return attacher.Attach(spec, nodeName)
  78. },
  79. expectedDevice: "/dev/disk/by-id/wwn-0x" + uuid,
  80. },
  81. // Attach call fails
  82. {
  83. name: "Attach_Negative",
  84. attach: attachCall{diskName, nodeName, "", attachError},
  85. test: func(testcase *testcase) (string, error) {
  86. attacher := newAttacher(testcase)
  87. return attacher.Attach(spec, nodeName)
  88. },
  89. expectedError: attachError,
  90. },
  91. // Detach succeeds
  92. {
  93. name: "Detach_Positive",
  94. diskIsAttached: diskIsAttachedCall{diskName, nodeName, true, nil},
  95. detach: detachCall{diskName, nodeName, nil},
  96. test: func(testcase *testcase) (string, error) {
  97. detacher := newDetacher(testcase)
  98. return "", detacher.Detach(diskName, nodeName)
  99. },
  100. },
  101. // Disk is already detached
  102. {
  103. name: "Detach_Positive_AlreadyDetached",
  104. diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, nil},
  105. test: func(testcase *testcase) (string, error) {
  106. detacher := newDetacher(testcase)
  107. return "", detacher.Detach(diskName, nodeName)
  108. },
  109. },
  110. // Detach succeeds when DiskIsAttached fails
  111. {
  112. name: "Detach_Positive_CheckFails",
  113. diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, diskCheckError},
  114. detach: detachCall{diskName, nodeName, nil},
  115. test: func(testcase *testcase) (string, error) {
  116. detacher := newDetacher(testcase)
  117. return "", detacher.Detach(diskName, nodeName)
  118. },
  119. },
  120. // Detach fails
  121. {
  122. name: "Detach_Negative",
  123. diskIsAttached: diskIsAttachedCall{diskName, nodeName, false, diskCheckError},
  124. detach: detachCall{diskName, nodeName, detachError},
  125. test: func(testcase *testcase) (string, error) {
  126. detacher := newDetacher(testcase)
  127. return "", detacher.Detach(diskName, nodeName)
  128. },
  129. expectedError: detachError,
  130. },
  131. }
  132. for _, testcase := range tests {
  133. testcase.t = t
  134. device, err := testcase.test(&testcase)
  135. if err != testcase.expectedError {
  136. t.Errorf("%s failed: expected err=%q, got %q", testcase.name, testcase.expectedError.Error(), err.Error())
  137. }
  138. if device != testcase.expectedDevice {
  139. t.Errorf("%s failed: expected device=%q, got %q", testcase.name, testcase.expectedDevice, device)
  140. }
  141. t.Logf("Test %q succeeded", testcase.name)
  142. }
  143. }
  144. // newPlugin creates a new vsphereVolumePlugin with fake cloud, NewAttacher
  145. // and NewDetacher won't work.
  146. func newPlugin() *vsphereVolumePlugin {
  147. host := volumetest.NewFakeVolumeHost("/tmp", nil, nil)
  148. plugins := ProbeVolumePlugins()
  149. plugin := plugins[0]
  150. plugin.Init(host)
  151. return plugin.(*vsphereVolumePlugin)
  152. }
  153. func newAttacher(testcase *testcase) *vsphereVMDKAttacher {
  154. return &vsphereVMDKAttacher{
  155. host: nil,
  156. vsphereVolumes: testcase,
  157. }
  158. }
  159. func newDetacher(testcase *testcase) *vsphereVMDKDetacher {
  160. return &vsphereVMDKDetacher{
  161. vsphereVolumes: testcase,
  162. }
  163. }
  164. func createVolSpec(name string) *volume.Spec {
  165. return &volume.Spec{
  166. Volume: &v1.Volume{
  167. VolumeSource: v1.VolumeSource{
  168. VsphereVolume: &v1.VsphereVirtualDiskVolumeSource{
  169. VolumePath: name,
  170. },
  171. },
  172. },
  173. }
  174. }
  175. func createPVSpec(name string) *volume.Spec {
  176. return &volume.Spec{
  177. PersistentVolume: &v1.PersistentVolume{
  178. Spec: v1.PersistentVolumeSpec{
  179. PersistentVolumeSource: v1.PersistentVolumeSource{
  180. VsphereVolume: &v1.VsphereVirtualDiskVolumeSource{
  181. VolumePath: name,
  182. },
  183. },
  184. },
  185. },
  186. }
  187. }
  188. // Fake vSphere implementation
  189. type attachCall struct {
  190. diskName string
  191. nodeName types.NodeName
  192. retDeviceUUID string
  193. ret error
  194. }
  195. type detachCall struct {
  196. diskName string
  197. nodeName types.NodeName
  198. ret error
  199. }
  200. type diskIsAttachedCall struct {
  201. diskName string
  202. nodeName types.NodeName
  203. isAttached bool
  204. ret error
  205. }
  206. func (testcase *testcase) AttachDisk(diskName string, storagePolicyName string, nodeName types.NodeName) (string, error) {
  207. expected := &testcase.attach
  208. if expected.diskName == "" && expected.nodeName == "" {
  209. // testcase.attach looks uninitialized, test did not expect to call
  210. // AttachDisk
  211. testcase.t.Errorf("Unexpected AttachDisk call!")
  212. return "", errors.New("Unexpected AttachDisk call!")
  213. }
  214. if expected.diskName != diskName {
  215. testcase.t.Errorf("Unexpected AttachDisk call: expected diskName %s, got %s", expected.diskName, diskName)
  216. return "", errors.New("Unexpected AttachDisk call: wrong diskName")
  217. }
  218. if expected.nodeName != nodeName {
  219. testcase.t.Errorf("Unexpected AttachDisk call: expected nodeName %s, got %s", expected.nodeName, nodeName)
  220. return "", errors.New("Unexpected AttachDisk call: wrong nodeName")
  221. }
  222. klog.V(4).Infof("AttachDisk call: %s, %s, returning %q, %v", diskName, nodeName, expected.retDeviceUUID, expected.ret)
  223. return expected.retDeviceUUID, expected.ret
  224. }
  225. func (testcase *testcase) DetachDisk(diskName string, nodeName types.NodeName) error {
  226. expected := &testcase.detach
  227. if expected.diskName == "" && expected.nodeName == "" {
  228. // testcase.detach looks uninitialized, test did not expect to call
  229. // DetachDisk
  230. testcase.t.Errorf("Unexpected DetachDisk call!")
  231. return errors.New("Unexpected DetachDisk call!")
  232. }
  233. if expected.diskName != diskName {
  234. testcase.t.Errorf("Unexpected DetachDisk call: expected diskName %s, got %s", expected.diskName, diskName)
  235. return errors.New("Unexpected DetachDisk call: wrong diskName")
  236. }
  237. if expected.nodeName != nodeName {
  238. testcase.t.Errorf("Unexpected DetachDisk call: expected nodeName %s, got %s", expected.nodeName, nodeName)
  239. return errors.New("Unexpected DetachDisk call: wrong nodeName")
  240. }
  241. klog.V(4).Infof("DetachDisk call: %s, %s, returning %v", diskName, nodeName, expected.ret)
  242. return expected.ret
  243. }
  244. func (testcase *testcase) DiskIsAttached(diskName string, nodeName types.NodeName) (bool, error) {
  245. expected := &testcase.diskIsAttached
  246. if expected.diskName == "" && expected.nodeName == "" {
  247. // testcase.diskIsAttached looks uninitialized, test did not expect to
  248. // call DiskIsAttached
  249. testcase.t.Errorf("Unexpected DiskIsAttached call!")
  250. return false, errors.New("Unexpected DiskIsAttached call!")
  251. }
  252. if expected.diskName != diskName {
  253. testcase.t.Errorf("Unexpected DiskIsAttached call: expected diskName %s, got %s", expected.diskName, diskName)
  254. return false, errors.New("Unexpected DiskIsAttached call: wrong diskName")
  255. }
  256. if expected.nodeName != nodeName {
  257. testcase.t.Errorf("Unexpected DiskIsAttached call: expected nodeName %s, got %s", expected.nodeName, nodeName)
  258. return false, errors.New("Unexpected DiskIsAttached call: wrong nodeName")
  259. }
  260. klog.V(4).Infof("DiskIsAttached call: %s, %s, returning %v, %v", diskName, nodeName, expected.isAttached, expected.ret)
  261. return expected.isAttached, expected.ret
  262. }
  263. func (testcase *testcase) DisksAreAttached(nodeVolumes map[types.NodeName][]string) (map[types.NodeName]map[string]bool, error) {
  264. return nil, errors.New("Not implemented")
  265. }
  266. func (testcase *testcase) CreateVolume(volumeOptions *vclib.VolumeOptions) (volumePath string, err error) {
  267. return "", errors.New("Not implemented")
  268. }
  269. func (testcase *testcase) DeleteVolume(vmDiskPath string) error {
  270. return errors.New("Not implemented")
  271. }