/test/unmountvolume_tester.py

https://github.com/hpe-storage/python-hpedockerplugin · Python · 267 lines · 187 code · 44 blank · 36 comment · 15 complexity · 91f6ff0e2399447a49deeaa9617a61f5 MD5 · raw file

  1. # import mock
  2. import copy
  3. import test.fake_3par_data as data
  4. import test.hpe_docker_unit_test as hpedockerunittest
  5. from hpe3parclient import exceptions
  6. class UnmountVolumeUnitTest(hpedockerunittest.HpeDockerUnitTestExecutor):
  7. def __init__(self, is_snap=False):
  8. self._is_snap = is_snap
  9. self._vol = copy.deepcopy(data.vol_mounted_on_this_node)
  10. if is_snap:
  11. self._vol['id'] = data.SNAPSHOT_ID1
  12. self._vol['name'] = data.SNAPSHOT_ID1
  13. self._vol['display_name'] = data.SNAPSHOT_NAME1
  14. self._vol['is_snap'] = True
  15. def _get_plugin_api(self):
  16. return 'volumedriver_unmount'
  17. def get_request_params(self):
  18. return {"Name": self._vol['display_name'],
  19. "ID": "Fake-Mount-ID"}
  20. def setup_mock_objects(self):
  21. # Call child class functions to configure mock objects
  22. self._setup_mock_3parclient()
  23. self._setup_mock_etcd()
  24. self._setup_mock_fileutil()
  25. self._setup_mock_protocol_connector()
  26. self._setup_mock_osbrick_connector()
  27. def _setup_mock_etcd(self):
  28. mock_etcd = self.mock_objects['mock_etcd']
  29. mock_etcd.get_vol_byname.return_value = self._vol
  30. mock_etcd.get_vol_path_info.return_value = \
  31. {'path': '/dummy-path',
  32. 'connection_info': {'data': 'dummy-conn-inf'},
  33. 'mount_dir': '/dummy-mnt-dir'}
  34. def _setup_mock_osbrick_connector(self):
  35. mock_connector = self.mock_objects['mock_osbricks_connector']
  36. # Same connector has info for both FC and ISCSI
  37. mock_connector.get_connector_properties.return_value = \
  38. data.connector_multipath_enabled
  39. def _setup_mock_3parclient(self):
  40. pass
  41. def _setup_mock_fileutil(self):
  42. pass
  43. def _setup_mock_protocol_connector(self):
  44. pass
  45. # Other volumes are present for the host hence host shouldn't
  46. # get deleted in this case
  47. class TestUnmountOneVolumeForHost(UnmountVolumeUnitTest):
  48. def __init__(self, **kwargs):
  49. super(type(self), self).__init__(**kwargs)
  50. def _setup_mock_3parclient(self):
  51. mock_3parclient = self.mock_objects['mock_3parclient']
  52. mock_3parclient.queryHost.return_value = data.fake_hosts
  53. # Returning more VLUNs
  54. if not self._is_snap:
  55. mock_3parclient.getHostVLUNs.side_effect = \
  56. [data.host_vluns, data.host_vluns]
  57. else:
  58. mock_3parclient.getHostVLUNs.side_effect = \
  59. [data.snap_host_vluns, data.snap_host_vluns]
  60. def check_response(self, resp):
  61. mock_3parclient = self.mock_objects['mock_3parclient']
  62. mock_3parclient.getWsApiVersion.assert_called()
  63. mock_3parclient.queryHost.assert_called()
  64. mock_3parclient.getHostVLUNs.assert_called()
  65. mock_3parclient.deleteVLUN.assert_called()
  66. mock_3parclient.deleteHost.assert_called()
  67. # mock_3parclient.removeVolumeMetaData.assert_called()
  68. # Last volume getting unmounted in which case host should also
  69. # get removed
  70. class TestUnmountLastVolumeForHost(UnmountVolumeUnitTest):
  71. def __init__(self, **kwargs):
  72. super(type(self), self).__init__(**kwargs)
  73. def _setup_mock_3parclient(self):
  74. mock_3parclient = self.mock_objects['mock_3parclient']
  75. mock_3parclient.queryHost.return_value = data.fake_hosts
  76. # Returning HTTPNotFound second time would mean we removed
  77. # the last LUN and hence VHOST should be removed
  78. if not self._is_snap:
  79. mock_3parclient.getHostVLUNs.side_effect = \
  80. [data.host_vluns, exceptions.HTTPNotFound('fake')]
  81. else:
  82. mock_3parclient.getHostVLUNs.side_effect = \
  83. [data.snap_host_vluns, exceptions.HTTPNotFound('fake')]
  84. def check_response(self, resp):
  85. mock_3parclient = self.mock_objects['mock_3parclient']
  86. mock_3parclient.getWsApiVersion.assert_called()
  87. mock_3parclient.queryHost.assert_called()
  88. mock_3parclient.getHostVLUNs.assert_called()
  89. mock_3parclient.deleteVLUN.assert_called()
  90. mock_3parclient.deleteHost.assert_called()
  91. # mock_3parclient.removeVolumeMetaData.assert_called()
  92. # Volume is mounted on the same node more than once
  93. # Unmount once should not
  94. class TestUnmountVolOnceMountedTwiceOnThisNode(UnmountVolumeUnitTest):
  95. def __init__(self, **kwargs):
  96. super(type(self), self).__init__(**kwargs)
  97. self._vol = copy.deepcopy(data.volume_mounted_twice_on_this_node)
  98. if self._is_snap:
  99. self._vol['name'] = data.SNAPSHOT_NAME1
  100. self._vol['id'] = data.SNAPSHOT_ID1
  101. self._vol['display_name'] = data.SNAPSHOT_NAME1
  102. self._vol['is_snap'] = True
  103. def _setup_mock_etcd(self):
  104. mock_etcd = self.mock_objects['mock_etcd']
  105. mock_etcd.get_vol_byname.return_value = self._vol
  106. def check_response(self, resp):
  107. self._test_case.assertEqual(resp, {u"Err": ''})
  108. mock_etcd = self.mock_objects['mock_etcd']
  109. mock_etcd.update_vol.assert_called_with(self._vol['id'],
  110. 'node_mount_info',
  111. self._vol['node_mount_info'])
  112. # node_id_list should have only one node-id left after
  113. # un-mount is called
  114. self._test_case.assertEqual(len(self._vol['node_mount_info']
  115. [data.THIS_NODE_ID]), 1)
  116. mock_3parclient = self.mock_objects['mock_3parclient']
  117. mock_3parclient.getWsApiVersion.assert_called()
  118. mock_3parclient.queryHost.assert_not_called()
  119. mock_3parclient.getHostVLUNs.assert_not_called()
  120. mock_3parclient.deleteVLUN.assert_not_called()
  121. mock_3parclient.deleteHost.assert_not_called()
  122. # Volume is mounted on the same node more than once
  123. # Unmount once should not
  124. class TestUnmountVolMountedTwiceOnThisNode(UnmountVolumeUnitTest):
  125. # This TC needs to be executed twice from outside and for each
  126. # execution, the state of volume gets modified. Setting up
  127. # the volume object to be used across two runs along with
  128. # the run-count that is used to take decisions
  129. def __init__(self, tc_run_cnt, **kwargs):
  130. super(type(self), self).__init__(**kwargs)
  131. self._tc_run_cnt = tc_run_cnt
  132. self._vol = copy.deepcopy(data.volume_mounted_twice_on_this_node)
  133. def _setup_mock_3parclient(self):
  134. if self._tc_run_cnt == 1:
  135. mock_3parclient = self.mock_objects['mock_3parclient']
  136. mock_3parclient.queryHost.return_value = data.fake_hosts
  137. # Returning more VLUNs
  138. if not self._is_snap:
  139. mock_3parclient.getHostVLUNs.side_effect = \
  140. [data.host_vluns, data.host_vluns]
  141. else:
  142. mock_3parclient.getHostVLUNs.side_effect = \
  143. [data.snap_host_vluns, data.snap_host_vluns]
  144. def _setup_mock_etcd(self):
  145. mock_etcd = self.mock_objects['mock_etcd']
  146. mock_etcd.get_vol_byname.return_value = self._vol
  147. mock_etcd.get_vol_path_info.return_value = \
  148. {'path': '/dummy-path',
  149. 'connection_info': {'data': 'dummy-conn-inf'},
  150. 'mount_dir': '/dummy-mnt-dir'}
  151. def check_response(self, resp):
  152. self._test_case.assertEqual(resp, {u"Err": ''})
  153. vol = self._vol
  154. mock_etcd = self.mock_objects['mock_etcd']
  155. if self._tc_run_cnt == 0:
  156. mock_etcd.update_vol.assert_called_with(vol['id'],
  157. 'node_mount_info',
  158. vol['node_mount_info'])
  159. # node_id_list should have only one node-id left after
  160. # un-mount is called
  161. self._test_case.assertEqual(len(vol['node_mount_info']
  162. [data.THIS_NODE_ID]), 1)
  163. elif self._tc_run_cnt == 1:
  164. mock_etcd.save_vol.assert_called_with(vol)
  165. self._test_case.assertNotIn('node_mount_info',
  166. self._vol)
  167. mock_3parclient = self.mock_objects['mock_3parclient']
  168. mock_3parclient.getWsApiVersion.assert_called()
  169. if self._tc_run_cnt == 0:
  170. mock_3parclient.queryHost.assert_not_called()
  171. mock_3parclient.getHostVLUNs.assert_not_called()
  172. mock_3parclient.deleteVLUN.assert_not_called()
  173. mock_3parclient.deleteHost.assert_not_called()
  174. elif self._tc_run_cnt == 1:
  175. mock_3parclient.queryHost.assert_called()
  176. mock_3parclient.getHostVLUNs.assert_called()
  177. mock_3parclient.deleteVLUN.assert_called()
  178. mock_3parclient.deleteHost.assert_called()
  179. self._tc_run_cnt += 1
  180. # This TC should carry out the cleanup steps
  181. class TestUnmountVolNotOwnedByThisNode(UnmountVolumeUnitTest):
  182. # This TC needs to be executed twice from outside and for each
  183. # execution, the state of volume gets modified. Setting up
  184. # the volume object to be used across two runs along with
  185. # the run-count that is used to take decisions
  186. def __init__(self, **kwargs):
  187. super(type(self), self).__init__(**kwargs)
  188. self._vol = copy.deepcopy(data.vol_mounted_on_other_node)
  189. def _setup_mock_3parclient(self):
  190. mock_3parclient = self.mock_objects['mock_3parclient']
  191. mock_3parclient.queryHost.return_value = data.fake_hosts
  192. # Returning more VLUNs
  193. if not self._is_snap:
  194. mock_3parclient.getHostVLUNs.side_effect = \
  195. [data.host_vluns, data.host_vluns]
  196. else:
  197. mock_3parclient.getHostVLUNs.side_effect = \
  198. [data.snap_host_vluns, data.snap_host_vluns]
  199. def _setup_mock_etcd(self):
  200. mock_etcd = self.mock_objects['mock_etcd']
  201. mock_etcd.get_vol_byname.return_value = self._vol
  202. mock_etcd.get_vol_path_info.return_value = \
  203. {'path': '/dummy-path',
  204. 'connection_info': {'data': 'dummy-conn-inf'},
  205. 'mount_dir': '/dummy-mnt-dir'}
  206. def check_response(self, resp):
  207. self._test_case.assertEqual(resp, {u"Err": ''})
  208. vol = self._vol
  209. mock_etcd = self.mock_objects['mock_etcd']
  210. mock_etcd.save_vol.assert_called_with(vol)
  211. self._test_case.assertIn('node_mount_info',
  212. self._vol)
  213. mock_3parclient = self.mock_objects['mock_3parclient']
  214. mock_3parclient.getWsApiVersion.assert_called()
  215. mock_3parclient.queryHost.assert_called()
  216. mock_3parclient.getHostVLUNs.assert_called()
  217. mock_3parclient.deleteVLUN.assert_called()
  218. mock_3parclient.deleteHost.assert_called()
  219. # # TODO:
  220. # class TestUnmountVolumeChapCredentialsNotFound(UnmountVolumeUnitTest):
  221. # pass
  222. # class TestUnmountVolumeHostSeesRemoveVHost(UnmountVolumeUnitTest)
  223. # class TestUnmountVolumeHostSeesKeepVHost(UnmountVolumeUnitTest):