test_gitfs.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  1. # -*- coding: utf-8 -*-
  2. """
  3. :codeauthor: Erik Johnson <erik@saltstack.com>
  4. """
  5. from __future__ import absolute_import, print_function, unicode_literals
  6. import errno
  7. import logging
  8. import os
  9. import shutil
  10. import stat
  11. import tempfile
  12. import textwrap
  13. import salt.ext.six
  14. import salt.ext.tornado.ioloop
  15. import salt.fileserver.gitfs as gitfs
  16. import salt.utils.files
  17. import salt.utils.gitfs
  18. import salt.utils.platform
  19. import salt.utils.win_functions
  20. import salt.utils.yaml
  21. from salt.utils.gitfs import (
  22. GITPYTHON_MINVER,
  23. GITPYTHON_VERSION,
  24. LIBGIT2_MINVER,
  25. LIBGIT2_VERSION,
  26. PYGIT2_MINVER,
  27. PYGIT2_VERSION,
  28. )
  29. from tests.support.helpers import patched_environ, slowTest
  30. from tests.support.mixins import LoaderModuleMockMixin
  31. from tests.support.mock import patch
  32. from tests.support.runtests import RUNTIME_VARS
  33. from tests.support.unit import TestCase, skipIf
  34. try:
  35. import pwd # pylint: disable=unused-import
  36. except ImportError:
  37. pass
  38. try:
  39. import git
  40. # We still need to use GitPython here for temp repo setup, so we do need to
  41. # actually import it. But we don't need import pygit2 in this module, we
  42. # can just use the LooseVersion instances imported along with
  43. # salt.utils.gitfs to check if we have a compatible version.
  44. HAS_GITPYTHON = GITPYTHON_VERSION >= GITPYTHON_MINVER
  45. except (ImportError, AttributeError):
  46. HAS_GITPYTHON = False
  47. try:
  48. HAS_PYGIT2 = PYGIT2_VERSION >= PYGIT2_MINVER and LIBGIT2_VERSION >= LIBGIT2_MINVER
  49. except AttributeError:
  50. HAS_PYGIT2 = False
  51. log = logging.getLogger(__name__)
  52. UNICODE_FILENAME = "питон.txt"
  53. UNICODE_DIRNAME = UNICODE_ENVNAME = "соль"
  54. TAG_NAME = "mytag"
  55. def _rmtree_error(func, path, excinfo):
  56. os.chmod(path, stat.S_IWRITE)
  57. func(path)
  58. def _clear_instance_map():
  59. try:
  60. del salt.utils.gitfs.GitFS.instance_map[
  61. salt.ext.tornado.ioloop.IOLoop.current()
  62. ]
  63. except KeyError:
  64. pass
  65. @skipIf(not HAS_GITPYTHON, "GitPython >= {0} required".format(GITPYTHON_MINVER))
  66. class GitfsConfigTestCase(TestCase, LoaderModuleMockMixin):
  67. def setup_loader_modules(self):
  68. opts = {
  69. "sock_dir": self.tmp_sock_dir,
  70. "gitfs_remotes": ["file://" + self.tmp_repo_dir],
  71. "gitfs_root": "",
  72. "fileserver_backend": ["gitfs"],
  73. "gitfs_base": "master",
  74. "gitfs_fallback": "",
  75. "fileserver_events": True,
  76. "transport": "zeromq",
  77. "gitfs_mountpoint": "",
  78. "gitfs_saltenv": [],
  79. "gitfs_saltenv_whitelist": [],
  80. "gitfs_saltenv_blacklist": [],
  81. "gitfs_user": "",
  82. "gitfs_password": "",
  83. "gitfs_insecure_auth": False,
  84. "gitfs_privkey": "",
  85. "gitfs_pubkey": "",
  86. "gitfs_passphrase": "",
  87. "gitfs_refspecs": [
  88. "+refs/heads/*:refs/remotes/origin/*",
  89. "+refs/tags/*:refs/tags/*",
  90. ],
  91. "gitfs_ssl_verify": True,
  92. "gitfs_disable_saltenv_mapping": False,
  93. "gitfs_ref_types": ["branch", "tag", "sha"],
  94. "gitfs_update_interval": 60,
  95. "__role": "master",
  96. }
  97. opts["cachedir"] = self.tmp_cachedir
  98. opts["sock_dir"] = self.tmp_sock_dir
  99. return {gitfs: {"__opts__": opts}}
  100. @classmethod
  101. def setUpClass(cls):
  102. # Clear the instance map so that we make sure to create a new instance
  103. # for this test class.
  104. _clear_instance_map()
  105. cls.tmp_repo_dir = os.path.join(RUNTIME_VARS.TMP, "gitfs_root")
  106. if salt.utils.platform.is_windows():
  107. cls.tmp_repo_dir = cls.tmp_repo_dir.replace("\\", "/")
  108. cls.tmp_cachedir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  109. cls.tmp_sock_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  110. @classmethod
  111. def tearDownClass(cls):
  112. """
  113. Remove the temporary git repository and gitfs cache directory to ensure
  114. a clean environment for the other test class(es).
  115. """
  116. for path in (cls.tmp_cachedir, cls.tmp_sock_dir):
  117. try:
  118. shutil.rmtree(path, onerror=_rmtree_error)
  119. except OSError as exc:
  120. if exc.errno == errno.EACCES:
  121. log.error("Access error removeing file %s", path)
  122. continue
  123. if exc.errno != errno.EEXIST:
  124. raise
  125. def test_per_saltenv_config(self):
  126. opts_override = textwrap.dedent(
  127. """
  128. gitfs_root: salt
  129. gitfs_saltenv:
  130. - baz:
  131. # when loaded, the "salt://" prefix will be removed
  132. - mountpoint: salt://baz_mountpoint
  133. - ref: baz_branch
  134. - root: baz_root
  135. gitfs_remotes:
  136. - file://{0}tmp/repo1:
  137. - saltenv:
  138. - foo:
  139. - ref: foo_branch
  140. - root: foo_root
  141. - file://{0}tmp/repo2:
  142. - mountpoint: repo2
  143. - saltenv:
  144. - baz:
  145. - mountpoint: abc
  146. """.format(
  147. "/" if salt.utils.platform.is_windows() else ""
  148. )
  149. )
  150. with patch.dict(gitfs.__opts__, salt.utils.yaml.safe_load(opts_override)):
  151. git_fs = salt.utils.gitfs.GitFS(
  152. gitfs.__opts__,
  153. gitfs.__opts__["gitfs_remotes"],
  154. per_remote_overrides=gitfs.PER_REMOTE_OVERRIDES,
  155. per_remote_only=gitfs.PER_REMOTE_ONLY,
  156. )
  157. # repo1 (branch: foo)
  158. # The mountpoint should take the default (from gitfs_mountpoint), while
  159. # ref and root should take the per-saltenv params.
  160. self.assertEqual(git_fs.remotes[0].mountpoint("foo"), "")
  161. self.assertEqual(git_fs.remotes[0].ref("foo"), "foo_branch")
  162. self.assertEqual(git_fs.remotes[0].root("foo"), "foo_root")
  163. # repo1 (branch: bar)
  164. # The 'bar' branch does not have a per-saltenv configuration set, so
  165. # each of the below values should fall back to global values.
  166. self.assertEqual(git_fs.remotes[0].mountpoint("bar"), "")
  167. self.assertEqual(git_fs.remotes[0].ref("bar"), "bar")
  168. self.assertEqual(git_fs.remotes[0].root("bar"), "salt")
  169. # repo1 (branch: baz)
  170. # The 'baz' branch does not have a per-saltenv configuration set, but
  171. # it is defined in the gitfs_saltenv parameter, so the values
  172. # from that parameter should be returned.
  173. self.assertEqual(git_fs.remotes[0].mountpoint("baz"), "baz_mountpoint")
  174. self.assertEqual(git_fs.remotes[0].ref("baz"), "baz_branch")
  175. self.assertEqual(git_fs.remotes[0].root("baz"), "baz_root")
  176. # repo2 (branch: foo)
  177. # The mountpoint should take the per-remote mountpoint value of
  178. # 'repo2', while ref and root should fall back to global values.
  179. self.assertEqual(git_fs.remotes[1].mountpoint("foo"), "repo2")
  180. self.assertEqual(git_fs.remotes[1].ref("foo"), "foo")
  181. self.assertEqual(git_fs.remotes[1].root("foo"), "salt")
  182. # repo2 (branch: bar)
  183. # The 'bar' branch does not have a per-saltenv configuration set, so
  184. # the mountpoint should take the per-remote mountpoint value of
  185. # 'repo2', while ref and root should fall back to global values.
  186. self.assertEqual(git_fs.remotes[1].mountpoint("bar"), "repo2")
  187. self.assertEqual(git_fs.remotes[1].ref("bar"), "bar")
  188. self.assertEqual(git_fs.remotes[1].root("bar"), "salt")
  189. # repo2 (branch: baz)
  190. # The 'baz' branch has the mountpoint configured as a per-saltenv
  191. # parameter. The other two should take the values defined in
  192. # gitfs_saltenv.
  193. self.assertEqual(git_fs.remotes[1].mountpoint("baz"), "abc")
  194. self.assertEqual(git_fs.remotes[1].ref("baz"), "baz_branch")
  195. self.assertEqual(git_fs.remotes[1].root("baz"), "baz_root")
  196. LOAD = {"saltenv": "base"}
  197. class GitFSTestFuncs(object):
  198. """
  199. These are where the tests go, so that they can be run using both GitPython
  200. and pygit2.
  201. NOTE: The gitfs.update() has to happen AFTER the setUp is called. This is
  202. because running it inside the setUp will spawn a new singleton, which means
  203. that tests which need to mock the __opts__ will be too late; the setUp will
  204. have created a new singleton that will bypass our mocking. To ensure that
  205. our tests are reliable and correct, we want to make sure that each test
  206. uses a new gitfs object, allowing different manipulations of the opts to be
  207. tested.
  208. Therefore, keep the following in mind:
  209. 1. Each test needs to call gitfs.update() *after* any patching, and
  210. *before* calling the function being tested.
  211. 2. Do *NOT* move the gitfs.update() into the setUp.
  212. """
  213. @slowTest
  214. def test_file_list(self):
  215. gitfs.update()
  216. ret = gitfs.file_list(LOAD)
  217. self.assertIn("testfile", ret)
  218. self.assertIn(UNICODE_FILENAME, ret)
  219. # This function does not use os.sep, the Salt fileserver uses the
  220. # forward slash, hence it being explicitly used to join here.
  221. self.assertIn("/".join((UNICODE_DIRNAME, "foo.txt")), ret)
  222. @slowTest
  223. def test_dir_list(self):
  224. gitfs.update()
  225. ret = gitfs.dir_list(LOAD)
  226. self.assertIn("grail", ret)
  227. self.assertIn(UNICODE_DIRNAME, ret)
  228. def test_find_and_serve_file(self):
  229. with patch.dict(gitfs.__opts__, {"file_buffer_size": 262144}):
  230. gitfs.update()
  231. # find_file
  232. ret = gitfs.find_file("testfile")
  233. self.assertEqual("testfile", ret["rel"])
  234. full_path_to_file = salt.utils.path.join(
  235. gitfs.__opts__["cachedir"], "gitfs", "refs", "base", "testfile"
  236. )
  237. self.assertEqual(full_path_to_file, ret["path"])
  238. # serve_file
  239. load = {"saltenv": "base", "path": full_path_to_file, "loc": 0}
  240. fnd = {"path": full_path_to_file, "rel": "testfile"}
  241. ret = gitfs.serve_file(load, fnd)
  242. with salt.utils.files.fopen(
  243. os.path.join(RUNTIME_VARS.BASE_FILES, "testfile"), "r"
  244. ) as fp_: # NB: Why not 'rb'?
  245. data = fp_.read()
  246. self.assertDictEqual(ret, {"data": data, "dest": "testfile"})
  247. def test_file_list_fallback(self):
  248. with patch.dict(gitfs.__opts__, {"gitfs_fallback": "master"}):
  249. gitfs.update()
  250. ret = gitfs.file_list({"saltenv": "notexisting"})
  251. self.assertIn("testfile", ret)
  252. self.assertIn(UNICODE_FILENAME, ret)
  253. # This function does not use os.sep, the Salt fileserver uses the
  254. # forward slash, hence it being explicitly used to join here.
  255. self.assertIn("/".join((UNICODE_DIRNAME, "foo.txt")), ret)
  256. def test_dir_list_fallback(self):
  257. with patch.dict(gitfs.__opts__, {"gitfs_fallback": "master"}):
  258. gitfs.update()
  259. ret = gitfs.dir_list({"saltenv": "notexisting"})
  260. self.assertIn("grail", ret)
  261. self.assertIn(UNICODE_DIRNAME, ret)
  262. def test_find_and_serve_file_fallback(self):
  263. with patch.dict(
  264. gitfs.__opts__, {"file_buffer_size": 262144, "gitfs_fallback": "master"}
  265. ):
  266. gitfs.update()
  267. # find_file
  268. ret = gitfs.find_file("testfile", tgt_env="notexisting")
  269. self.assertEqual("testfile", ret["rel"])
  270. full_path_to_file = salt.utils.path.join(
  271. gitfs.__opts__["cachedir"], "gitfs", "refs", "notexisting", "testfile"
  272. )
  273. self.assertEqual(full_path_to_file, ret["path"])
  274. # serve_file
  275. load = {"saltenv": "notexisting", "path": full_path_to_file, "loc": 0}
  276. fnd = {"path": full_path_to_file, "rel": "testfile"}
  277. ret = gitfs.serve_file(load, fnd)
  278. with salt.utils.files.fopen(
  279. os.path.join(RUNTIME_VARS.BASE_FILES, "testfile"), "r"
  280. ) as fp_: # NB: Why not 'rb'?
  281. data = fp_.read()
  282. self.assertDictEqual(ret, {"data": data, "dest": "testfile"})
  283. @slowTest
  284. def test_envs(self):
  285. gitfs.update()
  286. ret = gitfs.envs(ignore_cache=True)
  287. self.assertIn("base", ret)
  288. self.assertIn(UNICODE_ENVNAME, ret)
  289. self.assertIn(TAG_NAME, ret)
  290. @slowTest
  291. def test_ref_types_global(self):
  292. """
  293. Test the global gitfs_ref_types config option
  294. """
  295. with patch.dict(gitfs.__opts__, {"gitfs_ref_types": ["branch"]}):
  296. gitfs.update()
  297. ret = gitfs.envs(ignore_cache=True)
  298. # Since we are restricting to branches only, the tag should not
  299. # appear in the envs list.
  300. self.assertIn("base", ret)
  301. self.assertIn(UNICODE_ENVNAME, ret)
  302. self.assertNotIn(TAG_NAME, ret)
  303. @slowTest
  304. def test_ref_types_per_remote(self):
  305. """
  306. Test the per_remote ref_types config option, using a different
  307. ref_types setting than the global test.
  308. """
  309. remotes = [{"file://" + self.tmp_repo_dir: [{"ref_types": ["tag"]}]}]
  310. with patch.dict(gitfs.__opts__, {"gitfs_remotes": remotes}):
  311. gitfs.update()
  312. ret = gitfs.envs(ignore_cache=True)
  313. # Since we are restricting to tags only, the tag should appear in
  314. # the envs list, but the branches should not.
  315. self.assertNotIn("base", ret)
  316. self.assertNotIn(UNICODE_ENVNAME, ret)
  317. self.assertIn(TAG_NAME, ret)
  318. @slowTest
  319. def test_disable_saltenv_mapping_global_with_mapping_defined_globally(self):
  320. """
  321. Test the global gitfs_disable_saltenv_mapping config option, combined
  322. with the per-saltenv mapping being defined in the global gitfs_saltenv
  323. option.
  324. """
  325. opts = salt.utils.yaml.safe_load(
  326. textwrap.dedent(
  327. """\
  328. gitfs_disable_saltenv_mapping: True
  329. gitfs_saltenv:
  330. - foo:
  331. - ref: somebranch
  332. """
  333. )
  334. )
  335. with patch.dict(gitfs.__opts__, opts):
  336. gitfs.update()
  337. ret = gitfs.envs(ignore_cache=True)
  338. # Since we are restricting to tags only, the tag should appear in
  339. # the envs list, but the branches should not.
  340. self.assertEqual(ret, ["base", "foo"])
  341. @slowTest
  342. def test_saltenv_blacklist(self):
  343. """
  344. test saltenv_blacklist
  345. """
  346. opts = salt.utils.yaml.safe_load(
  347. textwrap.dedent(
  348. """\
  349. gitfs_saltenv_blacklist: base
  350. """
  351. )
  352. )
  353. with patch.dict(gitfs.__opts__, opts):
  354. gitfs.update()
  355. ret = gitfs.envs(ignore_cache=True)
  356. assert "base" not in ret
  357. assert UNICODE_ENVNAME in ret
  358. assert "mytag" in ret
  359. @slowTest
  360. def test_saltenv_whitelist(self):
  361. """
  362. test saltenv_whitelist
  363. """
  364. opts = salt.utils.yaml.safe_load(
  365. textwrap.dedent(
  366. """\
  367. gitfs_saltenv_whitelist: base
  368. """
  369. )
  370. )
  371. with patch.dict(gitfs.__opts__, opts):
  372. gitfs.update()
  373. ret = gitfs.envs(ignore_cache=True)
  374. assert "base" in ret
  375. assert UNICODE_ENVNAME not in ret
  376. assert "mytag" not in ret
  377. @slowTest
  378. def test_env_deprecated_opts(self):
  379. """
  380. ensure deprecated options gitfs_env_whitelist
  381. and gitfs_env_blacklist do not cause gitfs to
  382. not load.
  383. """
  384. opts = salt.utils.yaml.safe_load(
  385. textwrap.dedent(
  386. """\
  387. gitfs_env_whitelist: base
  388. gitfs_env_blacklist: ''
  389. """
  390. )
  391. )
  392. with patch.dict(gitfs.__opts__, opts):
  393. gitfs.update()
  394. ret = gitfs.envs(ignore_cache=True)
  395. assert "base" in ret
  396. assert UNICODE_ENVNAME in ret
  397. assert "mytag" in ret
  398. @slowTest
  399. def test_disable_saltenv_mapping_global_with_mapping_defined_per_remote(self):
  400. """
  401. Test the global gitfs_disable_saltenv_mapping config option, combined
  402. with the per-saltenv mapping being defined in the remote itself via the
  403. "saltenv" per-remote option.
  404. """
  405. opts = salt.utils.yaml.safe_load(
  406. textwrap.dedent(
  407. """\
  408. gitfs_disable_saltenv_mapping: True
  409. gitfs_remotes:
  410. - {0}:
  411. - saltenv:
  412. - bar:
  413. - ref: somebranch
  414. """.format(
  415. self.tmp_repo_dir
  416. )
  417. )
  418. )
  419. with patch.dict(gitfs.__opts__, opts):
  420. gitfs.update()
  421. ret = gitfs.envs(ignore_cache=True)
  422. # Since we are restricting to tags only, the tag should appear in
  423. # the envs list, but the branches should not.
  424. self.assertEqual(ret, ["bar", "base"])
  425. @slowTest
  426. def test_disable_saltenv_mapping_per_remote_with_mapping_defined_globally(self):
  427. """
  428. Test the per-remote disable_saltenv_mapping config option, combined
  429. with the per-saltenv mapping being defined in the global gitfs_saltenv
  430. option.
  431. """
  432. opts = salt.utils.yaml.safe_load(
  433. textwrap.dedent(
  434. """\
  435. gitfs_remotes:
  436. - {0}:
  437. - disable_saltenv_mapping: True
  438. gitfs_saltenv:
  439. - hello:
  440. - ref: somebranch
  441. """.format(
  442. self.tmp_repo_dir
  443. )
  444. )
  445. )
  446. with patch.dict(gitfs.__opts__, opts):
  447. gitfs.update()
  448. ret = gitfs.envs(ignore_cache=True)
  449. # Since we are restricting to tags only, the tag should appear in
  450. # the envs list, but the branches should not.
  451. self.assertEqual(ret, ["base", "hello"])
  452. @slowTest
  453. def test_disable_saltenv_mapping_per_remote_with_mapping_defined_per_remote(self):
  454. """
  455. Test the per-remote disable_saltenv_mapping config option, combined
  456. with the per-saltenv mapping being defined in the remote itself via the
  457. "saltenv" per-remote option.
  458. """
  459. opts = salt.utils.yaml.safe_load(
  460. textwrap.dedent(
  461. """\
  462. gitfs_remotes:
  463. - {0}:
  464. - disable_saltenv_mapping: True
  465. - saltenv:
  466. - world:
  467. - ref: somebranch
  468. """.format(
  469. self.tmp_repo_dir
  470. )
  471. )
  472. )
  473. with patch.dict(gitfs.__opts__, opts):
  474. gitfs.update()
  475. ret = gitfs.envs(ignore_cache=True)
  476. # Since we are restricting to tags only, the tag should appear in
  477. # the envs list, but the branches should not.
  478. self.assertEqual(ret, ["base", "world"])
  479. class GitFSTestBase(object):
  480. @classmethod
  481. def setUpClass(cls):
  482. cls.tmp_repo_dir = os.path.join(RUNTIME_VARS.TMP, "gitfs_root")
  483. if salt.utils.platform.is_windows():
  484. cls.tmp_repo_dir = cls.tmp_repo_dir.replace("\\", "/")
  485. cls.tmp_cachedir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  486. cls.tmp_sock_dir = tempfile.mkdtemp(dir=RUNTIME_VARS.TMP)
  487. try:
  488. shutil.rmtree(cls.tmp_repo_dir)
  489. except OSError as exc:
  490. if exc.errno == errno.EACCES:
  491. log.error("Access error removing file %s", cls.tmp_repo_dir)
  492. elif exc.errno != errno.ENOENT:
  493. raise
  494. shutil.copytree(
  495. salt.ext.six.text_type(RUNTIME_VARS.BASE_FILES),
  496. salt.ext.six.text_type(cls.tmp_repo_dir + "/"),
  497. symlinks=True,
  498. )
  499. repo = git.Repo.init(cls.tmp_repo_dir)
  500. try:
  501. if salt.utils.platform.is_windows():
  502. username = salt.utils.win_functions.get_current_user()
  503. else:
  504. username = pwd.getpwuid(os.geteuid()).pw_name
  505. except AttributeError:
  506. log.error("Unable to get effective username, falling back to 'root'.")
  507. username = str("root")
  508. with patched_environ(USERNAME=username):
  509. repo.index.add([x for x in os.listdir(cls.tmp_repo_dir) if x != ".git"])
  510. repo.index.commit("Test")
  511. # Add another branch with unicode characters in the name
  512. repo.create_head(UNICODE_ENVNAME, "HEAD")
  513. # Add a tag
  514. repo.create_tag(TAG_NAME, "HEAD")
  515. # Older GitPython versions do not have a close method.
  516. if hasattr(repo, "close"):
  517. repo.close()
  518. @classmethod
  519. def tearDownClass(cls):
  520. """
  521. Remove the temporary git repository and gitfs cache directory to ensure
  522. a clean environment for the other test class(es).
  523. """
  524. for path in (cls.tmp_cachedir, cls.tmp_sock_dir, cls.tmp_repo_dir):
  525. try:
  526. salt.utils.files.rm_rf(path)
  527. except OSError as exc:
  528. if exc.errno == errno.EACCES:
  529. log.error("Access error removeing file %s", path)
  530. elif exc.errno != errno.EEXIST:
  531. raise
  532. def setUp(self):
  533. """
  534. We don't want to check in another .git dir into GH because that just
  535. gets messy. Instead, we'll create a temporary repo on the fly for the
  536. tests to examine.
  537. Also ensure we A) don't re-use the singleton, and B) that the cachedirs
  538. are cleared. This keeps these performance enhancements from affecting
  539. the results of subsequent tests.
  540. """
  541. if not gitfs.__virtual__():
  542. self.skipTest("GitFS could not be loaded. Skipping GitFS tests!")
  543. _clear_instance_map()
  544. for subdir in ("gitfs", "file_lists"):
  545. try:
  546. salt.utils.files.rm_rf(os.path.join(self.tmp_cachedir, subdir))
  547. except OSError as exc:
  548. if exc.errno == errno.EACCES:
  549. log.warning(
  550. "Access error removeing file %s",
  551. os.path.join(self.tmp_cachedir, subdir),
  552. )
  553. continue
  554. if exc.errno != errno.ENOENT:
  555. raise
  556. if salt.ext.six.PY3 and salt.utils.platform.is_windows():
  557. self.setUpClass()
  558. self.setup_loader_modules()
  559. @skipIf(not HAS_GITPYTHON, "GitPython >= {0} required".format(GITPYTHON_MINVER))
  560. class GitPythonTest(GitFSTestBase, GitFSTestFuncs, TestCase, LoaderModuleMockMixin):
  561. def setup_loader_modules(self):
  562. opts = {
  563. "sock_dir": self.tmp_sock_dir,
  564. "gitfs_remotes": ["file://" + self.tmp_repo_dir],
  565. "gitfs_root": "",
  566. "fileserver_backend": ["gitfs"],
  567. "gitfs_base": "master",
  568. "gitfs_fallback": "",
  569. "fileserver_events": True,
  570. "transport": "zeromq",
  571. "gitfs_mountpoint": "",
  572. "gitfs_saltenv": [],
  573. "gitfs_saltenv_whitelist": [],
  574. "gitfs_saltenv_blacklist": [],
  575. "gitfs_user": "",
  576. "gitfs_password": "",
  577. "gitfs_insecure_auth": False,
  578. "gitfs_privkey": "",
  579. "gitfs_pubkey": "",
  580. "gitfs_passphrase": "",
  581. "gitfs_refspecs": [
  582. "+refs/heads/*:refs/remotes/origin/*",
  583. "+refs/tags/*:refs/tags/*",
  584. ],
  585. "gitfs_ssl_verify": True,
  586. "gitfs_disable_saltenv_mapping": False,
  587. "gitfs_ref_types": ["branch", "tag", "sha"],
  588. "gitfs_update_interval": 60,
  589. "__role": "master",
  590. }
  591. opts["cachedir"] = self.tmp_cachedir
  592. opts["sock_dir"] = self.tmp_sock_dir
  593. opts["gitfs_provider"] = "gitpython"
  594. return {gitfs: {"__opts__": opts}}
  595. @skipIf(
  596. not HAS_GITPYTHON,
  597. "GitPython >= {0} required for temp repo setup".format(GITPYTHON_MINVER),
  598. )
  599. @skipIf(
  600. not HAS_PYGIT2,
  601. "pygit2 >= {0} and libgit2 >= {1} required".format(PYGIT2_MINVER, LIBGIT2_MINVER),
  602. )
  603. @skipIf(
  604. salt.utils.platform.is_windows(),
  605. "Skip Pygit2 on windows, due to pygit2 access error on windows",
  606. )
  607. class Pygit2Test(GitFSTestBase, GitFSTestFuncs, TestCase, LoaderModuleMockMixin):
  608. def setup_loader_modules(self):
  609. opts = {
  610. "sock_dir": self.tmp_sock_dir,
  611. "gitfs_remotes": ["file://" + self.tmp_repo_dir],
  612. "gitfs_root": "",
  613. "fileserver_backend": ["gitfs"],
  614. "gitfs_base": "master",
  615. "gitfs_fallback": "",
  616. "fileserver_events": True,
  617. "transport": "zeromq",
  618. "gitfs_mountpoint": "",
  619. "gitfs_saltenv": [],
  620. "gitfs_saltenv_whitelist": [],
  621. "gitfs_saltenv_blacklist": [],
  622. "gitfs_user": "",
  623. "gitfs_password": "",
  624. "gitfs_insecure_auth": False,
  625. "gitfs_privkey": "",
  626. "gitfs_pubkey": "",
  627. "gitfs_passphrase": "",
  628. "gitfs_refspecs": [
  629. "+refs/heads/*:refs/remotes/origin/*",
  630. "+refs/tags/*:refs/tags/*",
  631. ],
  632. "gitfs_ssl_verify": True,
  633. "gitfs_disable_saltenv_mapping": False,
  634. "gitfs_ref_types": ["branch", "tag", "sha"],
  635. "gitfs_update_interval": 60,
  636. "__role": "master",
  637. }
  638. opts["cachedir"] = self.tmp_cachedir
  639. opts["sock_dir"] = self.tmp_sock_dir
  640. opts["gitfs_provider"] = "pygit2"
  641. return {gitfs: {"__opts__": opts}}