class TestGitRepositoryCheckSync(unittest.TestCase): """Test whether the GitRepository _check_sync_logic functionality is correct. Note: there are a lot of combinations of state: - external description - tag, branch - working copy - doesn't exist (not checked out) - exists, no git info - incorrect protocol, e.g. svn, or tarball? - exists, git info - as expected: - different from expected: - detached tag, - detached hash, - detached branch (compare remote and branch), - tracking branch (compare remote and branch), - same remote - different remote - untracked branch Test list: - doesn't exist - exists no git info - num_external * (working copy expected + num_working copy different) - total tests = 16 """ # NOTE(bja, 2017-11) pylint complains about long method names, but # it is hard to differentiate tests without making them more # cryptic. Also complains about too many public methods, but it # doesn't really make sense to break this up. # pylint: disable=invalid-name,too-many-public-methods TMP_FAKE_DIR = 'fake' TMP_FAKE_GIT_DIR = os.path.join(TMP_FAKE_DIR, '.git') def setUp(self): """Setup reusable git repository object """ self._name = 'component' rdata = { ExternalsDescription.PROTOCOL: 'git', ExternalsDescription.REPO_URL: '/path/to/local/repo', ExternalsDescription.TAG: 'tag1', } data = { self._name: { ExternalsDescription.REQUIRED: False, ExternalsDescription.PATH: self.TMP_FAKE_DIR, ExternalsDescription.EXTERNALS: EMPTY_STR, ExternalsDescription.REPO: rdata, }, } model = ExternalsDescriptionDict(data) repo = model[self._name][ExternalsDescription.REPO] self._repo = GitRepository('test', repo) # The unit tests here don't care about the result of # _current_ref, but we replace it here so that we don't need to # worry about calling a possibly slow and possibly # error-producing command (since _current_ref calls various git # functions): self._repo._current_ref = self._current_ref_empty self._create_tmp_git_dir() def tearDown(self): """Cleanup tmp stuff on the file system """ self._remove_tmp_git_dir() def _create_tmp_git_dir(self): """Create a temporary fake git directory for testing purposes. """ if not os.path.exists(self.TMP_FAKE_GIT_DIR): os.makedirs(self.TMP_FAKE_GIT_DIR) def _remove_tmp_git_dir(self): """Remove the temporary fake git directory """ if os.path.exists(self.TMP_FAKE_DIR): shutil.rmtree(self.TMP_FAKE_DIR) # # mock methods replacing git system calls # @staticmethod def _current_ref_empty(): """Return an empty string. """ return EMPTY_STR @staticmethod def _git_remote_origin_upstream(): """Return an info string that is a checkout hash """ return GIT_REMOTE_OUTPUT_ORIGIN_UPSTREAM @staticmethod def _git_remote_none(): """Return an info string that is a checkout hash """ return EMPTY_STR @staticmethod def _git_current_hash(myhash): """Return a function that takes the place of repo._git_current_hash, which returns the given hash """ def my_git_current_hash(): """mock function that can take the place of repo._git_current_hash""" return 0, myhash return my_git_current_hash def _git_revparse_commit(self, expected_ref, mystatus, myhash): """Return a function that takes the place of repo._git_revparse_commit, which returns a tuple: (mystatus, myhash). Expects the passed-in ref to equal expected_ref status = 0 implies success, non-zero implies failure """ def my_git_revparse_commit(ref): """mock function that can take the place of repo._git_revparse_commit""" self.assertEqual(expected_ref, ref) return mystatus, myhash return my_git_revparse_commit # ---------------------------------------------------------------- # # Tests where working copy doesn't exist or is invalid # # ---------------------------------------------------------------- def test_sync_dir_not_exist(self): """Test that a directory that doesn't exist returns an error status Note: the Repository classes should be prevented from ever working on an empty directory by the _Source object. """ stat = ExternalStatus() self._repo._check_sync(stat, 'invalid_directory_name') self.assertEqual(stat.sync_state, ExternalStatus.STATUS_ERROR) # check_dir should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_dir_exist_no_git_info(self): """Test that a non-existent git repo returns an unknown status """ stat = ExternalStatus() # Now we over-ride the _git_remote_verbose method on the repo to return # a known value without requiring access to git. self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._tag = 'tag1' self._repo._git_current_hash = self._git_current_hash('') self._repo._git_revparse_commit = self._git_revparse_commit( 'tag1', 1, '') self._repo._check_sync(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.UNKNOWN) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) # ------------------------------------------------------------------------ # # Tests where version in configuration file is not a valid reference # # ------------------------------------------------------------------------ def test_sync_invalid_reference(self): """Test that an invalid reference returns out-of-sync """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._tag = 'tag1' self._repo._git_current_hash = self._git_current_hash('abc123') self._repo._git_revparse_commit = self._git_revparse_commit( 'tag1', 1, '') self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) # ---------------------------------------------------------------- # # Tests where external description specifies a tag # # ---------------------------------------------------------------- def test_sync_tag_on_same_hash(self): """Test expect tag on same hash --> status ok """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._tag = 'tag1' self._repo._git_current_hash = self._git_current_hash('abc123') self._repo._git_revparse_commit = self._git_revparse_commit( 'tag1', 0, 'abc123') self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.STATUS_OK) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_tag_on_different_hash(self): """Test expect tag on a different hash --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._tag = 'tag1' self._repo._git_current_hash = self._git_current_hash('def456') self._repo._git_revparse_commit = self._git_revparse_commit( 'tag1', 0, 'abc123') self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) # ---------------------------------------------------------------- # # Tests where external description specifies a hash # # ---------------------------------------------------------------- def test_sync_hash_on_same_hash(self): """Test expect hash on same hash --> status ok """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._tag = '' self._repo._hash = 'abc' self._repo._git_current_hash = self._git_current_hash('abc123') self._repo._git_revparse_commit = self._git_revparse_commit( 'abc', 0, 'abc123') self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.STATUS_OK) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_hash_on_different_hash(self): """Test expect hash on a different hash --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._tag = '' self._repo._hash = 'abc' self._repo._git_current_hash = self._git_current_hash('def456') self._repo._git_revparse_commit = self._git_revparse_commit( 'abc', 0, 'abc123') self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) # ---------------------------------------------------------------- # # Tests where external description specifies a branch # # ---------------------------------------------------------------- def test_sync_branch_on_same_hash(self): """Test expect branch on same hash --> status ok """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature-2' self._repo._tag = '' self._repo._git_current_hash = self._git_current_hash('abc123') self._repo._git_revparse_commit = (self._git_revparse_commit( 'origin/feature-2', 0, 'abc123')) self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.STATUS_OK) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_branch_on_diff_hash(self): """Test expect branch on diff hash --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature-2' self._repo._tag = '' self._repo._git_current_hash = self._git_current_hash('abc123') self._repo._git_revparse_commit = (self._git_revparse_commit( 'origin/feature-2', 0, 'def456')) self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_branch_diff_remote(self): """Test _determine_remote_name with a different remote """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature-2' self._repo._tag = '' self._repo._url = '/path/to/other/repo' self._repo._git_current_hash = self._git_current_hash('abc123') self._repo._git_revparse_commit = (self._git_revparse_commit( 'upstream/feature-2', 0, 'def456')) self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) # The test passes if _git_revparse_commit is called with the # expected argument def test_sync_branch_diff_remote2(self): """Test _determine_remote_name with a different remote """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature-2' self._repo._tag = '' self._repo._url = '/path/to/local/repo2' self._repo._git_current_hash = self._git_current_hash('abc123') self._repo._git_revparse_commit = (self._git_revparse_commit( 'other/feature-2', 0, 'def789')) self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) # The test passes if _git_revparse_commit is called with the # expected argument def test_sync_branch_on_unknown_remote(self): """Test expect branch, but remote is unknown --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature-2' self._repo._tag = '' self._repo._url = '/path/to/unknown/repo' self._repo._git_current_hash = self._git_current_hash('abc123') self._repo._git_revparse_commit = (self._git_revparse_commit( 'unknown_remote/feature-2', 1, '')) self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_branch_on_untracked_local(self): """Test expect branch, on untracked branch in local repo --> status ok Setting the externals description to '.' indicates that the user only wants to consider the current local repo state without fetching from remotes. This is required to preserve the current branch of a repository during an update. """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature3' self._repo._tag = '' self._repo._url = '.' self._repo._git_current_hash = self._git_current_hash('abc123') self._repo._git_revparse_commit = (self._git_revparse_commit( 'feature3', 0, 'abc123')) self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.STATUS_OK) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)
class TestGitRepositoryCheckSync(unittest.TestCase): """Test whether the GitRepository _check_sync_logic functionality is correct. Note: there are a lot of combinations of state: - external description - tag, branch - working copy - doesn't exist (not checked out) - exists, no git info - incorrect protocol, e.g. svn, or tarball? - exists, git info - as expected: - different from expected: - detached tag, - detached hash, - detached branch (compare remote and branch), - tracking branch (compare remote and branch), - same remote - different remote - untracked branch Test list: - doesn't exist - exists no git info - num_external * (working copy expected + num_working copy different) - total tests = 16 """ # NOTE(bja, 2017-11) pylint complains about long method names, but # it is hard to differentiate tests without making them more # cryptic. Also complains about too many public methods, but it # doesn't really make sense to break this up. # pylint: disable=invalid-name,too-many-public-methods TMP_FAKE_DIR = 'fake' TMP_FAKE_GIT_DIR = os.path.join(TMP_FAKE_DIR, '.git') def setUp(self): """Setup reusable git repository object """ self._name = 'component' rdata = { ExternalsDescription.PROTOCOL: 'git', ExternalsDescription.REPO_URL: '/path/to/local/repo', ExternalsDescription.TAG: 'tag1', ExternalsDescription.BRANCH: EMPTY_STR } data = { self._name: { ExternalsDescription.REQUIRED: False, ExternalsDescription.PATH: self.TMP_FAKE_DIR, ExternalsDescription.EXTERNALS: EMPTY_STR, ExternalsDescription.REPO: rdata, }, } model = ExternalsDescriptionDict(data) repo = model[self._name][ExternalsDescription.REPO] self._repo = GitRepository('test', repo) self._create_tmp_git_dir() def tearDown(self): """Cleanup tmp stuff on the file system """ self._remove_tmp_git_dir() def _create_tmp_git_dir(self): """Create a temporary fake git directory for testing purposes. """ if not os.path.exists(self.TMP_FAKE_GIT_DIR): os.makedirs(self.TMP_FAKE_GIT_DIR) def _remove_tmp_git_dir(self): """Remove the temporary fake git directory """ if os.path.exists(self.TMP_FAKE_DIR): shutil.rmtree(self.TMP_FAKE_DIR) # # mock methods replacing git system calls # @staticmethod def _git_branch_empty(): """Return an empty info string. Simulates git info failing. """ return EMPTY_STR @staticmethod def _git_branch_detached_tag(): """Return an info sting that is a checkouted tag """ return GIT_BRANCH_OUTPUT_DETACHED_TAG @staticmethod def _git_branch_detached_hash(): """Return an info string that is a checkout hash """ return GIT_BRANCH_OUTPUT_DETACHED_HASH @staticmethod def _git_branch_detached_branch(): """Return an info string that is a checkout hash """ return GIT_BRANCH_OUTPUT_DETACHED_BRANCH @staticmethod def _git_branch_untracked_branch(): """Return an info string that is a checkout branch """ return GIT_BRANCH_OUTPUT_UNTRACKED_BRANCH @staticmethod def _git_branch_tracked_branch(): """Return an info string that is a checkout branch """ return GIT_BRANCH_OUTPUT_TRACKING_BRANCH @staticmethod def _git_remote_origin_upstream(): """Return an info string that is a checkout hash """ return GIT_REMOTE_OUTPUT_ORIGIN_UPSTREAM @staticmethod def _git_remote_none(): """Return an info string that is a checkout hash """ return EMPTY_STR # ---------------------------------------------------------------- # # Tests where working copy doesn't exist or is invalid # # ---------------------------------------------------------------- def test_sync_dir_not_exist(self): """Test that a directory that doesn't exist returns an error status Note: the Repository classes should be prevented from ever working on an empty directory by the _Source object. """ stat = ExternalStatus() self._repo._check_sync(stat, 'invalid_directory_name') self.assertEqual(stat.sync_state, ExternalStatus.STATUS_ERROR) # check_dir should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_dir_exist_no_git_info(self): """Test that an empty info string returns an unknown status """ stat = ExternalStatus() # Now we over-ride the _git_branch method on the repo to return # a known value without requiring access to git. self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._git_branch_vv = self._git_branch_empty self._repo._check_sync(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.UNKNOWN) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) # ---------------------------------------------------------------- # # Tests where external description specifies a tag # # Perturbations of working dir state: on detached # {tag|branch|hash}, tracking branch, untracked branch. # # ---------------------------------------------------------------- def test_sync_tag_on_detached_tag(self): """Test expect tag on detached tag --> status ok """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = '' self._repo._tag = 'tag1' self._repo._git_branch_vv = self._git_branch_detached_tag self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.STATUS_OK) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_tag_on_diff_tag(self): """Test expect tag on diff tag --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = '' self._repo._tag = 'tag2' self._repo._git_branch_vv = self._git_branch_detached_tag self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_tag_on_detached_hash(self): """Test expect tag on detached hash --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = '' self._repo._tag = 'tag1' self._repo._git_branch_vv = self._git_branch_detached_hash self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_tag_on_detached_branch(self): """Test expect tag on detached branch --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = '' self._repo._tag = 'tag1' self._repo._git_branch_vv = self._git_branch_detached_branch self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_tag_on_tracking_branch(self): """Test expect tag on tracking branch --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = '' self._repo._tag = 'tag1' self._repo._git_branch_vv = self._git_branch_tracked_branch self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_tag_on_untracked_branch(self): """Test expect tag on untracked branch --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = '' self._repo._tag = 'tag1' self._repo._git_branch_vv = self._git_branch_untracked_branch self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) # ---------------------------------------------------------------- # # Tests where external description specifies a branch # # Perturbations of working dir state: on detached # {tag|branch|hash}, tracking branch, untracked branch. # # ---------------------------------------------------------------- def test_sync_branch_on_detached_branch_same_remote(self): """Test expect branch on detached branch with same remote --> status ok """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature-2' self._repo._tag = '' self._repo._git_branch_vv = self._git_branch_detached_branch self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.STATUS_OK) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_branch_on_detached_branch_diff_remote(self): """Test expect branch on detached branch, different remote --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature-2' self._repo._tag = '' self._repo._url = '/path/to/other/repo' self._repo._git_branch_vv = self._git_branch_detached_branch self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_branch_on_detached_branch_diff_remote2(self): """Test expect branch on detached branch, different remote --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature-2' self._repo._tag = '' self._repo._url = '/path/to/local/repo2' self._repo._git_branch_vv = self._git_branch_detached_branch self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_branch_on_diff_branch(self): """Test expect branch on diff branch --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'nice_new_feature' self._repo._tag = '' self._repo._git_branch_vv = self._git_branch_detached_branch self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_branch_on_detached_hash(self): """Test expect branch on detached hash --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature-2' self._repo._tag = '' self._repo._git_branch_vv = self._git_branch_detached_hash self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_branch_on_detached_tag(self): """Test expect branch on detached tag --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature-2' self._repo._tag = '' self._repo._git_branch_vv = self._git_branch_detached_tag self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_branch_on_tracking_branch_same_remote(self): """Test expect branch on tracking branch with same remote --> status ok """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature-2' self._repo._tag = '' self._repo._git_branch_vv = self._git_branch_tracked_branch self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.STATUS_OK) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_branch_on_tracking_branch_diff_remote(self): """Test expect branch on tracking branch with different remote--> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature-2' self._repo._tag = '' self._repo._url = '/path/to/other/repo' self._repo._git_branch_vv = self._git_branch_tracked_branch self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_branch_on_untracked_branch(self): """Test expect branch on untracked branch --> status modified NOTE(bja, 2017-11) the externals description url is always a remote repository. A local untracked branch only exists locally, therefore it is always a modified state, even if this is what the user wants. """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature-2' self._repo._tag = '' self._repo._git_branch_vv = self._git_branch_untracked_branch self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_branch_on_unknown_remote(self): """Test expect branch, but remote is unknown --> status modified """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature-2' self._repo._tag = '' self._repo._url = '/path/to/unknown/repo' self._repo._git_branch_vv = self._git_branch_untracked_branch self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.MODEL_MODIFIED) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT) def test_sync_branch_on_untracked_local(self): """Test expect branch, on untracked branch in local repo --> status ok Setting the externals description to '.' indicates that the user only want's to consider the current local repo state without fetching from remotes. This is required to preserve the current branch of a repository during an update. NOTE(bja, 2017-11) the externals description is always a remote repository. A local untracked branch only exists locally, therefore it is always a modified state, even if this is what the user wants. """ stat = ExternalStatus() self._repo._git_remote_verbose = self._git_remote_origin_upstream self._repo._branch = 'feature3' self._repo._tag = '' self._repo._git_branch_vv = self._git_branch_untracked_branch self._repo._url = '.' self._repo._check_sync_logic(stat, self.TMP_FAKE_DIR) self.assertEqual(stat.sync_state, ExternalStatus.STATUS_OK) # check_sync should only modify the sync_state, not clean_state self.assertEqual(stat.clean_state, ExternalStatus.DEFAULT)