sio_mgr_test.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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 scaleio
  14. import (
  15. "errors"
  16. "testing"
  17. "time"
  18. siotypes "github.com/thecodeteam/goscaleio/types/v1"
  19. "k8s.io/utils/exec/testing"
  20. )
  21. var (
  22. fakeSdcID = "test-sdc-123456789"
  23. fakeVolumeID = "1234567890"
  24. fakeDev = "/dev/testABC"
  25. fakeConfig = map[string]string{
  26. confKey.gateway: "http://sio.gateway:1234",
  27. confKey.sslEnabled: "false",
  28. confKey.system: "scaleio",
  29. confKey.volumeName: "sio-0001",
  30. confKey.secretName: "sio-secret",
  31. confKey.username: "c2lvdXNlcgo=", // siouser
  32. confKey.password: "c2lvcGFzc3dvcmQK", // siopassword
  33. }
  34. )
  35. func newTestMgr(t *testing.T) *sioMgr {
  36. mgr, err := newSioMgr(fakeConfig, &testingexec.FakeExec{})
  37. if err != nil {
  38. t.Error(err)
  39. }
  40. mgr.client = newFakeSio()
  41. return mgr
  42. }
  43. func TestMgrNew(t *testing.T) {
  44. mgr, err := newSioMgr(fakeConfig, &testingexec.FakeExec{})
  45. if err != nil {
  46. t.Fatal(err)
  47. }
  48. if mgr.configData == nil {
  49. t.Fatal("configuration data not set")
  50. }
  51. if mgr.configData[confKey.volumeName] != "sio-0001" {
  52. t.Errorf("expecting %s, got %s", "sio-0001", mgr.configData[confKey.volumeName])
  53. }
  54. // check defaults
  55. if mgr.configData[confKey.protectionDomain] != "default" {
  56. t.Errorf("unexpected value for confData[protectionDomain] %s", mgr.configData[confKey.protectionDomain])
  57. }
  58. if mgr.configData[confKey.storagePool] != "default" {
  59. t.Errorf("unexpected value for confData[storagePool] %s", mgr.configData[confKey.storagePool])
  60. }
  61. if mgr.configData[confKey.storageMode] != "ThinProvisioned" {
  62. t.Errorf("unexpected value for confData[storageMode] %s", mgr.configData[confKey.storageMode])
  63. }
  64. }
  65. func TestMgrGetClient(t *testing.T) {
  66. mgr := newTestMgr(t)
  67. _, err := mgr.getClient()
  68. if err != nil {
  69. t.Fatal(err)
  70. }
  71. if mgr.client == nil {
  72. t.Fatal("mgr.client not set")
  73. }
  74. }
  75. func TestMgrCreateVolume(t *testing.T) {
  76. mgr := newTestMgr(t)
  77. vol, err := mgr.CreateVolume("test-vol-0001", 8*1024*1024)
  78. if err != nil {
  79. t.Fatal(err)
  80. }
  81. if vol.Name != "test-vol-0001" {
  82. t.Errorf("unexpected vol.Name %s", vol.Name)
  83. }
  84. }
  85. func TestMgrAttachVolume(t *testing.T) {
  86. mgr := newTestMgr(t)
  87. mgr.CreateVolume("test-vol-0001", 8*1024*1024)
  88. device, err := mgr.AttachVolume("test-vol-0001", false)
  89. if err != nil {
  90. t.Fatal(err)
  91. }
  92. if device != "/dev/testABC" {
  93. t.Errorf("unexpected value for mapped device %s", device)
  94. }
  95. }
  96. func TestMgrAttachVolume_AlreadyAttached(t *testing.T) {
  97. mgr := newTestMgr(t)
  98. mgr.CreateVolume("test-vol-0001", 8*1024*1024)
  99. mgr.AttachVolume("test-vol-0001", false)
  100. dev, err := mgr.AttachVolume("test-vol-0001", false)
  101. if err != nil {
  102. t.Fatalf("unexpected error: %v", err)
  103. }
  104. if dev != "/dev/testABC" {
  105. t.Errorf("unexpected value for mapped device %s", dev)
  106. }
  107. }
  108. func TestMgrAttachVolume_VolumeNotFoundError(t *testing.T) {
  109. mgr := newTestMgr(t)
  110. mgr.CreateVolume("test-vol-0001", 8*1024*1024)
  111. _, err := mgr.AttachVolume("test-vol-0002", false)
  112. if err == nil {
  113. t.Error("attachVolume should fail with volume not found error")
  114. }
  115. }
  116. func TestMgrAttachVolume_WaitForAttachError(t *testing.T) {
  117. mgr := newTestMgr(t)
  118. mgr.CreateVolume("test-vol-0001", 8*1024*1024)
  119. go func() {
  120. c := mgr.client.(*fakeSio)
  121. close(c.waitAttachCtrl)
  122. }()
  123. _, err := mgr.AttachVolume("test-vol-0001", false)
  124. if err == nil {
  125. t.Error("attachVolume should fail with attach timeout error")
  126. }
  127. }
  128. func TestMgrDetachVolume(t *testing.T) {
  129. mgr := newTestMgr(t)
  130. mgr.CreateVolume("test-vol-0001", 8*1024*1024)
  131. mgr.AttachVolume("test-vol-0001", false)
  132. if err := mgr.DetachVolume("test-vol-0001"); err != nil {
  133. t.Fatal(err)
  134. }
  135. fakeSio := mgr.client.(*fakeSio)
  136. if len(fakeSio.volume.MappedSdcInfo) != 0 {
  137. t.Errorf("expecting attached sdc to 0, got %d", len(fakeSio.volume.MappedSdcInfo))
  138. }
  139. if len(fakeSio.devs) != 0 {
  140. t.Errorf("expecting local devs to be 0, got %d", len(fakeSio.devs))
  141. }
  142. }
  143. func TestMgrDetachVolume_VolumeNotFound(t *testing.T) {
  144. mgr := newTestMgr(t)
  145. mgr.CreateVolume("test-vol-0001", 8*1024*1024)
  146. mgr.AttachVolume("test-vol-0001", false)
  147. err := mgr.DetachVolume("test-vol-0002")
  148. if err == nil {
  149. t.Fatal("expected a volume not found failure")
  150. }
  151. }
  152. func TestMgrDetachVolume_VolumeNotAttached(t *testing.T) {
  153. mgr := newTestMgr(t)
  154. mgr.CreateVolume("test-vol-0001", 8*1024*1024)
  155. err := mgr.DetachVolume("test-vol-0001")
  156. if err != nil {
  157. t.Fatal(err)
  158. }
  159. }
  160. func TestMgrDetachVolume_VolumeAlreadyDetached(t *testing.T) {
  161. mgr := newTestMgr(t)
  162. mgr.CreateVolume("test-vol-0001", 8*1024*1024)
  163. mgr.AttachVolume("test-vol-0001", false)
  164. mgr.DetachVolume("test-vol-0001")
  165. err := mgr.DetachVolume("test-vol-0001")
  166. if err != nil {
  167. t.Fatal("failed detaching a volume already detached")
  168. }
  169. }
  170. func TestMgrDetachVolume_WaitForDetachError(t *testing.T) {
  171. mgr := newTestMgr(t)
  172. mgr.CreateVolume("test-vol-0001", 8*1024*1024)
  173. mgr.AttachVolume("test-vol-0001", false)
  174. err := mgr.DetachVolume("test-vol-0001")
  175. if err != nil {
  176. t.Error("detachVolume failed")
  177. }
  178. }
  179. func TestMgrDeleteVolume(t *testing.T) {
  180. mgr := newTestMgr(t)
  181. mgr.CreateVolume("test-vol-0001", 8*1024*1024)
  182. err := mgr.DeleteVolume("test-vol-0001")
  183. if err != nil {
  184. t.Fatal(err)
  185. }
  186. sio := mgr.client.(*fakeSio)
  187. if sio.volume != nil {
  188. t.Errorf("volume not nil after delete operation")
  189. }
  190. }
  191. func TestMgrDeleteVolume_VolumeNotFound(t *testing.T) {
  192. mgr := newTestMgr(t)
  193. mgr.CreateVolume("test-vol-0001", 8*1024*1024)
  194. err := mgr.DeleteVolume("test-vol-0002")
  195. if err == nil {
  196. t.Fatal("expected volume not found error")
  197. }
  198. }
  199. // ************************************************************
  200. // Helper Test Types
  201. // ************************************************************
  202. type fakeSio struct {
  203. volume *siotypes.Volume
  204. waitAttachCtrl chan struct{}
  205. waitDetachCtrl chan struct{}
  206. devs map[string]string
  207. isMultiMap bool
  208. }
  209. func newFakeSio() *fakeSio {
  210. return &fakeSio{
  211. waitAttachCtrl: make(chan struct{}),
  212. waitDetachCtrl: make(chan struct{}),
  213. }
  214. }
  215. func (f *fakeSio) FindVolume(volumeName string) (*siotypes.Volume, error) {
  216. if f.volume == nil || f.volume.Name != volumeName {
  217. return nil, errors.New("volume not found")
  218. }
  219. return f.volume, nil
  220. }
  221. func (f *fakeSio) Volume(id sioVolumeID) (*siotypes.Volume, error) {
  222. if f.volume == nil || f.volume.ID != string(id) {
  223. return nil, errors.New("volume not found")
  224. }
  225. return f.volume, nil
  226. }
  227. func (f *fakeSio) CreateVolume(volName string, sizeGB int64) (*siotypes.Volume, error) {
  228. f.volume = &siotypes.Volume{
  229. ID: fakeVolumeID,
  230. Name: volName,
  231. SizeInKb: int(sizeGB),
  232. VolumeType: "test",
  233. }
  234. return f.volume, nil
  235. }
  236. func (f *fakeSio) AttachVolume(id sioVolumeID, multiMaps bool) error {
  237. f.isMultiMap = multiMaps
  238. _, err := f.Volume(id)
  239. if err != nil {
  240. return err
  241. }
  242. f.volume.MappedSdcInfo = []*siotypes.MappedSdcInfo{
  243. {SdcID: fakeSdcID},
  244. }
  245. return nil
  246. }
  247. func (f *fakeSio) DetachVolume(id sioVolumeID) error {
  248. if _, err := f.Volume(id); err != nil {
  249. return err
  250. }
  251. f.volume.MappedSdcInfo = nil
  252. delete(f.devs, f.volume.ID)
  253. return nil
  254. }
  255. func (f *fakeSio) DeleteVolume(id sioVolumeID) error {
  256. if _, err := f.Volume(id); err != nil {
  257. return err
  258. }
  259. f.volume = nil
  260. return nil
  261. }
  262. func (f *fakeSio) IID() (string, error) {
  263. return fakeSdcID, nil
  264. }
  265. func (f *fakeSio) Devs() (map[string]string, error) {
  266. if f.volume == nil {
  267. return nil, errors.New("volume not found")
  268. }
  269. f.devs = map[string]string{
  270. f.volume.ID: fakeDev,
  271. }
  272. return f.devs, nil
  273. }
  274. func (f *fakeSio) GetVolumeRefs(volID sioVolumeID) (int, error) {
  275. if f.volume == nil {
  276. return 0, nil
  277. }
  278. return 1, nil
  279. }
  280. func (f *fakeSio) WaitForAttachedDevice(token string) (string, error) {
  281. select {
  282. case <-time.After(500 * time.Millisecond):
  283. return fakeDev, nil
  284. case <-f.waitAttachCtrl:
  285. return "", errors.New("attached device timeout")
  286. }
  287. }
  288. func (f *fakeSio) WaitForDetachedDevice(token string) error {
  289. select {
  290. case <-time.After(500 * time.Millisecond):
  291. delete(f.devs, f.volume.ID)
  292. return nil
  293. case <-f.waitDetachCtrl:
  294. return errors.New("detach device timeout")
  295. }
  296. }