1
0

test_archive.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. import os.path
  2. import pytest
  3. import salt.modules.archive as archive
  4. from salt.exceptions import CommandNotFoundError
  5. from tests.support.mock import MagicMock, patch
  6. class ZipFileMock(MagicMock):
  7. def __init__(self, files=None, **kwargs): # pylint: disable=W0231
  8. if files is None:
  9. files = ["salt"]
  10. MagicMock.__init__(self, **kwargs)
  11. self._files = files
  12. self.external_attr = 0o0777 << 16
  13. def namelist(self):
  14. return self._files
  15. @pytest.fixture(autouse=True)
  16. def setup_loader():
  17. setup_loader_modules = {archive: {"__grains__": {"id": 0}}}
  18. with pytest.helpers.loader_mock(setup_loader_modules) as loader_mock:
  19. yield loader_mock
  20. def test_tar():
  21. with patch("glob.glob", lambda pathname: [pathname]):
  22. with patch("salt.utils.path.which", lambda exe: exe):
  23. mock = MagicMock(return_value="salt")
  24. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  25. ret = archive.tar(
  26. "-zcvf",
  27. "foo.tar",
  28. ["/tmp/something-to-compress-1", "/tmp/something-to-compress-2"],
  29. template=None,
  30. )
  31. assert ["salt"] == ret
  32. mock.assert_called_once_with(
  33. [
  34. "tar",
  35. "-zcvf",
  36. "foo.tar",
  37. "/tmp/something-to-compress-1",
  38. "/tmp/something-to-compress-2",
  39. ],
  40. runas=None,
  41. python_shell=False,
  42. template=None,
  43. cwd=None,
  44. )
  45. mock = MagicMock(return_value="salt")
  46. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  47. ret = archive.tar(
  48. "-zcvf",
  49. "foo.tar",
  50. "/tmp/something-to-compress-1,/tmp/something-to-compress-2",
  51. template=None,
  52. )
  53. assert ["salt"] == ret
  54. mock.assert_called_once_with(
  55. [
  56. "tar",
  57. "-zcvf",
  58. "foo.tar",
  59. "/tmp/something-to-compress-1",
  60. "/tmp/something-to-compress-2",
  61. ],
  62. runas=None,
  63. python_shell=False,
  64. template=None,
  65. cwd=None,
  66. )
  67. def test_tar_raises_exception_if_not_found():
  68. with patch("salt.utils.path.which", lambda exe: None):
  69. mock = MagicMock(return_value="salt")
  70. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  71. with pytest.raises(CommandNotFoundError):
  72. archive.tar("zxvf", "foo.tar", "/tmp/something-to-compress")
  73. assert not mock.called
  74. def test_gzip():
  75. mock = MagicMock(return_value="salt")
  76. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  77. with patch("salt.utils.path.which", lambda exe: exe):
  78. ret = archive.gzip("/tmp/something-to-compress")
  79. assert ["salt"] == ret
  80. mock.assert_called_once_with(
  81. ["gzip", "/tmp/something-to-compress"],
  82. runas=None,
  83. python_shell=False,
  84. template=None,
  85. )
  86. def test_gzip_raises_exception_if_not_found():
  87. mock = MagicMock(return_value="salt")
  88. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  89. with patch("salt.utils.path.which", lambda exe: None):
  90. with pytest.raises(CommandNotFoundError):
  91. archive.gzip("/tmp/something-to-compress")
  92. assert not mock.called
  93. def test_gunzip():
  94. mock = MagicMock(return_value="salt")
  95. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  96. with patch("salt.utils.path.which", lambda exe: exe):
  97. ret = archive.gunzip("/tmp/something-to-decompress.tar.gz")
  98. assert ["salt"] == ret
  99. mock.assert_called_once_with(
  100. ["gunzip", "/tmp/something-to-decompress.tar.gz"],
  101. runas=None,
  102. python_shell=False,
  103. template=None,
  104. )
  105. def test_gunzip_raises_exception_if_not_found():
  106. mock = MagicMock(return_value="salt")
  107. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  108. with patch("salt.utils.path.which", lambda exe: None):
  109. with pytest.raises(CommandNotFoundError):
  110. archive.gunzip("/tmp/something-to-decompress.tar.gz")
  111. assert not mock.called
  112. def test_cmd_zip():
  113. with patch("glob.glob", lambda pathname: [pathname]):
  114. with patch("salt.utils.path.which", lambda exe: exe):
  115. mock = MagicMock(return_value="salt")
  116. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  117. ret = archive.cmd_zip(
  118. "/tmp/salt.{{grains.id}}.zip",
  119. "/tmp/tmpePe8yO,/tmp/tmpLeSw1A",
  120. template="jinja",
  121. )
  122. assert ["salt"] == ret
  123. mock.assert_called_once_with(
  124. [
  125. "zip",
  126. "-r",
  127. "/tmp/salt.{{grains.id}}.zip",
  128. "/tmp/tmpePe8yO",
  129. "/tmp/tmpLeSw1A",
  130. ],
  131. runas=None,
  132. python_shell=False,
  133. template="jinja",
  134. cwd=None,
  135. )
  136. mock = MagicMock(return_value="salt")
  137. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  138. ret = archive.cmd_zip(
  139. "/tmp/salt.{{grains.id}}.zip",
  140. ["/tmp/tmpePe8yO", "/tmp/tmpLeSw1A"],
  141. template="jinja",
  142. )
  143. assert ["salt"] == ret
  144. mock.assert_called_once_with(
  145. [
  146. "zip",
  147. "-r",
  148. "/tmp/salt.{{grains.id}}.zip",
  149. "/tmp/tmpePe8yO",
  150. "/tmp/tmpLeSw1A",
  151. ],
  152. runas=None,
  153. python_shell=False,
  154. template="jinja",
  155. cwd=None,
  156. )
  157. def test_zip():
  158. with patch("glob.glob", lambda pathname: [pathname]):
  159. with patch.multiple(
  160. os.path,
  161. **{
  162. "isdir": MagicMock(return_value=False),
  163. "exists": MagicMock(return_value=True),
  164. }
  165. ):
  166. with patch("zipfile.ZipFile", MagicMock()):
  167. ret = archive.zip_(
  168. "/tmp/salt.{{grains.id}}.zip",
  169. "/tmp/tmpePe8yO,/tmp/tmpLeSw1A",
  170. template="jinja",
  171. )
  172. expected = [
  173. os.path.join("tmp", "tmpePe8yO"),
  174. os.path.join("tmp", "tmpLeSw1A"),
  175. ]
  176. assert expected == ret
  177. def test_zip_raises_exception_if_not_found():
  178. mock = MagicMock(return_value="salt")
  179. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  180. with patch("salt.utils.path.which", lambda exe: None):
  181. with pytest.raises(CommandNotFoundError):
  182. archive.cmd_zip(
  183. "/tmp/salt.{{grains.id}}.zip",
  184. "/tmp/tmpePe8yO,/tmp/tmpLeSw1A",
  185. template="jinja",
  186. )
  187. assert not mock.called
  188. def test_cmd_unzip():
  189. def _get_mock():
  190. """
  191. Create a new MagicMock for each scenario in this test, so that
  192. assert_called_once_with doesn't complain that the same mock object
  193. is called more than once.
  194. """
  195. return MagicMock(
  196. return_value={"stdout": "salt", "stderr": "", "pid": 12345, "retcode": 0}
  197. )
  198. with patch("salt.utils.path.which", lambda exe: exe):
  199. mock = _get_mock()
  200. with patch.dict(archive.__salt__, {"cmd.run_all": mock}):
  201. ret = archive.cmd_unzip(
  202. "/tmp/salt.{{grains.id}}.zip",
  203. "/tmp/dest",
  204. excludes="/tmp/tmpePe8yO,/tmp/tmpLeSw1A",
  205. template="jinja",
  206. )
  207. assert ["salt"] == ret
  208. mock.assert_called_once_with(
  209. [
  210. "unzip",
  211. "/tmp/salt.{{grains.id}}.zip",
  212. "-d",
  213. "/tmp/dest",
  214. "-x",
  215. "/tmp/tmpePe8yO",
  216. "/tmp/tmpLeSw1A",
  217. ],
  218. output_loglevel="debug",
  219. python_shell=False,
  220. redirect_stderr=True,
  221. runas=None,
  222. template="jinja",
  223. )
  224. mock = _get_mock()
  225. with patch.dict(archive.__salt__, {"cmd.run_all": mock}):
  226. ret = archive.cmd_unzip(
  227. "/tmp/salt.{{grains.id}}.zip",
  228. "/tmp/dest",
  229. excludes=["/tmp/tmpePe8yO", "/tmp/tmpLeSw1A"],
  230. template="jinja",
  231. )
  232. assert ["salt"] == ret
  233. mock.assert_called_once_with(
  234. [
  235. "unzip",
  236. "/tmp/salt.{{grains.id}}.zip",
  237. "-d",
  238. "/tmp/dest",
  239. "-x",
  240. "/tmp/tmpePe8yO",
  241. "/tmp/tmpLeSw1A",
  242. ],
  243. output_loglevel="debug",
  244. python_shell=False,
  245. redirect_stderr=True,
  246. runas=None,
  247. template="jinja",
  248. )
  249. mock = _get_mock()
  250. with patch.dict(archive.__salt__, {"cmd.run_all": mock}):
  251. ret = archive.cmd_unzip(
  252. "/tmp/salt.{{grains.id}}.zip",
  253. "/tmp/dest",
  254. excludes="/tmp/tmpePe8yO,/tmp/tmpLeSw1A",
  255. template="jinja",
  256. options="-fo",
  257. )
  258. assert ["salt"] == ret
  259. mock.assert_called_once_with(
  260. [
  261. "unzip",
  262. "-fo",
  263. "/tmp/salt.{{grains.id}}.zip",
  264. "-d",
  265. "/tmp/dest",
  266. "-x",
  267. "/tmp/tmpePe8yO",
  268. "/tmp/tmpLeSw1A",
  269. ],
  270. output_loglevel="debug",
  271. python_shell=False,
  272. redirect_stderr=True,
  273. runas=None,
  274. template="jinja",
  275. )
  276. mock = _get_mock()
  277. with patch.dict(archive.__salt__, {"cmd.run_all": mock}):
  278. ret = archive.cmd_unzip(
  279. "/tmp/salt.{{grains.id}}.zip",
  280. "/tmp/dest",
  281. excludes=["/tmp/tmpePe8yO", "/tmp/tmpLeSw1A"],
  282. template="jinja",
  283. options="-fo",
  284. )
  285. assert ["salt"] == ret
  286. mock.assert_called_once_with(
  287. [
  288. "unzip",
  289. "-fo",
  290. "/tmp/salt.{{grains.id}}.zip",
  291. "-d",
  292. "/tmp/dest",
  293. "-x",
  294. "/tmp/tmpePe8yO",
  295. "/tmp/tmpLeSw1A",
  296. ],
  297. output_loglevel="debug",
  298. python_shell=False,
  299. redirect_stderr=True,
  300. runas=None,
  301. template="jinja",
  302. )
  303. mock = _get_mock()
  304. with patch.dict(archive.__salt__, {"cmd.run_all": mock}):
  305. ret = archive.cmd_unzip(
  306. "/tmp/salt.{{grains.id}}.zip",
  307. "/tmp/dest",
  308. excludes=["/tmp/tmpePe8yO", "/tmp/tmpLeSw1A"],
  309. template="jinja",
  310. options="-fo",
  311. password="asdf",
  312. )
  313. assert ["salt"] == ret
  314. mock.assert_called_once_with(
  315. [
  316. "unzip",
  317. "-P",
  318. "asdf",
  319. "-fo",
  320. "/tmp/salt.{{grains.id}}.zip",
  321. "-d",
  322. "/tmp/dest",
  323. "-x",
  324. "/tmp/tmpePe8yO",
  325. "/tmp/tmpLeSw1A",
  326. ],
  327. output_loglevel="quiet",
  328. python_shell=False,
  329. redirect_stderr=True,
  330. runas=None,
  331. template="jinja",
  332. )
  333. def test_unzip():
  334. mock = ZipFileMock()
  335. with patch("zipfile.ZipFile", mock):
  336. ret = archive.unzip(
  337. "/tmp/salt.{{grains.id}}.zip",
  338. "/tmp/dest",
  339. excludes="/tmp/tmpePe8yO,/tmp/tmpLeSw1A",
  340. template="jinja",
  341. extract_perms=False,
  342. )
  343. assert ["salt"] == ret
  344. def test_unzip_raises_exception_if_not_found():
  345. mock = MagicMock(return_value="salt")
  346. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  347. with patch("salt.utils.path.which", lambda exe: None):
  348. with pytest.raises(CommandNotFoundError):
  349. archive.cmd_unzip(
  350. "/tmp/salt.{{grains.id}}.zip",
  351. "/tmp/dest",
  352. excludes="/tmp/tmpePe8yO,/tmp/tmpLeSw1A",
  353. template="jinja",
  354. )
  355. assert not mock.called
  356. def test_rar():
  357. with patch("glob.glob", lambda pathname: [pathname]):
  358. with patch("salt.utils.path.which", lambda exe: exe):
  359. mock = MagicMock(return_value="salt")
  360. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  361. ret = archive.rar(
  362. "/tmp/rarfile.rar", "/tmp/sourcefile1,/tmp/sourcefile2"
  363. )
  364. assert ["salt"] == ret
  365. mock.assert_called_once_with(
  366. [
  367. "rar",
  368. "a",
  369. "-idp",
  370. "/tmp/rarfile.rar",
  371. "/tmp/sourcefile1",
  372. "/tmp/sourcefile2",
  373. ],
  374. runas=None,
  375. python_shell=False,
  376. template=None,
  377. cwd=None,
  378. )
  379. mock = MagicMock(return_value="salt")
  380. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  381. ret = archive.rar(
  382. "/tmp/rarfile.rar", ["/tmp/sourcefile1", "/tmp/sourcefile2"]
  383. )
  384. assert ["salt"] == ret
  385. mock.assert_called_once_with(
  386. [
  387. "rar",
  388. "a",
  389. "-idp",
  390. "/tmp/rarfile.rar",
  391. "/tmp/sourcefile1",
  392. "/tmp/sourcefile2",
  393. ],
  394. runas=None,
  395. python_shell=False,
  396. template=None,
  397. cwd=None,
  398. )
  399. def test_rar_raises_exception_if_not_found():
  400. mock = MagicMock(return_value="salt")
  401. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  402. with patch("salt.utils.path.which", lambda exe: None):
  403. with pytest.raises(CommandNotFoundError):
  404. archive.rar("/tmp/rarfile.rar", "/tmp/sourcefile1,/tmp/sourcefile2")
  405. assert not mock.called
  406. @pytest.mark.skip_if_binaries_missing("unrar", "rar", message="unrar not installed")
  407. def test_unrar():
  408. with patch(
  409. "salt.utils.path.which_bin",
  410. lambda exe: exe[0] if isinstance(exe, (list, tuple)) else exe,
  411. ):
  412. with patch(
  413. "salt.utils.path.which",
  414. lambda exe: exe[0] if isinstance(exe, (list, tuple)) else exe,
  415. ):
  416. mock = MagicMock(return_value="salt")
  417. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  418. ret = archive.unrar(
  419. "/tmp/rarfile.rar", "/home/strongbad/", excludes="file_1,file_2"
  420. )
  421. assert ["salt"] == ret
  422. mock.assert_called_once_with(
  423. [
  424. "unrar",
  425. "x",
  426. "-idp",
  427. "/tmp/rarfile.rar",
  428. "-x",
  429. "file_1",
  430. "-x",
  431. "file_2",
  432. "/home/strongbad/",
  433. ],
  434. runas=None,
  435. python_shell=False,
  436. template=None,
  437. )
  438. mock = MagicMock(return_value="salt")
  439. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  440. ret = archive.unrar(
  441. "/tmp/rarfile.rar",
  442. "/home/strongbad/",
  443. excludes=["file_1", "file_2"],
  444. )
  445. assert ["salt"] == ret
  446. mock.assert_called_once_with(
  447. [
  448. "unrar",
  449. "x",
  450. "-idp",
  451. "/tmp/rarfile.rar",
  452. "-x",
  453. "file_1",
  454. "-x",
  455. "file_2",
  456. "/home/strongbad/",
  457. ],
  458. runas=None,
  459. python_shell=False,
  460. template=None,
  461. )
  462. def test_unrar_raises_exception_if_not_found():
  463. with patch("salt.utils.path.which_bin", lambda exe: None):
  464. mock = MagicMock(return_value="salt")
  465. with patch.dict(archive.__salt__, {"cmd.run": mock}):
  466. with pytest.raises(CommandNotFoundError):
  467. archive.unrar(
  468. "/tmp/rarfile.rar", "/home/strongbad/",
  469. )
  470. assert not mock.called
  471. def test_trim_files():
  472. with patch("salt.utils.path.which_bin", lambda exe: exe):
  473. source = "file.tar.gz"
  474. tmp_dir = "temp"
  475. files = [
  476. "\n".join(["file1"] * 200),
  477. "\n".join(["file2"] * 200),
  478. "this\nthat\nother",
  479. "this\nthat\nother",
  480. "this\nthat\nother",
  481. ]
  482. trim_opt = [True, False, 3, 1, 0]
  483. trim_100 = ["file1"] * 100
  484. trim_100.append("List trimmed after 100 files.")
  485. expected = [
  486. trim_100,
  487. ["file2"] * 200,
  488. ["this", "that", "other"],
  489. ["this", "List trimmed after 1 files."],
  490. ["List trimmed after 0 files."],
  491. ]
  492. for test_files, test_trim_opts, test_expected in zip(files, trim_opt, expected):
  493. with patch.dict(
  494. archive.__salt__, {"cmd.run": MagicMock(return_value=test_files)}
  495. ):
  496. ret = archive.unrar(source, tmp_dir, trim_output=test_trim_opts)
  497. assert ret == test_expected