# -*- coding: utf-8 -*- ''' :codeauthor: :email:`Erik Johnson ` ''' # Import Python libs from __future__ import absolute_import import copy import logging import os import subprocess from distutils.version import LooseVersion # Import Salt Testing Libs from salttesting import TestCase, skipIf from salttesting.mock import ( MagicMock, patch, NO_MOCK, NO_MOCK_REASON ) # Import Salt Libs from salt.modules import git as git_mod # Don't potentially shadow GitPython # Globals git_mod.__salt__ = {} git_mod.__context__ = {} log = logging.getLogger(__name__) WORKTREE_ROOT = '/tmp/salt-tests-tmpdir/main' WORKTREE_INFO = { WORKTREE_ROOT: { 'HEAD': '119f025073875a938f2456f5ffd7d04e79e5a427', 'branch': 'refs/heads/master', 'stale': False, }, '/tmp/salt-tests-tmpdir/worktree1': { 'HEAD': 'd8d19cf75d7cc3bdc598dc2d472881d26b51a6bf', 'branch': 'refs/heads/worktree1', 'stale': False, }, '/tmp/salt-tests-tmpdir/worktree2': { 'HEAD': '56332ca504aa8b37bb62b54272d52b1d6d832629', 'branch': 'refs/heads/worktree2', 'stale': True, }, '/tmp/salt-tests-tmpdir/worktree3': { 'HEAD': 'e148ea2d521313579f661373fbb93a48a5a6d40d', 'branch': 'detached', 'tags': ['v1.1'], 'stale': False, }, '/tmp/salt-tests-tmpdir/worktree4': { 'HEAD': '6bbac64d3ad5582b3147088a708952df185db020', 'branch': 'detached', 'stale': True, }, } def _git_version(): git_version = subprocess.Popen( ['git', '--version'], shell=False, close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] if not git_version: log.error('Git not installed') return False log.debug('Detected git version ' + git_version) return LooseVersion(git_version.split()[-1]) @skipIf(NO_MOCK, NO_MOCK_REASON) class GitTestCase(TestCase): ''' Test cases for salt.modules.git ''' def test_list_worktrees(self): ''' This tests git.list_worktrees ''' def _build_worktree_output(path): ''' Build 'git worktree list' output for a given path ''' return 'worktree {0}\nHEAD {1}\n{2}\n'.format( path, WORKTREE_INFO[path]['HEAD'], 'branch {0}'.format(WORKTREE_INFO[path]['branch']) if WORKTREE_INFO[path]['branch'] != 'detached' else 'detached' ) # Build dict for _cmd_run_side_effect below. Start with the output from # 'git worktree list'. _cmd_run_values = { 'git worktree list --porcelain': '\n'.join( [_build_worktree_output(x) for x in WORKTREE_INFO] ), 'git --version': 'git version 2.7.0', } # Add 'git tag --points-at' output for detached HEAD worktrees with # tags pointing at HEAD. for path in WORKTREE_INFO: if WORKTREE_INFO[path]['branch'] != 'detached': continue key = 'git tag --points-at ' + WORKTREE_INFO[path]['HEAD'] _cmd_run_values[key] = '\n'.join( WORKTREE_INFO[path].get('tags', []) ) def _cmd_run_side_effect(key, **kwargs): # Not using dict.get() here because we want to know if # _cmd_run_values doesn't account for all uses of cmd.run_all. return {'stdout': _cmd_run_values[' '.join(key)], 'stderr': '', 'retcode': 0, 'pid': 12345} def _isdir_side_effect(key): # os.path.isdir() would return True on a non-stale worktree return not WORKTREE_INFO[key].get('stale', False) # Build return dict for comparison worktree_ret = copy.deepcopy(WORKTREE_INFO) for key in worktree_ret: ptr = worktree_ret.get(key) ptr['detached'] = ptr['branch'] == 'detached' ptr['branch'] = None \ if ptr['detached'] \ else ptr['branch'].replace('refs/heads/', '', 1) cmd_run_mock = MagicMock(side_effect=_cmd_run_side_effect) isdir_mock = MagicMock(side_effect=_isdir_side_effect) with patch.dict(git_mod.__salt__, {'cmd.run_all': cmd_run_mock}): with patch.object(os.path, 'isdir', isdir_mock): # Test all=True. Include all return data. self.maxDiff = None self.assertEqual( git_mod.list_worktrees( WORKTREE_ROOT, all=True, stale=False ), worktree_ret ) # Test all=False and stale=False. Exclude stale worktrees from # return data. self.assertEqual( git_mod.list_worktrees( WORKTREE_ROOT, all=False, stale=False ), dict([(x, worktree_ret[x]) for x in WORKTREE_INFO if not WORKTREE_INFO[x].get('stale', False)]) ) # Test stale=True. Exclude non-stale worktrees from return # data. self.assertEqual( git_mod.list_worktrees( WORKTREE_ROOT, all=False, stale=True ), dict([(x, worktree_ret[x]) for x in WORKTREE_INFO if WORKTREE_INFO[x].get('stale', False)]) ) if __name__ == '__main__': from integration import run_tests run_tests(GitTestCase, needs_daemon=False)