test_zfs.py 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079
  1. # -*- coding: utf-8 -*-
  2. """
  3. Tests for the zfs utils library
  4. :codeauthor: Jorge Schrauwen <sjorge@blackdot.be>
  5. :maintainer: Jorge Schrauwen <sjorge@blackdot.be>
  6. :maturity: new
  7. :platform: illumos,freebsd,linux
  8. .. versionadded:: 2018.3.1
  9. """
  10. # Import Python libs
  11. from __future__ import absolute_import, print_function, unicode_literals
  12. # Import Salt Execution module to test
  13. import salt.utils.zfs as zfs
  14. # Import Salt Utils
  15. from salt.utils.odict import OrderedDict
  16. from tests.support.mock import MagicMock, patch
  17. from tests.support.unit import TestCase
  18. # Import Salt Testing libs
  19. from tests.support.zfs import ZFSMockData
  20. # Skip this test case if we don't have access to mock!
  21. class ZfsUtilsTestCase(TestCase):
  22. """
  23. This class contains a set of functions that test salt.utils.zfs utils
  24. """
  25. def setUp(self):
  26. # property_map mocks
  27. mock_data = ZFSMockData()
  28. self.pmap_zfs = mock_data.pmap_zfs
  29. self.pmap_zpool = mock_data.pmap_zpool
  30. self.pmap_exec_zfs = mock_data.pmap_exec_zfs
  31. self.pmap_exec_zpool = mock_data.pmap_exec_zpool
  32. for name in ("pmap_zfs", "pmap_zpool", "pmap_exec_zfs", "pmap_exec_zpool"):
  33. self.addCleanup(delattr, self, name)
  34. # NOTE: test parameter parsing
  35. def test_is_supported(self):
  36. """
  37. Test zfs.is_supported method
  38. """
  39. for value in [False, True]:
  40. with patch("salt.utils.path.which", MagicMock(return_value=value)):
  41. with patch(
  42. "salt.utils.platform.is_linux", MagicMock(return_value=value)
  43. ):
  44. self.assertEqual(value, zfs.is_supported())
  45. def test_property_data_zpool(self):
  46. """
  47. Test parsing of zpool get output
  48. """
  49. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  50. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  51. with patch.object(
  52. zfs, "_exec", MagicMock(return_value=self.pmap_exec_zpool)
  53. ):
  54. self.assertEqual(zfs.property_data_zpool(), self.pmap_zpool)
  55. def test_property_data_zfs(self):
  56. """
  57. Test parsing of zfs get output
  58. """
  59. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  60. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  61. with patch.object(
  62. zfs, "_exec", MagicMock(return_value=self.pmap_exec_zfs)
  63. ):
  64. self.assertEqual(zfs.property_data_zfs(), self.pmap_zfs)
  65. # NOTE: testing from_bool results
  66. def test_from_bool_on(self):
  67. """
  68. Test from_bool with 'on'
  69. """
  70. self.assertTrue(zfs.from_bool("on"))
  71. self.assertTrue(zfs.from_bool(zfs.from_bool("on")))
  72. def test_from_bool_off(self):
  73. """
  74. Test from_bool with 'off'
  75. """
  76. self.assertFalse(zfs.from_bool("off"))
  77. self.assertFalse(zfs.from_bool(zfs.from_bool("off")))
  78. def test_from_bool_none(self):
  79. """
  80. Test from_bool with 'none'
  81. """
  82. self.assertEqual(zfs.from_bool("none"), None)
  83. self.assertEqual(zfs.from_bool(zfs.from_bool("none")), None)
  84. def test_from_bool_passthrough(self):
  85. """
  86. Test from_bool with 'passthrough'
  87. """
  88. self.assertEqual(zfs.from_bool("passthrough"), "passthrough")
  89. self.assertEqual(zfs.from_bool(zfs.from_bool("passthrough")), "passthrough")
  90. def test_from_bool_alt_yes(self):
  91. """
  92. Test from_bool_alt with 'yes'
  93. """
  94. self.assertTrue(zfs.from_bool_alt("yes"))
  95. self.assertTrue(zfs.from_bool_alt(zfs.from_bool_alt("yes")))
  96. def test_from_bool_alt_no(self):
  97. """
  98. Test from_bool_alt with 'no'
  99. """
  100. self.assertFalse(zfs.from_bool_alt("no"))
  101. self.assertFalse(zfs.from_bool_alt(zfs.from_bool_alt("no")))
  102. def test_from_bool_alt_none(self):
  103. """
  104. Test from_bool_alt with 'none'
  105. """
  106. self.assertEqual(zfs.from_bool_alt("none"), None)
  107. self.assertEqual(zfs.from_bool_alt(zfs.from_bool_alt("none")), None)
  108. def test_from_bool_alt_passthrough(self):
  109. """
  110. Test from_bool_alt with 'passthrough'
  111. """
  112. self.assertEqual(zfs.from_bool_alt("passthrough"), "passthrough")
  113. self.assertEqual(
  114. zfs.from_bool_alt(zfs.from_bool_alt("passthrough")), "passthrough"
  115. )
  116. # NOTE: testing to_bool results
  117. def test_to_bool_true(self):
  118. """
  119. Test to_bool with True
  120. """
  121. self.assertEqual(zfs.to_bool(True), "on")
  122. self.assertEqual(zfs.to_bool(zfs.to_bool(True)), "on")
  123. def test_to_bool_false(self):
  124. """
  125. Test to_bool with False
  126. """
  127. self.assertEqual(zfs.to_bool(False), "off")
  128. self.assertEqual(zfs.to_bool(zfs.to_bool(False)), "off")
  129. def test_to_bool_none(self):
  130. """
  131. Test to_bool with None
  132. """
  133. self.assertEqual(zfs.to_bool(None), "none")
  134. self.assertEqual(zfs.to_bool(zfs.to_bool(None)), "none")
  135. def test_to_bool_passthrough(self):
  136. """
  137. Test to_bool with 'passthrough'
  138. """
  139. self.assertEqual(zfs.to_bool("passthrough"), "passthrough")
  140. self.assertEqual(zfs.to_bool(zfs.to_bool("passthrough")), "passthrough")
  141. def test_to_bool_alt_true(self):
  142. """
  143. Test to_bool_alt with True
  144. """
  145. self.assertEqual(zfs.to_bool_alt(True), "yes")
  146. self.assertEqual(zfs.to_bool_alt(zfs.to_bool_alt(True)), "yes")
  147. def test_to_bool_alt_false(self):
  148. """
  149. Test to_bool_alt with False
  150. """
  151. self.assertEqual(zfs.to_bool_alt(False), "no")
  152. self.assertEqual(zfs.to_bool_alt(zfs.to_bool_alt(False)), "no")
  153. def test_to_bool_alt_none(self):
  154. """
  155. Test to_bool_alt with None
  156. """
  157. self.assertEqual(zfs.to_bool_alt(None), "none")
  158. self.assertEqual(zfs.to_bool_alt(zfs.to_bool_alt(None)), "none")
  159. def test_to_bool_alt_passthrough(self):
  160. """
  161. Test to_bool_alt with 'passthrough'
  162. """
  163. self.assertEqual(zfs.to_bool_alt("passthrough"), "passthrough")
  164. self.assertEqual(zfs.to_bool_alt(zfs.to_bool_alt("passthrough")), "passthrough")
  165. # NOTE: testing from_numeric results
  166. def test_from_numeric_str(self):
  167. """
  168. Test from_numeric with '42'
  169. """
  170. self.assertEqual(zfs.from_numeric("42"), 42)
  171. self.assertEqual(zfs.from_numeric(zfs.from_numeric("42")), 42)
  172. def test_from_numeric_int(self):
  173. """
  174. Test from_numeric with 42
  175. """
  176. self.assertEqual(zfs.from_numeric(42), 42)
  177. self.assertEqual(zfs.from_numeric(zfs.from_numeric(42)), 42)
  178. def test_from_numeric_none(self):
  179. """
  180. Test from_numeric with 'none'
  181. """
  182. self.assertEqual(zfs.from_numeric("none"), None)
  183. self.assertEqual(zfs.from_numeric(zfs.from_numeric("none")), None)
  184. def test_from_numeric_passthrough(self):
  185. """
  186. Test from_numeric with 'passthrough'
  187. """
  188. self.assertEqual(zfs.from_numeric("passthrough"), "passthrough")
  189. self.assertEqual(
  190. zfs.from_numeric(zfs.from_numeric("passthrough")), "passthrough"
  191. )
  192. # NOTE: testing to_numeric results
  193. def test_to_numeric_str(self):
  194. """
  195. Test to_numeric with '42'
  196. """
  197. self.assertEqual(zfs.to_numeric("42"), 42)
  198. self.assertEqual(zfs.to_numeric(zfs.to_numeric("42")), 42)
  199. def test_to_numeric_int(self):
  200. """
  201. Test to_numeric with 42
  202. """
  203. self.assertEqual(zfs.to_numeric(42), 42)
  204. self.assertEqual(zfs.to_numeric(zfs.to_numeric(42)), 42)
  205. def test_to_numeric_none(self):
  206. """
  207. Test to_numeric with 'none'
  208. """
  209. self.assertEqual(zfs.to_numeric(None), "none")
  210. self.assertEqual(zfs.to_numeric(zfs.to_numeric(None)), "none")
  211. def test_to_numeric_passthrough(self):
  212. """
  213. Test to_numeric with 'passthrough'
  214. """
  215. self.assertEqual(zfs.to_numeric("passthrough"), "passthrough")
  216. self.assertEqual(zfs.to_numeric(zfs.to_numeric("passthrough")), "passthrough")
  217. # NOTE: testing from_size results
  218. def test_from_size_absolute(self):
  219. """
  220. Test from_size with '5G'
  221. """
  222. self.assertEqual(zfs.from_size("5G"), 5368709120)
  223. self.assertEqual(zfs.from_size(zfs.from_size("5G")), 5368709120)
  224. def test_from_size_decimal(self):
  225. """
  226. Test from_size with '4.20M'
  227. """
  228. self.assertEqual(zfs.from_size("4.20M"), 4404019)
  229. self.assertEqual(zfs.from_size(zfs.from_size("4.20M")), 4404019)
  230. def test_from_size_none(self):
  231. """
  232. Test from_size with 'none'
  233. """
  234. self.assertEqual(zfs.from_size("none"), None)
  235. self.assertEqual(zfs.from_size(zfs.from_size("none")), None)
  236. def test_from_size_passthrough(self):
  237. """
  238. Test from_size with 'passthrough'
  239. """
  240. self.assertEqual(zfs.from_size("passthrough"), "passthrough")
  241. self.assertEqual(zfs.from_size(zfs.from_size("passthrough")), "passthrough")
  242. # NOTE: testing to_size results
  243. def test_to_size_str_absolute(self):
  244. """
  245. Test to_size with '5368709120'
  246. """
  247. self.assertEqual(zfs.to_size("5368709120"), "5G")
  248. self.assertEqual(zfs.to_size(zfs.to_size("5368709120")), "5G")
  249. def test_to_size_str_decimal(self):
  250. """
  251. Test to_size with '4404019'
  252. """
  253. self.assertEqual(zfs.to_size("4404019"), "4.20M")
  254. self.assertEqual(zfs.to_size(zfs.to_size("4404019")), "4.20M")
  255. def test_to_size_int_absolute(self):
  256. """
  257. Test to_size with 5368709120
  258. """
  259. self.assertEqual(zfs.to_size(5368709120), "5G")
  260. self.assertEqual(zfs.to_size(zfs.to_size(5368709120)), "5G")
  261. def test_to_size_int_decimal(self):
  262. """
  263. Test to_size with 4404019
  264. """
  265. self.assertEqual(zfs.to_size(4404019), "4.20M")
  266. self.assertEqual(zfs.to_size(zfs.to_size(4404019)), "4.20M")
  267. def test_to_size_none(self):
  268. """
  269. Test to_size with 'none'
  270. """
  271. self.assertEqual(zfs.to_size(None), "none")
  272. self.assertEqual(zfs.to_size(zfs.to_size(None)), "none")
  273. def test_to_size_passthrough(self):
  274. """
  275. Test to_size with 'passthrough'
  276. """
  277. self.assertEqual(zfs.to_size("passthrough"), "passthrough")
  278. self.assertEqual(zfs.to_size(zfs.to_size("passthrough")), "passthrough")
  279. # NOTE: testing from_str results
  280. def test_from_str_space(self):
  281. """
  282. Test from_str with "\"my pool/my dataset\"
  283. """
  284. self.assertEqual(zfs.from_str('"my pool/my dataset"'), "my pool/my dataset")
  285. self.assertEqual(
  286. zfs.from_str(zfs.from_str('"my pool/my dataset"')), "my pool/my dataset"
  287. )
  288. def test_from_str_squote_space(self):
  289. """
  290. Test from_str with "my pool/jorge's dataset"
  291. """
  292. self.assertEqual(
  293. zfs.from_str("my pool/jorge's dataset"), "my pool/jorge's dataset"
  294. )
  295. self.assertEqual(
  296. zfs.from_str(zfs.from_str("my pool/jorge's dataset")),
  297. "my pool/jorge's dataset",
  298. )
  299. def test_from_str_dquote_space(self):
  300. """
  301. Test from_str with "my pool/the \"good\" stuff"
  302. """
  303. self.assertEqual(
  304. zfs.from_str('my pool/the "good" stuff'), 'my pool/the "good" stuff'
  305. )
  306. self.assertEqual(
  307. zfs.from_str(zfs.from_str('my pool/the "good" stuff')),
  308. 'my pool/the "good" stuff',
  309. )
  310. def test_from_str_none(self):
  311. """
  312. Test from_str with 'none'
  313. """
  314. self.assertEqual(zfs.from_str("none"), None)
  315. self.assertEqual(zfs.from_str(zfs.from_str("none")), None)
  316. def test_from_str_passthrough(self):
  317. """
  318. Test from_str with 'passthrough'
  319. """
  320. self.assertEqual(zfs.from_str("passthrough"), "passthrough")
  321. self.assertEqual(zfs.from_str(zfs.from_str("passthrough")), "passthrough")
  322. # NOTE: testing to_str results
  323. def test_to_str_space(self):
  324. """
  325. Test to_str with 'my pool/my dataset'
  326. """
  327. # NOTE: for fun we use both the '"str"' and "\"str\"" way of getting the literal string: "str"
  328. self.assertEqual(zfs.to_str("my pool/my dataset"), '"my pool/my dataset"')
  329. self.assertEqual(
  330. zfs.to_str(zfs.to_str("my pool/my dataset")), '"my pool/my dataset"'
  331. )
  332. def test_to_str_squote_space(self):
  333. """
  334. Test to_str with "my pool/jorge's dataset"
  335. """
  336. self.assertEqual(
  337. zfs.to_str("my pool/jorge's dataset"), '"my pool/jorge\'s dataset"'
  338. )
  339. self.assertEqual(
  340. zfs.to_str(zfs.to_str("my pool/jorge's dataset")),
  341. '"my pool/jorge\'s dataset"',
  342. )
  343. def test_to_str_none(self):
  344. """
  345. Test to_str with 'none'
  346. """
  347. self.assertEqual(zfs.to_str(None), "none")
  348. self.assertEqual(zfs.to_str(zfs.to_str(None)), "none")
  349. def test_to_str_passthrough(self):
  350. """
  351. Test to_str with 'passthrough'
  352. """
  353. self.assertEqual(zfs.to_str("passthrough"), "passthrough")
  354. self.assertEqual(zfs.to_str(zfs.to_str("passthrough")), "passthrough")
  355. # NOTE: testing is_snapshot
  356. def test_is_snapshot_snapshot(self):
  357. """
  358. Test is_snapshot with a valid snapshot name
  359. """
  360. self.assertTrue(zfs.is_snapshot("zpool_name/dataset@backup"))
  361. def test_is_snapshot_bookmark(self):
  362. """
  363. Test is_snapshot with a valid bookmark name
  364. """
  365. self.assertFalse(zfs.is_snapshot("zpool_name/dataset#backup"))
  366. def test_is_snapshot_filesystem(self):
  367. """
  368. Test is_snapshot with a valid filesystem name
  369. """
  370. self.assertFalse(zfs.is_snapshot("zpool_name/dataset"))
  371. # NOTE: testing is_bookmark
  372. def test_is_bookmark_snapshot(self):
  373. """
  374. Test is_bookmark with a valid snapshot name
  375. """
  376. self.assertFalse(zfs.is_bookmark("zpool_name/dataset@backup"))
  377. def test_is_bookmark_bookmark(self):
  378. """
  379. Test is_bookmark with a valid bookmark name
  380. """
  381. self.assertTrue(zfs.is_bookmark("zpool_name/dataset#backup"))
  382. def test_is_bookmark_filesystem(self):
  383. """
  384. Test is_bookmark with a valid filesystem name
  385. """
  386. self.assertFalse(zfs.is_bookmark("zpool_name/dataset"))
  387. # NOTE: testing is_dataset
  388. def test_is_dataset_snapshot(self):
  389. """
  390. Test is_dataset with a valid snapshot name
  391. """
  392. self.assertFalse(zfs.is_dataset("zpool_name/dataset@backup"))
  393. def test_is_dataset_bookmark(self):
  394. """
  395. Test is_dataset with a valid bookmark name
  396. """
  397. self.assertFalse(zfs.is_dataset("zpool_name/dataset#backup"))
  398. def test_is_dataset_filesystem(self):
  399. """
  400. Test is_dataset with a valid filesystem/volume name
  401. """
  402. self.assertTrue(zfs.is_dataset("zpool_name/dataset"))
  403. # NOTE: testing zfs_command
  404. def test_zfs_command_simple(self):
  405. """
  406. Test if zfs_command builds the correct string
  407. """
  408. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  409. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  410. with patch.object(
  411. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  412. ):
  413. with patch.object(
  414. zfs,
  415. "property_data_zpool",
  416. MagicMock(return_value=self.pmap_zpool),
  417. ):
  418. self.assertEqual(zfs.zfs_command("list"), "/sbin/zfs list")
  419. def test_zfs_command_none_target(self):
  420. """
  421. Test if zfs_command builds the correct string with a target of None
  422. """
  423. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  424. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  425. with patch.object(
  426. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  427. ):
  428. with patch.object(
  429. zfs,
  430. "property_data_zpool",
  431. MagicMock(return_value=self.pmap_zpool),
  432. ):
  433. self.assertEqual(
  434. zfs.zfs_command("list", target=[None, "mypool", None]),
  435. "/sbin/zfs list mypool",
  436. )
  437. def test_zfs_command_flag(self):
  438. """
  439. Test if zfs_command builds the correct string
  440. """
  441. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  442. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  443. with patch.object(
  444. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  445. ):
  446. with patch.object(
  447. zfs,
  448. "property_data_zpool",
  449. MagicMock(return_value=self.pmap_zpool),
  450. ):
  451. my_flags = [
  452. "-r", # recursive
  453. ]
  454. self.assertEqual(
  455. zfs.zfs_command("list", flags=my_flags), "/sbin/zfs list -r"
  456. )
  457. def test_zfs_command_opt(self):
  458. """
  459. Test if zfs_command builds the correct string
  460. """
  461. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  462. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  463. with patch.object(
  464. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  465. ):
  466. with patch.object(
  467. zfs,
  468. "property_data_zpool",
  469. MagicMock(return_value=self.pmap_zpool),
  470. ):
  471. my_opts = {
  472. "-t": "snap", # only list snapshots
  473. }
  474. self.assertEqual(
  475. zfs.zfs_command("list", opts=my_opts),
  476. "/sbin/zfs list -t snap",
  477. )
  478. def test_zfs_command_flag_opt(self):
  479. """
  480. Test if zfs_command builds the correct string
  481. """
  482. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  483. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  484. with patch.object(
  485. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  486. ):
  487. with patch.object(
  488. zfs,
  489. "property_data_zpool",
  490. MagicMock(return_value=self.pmap_zpool),
  491. ):
  492. my_flags = [
  493. "-r", # recursive
  494. ]
  495. my_opts = {
  496. "-t": "snap", # only list snapshots
  497. }
  498. self.assertEqual(
  499. zfs.zfs_command("list", flags=my_flags, opts=my_opts),
  500. "/sbin/zfs list -r -t snap",
  501. )
  502. def test_zfs_command_target(self):
  503. """
  504. Test if zfs_command builds the correct string
  505. """
  506. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  507. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  508. with patch.object(
  509. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  510. ):
  511. with patch.object(
  512. zfs,
  513. "property_data_zpool",
  514. MagicMock(return_value=self.pmap_zpool),
  515. ):
  516. my_flags = [
  517. "-r", # recursive
  518. ]
  519. my_opts = {
  520. "-t": "snap", # only list snapshots
  521. }
  522. self.assertEqual(
  523. zfs.zfs_command(
  524. "list", flags=my_flags, opts=my_opts, target="mypool"
  525. ),
  526. "/sbin/zfs list -r -t snap mypool",
  527. )
  528. def test_zfs_command_target_with_space(self):
  529. """
  530. Test if zfs_command builds the correct string
  531. """
  532. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  533. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  534. with patch.object(
  535. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  536. ):
  537. with patch.object(
  538. zfs,
  539. "property_data_zpool",
  540. MagicMock(return_value=self.pmap_zpool),
  541. ):
  542. my_flags = [
  543. "-r", # recursive
  544. ]
  545. my_opts = {
  546. "-t": "snap", # only list snapshots
  547. }
  548. self.assertEqual(
  549. zfs.zfs_command(
  550. "list", flags=my_flags, opts=my_opts, target="my pool"
  551. ),
  552. '/sbin/zfs list -r -t snap "my pool"',
  553. )
  554. def test_zfs_command_property(self):
  555. """
  556. Test if zfs_command builds the correct string
  557. """
  558. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  559. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  560. with patch.object(
  561. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  562. ):
  563. with patch.object(
  564. zfs,
  565. "property_data_zpool",
  566. MagicMock(return_value=self.pmap_zpool),
  567. ):
  568. self.assertEqual(
  569. zfs.zfs_command(
  570. "get", property_name="quota", target="mypool"
  571. ),
  572. "/sbin/zfs get quota mypool",
  573. )
  574. def test_zfs_command_property_value(self):
  575. """
  576. Test if zfs_command builds the correct string
  577. """
  578. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  579. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  580. with patch.object(
  581. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  582. ):
  583. with patch.object(
  584. zfs,
  585. "property_data_zpool",
  586. MagicMock(return_value=self.pmap_zpool),
  587. ):
  588. my_flags = [
  589. "-r", # recursive
  590. ]
  591. self.assertEqual(
  592. zfs.zfs_command(
  593. "set",
  594. flags=my_flags,
  595. property_name="quota",
  596. property_value="5G",
  597. target="mypool",
  598. ),
  599. "/sbin/zfs set -r quota=5368709120 mypool",
  600. )
  601. def test_zfs_command_multi_property_value(self):
  602. """
  603. Test if zfs_command builds the correct string
  604. """
  605. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  606. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  607. with patch.object(
  608. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  609. ):
  610. with patch.object(
  611. zfs,
  612. "property_data_zpool",
  613. MagicMock(return_value=self.pmap_zpool),
  614. ):
  615. property_name = ["quota", "readonly"]
  616. property_value = ["5G", "no"]
  617. self.assertEqual(
  618. zfs.zfs_command(
  619. "set",
  620. property_name=property_name,
  621. property_value=property_value,
  622. target="mypool",
  623. ),
  624. "/sbin/zfs set quota=5368709120 readonly=off mypool",
  625. )
  626. def test_zfs_command_fs_props(self):
  627. """
  628. Test if zfs_command builds the correct string
  629. """
  630. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  631. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  632. with patch.object(
  633. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  634. ):
  635. with patch.object(
  636. zfs,
  637. "property_data_zpool",
  638. MagicMock(return_value=self.pmap_zpool),
  639. ):
  640. my_flags = [
  641. "-p", # create parent
  642. ]
  643. my_props = {
  644. "quota": "1G",
  645. "compression": "lz4",
  646. }
  647. self.assertEqual(
  648. zfs.zfs_command(
  649. "create",
  650. flags=my_flags,
  651. filesystem_properties=my_props,
  652. target="mypool/dataset",
  653. ),
  654. "/sbin/zfs create -p -o compression=lz4 -o quota=1073741824 mypool/dataset",
  655. )
  656. def test_zfs_command_fs_props_with_space(self):
  657. """
  658. Test if zfs_command builds the correct string
  659. """
  660. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  661. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  662. with patch.object(
  663. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  664. ):
  665. with patch.object(
  666. zfs,
  667. "property_data_zpool",
  668. MagicMock(return_value=self.pmap_zpool),
  669. ):
  670. my_props = {
  671. "quota": "4.2M",
  672. "compression": "lz4",
  673. }
  674. self.assertEqual(
  675. zfs.zfs_command(
  676. "create",
  677. filesystem_properties=my_props,
  678. target="my pool/jorge's dataset",
  679. ),
  680. '/sbin/zfs create -o compression=lz4 -o quota=4404019 "my pool/jorge\'s dataset"',
  681. )
  682. # NOTE: testing zpool_command
  683. def test_zpool_command_simple(self):
  684. """
  685. Test if zfs_command builds the correct string
  686. """
  687. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  688. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  689. with patch.object(
  690. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  691. ):
  692. with patch.object(
  693. zfs,
  694. "property_data_zpool",
  695. MagicMock(return_value=self.pmap_zpool),
  696. ):
  697. self.assertEqual(zfs.zpool_command("list"), "/sbin/zpool list")
  698. def test_zpool_command_opt(self):
  699. """
  700. Test if zpool_command builds the correct string
  701. """
  702. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  703. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  704. with patch.object(
  705. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  706. ):
  707. with patch.object(
  708. zfs,
  709. "property_data_zpool",
  710. MagicMock(return_value=self.pmap_zpool),
  711. ):
  712. my_opts = {
  713. "-o": "name,size", # show only name and size
  714. }
  715. self.assertEqual(
  716. zfs.zpool_command("list", opts=my_opts),
  717. "/sbin/zpool list -o name,size",
  718. )
  719. def test_zpool_command_opt_list(self):
  720. """
  721. Test if zpool_command builds the correct string
  722. """
  723. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  724. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  725. with patch.object(
  726. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  727. ):
  728. with patch.object(
  729. zfs,
  730. "property_data_zpool",
  731. MagicMock(return_value=self.pmap_zpool),
  732. ):
  733. my_opts = {
  734. "-d": ["/tmp", "/zvol"],
  735. }
  736. self.assertEqual(
  737. zfs.zpool_command("import", opts=my_opts, target="mypool"),
  738. "/sbin/zpool import -d /tmp -d /zvol mypool",
  739. )
  740. def test_zpool_command_flag_opt(self):
  741. """
  742. Test if zpool_command builds the correct string
  743. """
  744. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  745. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  746. with patch.object(
  747. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  748. ):
  749. with patch.object(
  750. zfs,
  751. "property_data_zpool",
  752. MagicMock(return_value=self.pmap_zpool),
  753. ):
  754. my_opts = {
  755. "-o": "name,size", # show only name and size
  756. }
  757. self.assertEqual(
  758. zfs.zpool_command("list", opts=my_opts),
  759. "/sbin/zpool list -o name,size",
  760. )
  761. def test_zpool_command_target(self):
  762. """
  763. Test if zpool_command builds the correct string
  764. """
  765. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  766. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  767. with patch.object(
  768. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  769. ):
  770. with patch.object(
  771. zfs,
  772. "property_data_zpool",
  773. MagicMock(return_value=self.pmap_zpool),
  774. ):
  775. my_opts = {
  776. "-o": "name,size", # show only name and size
  777. }
  778. self.assertEqual(
  779. zfs.zpool_command("list", opts=my_opts, target="mypool"),
  780. "/sbin/zpool list -o name,size mypool",
  781. )
  782. def test_zpool_command_target_with_space(self):
  783. """
  784. Test if zpool_command builds the correct string
  785. """
  786. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  787. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  788. with patch.object(
  789. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  790. ):
  791. with patch.object(
  792. zfs,
  793. "property_data_zpool",
  794. MagicMock(return_value=self.pmap_zpool),
  795. ):
  796. fs_props = {
  797. "quota": "100G",
  798. }
  799. pool_props = {
  800. "comment": "jorge's comment has a space",
  801. }
  802. self.assertEqual(
  803. zfs.zpool_command(
  804. "create",
  805. pool_properties=pool_props,
  806. filesystem_properties=fs_props,
  807. target="my pool",
  808. ),
  809. '/sbin/zpool create -O quota=107374182400 -o comment="jorge\'s comment has a space" "my pool"',
  810. )
  811. def test_zpool_command_property(self):
  812. """
  813. Test if zpool_command builds the correct string
  814. """
  815. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  816. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  817. with patch.object(
  818. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  819. ):
  820. with patch.object(
  821. zfs,
  822. "property_data_zpool",
  823. MagicMock(return_value=self.pmap_zpool),
  824. ):
  825. self.assertEqual(
  826. zfs.zpool_command(
  827. "get", property_name="comment", target="mypool"
  828. ),
  829. "/sbin/zpool get comment mypool",
  830. )
  831. def test_zpool_command_property_value(self):
  832. """
  833. Test if zpool_command builds the correct string
  834. """
  835. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  836. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  837. with patch.object(
  838. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  839. ):
  840. with patch.object(
  841. zfs,
  842. "property_data_zpool",
  843. MagicMock(return_value=self.pmap_zpool),
  844. ):
  845. my_flags = [
  846. "-v", # verbose
  847. ]
  848. self.assertEqual(
  849. zfs.zpool_command(
  850. "iostat", flags=my_flags, target=["mypool", 60, 1]
  851. ),
  852. "/sbin/zpool iostat -v mypool 60 1",
  853. )
  854. def test_parse_command_result_success(self):
  855. """
  856. Test if parse_command_result returns the expected result
  857. """
  858. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  859. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  860. with patch.object(
  861. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  862. ):
  863. with patch.object(
  864. zfs,
  865. "property_data_zpool",
  866. MagicMock(return_value=self.pmap_zpool),
  867. ):
  868. res = {}
  869. res["retcode"] = 0
  870. res["stderr"] = ""
  871. res["stdout"] = ""
  872. self.assertEqual(
  873. zfs.parse_command_result(res, "tested"),
  874. OrderedDict([("tested", True)]),
  875. )
  876. def test_parse_command_result_success_nolabel(self):
  877. """
  878. Test if parse_command_result returns the expected result
  879. """
  880. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  881. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  882. with patch.object(
  883. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  884. ):
  885. with patch.object(
  886. zfs,
  887. "property_data_zpool",
  888. MagicMock(return_value=self.pmap_zpool),
  889. ):
  890. res = {}
  891. res["retcode"] = 0
  892. res["stderr"] = ""
  893. res["stdout"] = ""
  894. self.assertEqual(
  895. zfs.parse_command_result(res), OrderedDict(),
  896. )
  897. def test_parse_command_result_fail(self):
  898. """
  899. Test if parse_command_result returns the expected result on failure
  900. """
  901. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  902. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  903. with patch.object(
  904. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  905. ):
  906. with patch.object(
  907. zfs,
  908. "property_data_zpool",
  909. MagicMock(return_value=self.pmap_zpool),
  910. ):
  911. res = {}
  912. res["retcode"] = 1
  913. res["stderr"] = ""
  914. res["stdout"] = ""
  915. self.assertEqual(
  916. zfs.parse_command_result(res, "tested"),
  917. OrderedDict([("tested", False)]),
  918. )
  919. def test_parse_command_result_nolabel(self):
  920. """
  921. Test if parse_command_result returns the expected result on failure
  922. """
  923. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  924. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  925. with patch.object(
  926. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  927. ):
  928. with patch.object(
  929. zfs,
  930. "property_data_zpool",
  931. MagicMock(return_value=self.pmap_zpool),
  932. ):
  933. res = {}
  934. res["retcode"] = 1
  935. res["stderr"] = ""
  936. res["stdout"] = ""
  937. self.assertEqual(
  938. zfs.parse_command_result(res), OrderedDict(),
  939. )
  940. def test_parse_command_result_fail_message(self):
  941. """
  942. Test if parse_command_result returns the expected result on failure with stderr
  943. """
  944. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  945. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  946. with patch.object(
  947. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  948. ):
  949. with patch.object(
  950. zfs,
  951. "property_data_zpool",
  952. MagicMock(return_value=self.pmap_zpool),
  953. ):
  954. res = {}
  955. res["retcode"] = 1
  956. res["stderr"] = "\n".join(
  957. ["ice is not hot", "usage:", "this should not be printed"]
  958. )
  959. res["stdout"] = ""
  960. self.assertEqual(
  961. zfs.parse_command_result(res, "tested"),
  962. OrderedDict(
  963. [("tested", False), ("error", "ice is not hot")]
  964. ),
  965. )
  966. def test_parse_command_result_fail_message_nolabel(self):
  967. """
  968. Test if parse_command_result returns the expected result on failure with stderr
  969. """
  970. with patch.object(zfs, "_zfs_cmd", MagicMock(return_value="/sbin/zfs")):
  971. with patch.object(zfs, "_zpool_cmd", MagicMock(return_value="/sbin/zpool")):
  972. with patch.object(
  973. zfs, "property_data_zfs", MagicMock(return_value=self.pmap_zfs)
  974. ):
  975. with patch.object(
  976. zfs,
  977. "property_data_zpool",
  978. MagicMock(return_value=self.pmap_zpool),
  979. ):
  980. res = {}
  981. res["retcode"] = 1
  982. res["stderr"] = "\n".join(
  983. ["ice is not hot", "usage:", "this should not be printed"]
  984. )
  985. res["stdout"] = ""
  986. self.assertEqual(
  987. zfs.parse_command_result(res),
  988. OrderedDict([("error", "ice is not hot")]),
  989. )