##// END OF EJS Templates
tests: fixed tests for new source ref checking.
marcink -
r2473:32635607 default
parent child Browse files
Show More
@@ -1,1271 +1,1289 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import datetime
21 import datetime
22 import mock
22 import mock
23 import os
23 import os
24 import sys
24 import sys
25 import shutil
25 import shutil
26
26
27 import pytest
27 import pytest
28
28
29 from rhodecode.lib.utils import make_db_config
29 from rhodecode.lib.utils import make_db_config
30 from rhodecode.lib.vcs.backends.base import Reference
30 from rhodecode.lib.vcs.backends.base import Reference
31 from rhodecode.lib.vcs.backends.git import (
31 from rhodecode.lib.vcs.backends.git import (
32 GitRepository, GitCommit, discover_git_version)
32 GitRepository, GitCommit, discover_git_version)
33 from rhodecode.lib.vcs.exceptions import (
33 from rhodecode.lib.vcs.exceptions import (
34 RepositoryError, VCSError, NodeDoesNotExistError)
34 RepositoryError, VCSError, NodeDoesNotExistError)
35 from rhodecode.lib.vcs.nodes import (
35 from rhodecode.lib.vcs.nodes import (
36 NodeKind, FileNode, DirNode, NodeState, SubModuleNode)
36 NodeKind, FileNode, DirNode, NodeState, SubModuleNode)
37 from rhodecode.tests import TEST_GIT_REPO, TEST_GIT_REPO_CLONE, get_new_dir
37 from rhodecode.tests import TEST_GIT_REPO, TEST_GIT_REPO_CLONE, get_new_dir
38 from rhodecode.tests.vcs.conftest import BackendTestMixin
38 from rhodecode.tests.vcs.conftest import BackendTestMixin
39
39
40
40
41 pytestmark = pytest.mark.backends("git")
41 pytestmark = pytest.mark.backends("git")
42
42
43
43
44 def repo_path_generator():
44 def repo_path_generator():
45 """
45 """
46 Return a different path to be used for cloning repos.
46 Return a different path to be used for cloning repos.
47 """
47 """
48 i = 0
48 i = 0
49 while True:
49 while True:
50 i += 1
50 i += 1
51 yield '%s-%d' % (TEST_GIT_REPO_CLONE, i)
51 yield '%s-%d' % (TEST_GIT_REPO_CLONE, i)
52
52
53
53
54 REPO_PATH_GENERATOR = repo_path_generator()
54 REPO_PATH_GENERATOR = repo_path_generator()
55
55
56
56
57 class TestGitRepository:
57 class TestGitRepository:
58
58
59 # pylint: disable=protected-access
59 # pylint: disable=protected-access
60
60
61 def __check_for_existing_repo(self):
61 def __check_for_existing_repo(self):
62 if os.path.exists(TEST_GIT_REPO_CLONE):
62 if os.path.exists(TEST_GIT_REPO_CLONE):
63 self.fail('Cannot test git clone repo as location %s already '
63 self.fail('Cannot test git clone repo as location %s already '
64 'exists. You should manually remove it first.'
64 'exists. You should manually remove it first.'
65 % TEST_GIT_REPO_CLONE)
65 % TEST_GIT_REPO_CLONE)
66
66
67 @pytest.fixture(autouse=True)
67 @pytest.fixture(autouse=True)
68 def prepare(self, request, baseapp):
68 def prepare(self, request, baseapp):
69 self.repo = GitRepository(TEST_GIT_REPO, bare=True)
69 self.repo = GitRepository(TEST_GIT_REPO, bare=True)
70
70
71 def get_clone_repo(self):
71 def get_clone_repo(self):
72 """
72 """
73 Return a non bare clone of the base repo.
73 Return a non bare clone of the base repo.
74 """
74 """
75 clone_path = next(REPO_PATH_GENERATOR)
75 clone_path = next(REPO_PATH_GENERATOR)
76 repo_clone = GitRepository(
76 repo_clone = GitRepository(
77 clone_path, create=True, src_url=self.repo.path, bare=False)
77 clone_path, create=True, src_url=self.repo.path, bare=False)
78
78
79 return repo_clone
79 return repo_clone
80
80
81 def get_empty_repo(self, bare=False):
81 def get_empty_repo(self, bare=False):
82 """
82 """
83 Return a non bare empty repo.
83 Return a non bare empty repo.
84 """
84 """
85 return GitRepository(next(REPO_PATH_GENERATOR), create=True, bare=bare)
85 return GitRepository(next(REPO_PATH_GENERATOR), create=True, bare=bare)
86
86
87 def test_wrong_repo_path(self):
87 def test_wrong_repo_path(self):
88 wrong_repo_path = '/tmp/errorrepo_git'
88 wrong_repo_path = '/tmp/errorrepo_git'
89 with pytest.raises(RepositoryError):
89 with pytest.raises(RepositoryError):
90 GitRepository(wrong_repo_path)
90 GitRepository(wrong_repo_path)
91
91
92 def test_repo_clone(self):
92 def test_repo_clone(self):
93 self.__check_for_existing_repo()
93 self.__check_for_existing_repo()
94 repo = GitRepository(TEST_GIT_REPO)
94 repo = GitRepository(TEST_GIT_REPO)
95 repo_clone = GitRepository(
95 repo_clone = GitRepository(
96 TEST_GIT_REPO_CLONE,
96 TEST_GIT_REPO_CLONE,
97 src_url=TEST_GIT_REPO, create=True, update_after_clone=True)
97 src_url=TEST_GIT_REPO, create=True, update_after_clone=True)
98 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
98 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
99 # Checking hashes of commits should be enough
99 # Checking hashes of commits should be enough
100 for commit in repo.get_commits():
100 for commit in repo.get_commits():
101 raw_id = commit.raw_id
101 raw_id = commit.raw_id
102 assert raw_id == repo_clone.get_commit(raw_id).raw_id
102 assert raw_id == repo_clone.get_commit(raw_id).raw_id
103
103
104 def test_repo_clone_without_create(self):
104 def test_repo_clone_without_create(self):
105 with pytest.raises(RepositoryError):
105 with pytest.raises(RepositoryError):
106 GitRepository(
106 GitRepository(
107 TEST_GIT_REPO_CLONE + '_wo_create', src_url=TEST_GIT_REPO)
107 TEST_GIT_REPO_CLONE + '_wo_create', src_url=TEST_GIT_REPO)
108
108
109 def test_repo_clone_with_update(self):
109 def test_repo_clone_with_update(self):
110 repo = GitRepository(TEST_GIT_REPO)
110 repo = GitRepository(TEST_GIT_REPO)
111 clone_path = TEST_GIT_REPO_CLONE + '_with_update'
111 clone_path = TEST_GIT_REPO_CLONE + '_with_update'
112 repo_clone = GitRepository(
112 repo_clone = GitRepository(
113 clone_path,
113 clone_path,
114 create=True, src_url=TEST_GIT_REPO, update_after_clone=True)
114 create=True, src_url=TEST_GIT_REPO, update_after_clone=True)
115 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
115 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
116
116
117 # check if current workdir was updated
117 # check if current workdir was updated
118 fpath = os.path.join(clone_path, 'MANIFEST.in')
118 fpath = os.path.join(clone_path, 'MANIFEST.in')
119 assert os.path.isfile(fpath)
119 assert os.path.isfile(fpath)
120
120
121 def test_repo_clone_without_update(self):
121 def test_repo_clone_without_update(self):
122 repo = GitRepository(TEST_GIT_REPO)
122 repo = GitRepository(TEST_GIT_REPO)
123 clone_path = TEST_GIT_REPO_CLONE + '_without_update'
123 clone_path = TEST_GIT_REPO_CLONE + '_without_update'
124 repo_clone = GitRepository(
124 repo_clone = GitRepository(
125 clone_path,
125 clone_path,
126 create=True, src_url=TEST_GIT_REPO, update_after_clone=False)
126 create=True, src_url=TEST_GIT_REPO, update_after_clone=False)
127 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
127 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
128 # check if current workdir was *NOT* updated
128 # check if current workdir was *NOT* updated
129 fpath = os.path.join(clone_path, 'MANIFEST.in')
129 fpath = os.path.join(clone_path, 'MANIFEST.in')
130 # Make sure it's not bare repo
130 # Make sure it's not bare repo
131 assert not repo_clone.bare
131 assert not repo_clone.bare
132 assert not os.path.isfile(fpath)
132 assert not os.path.isfile(fpath)
133
133
134 def test_repo_clone_into_bare_repo(self):
134 def test_repo_clone_into_bare_repo(self):
135 repo = GitRepository(TEST_GIT_REPO)
135 repo = GitRepository(TEST_GIT_REPO)
136 clone_path = TEST_GIT_REPO_CLONE + '_bare.git'
136 clone_path = TEST_GIT_REPO_CLONE + '_bare.git'
137 repo_clone = GitRepository(
137 repo_clone = GitRepository(
138 clone_path, create=True, src_url=repo.path, bare=True)
138 clone_path, create=True, src_url=repo.path, bare=True)
139 assert repo_clone.bare
139 assert repo_clone.bare
140
140
141 def test_create_repo_is_not_bare_by_default(self):
141 def test_create_repo_is_not_bare_by_default(self):
142 repo = GitRepository(get_new_dir('not-bare-by-default'), create=True)
142 repo = GitRepository(get_new_dir('not-bare-by-default'), create=True)
143 assert not repo.bare
143 assert not repo.bare
144
144
145 def test_create_bare_repo(self):
145 def test_create_bare_repo(self):
146 repo = GitRepository(get_new_dir('bare-repo'), create=True, bare=True)
146 repo = GitRepository(get_new_dir('bare-repo'), create=True, bare=True)
147 assert repo.bare
147 assert repo.bare
148
148
149 def test_update_server_info(self):
149 def test_update_server_info(self):
150 self.repo._update_server_info()
150 self.repo._update_server_info()
151
151
152 def test_fetch(self, vcsbackend_git):
152 def test_fetch(self, vcsbackend_git):
153 # Note: This is a git specific part of the API, it's only implemented
153 # Note: This is a git specific part of the API, it's only implemented
154 # by the git backend.
154 # by the git backend.
155 source_repo = vcsbackend_git.repo
155 source_repo = vcsbackend_git.repo
156 target_repo = vcsbackend_git.create_repo()
156 target_repo = vcsbackend_git.create_repo()
157 target_repo.fetch(source_repo.path)
157 target_repo.fetch(source_repo.path)
158 # Note: Get a fresh instance, avoids caching trouble
158 # Note: Get a fresh instance, avoids caching trouble
159 target_repo = vcsbackend_git.backend(target_repo.path)
159 target_repo = vcsbackend_git.backend(target_repo.path)
160 assert len(source_repo.commit_ids) == len(target_repo.commit_ids)
160 assert len(source_repo.commit_ids) == len(target_repo.commit_ids)
161
161
162 def test_commit_ids(self):
162 def test_commit_ids(self):
163 # there are 112 commits (by now)
163 # there are 112 commits (by now)
164 # so we can assume they would be available from now on
164 # so we can assume they would be available from now on
165 subset = set([
165 subset = set([
166 'c1214f7e79e02fc37156ff215cd71275450cffc3',
166 'c1214f7e79e02fc37156ff215cd71275450cffc3',
167 '38b5fe81f109cb111f549bfe9bb6b267e10bc557',
167 '38b5fe81f109cb111f549bfe9bb6b267e10bc557',
168 'fa6600f6848800641328adbf7811fd2372c02ab2',
168 'fa6600f6848800641328adbf7811fd2372c02ab2',
169 '102607b09cdd60e2793929c4f90478be29f85a17',
169 '102607b09cdd60e2793929c4f90478be29f85a17',
170 '49d3fd156b6f7db46313fac355dca1a0b94a0017',
170 '49d3fd156b6f7db46313fac355dca1a0b94a0017',
171 '2d1028c054665b962fa3d307adfc923ddd528038',
171 '2d1028c054665b962fa3d307adfc923ddd528038',
172 'd7e0d30fbcae12c90680eb095a4f5f02505ce501',
172 'd7e0d30fbcae12c90680eb095a4f5f02505ce501',
173 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
173 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
174 'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
174 'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
175 '8430a588b43b5d6da365400117c89400326e7992',
175 '8430a588b43b5d6da365400117c89400326e7992',
176 'd955cd312c17b02143c04fa1099a352b04368118',
176 'd955cd312c17b02143c04fa1099a352b04368118',
177 'f67b87e5c629c2ee0ba58f85197e423ff28d735b',
177 'f67b87e5c629c2ee0ba58f85197e423ff28d735b',
178 'add63e382e4aabc9e1afdc4bdc24506c269b7618',
178 'add63e382e4aabc9e1afdc4bdc24506c269b7618',
179 'f298fe1189f1b69779a4423f40b48edf92a703fc',
179 'f298fe1189f1b69779a4423f40b48edf92a703fc',
180 'bd9b619eb41994cac43d67cf4ccc8399c1125808',
180 'bd9b619eb41994cac43d67cf4ccc8399c1125808',
181 '6e125e7c890379446e98980d8ed60fba87d0f6d1',
181 '6e125e7c890379446e98980d8ed60fba87d0f6d1',
182 'd4a54db9f745dfeba6933bf5b1e79e15d0af20bd',
182 'd4a54db9f745dfeba6933bf5b1e79e15d0af20bd',
183 '0b05e4ed56c802098dfc813cbe779b2f49e92500',
183 '0b05e4ed56c802098dfc813cbe779b2f49e92500',
184 '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
184 '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
185 '45223f8f114c64bf4d6f853e3c35a369a6305520',
185 '45223f8f114c64bf4d6f853e3c35a369a6305520',
186 'ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
186 'ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
187 'f5ea29fc42ef67a2a5a7aecff10e1566699acd68',
187 'f5ea29fc42ef67a2a5a7aecff10e1566699acd68',
188 '27d48942240f5b91dfda77accd2caac94708cc7d',
188 '27d48942240f5b91dfda77accd2caac94708cc7d',
189 '622f0eb0bafd619d2560c26f80f09e3b0b0d78af',
189 '622f0eb0bafd619d2560c26f80f09e3b0b0d78af',
190 'e686b958768ee96af8029fe19c6050b1a8dd3b2b'])
190 'e686b958768ee96af8029fe19c6050b1a8dd3b2b'])
191 assert subset.issubset(set(self.repo.commit_ids))
191 assert subset.issubset(set(self.repo.commit_ids))
192
192
193 def test_slicing(self):
193 def test_slicing(self):
194 # 4 1 5 10 95
194 # 4 1 5 10 95
195 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
195 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
196 (10, 20, 10), (5, 100, 95)]:
196 (10, 20, 10), (5, 100, 95)]:
197 commit_ids = list(self.repo[sfrom:sto])
197 commit_ids = list(self.repo[sfrom:sto])
198 assert len(commit_ids) == size
198 assert len(commit_ids) == size
199 assert commit_ids[0] == self.repo.get_commit(commit_idx=sfrom)
199 assert commit_ids[0] == self.repo.get_commit(commit_idx=sfrom)
200 assert commit_ids[-1] == self.repo.get_commit(commit_idx=sto - 1)
200 assert commit_ids[-1] == self.repo.get_commit(commit_idx=sto - 1)
201
201
202 def test_branches(self):
202 def test_branches(self):
203 # TODO: Need more tests here
203 # TODO: Need more tests here
204 # Removed (those are 'remotes' branches for cloned repo)
204 # Removed (those are 'remotes' branches for cloned repo)
205 # assert 'master' in self.repo.branches
205 # assert 'master' in self.repo.branches
206 # assert 'gittree' in self.repo.branches
206 # assert 'gittree' in self.repo.branches
207 # assert 'web-branch' in self.repo.branches
207 # assert 'web-branch' in self.repo.branches
208 for __, commit_id in self.repo.branches.items():
208 for __, commit_id in self.repo.branches.items():
209 assert isinstance(self.repo.get_commit(commit_id), GitCommit)
209 assert isinstance(self.repo.get_commit(commit_id), GitCommit)
210
210
211 def test_tags(self):
211 def test_tags(self):
212 # TODO: Need more tests here
212 # TODO: Need more tests here
213 assert 'v0.1.1' in self.repo.tags
213 assert 'v0.1.1' in self.repo.tags
214 assert 'v0.1.2' in self.repo.tags
214 assert 'v0.1.2' in self.repo.tags
215 for __, commit_id in self.repo.tags.items():
215 for __, commit_id in self.repo.tags.items():
216 assert isinstance(self.repo.get_commit(commit_id), GitCommit)
216 assert isinstance(self.repo.get_commit(commit_id), GitCommit)
217
217
218 def _test_single_commit_cache(self, commit_id):
218 def _test_single_commit_cache(self, commit_id):
219 commit = self.repo.get_commit(commit_id)
219 commit = self.repo.get_commit(commit_id)
220 assert commit_id in self.repo.commits
220 assert commit_id in self.repo.commits
221 assert commit is self.repo.commits[commit_id]
221 assert commit is self.repo.commits[commit_id]
222
222
223 def test_initial_commit(self):
223 def test_initial_commit(self):
224 commit_id = self.repo.commit_ids[0]
224 commit_id = self.repo.commit_ids[0]
225 init_commit = self.repo.get_commit(commit_id)
225 init_commit = self.repo.get_commit(commit_id)
226 init_author = init_commit.author
226 init_author = init_commit.author
227
227
228 assert init_commit.message == 'initial import\n'
228 assert init_commit.message == 'initial import\n'
229 assert init_author == 'Marcin Kuzminski <marcin@python-blog.com>'
229 assert init_author == 'Marcin Kuzminski <marcin@python-blog.com>'
230 assert init_author == init_commit.committer
230 assert init_author == init_commit.committer
231 for path in ('vcs/__init__.py',
231 for path in ('vcs/__init__.py',
232 'vcs/backends/BaseRepository.py',
232 'vcs/backends/BaseRepository.py',
233 'vcs/backends/__init__.py'):
233 'vcs/backends/__init__.py'):
234 assert isinstance(init_commit.get_node(path), FileNode)
234 assert isinstance(init_commit.get_node(path), FileNode)
235 for path in ('', 'vcs', 'vcs/backends'):
235 for path in ('', 'vcs', 'vcs/backends'):
236 assert isinstance(init_commit.get_node(path), DirNode)
236 assert isinstance(init_commit.get_node(path), DirNode)
237
237
238 with pytest.raises(NodeDoesNotExistError):
238 with pytest.raises(NodeDoesNotExistError):
239 init_commit.get_node(path='foobar')
239 init_commit.get_node(path='foobar')
240
240
241 node = init_commit.get_node('vcs/')
241 node = init_commit.get_node('vcs/')
242 assert hasattr(node, 'kind')
242 assert hasattr(node, 'kind')
243 assert node.kind == NodeKind.DIR
243 assert node.kind == NodeKind.DIR
244
244
245 node = init_commit.get_node('vcs')
245 node = init_commit.get_node('vcs')
246 assert hasattr(node, 'kind')
246 assert hasattr(node, 'kind')
247 assert node.kind == NodeKind.DIR
247 assert node.kind == NodeKind.DIR
248
248
249 node = init_commit.get_node('vcs/__init__.py')
249 node = init_commit.get_node('vcs/__init__.py')
250 assert hasattr(node, 'kind')
250 assert hasattr(node, 'kind')
251 assert node.kind == NodeKind.FILE
251 assert node.kind == NodeKind.FILE
252
252
253 def test_not_existing_commit(self):
253 def test_not_existing_commit(self):
254 with pytest.raises(RepositoryError):
254 with pytest.raises(RepositoryError):
255 self.repo.get_commit('f' * 40)
255 self.repo.get_commit('f' * 40)
256
256
257 def test_commit10(self):
257 def test_commit10(self):
258
258
259 commit10 = self.repo.get_commit(self.repo.commit_ids[9])
259 commit10 = self.repo.get_commit(self.repo.commit_ids[9])
260 README = """===
260 README = """===
261 VCS
261 VCS
262 ===
262 ===
263
263
264 Various Version Control System management abstraction layer for Python.
264 Various Version Control System management abstraction layer for Python.
265
265
266 Introduction
266 Introduction
267 ------------
267 ------------
268
268
269 TODO: To be written...
269 TODO: To be written...
270
270
271 """
271 """
272 node = commit10.get_node('README.rst')
272 node = commit10.get_node('README.rst')
273 assert node.kind == NodeKind.FILE
273 assert node.kind == NodeKind.FILE
274 assert node.content == README
274 assert node.content == README
275
275
276 def test_head(self):
276 def test_head(self):
277 assert self.repo.head == self.repo.get_commit().raw_id
277 assert self.repo.head == self.repo.get_commit().raw_id
278
278
279 def test_checkout_with_create(self):
279 def test_checkout_with_create(self):
280 repo_clone = self.get_clone_repo()
280 repo_clone = self.get_clone_repo()
281
281
282 new_branch = 'new_branch'
282 new_branch = 'new_branch'
283 assert repo_clone._current_branch() == 'master'
283 assert repo_clone._current_branch() == 'master'
284 assert set(repo_clone.branches) == set(('master',))
284 assert set(repo_clone.branches) == set(('master',))
285 repo_clone._checkout(new_branch, create=True)
285 repo_clone._checkout(new_branch, create=True)
286
286
287 # Branches is a lazy property so we need to recrete the Repo object.
287 # Branches is a lazy property so we need to recrete the Repo object.
288 repo_clone = GitRepository(repo_clone.path)
288 repo_clone = GitRepository(repo_clone.path)
289 assert set(repo_clone.branches) == set(('master', new_branch))
289 assert set(repo_clone.branches) == set(('master', new_branch))
290 assert repo_clone._current_branch() == new_branch
290 assert repo_clone._current_branch() == new_branch
291
291
292 def test_checkout(self):
292 def test_checkout(self):
293 repo_clone = self.get_clone_repo()
293 repo_clone = self.get_clone_repo()
294
294
295 repo_clone._checkout('new_branch', create=True)
295 repo_clone._checkout('new_branch', create=True)
296 repo_clone._checkout('master')
296 repo_clone._checkout('master')
297
297
298 assert repo_clone._current_branch() == 'master'
298 assert repo_clone._current_branch() == 'master'
299
299
300 def test_checkout_same_branch(self):
300 def test_checkout_same_branch(self):
301 repo_clone = self.get_clone_repo()
301 repo_clone = self.get_clone_repo()
302
302
303 repo_clone._checkout('master')
303 repo_clone._checkout('master')
304 assert repo_clone._current_branch() == 'master'
304 assert repo_clone._current_branch() == 'master'
305
305
306 def test_checkout_branch_already_exists(self):
306 def test_checkout_branch_already_exists(self):
307 repo_clone = self.get_clone_repo()
307 repo_clone = self.get_clone_repo()
308
308
309 with pytest.raises(RepositoryError):
309 with pytest.raises(RepositoryError):
310 repo_clone._checkout('master', create=True)
310 repo_clone._checkout('master', create=True)
311
311
312 def test_checkout_bare_repo(self):
312 def test_checkout_bare_repo(self):
313 with pytest.raises(RepositoryError):
313 with pytest.raises(RepositoryError):
314 self.repo._checkout('master')
314 self.repo._checkout('master')
315
315
316 def test_current_branch_bare_repo(self):
316 def test_current_branch_bare_repo(self):
317 with pytest.raises(RepositoryError):
317 with pytest.raises(RepositoryError):
318 self.repo._current_branch()
318 self.repo._current_branch()
319
319
320 def test_current_branch_empty_repo(self):
320 def test_current_branch_empty_repo(self):
321 repo = self.get_empty_repo()
321 repo = self.get_empty_repo()
322 assert repo._current_branch() is None
322 assert repo._current_branch() is None
323
323
324 def test_local_clone(self):
324 def test_local_clone(self):
325 clone_path = next(REPO_PATH_GENERATOR)
325 clone_path = next(REPO_PATH_GENERATOR)
326 self.repo._local_clone(clone_path, 'master')
326 self.repo._local_clone(clone_path, 'master')
327 repo_clone = GitRepository(clone_path)
327 repo_clone = GitRepository(clone_path)
328
328
329 assert self.repo.commit_ids == repo_clone.commit_ids
329 assert self.repo.commit_ids == repo_clone.commit_ids
330
330
331 def test_local_clone_with_specific_branch(self):
331 def test_local_clone_with_specific_branch(self):
332 source_repo = self.get_clone_repo()
332 source_repo = self.get_clone_repo()
333
333
334 # Create a new branch in source repo
334 # Create a new branch in source repo
335 new_branch_commit = source_repo.commit_ids[-3]
335 new_branch_commit = source_repo.commit_ids[-3]
336 source_repo._checkout(new_branch_commit)
336 source_repo._checkout(new_branch_commit)
337 source_repo._checkout('new_branch', create=True)
337 source_repo._checkout('new_branch', create=True)
338
338
339 clone_path = next(REPO_PATH_GENERATOR)
339 clone_path = next(REPO_PATH_GENERATOR)
340 source_repo._local_clone(clone_path, 'new_branch')
340 source_repo._local_clone(clone_path, 'new_branch')
341 repo_clone = GitRepository(clone_path)
341 repo_clone = GitRepository(clone_path)
342
342
343 assert source_repo.commit_ids[:-3 + 1] == repo_clone.commit_ids
343 assert source_repo.commit_ids[:-3 + 1] == repo_clone.commit_ids
344
344
345 clone_path = next(REPO_PATH_GENERATOR)
345 clone_path = next(REPO_PATH_GENERATOR)
346 source_repo._local_clone(clone_path, 'master')
346 source_repo._local_clone(clone_path, 'master')
347 repo_clone = GitRepository(clone_path)
347 repo_clone = GitRepository(clone_path)
348
348
349 assert source_repo.commit_ids == repo_clone.commit_ids
349 assert source_repo.commit_ids == repo_clone.commit_ids
350
350
351 def test_local_clone_fails_if_target_exists(self):
351 def test_local_clone_fails_if_target_exists(self):
352 with pytest.raises(RepositoryError):
352 with pytest.raises(RepositoryError):
353 self.repo._local_clone(self.repo.path, 'master')
353 self.repo._local_clone(self.repo.path, 'master')
354
354
355 def test_local_fetch(self):
355 def test_local_fetch(self):
356 target_repo = self.get_empty_repo()
356 target_repo = self.get_empty_repo()
357 source_repo = self.get_clone_repo()
357 source_repo = self.get_clone_repo()
358
358
359 # Create a new branch in source repo
359 # Create a new branch in source repo
360 master_commit = source_repo.commit_ids[-1]
360 master_commit = source_repo.commit_ids[-1]
361 new_branch_commit = source_repo.commit_ids[-3]
361 new_branch_commit = source_repo.commit_ids[-3]
362 source_repo._checkout(new_branch_commit)
362 source_repo._checkout(new_branch_commit)
363 source_repo._checkout('new_branch', create=True)
363 source_repo._checkout('new_branch', create=True)
364
364
365 target_repo._local_fetch(source_repo.path, 'new_branch')
365 target_repo._local_fetch(source_repo.path, 'new_branch')
366 assert target_repo._last_fetch_heads() == [new_branch_commit]
366 assert target_repo._last_fetch_heads() == [new_branch_commit]
367
367
368 target_repo._local_fetch(source_repo.path, 'master')
368 target_repo._local_fetch(source_repo.path, 'master')
369 assert target_repo._last_fetch_heads() == [master_commit]
369 assert target_repo._last_fetch_heads() == [master_commit]
370
370
371 def test_local_fetch_from_bare_repo(self):
371 def test_local_fetch_from_bare_repo(self):
372 target_repo = self.get_empty_repo()
372 target_repo = self.get_empty_repo()
373 target_repo._local_fetch(self.repo.path, 'master')
373 target_repo._local_fetch(self.repo.path, 'master')
374
374
375 master_commit = self.repo.commit_ids[-1]
375 master_commit = self.repo.commit_ids[-1]
376 assert target_repo._last_fetch_heads() == [master_commit]
376 assert target_repo._last_fetch_heads() == [master_commit]
377
377
378 def test_local_fetch_from_same_repo(self):
378 def test_local_fetch_from_same_repo(self):
379 with pytest.raises(ValueError):
379 with pytest.raises(ValueError):
380 self.repo._local_fetch(self.repo.path, 'master')
380 self.repo._local_fetch(self.repo.path, 'master')
381
381
382 def test_local_fetch_branch_does_not_exist(self):
382 def test_local_fetch_branch_does_not_exist(self):
383 target_repo = self.get_empty_repo()
383 target_repo = self.get_empty_repo()
384
384
385 with pytest.raises(RepositoryError):
385 with pytest.raises(RepositoryError):
386 target_repo._local_fetch(self.repo.path, 'new_branch')
386 target_repo._local_fetch(self.repo.path, 'new_branch')
387
387
388 def test_local_pull(self):
388 def test_local_pull(self):
389 target_repo = self.get_empty_repo()
389 target_repo = self.get_empty_repo()
390 source_repo = self.get_clone_repo()
390 source_repo = self.get_clone_repo()
391
391
392 # Create a new branch in source repo
392 # Create a new branch in source repo
393 master_commit = source_repo.commit_ids[-1]
393 master_commit = source_repo.commit_ids[-1]
394 new_branch_commit = source_repo.commit_ids[-3]
394 new_branch_commit = source_repo.commit_ids[-3]
395 source_repo._checkout(new_branch_commit)
395 source_repo._checkout(new_branch_commit)
396 source_repo._checkout('new_branch', create=True)
396 source_repo._checkout('new_branch', create=True)
397
397
398 target_repo._local_pull(source_repo.path, 'new_branch')
398 target_repo._local_pull(source_repo.path, 'new_branch')
399 target_repo = GitRepository(target_repo.path)
399 target_repo = GitRepository(target_repo.path)
400 assert target_repo.head == new_branch_commit
400 assert target_repo.head == new_branch_commit
401
401
402 target_repo._local_pull(source_repo.path, 'master')
402 target_repo._local_pull(source_repo.path, 'master')
403 target_repo = GitRepository(target_repo.path)
403 target_repo = GitRepository(target_repo.path)
404 assert target_repo.head == master_commit
404 assert target_repo.head == master_commit
405
405
406 def test_local_pull_in_bare_repo(self):
406 def test_local_pull_in_bare_repo(self):
407 with pytest.raises(RepositoryError):
407 with pytest.raises(RepositoryError):
408 self.repo._local_pull(self.repo.path, 'master')
408 self.repo._local_pull(self.repo.path, 'master')
409
409
410 def test_local_merge(self):
410 def test_local_merge(self):
411 target_repo = self.get_empty_repo()
411 target_repo = self.get_empty_repo()
412 source_repo = self.get_clone_repo()
412 source_repo = self.get_clone_repo()
413
413
414 # Create a new branch in source repo
414 # Create a new branch in source repo
415 master_commit = source_repo.commit_ids[-1]
415 master_commit = source_repo.commit_ids[-1]
416 new_branch_commit = source_repo.commit_ids[-3]
416 new_branch_commit = source_repo.commit_ids[-3]
417 source_repo._checkout(new_branch_commit)
417 source_repo._checkout(new_branch_commit)
418 source_repo._checkout('new_branch', create=True)
418 source_repo._checkout('new_branch', create=True)
419
419
420 # This is required as one cannot do a -ff-only merge in an empty repo.
420 # This is required as one cannot do a -ff-only merge in an empty repo.
421 target_repo._local_pull(source_repo.path, 'new_branch')
421 target_repo._local_pull(source_repo.path, 'new_branch')
422
422
423 target_repo._local_fetch(source_repo.path, 'master')
423 target_repo._local_fetch(source_repo.path, 'master')
424 merge_message = 'Merge message\n\nDescription:...'
424 merge_message = 'Merge message\n\nDescription:...'
425 user_name = 'Albert Einstein'
425 user_name = 'Albert Einstein'
426 user_email = 'albert@einstein.com'
426 user_email = 'albert@einstein.com'
427 target_repo._local_merge(merge_message, user_name, user_email,
427 target_repo._local_merge(merge_message, user_name, user_email,
428 target_repo._last_fetch_heads())
428 target_repo._last_fetch_heads())
429
429
430 target_repo = GitRepository(target_repo.path)
430 target_repo = GitRepository(target_repo.path)
431 assert target_repo.commit_ids[-2] == master_commit
431 assert target_repo.commit_ids[-2] == master_commit
432 last_commit = target_repo.get_commit(target_repo.head)
432 last_commit = target_repo.get_commit(target_repo.head)
433 assert last_commit.message.strip() == merge_message
433 assert last_commit.message.strip() == merge_message
434 assert last_commit.author == '%s <%s>' % (user_name, user_email)
434 assert last_commit.author == '%s <%s>' % (user_name, user_email)
435
435
436 assert not os.path.exists(
436 assert not os.path.exists(
437 os.path.join(target_repo.path, '.git', 'MERGE_HEAD'))
437 os.path.join(target_repo.path, '.git', 'MERGE_HEAD'))
438
438
439 def test_local_merge_raises_exception_on_conflict(self, vcsbackend_git):
439 def test_local_merge_raises_exception_on_conflict(self, vcsbackend_git):
440 target_repo = vcsbackend_git.create_repo(number_of_commits=1)
440 target_repo = vcsbackend_git.create_repo(number_of_commits=1)
441 vcsbackend_git.ensure_file('README', 'I will conflict with you!!!')
441 vcsbackend_git.ensure_file('README', 'I will conflict with you!!!')
442
442
443 target_repo._local_fetch(self.repo.path, 'master')
443 target_repo._local_fetch(self.repo.path, 'master')
444 with pytest.raises(RepositoryError):
444 with pytest.raises(RepositoryError):
445 target_repo._local_merge(
445 target_repo._local_merge(
446 'merge_message', 'user name', 'user@name.com',
446 'merge_message', 'user name', 'user@name.com',
447 target_repo._last_fetch_heads())
447 target_repo._last_fetch_heads())
448
448
449 # Check we are not left in an intermediate merge state
449 # Check we are not left in an intermediate merge state
450 assert not os.path.exists(
450 assert not os.path.exists(
451 os.path.join(target_repo.path, '.git', 'MERGE_HEAD'))
451 os.path.join(target_repo.path, '.git', 'MERGE_HEAD'))
452
452
453 def test_local_merge_into_empty_repo(self):
453 def test_local_merge_into_empty_repo(self):
454 target_repo = self.get_empty_repo()
454 target_repo = self.get_empty_repo()
455
455
456 # This is required as one cannot do a -ff-only merge in an empty repo.
456 # This is required as one cannot do a -ff-only merge in an empty repo.
457 target_repo._local_fetch(self.repo.path, 'master')
457 target_repo._local_fetch(self.repo.path, 'master')
458 with pytest.raises(RepositoryError):
458 with pytest.raises(RepositoryError):
459 target_repo._local_merge(
459 target_repo._local_merge(
460 'merge_message', 'user name', 'user@name.com',
460 'merge_message', 'user name', 'user@name.com',
461 target_repo._last_fetch_heads())
461 target_repo._last_fetch_heads())
462
462
463 def test_local_merge_in_bare_repo(self):
463 def test_local_merge_in_bare_repo(self):
464 with pytest.raises(RepositoryError):
464 with pytest.raises(RepositoryError):
465 self.repo._local_merge(
465 self.repo._local_merge(
466 'merge_message', 'user name', 'user@name.com', None)
466 'merge_message', 'user name', 'user@name.com', None)
467
467
468 def test_local_push_non_bare(self):
468 def test_local_push_non_bare(self):
469 target_repo = self.get_empty_repo()
469 target_repo = self.get_empty_repo()
470
470
471 pushed_branch = 'pushed_branch'
471 pushed_branch = 'pushed_branch'
472 self.repo._local_push('master', target_repo.path, pushed_branch)
472 self.repo._local_push('master', target_repo.path, pushed_branch)
473 # Fix the HEAD of the target repo, or otherwise GitRepository won't
473 # Fix the HEAD of the target repo, or otherwise GitRepository won't
474 # report any branches.
474 # report any branches.
475 with open(os.path.join(target_repo.path, '.git', 'HEAD'), 'w') as f:
475 with open(os.path.join(target_repo.path, '.git', 'HEAD'), 'w') as f:
476 f.write('ref: refs/heads/%s' % pushed_branch)
476 f.write('ref: refs/heads/%s' % pushed_branch)
477
477
478 target_repo = GitRepository(target_repo.path)
478 target_repo = GitRepository(target_repo.path)
479
479
480 assert (target_repo.branches[pushed_branch] ==
480 assert (target_repo.branches[pushed_branch] ==
481 self.repo.branches['master'])
481 self.repo.branches['master'])
482
482
483 def test_local_push_bare(self):
483 def test_local_push_bare(self):
484 target_repo = self.get_empty_repo(bare=True)
484 target_repo = self.get_empty_repo(bare=True)
485
485
486 pushed_branch = 'pushed_branch'
486 pushed_branch = 'pushed_branch'
487 self.repo._local_push('master', target_repo.path, pushed_branch)
487 self.repo._local_push('master', target_repo.path, pushed_branch)
488 # Fix the HEAD of the target repo, or otherwise GitRepository won't
488 # Fix the HEAD of the target repo, or otherwise GitRepository won't
489 # report any branches.
489 # report any branches.
490 with open(os.path.join(target_repo.path, 'HEAD'), 'w') as f:
490 with open(os.path.join(target_repo.path, 'HEAD'), 'w') as f:
491 f.write('ref: refs/heads/%s' % pushed_branch)
491 f.write('ref: refs/heads/%s' % pushed_branch)
492
492
493 target_repo = GitRepository(target_repo.path)
493 target_repo = GitRepository(target_repo.path)
494
494
495 assert (target_repo.branches[pushed_branch] ==
495 assert (target_repo.branches[pushed_branch] ==
496 self.repo.branches['master'])
496 self.repo.branches['master'])
497
497
498 def test_local_push_non_bare_target_branch_is_checked_out(self):
498 def test_local_push_non_bare_target_branch_is_checked_out(self):
499 target_repo = self.get_clone_repo()
499 target_repo = self.get_clone_repo()
500
500
501 pushed_branch = 'pushed_branch'
501 pushed_branch = 'pushed_branch'
502 # Create a new branch in source repo
502 # Create a new branch in source repo
503 new_branch_commit = target_repo.commit_ids[-3]
503 new_branch_commit = target_repo.commit_ids[-3]
504 target_repo._checkout(new_branch_commit)
504 target_repo._checkout(new_branch_commit)
505 target_repo._checkout(pushed_branch, create=True)
505 target_repo._checkout(pushed_branch, create=True)
506
506
507 self.repo._local_push('master', target_repo.path, pushed_branch)
507 self.repo._local_push('master', target_repo.path, pushed_branch)
508
508
509 target_repo = GitRepository(target_repo.path)
509 target_repo = GitRepository(target_repo.path)
510
510
511 assert (target_repo.branches[pushed_branch] ==
511 assert (target_repo.branches[pushed_branch] ==
512 self.repo.branches['master'])
512 self.repo.branches['master'])
513
513
514 def test_local_push_raises_exception_on_conflict(self, vcsbackend_git):
514 def test_local_push_raises_exception_on_conflict(self, vcsbackend_git):
515 target_repo = vcsbackend_git.create_repo(number_of_commits=1)
515 target_repo = vcsbackend_git.create_repo(number_of_commits=1)
516 with pytest.raises(RepositoryError):
516 with pytest.raises(RepositoryError):
517 self.repo._local_push('master', target_repo.path, 'master')
517 self.repo._local_push('master', target_repo.path, 'master')
518
518
519 def test_hooks_can_be_enabled_via_env_variable_for_local_push(self):
519 def test_hooks_can_be_enabled_via_env_variable_for_local_push(self):
520 target_repo = self.get_empty_repo(bare=True)
520 target_repo = self.get_empty_repo(bare=True)
521
521
522 with mock.patch.object(self.repo, 'run_git_command') as run_mock:
522 with mock.patch.object(self.repo, 'run_git_command') as run_mock:
523 self.repo._local_push(
523 self.repo._local_push(
524 'master', target_repo.path, 'master', enable_hooks=True)
524 'master', target_repo.path, 'master', enable_hooks=True)
525 env = run_mock.call_args[1]['extra_env']
525 env = run_mock.call_args[1]['extra_env']
526 assert 'RC_SKIP_HOOKS' not in env
526 assert 'RC_SKIP_HOOKS' not in env
527
527
528 def _add_failing_hook(self, repo_path, hook_name, bare=False):
528 def _add_failing_hook(self, repo_path, hook_name, bare=False):
529 path_components = (
529 path_components = (
530 ['hooks', hook_name] if bare else ['.git', 'hooks', hook_name])
530 ['hooks', hook_name] if bare else ['.git', 'hooks', hook_name])
531 hook_path = os.path.join(repo_path, *path_components)
531 hook_path = os.path.join(repo_path, *path_components)
532 with open(hook_path, 'w') as f:
532 with open(hook_path, 'w') as f:
533 script_lines = [
533 script_lines = [
534 '#!%s' % sys.executable,
534 '#!%s' % sys.executable,
535 'import os',
535 'import os',
536 'import sys',
536 'import sys',
537 'if os.environ.get("RC_SKIP_HOOKS"):',
537 'if os.environ.get("RC_SKIP_HOOKS"):',
538 ' sys.exit(0)',
538 ' sys.exit(0)',
539 'sys.exit(1)',
539 'sys.exit(1)',
540 ]
540 ]
541 f.write('\n'.join(script_lines))
541 f.write('\n'.join(script_lines))
542 os.chmod(hook_path, 0755)
542 os.chmod(hook_path, 0755)
543
543
544 def test_local_push_does_not_execute_hook(self):
544 def test_local_push_does_not_execute_hook(self):
545 target_repo = self.get_empty_repo()
545 target_repo = self.get_empty_repo()
546
546
547 pushed_branch = 'pushed_branch'
547 pushed_branch = 'pushed_branch'
548 self._add_failing_hook(target_repo.path, 'pre-receive')
548 self._add_failing_hook(target_repo.path, 'pre-receive')
549 self.repo._local_push('master', target_repo.path, pushed_branch)
549 self.repo._local_push('master', target_repo.path, pushed_branch)
550 # Fix the HEAD of the target repo, or otherwise GitRepository won't
550 # Fix the HEAD of the target repo, or otherwise GitRepository won't
551 # report any branches.
551 # report any branches.
552 with open(os.path.join(target_repo.path, '.git', 'HEAD'), 'w') as f:
552 with open(os.path.join(target_repo.path, '.git', 'HEAD'), 'w') as f:
553 f.write('ref: refs/heads/%s' % pushed_branch)
553 f.write('ref: refs/heads/%s' % pushed_branch)
554
554
555 target_repo = GitRepository(target_repo.path)
555 target_repo = GitRepository(target_repo.path)
556
556
557 assert (target_repo.branches[pushed_branch] ==
557 assert (target_repo.branches[pushed_branch] ==
558 self.repo.branches['master'])
558 self.repo.branches['master'])
559
559
560 def test_local_push_executes_hook(self):
560 def test_local_push_executes_hook(self):
561 target_repo = self.get_empty_repo(bare=True)
561 target_repo = self.get_empty_repo(bare=True)
562 self._add_failing_hook(target_repo.path, 'pre-receive', bare=True)
562 self._add_failing_hook(target_repo.path, 'pre-receive', bare=True)
563 with pytest.raises(RepositoryError):
563 with pytest.raises(RepositoryError):
564 self.repo._local_push(
564 self.repo._local_push(
565 'master', target_repo.path, 'master', enable_hooks=True)
565 'master', target_repo.path, 'master', enable_hooks=True)
566
566
567 def test_maybe_prepare_merge_workspace(self):
567 def test_maybe_prepare_merge_workspace(self):
568 workspace = self.repo._maybe_prepare_merge_workspace(
568 workspace = self.repo._maybe_prepare_merge_workspace(
569 'pr2', Reference('branch', 'master', 'unused'))
569 'pr2', Reference('branch', 'master', 'unused'),
570 Reference('branch', 'master', 'unused'))
570
571
571 assert os.path.isdir(workspace)
572 assert os.path.isdir(workspace)
572 workspace_repo = GitRepository(workspace)
573 workspace_repo = GitRepository(workspace)
573 assert workspace_repo.branches == self.repo.branches
574 assert workspace_repo.branches == self.repo.branches
574
575
575 # Calling it a second time should also succeed
576 # Calling it a second time should also succeed
576 workspace = self.repo._maybe_prepare_merge_workspace(
577 workspace = self.repo._maybe_prepare_merge_workspace(
577 'pr2', Reference('branch', 'master', 'unused'))
578 'pr2', Reference('branch', 'master', 'unused'),
579 Reference('branch', 'master', 'unused'))
580 assert os.path.isdir(workspace)
581
582 def test_maybe_prepare_merge_workspace_different_refs(self):
583 workspace = self.repo._maybe_prepare_merge_workspace(
584 'pr2', Reference('branch', 'master', 'unused'),
585 Reference('branch', 'develop', 'unused'))
586
587 assert os.path.isdir(workspace)
588 workspace_repo = GitRepository(workspace)
589 assert workspace_repo.branches == self.repo.branches
590
591 # Calling it a second time should also succeed
592 workspace = self.repo._maybe_prepare_merge_workspace(
593 'pr2', Reference('branch', 'master', 'unused'),
594 Reference('branch', 'develop', 'unused'))
578 assert os.path.isdir(workspace)
595 assert os.path.isdir(workspace)
579
596
580 def test_cleanup_merge_workspace(self):
597 def test_cleanup_merge_workspace(self):
581 workspace = self.repo._maybe_prepare_merge_workspace(
598 workspace = self.repo._maybe_prepare_merge_workspace(
582 'pr3', Reference('branch', 'master', 'unused'))
599 'pr3', Reference('branch', 'master', 'unused'),
600 Reference('branch', 'master', 'unused'))
583 self.repo.cleanup_merge_workspace('pr3')
601 self.repo.cleanup_merge_workspace('pr3')
584
602
585 assert not os.path.exists(workspace)
603 assert not os.path.exists(workspace)
586
604
587 def test_cleanup_merge_workspace_invalid_workspace_id(self):
605 def test_cleanup_merge_workspace_invalid_workspace_id(self):
588 # No assert: because in case of an inexistent workspace this function
606 # No assert: because in case of an inexistent workspace this function
589 # should still succeed.
607 # should still succeed.
590 self.repo.cleanup_merge_workspace('pr4')
608 self.repo.cleanup_merge_workspace('pr4')
591
609
592 def test_set_refs(self):
610 def test_set_refs(self):
593 test_ref = 'refs/test-refs/abcde'
611 test_ref = 'refs/test-refs/abcde'
594 test_commit_id = 'ecb86e1f424f2608262b130db174a7dfd25a6623'
612 test_commit_id = 'ecb86e1f424f2608262b130db174a7dfd25a6623'
595
613
596 self.repo.set_refs(test_ref, test_commit_id)
614 self.repo.set_refs(test_ref, test_commit_id)
597 stdout, _ = self.repo.run_git_command(['show-ref'])
615 stdout, _ = self.repo.run_git_command(['show-ref'])
598 assert test_ref in stdout
616 assert test_ref in stdout
599 assert test_commit_id in stdout
617 assert test_commit_id in stdout
600
618
601 def test_remove_ref(self):
619 def test_remove_ref(self):
602 test_ref = 'refs/test-refs/abcde'
620 test_ref = 'refs/test-refs/abcde'
603 test_commit_id = 'ecb86e1f424f2608262b130db174a7dfd25a6623'
621 test_commit_id = 'ecb86e1f424f2608262b130db174a7dfd25a6623'
604 self.repo.set_refs(test_ref, test_commit_id)
622 self.repo.set_refs(test_ref, test_commit_id)
605 stdout, _ = self.repo.run_git_command(['show-ref'])
623 stdout, _ = self.repo.run_git_command(['show-ref'])
606 assert test_ref in stdout
624 assert test_ref in stdout
607 assert test_commit_id in stdout
625 assert test_commit_id in stdout
608
626
609 self.repo.remove_ref(test_ref)
627 self.repo.remove_ref(test_ref)
610 stdout, _ = self.repo.run_git_command(['show-ref'])
628 stdout, _ = self.repo.run_git_command(['show-ref'])
611 assert test_ref not in stdout
629 assert test_ref not in stdout
612 assert test_commit_id not in stdout
630 assert test_commit_id not in stdout
613
631
614
632
615 class TestGitCommit(object):
633 class TestGitCommit(object):
616
634
617 @pytest.fixture(autouse=True)
635 @pytest.fixture(autouse=True)
618 def prepare(self):
636 def prepare(self):
619 self.repo = GitRepository(TEST_GIT_REPO)
637 self.repo = GitRepository(TEST_GIT_REPO)
620
638
621 def test_default_commit(self):
639 def test_default_commit(self):
622 tip = self.repo.get_commit()
640 tip = self.repo.get_commit()
623 assert tip == self.repo.get_commit(None)
641 assert tip == self.repo.get_commit(None)
624 assert tip == self.repo.get_commit('tip')
642 assert tip == self.repo.get_commit('tip')
625
643
626 def test_root_node(self):
644 def test_root_node(self):
627 tip = self.repo.get_commit()
645 tip = self.repo.get_commit()
628 assert tip.root is tip.get_node('')
646 assert tip.root is tip.get_node('')
629
647
630 def test_lazy_fetch(self):
648 def test_lazy_fetch(self):
631 """
649 """
632 Test if commit's nodes expands and are cached as we walk through
650 Test if commit's nodes expands and are cached as we walk through
633 the commit. This test is somewhat hard to write as order of tests
651 the commit. This test is somewhat hard to write as order of tests
634 is a key here. Written by running command after command in a shell.
652 is a key here. Written by running command after command in a shell.
635 """
653 """
636 commit_id = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
654 commit_id = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
637 assert commit_id in self.repo.commit_ids
655 assert commit_id in self.repo.commit_ids
638 commit = self.repo.get_commit(commit_id)
656 commit = self.repo.get_commit(commit_id)
639 assert len(commit.nodes) == 0
657 assert len(commit.nodes) == 0
640 root = commit.root
658 root = commit.root
641 assert len(commit.nodes) == 1
659 assert len(commit.nodes) == 1
642 assert len(root.nodes) == 8
660 assert len(root.nodes) == 8
643 # accessing root.nodes updates commit.nodes
661 # accessing root.nodes updates commit.nodes
644 assert len(commit.nodes) == 9
662 assert len(commit.nodes) == 9
645
663
646 docs = root.get_node('docs')
664 docs = root.get_node('docs')
647 # we haven't yet accessed anything new as docs dir was already cached
665 # we haven't yet accessed anything new as docs dir was already cached
648 assert len(commit.nodes) == 9
666 assert len(commit.nodes) == 9
649 assert len(docs.nodes) == 8
667 assert len(docs.nodes) == 8
650 # accessing docs.nodes updates commit.nodes
668 # accessing docs.nodes updates commit.nodes
651 assert len(commit.nodes) == 17
669 assert len(commit.nodes) == 17
652
670
653 assert docs is commit.get_node('docs')
671 assert docs is commit.get_node('docs')
654 assert docs is root.nodes[0]
672 assert docs is root.nodes[0]
655 assert docs is root.dirs[0]
673 assert docs is root.dirs[0]
656 assert docs is commit.get_node('docs')
674 assert docs is commit.get_node('docs')
657
675
658 def test_nodes_with_commit(self):
676 def test_nodes_with_commit(self):
659 commit_id = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
677 commit_id = '2a13f185e4525f9d4b59882791a2d397b90d5ddc'
660 commit = self.repo.get_commit(commit_id)
678 commit = self.repo.get_commit(commit_id)
661 root = commit.root
679 root = commit.root
662 docs = root.get_node('docs')
680 docs = root.get_node('docs')
663 assert docs is commit.get_node('docs')
681 assert docs is commit.get_node('docs')
664 api = docs.get_node('api')
682 api = docs.get_node('api')
665 assert api is commit.get_node('docs/api')
683 assert api is commit.get_node('docs/api')
666 index = api.get_node('index.rst')
684 index = api.get_node('index.rst')
667 assert index is commit.get_node('docs/api/index.rst')
685 assert index is commit.get_node('docs/api/index.rst')
668 assert index is commit.get_node('docs')\
686 assert index is commit.get_node('docs')\
669 .get_node('api')\
687 .get_node('api')\
670 .get_node('index.rst')
688 .get_node('index.rst')
671
689
672 def test_branch_and_tags(self):
690 def test_branch_and_tags(self):
673 """
691 """
674 rev0 = self.repo.commit_ids[0]
692 rev0 = self.repo.commit_ids[0]
675 commit0 = self.repo.get_commit(rev0)
693 commit0 = self.repo.get_commit(rev0)
676 assert commit0.branch == 'master'
694 assert commit0.branch == 'master'
677 assert commit0.tags == []
695 assert commit0.tags == []
678
696
679 rev10 = self.repo.commit_ids[10]
697 rev10 = self.repo.commit_ids[10]
680 commit10 = self.repo.get_commit(rev10)
698 commit10 = self.repo.get_commit(rev10)
681 assert commit10.branch == 'master'
699 assert commit10.branch == 'master'
682 assert commit10.tags == []
700 assert commit10.tags == []
683
701
684 rev44 = self.repo.commit_ids[44]
702 rev44 = self.repo.commit_ids[44]
685 commit44 = self.repo.get_commit(rev44)
703 commit44 = self.repo.get_commit(rev44)
686 assert commit44.branch == 'web-branch'
704 assert commit44.branch == 'web-branch'
687
705
688 tip = self.repo.get_commit('tip')
706 tip = self.repo.get_commit('tip')
689 assert 'tip' in tip.tags
707 assert 'tip' in tip.tags
690 """
708 """
691 # Those tests would fail - branches are now going
709 # Those tests would fail - branches are now going
692 # to be changed at main API in order to support git backend
710 # to be changed at main API in order to support git backend
693 pass
711 pass
694
712
695 def test_file_size(self):
713 def test_file_size(self):
696 to_check = (
714 to_check = (
697 ('c1214f7e79e02fc37156ff215cd71275450cffc3',
715 ('c1214f7e79e02fc37156ff215cd71275450cffc3',
698 'vcs/backends/BaseRepository.py', 502),
716 'vcs/backends/BaseRepository.py', 502),
699 ('d7e0d30fbcae12c90680eb095a4f5f02505ce501',
717 ('d7e0d30fbcae12c90680eb095a4f5f02505ce501',
700 'vcs/backends/hg.py', 854),
718 'vcs/backends/hg.py', 854),
701 ('6e125e7c890379446e98980d8ed60fba87d0f6d1',
719 ('6e125e7c890379446e98980d8ed60fba87d0f6d1',
702 'setup.py', 1068),
720 'setup.py', 1068),
703
721
704 ('d955cd312c17b02143c04fa1099a352b04368118',
722 ('d955cd312c17b02143c04fa1099a352b04368118',
705 'vcs/backends/base.py', 2921),
723 'vcs/backends/base.py', 2921),
706 ('ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
724 ('ca1eb7957a54bce53b12d1a51b13452f95bc7c7e',
707 'vcs/backends/base.py', 3936),
725 'vcs/backends/base.py', 3936),
708 ('f50f42baeed5af6518ef4b0cb2f1423f3851a941',
726 ('f50f42baeed5af6518ef4b0cb2f1423f3851a941',
709 'vcs/backends/base.py', 6189),
727 'vcs/backends/base.py', 6189),
710 )
728 )
711 for commit_id, path, size in to_check:
729 for commit_id, path, size in to_check:
712 node = self.repo.get_commit(commit_id).get_node(path)
730 node = self.repo.get_commit(commit_id).get_node(path)
713 assert node.is_file()
731 assert node.is_file()
714 assert node.size == size
732 assert node.size == size
715
733
716 def test_file_history_from_commits(self):
734 def test_file_history_from_commits(self):
717 node = self.repo[10].get_node('setup.py')
735 node = self.repo[10].get_node('setup.py')
718 commit_ids = [commit.raw_id for commit in node.history]
736 commit_ids = [commit.raw_id for commit in node.history]
719 assert ['ff7ca51e58c505fec0dd2491de52c622bb7a806b'] == commit_ids
737 assert ['ff7ca51e58c505fec0dd2491de52c622bb7a806b'] == commit_ids
720
738
721 node = self.repo[20].get_node('setup.py')
739 node = self.repo[20].get_node('setup.py')
722 node_ids = [commit.raw_id for commit in node.history]
740 node_ids = [commit.raw_id for commit in node.history]
723 assert ['191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
741 assert ['191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
724 'ff7ca51e58c505fec0dd2491de52c622bb7a806b'] == node_ids
742 'ff7ca51e58c505fec0dd2491de52c622bb7a806b'] == node_ids
725
743
726 # special case we check history from commit that has this particular
744 # special case we check history from commit that has this particular
727 # file changed this means we check if it's included as well
745 # file changed this means we check if it's included as well
728 node = self.repo.get_commit('191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e') \
746 node = self.repo.get_commit('191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e') \
729 .get_node('setup.py')
747 .get_node('setup.py')
730 node_ids = [commit.raw_id for commit in node.history]
748 node_ids = [commit.raw_id for commit in node.history]
731 assert ['191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
749 assert ['191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
732 'ff7ca51e58c505fec0dd2491de52c622bb7a806b'] == node_ids
750 'ff7ca51e58c505fec0dd2491de52c622bb7a806b'] == node_ids
733
751
734 def test_file_history(self):
752 def test_file_history(self):
735 # we can only check if those commits are present in the history
753 # we can only check if those commits are present in the history
736 # as we cannot update this test every time file is changed
754 # as we cannot update this test every time file is changed
737 files = {
755 files = {
738 'setup.py': [
756 'setup.py': [
739 '54386793436c938cff89326944d4c2702340037d',
757 '54386793436c938cff89326944d4c2702340037d',
740 '51d254f0ecf5df2ce50c0b115741f4cf13985dab',
758 '51d254f0ecf5df2ce50c0b115741f4cf13985dab',
741 '998ed409c795fec2012b1c0ca054d99888b22090',
759 '998ed409c795fec2012b1c0ca054d99888b22090',
742 '5e0eb4c47f56564395f76333f319d26c79e2fb09',
760 '5e0eb4c47f56564395f76333f319d26c79e2fb09',
743 '0115510b70c7229dbc5dc49036b32e7d91d23acd',
761 '0115510b70c7229dbc5dc49036b32e7d91d23acd',
744 '7cb3fd1b6d8c20ba89e2264f1c8baebc8a52d36e',
762 '7cb3fd1b6d8c20ba89e2264f1c8baebc8a52d36e',
745 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
763 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
746 '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
764 '191caa5b2c81ed17c0794bf7bb9958f4dcb0b87e',
747 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
765 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
748 ],
766 ],
749 'vcs/nodes.py': [
767 'vcs/nodes.py': [
750 '33fa3223355104431402a888fa77a4e9956feb3e',
768 '33fa3223355104431402a888fa77a4e9956feb3e',
751 'fa014c12c26d10ba682fadb78f2a11c24c8118e1',
769 'fa014c12c26d10ba682fadb78f2a11c24c8118e1',
752 'e686b958768ee96af8029fe19c6050b1a8dd3b2b',
770 'e686b958768ee96af8029fe19c6050b1a8dd3b2b',
753 'ab5721ca0a081f26bf43d9051e615af2cc99952f',
771 'ab5721ca0a081f26bf43d9051e615af2cc99952f',
754 'c877b68d18e792a66b7f4c529ea02c8f80801542',
772 'c877b68d18e792a66b7f4c529ea02c8f80801542',
755 '4313566d2e417cb382948f8d9d7c765330356054',
773 '4313566d2e417cb382948f8d9d7c765330356054',
756 '6c2303a793671e807d1cfc70134c9ca0767d98c2',
774 '6c2303a793671e807d1cfc70134c9ca0767d98c2',
757 '54386793436c938cff89326944d4c2702340037d',
775 '54386793436c938cff89326944d4c2702340037d',
758 '54000345d2e78b03a99d561399e8e548de3f3203',
776 '54000345d2e78b03a99d561399e8e548de3f3203',
759 '1c6b3677b37ea064cb4b51714d8f7498f93f4b2b',
777 '1c6b3677b37ea064cb4b51714d8f7498f93f4b2b',
760 '2d03ca750a44440fb5ea8b751176d1f36f8e8f46',
778 '2d03ca750a44440fb5ea8b751176d1f36f8e8f46',
761 '2a08b128c206db48c2f0b8f70df060e6db0ae4f8',
779 '2a08b128c206db48c2f0b8f70df060e6db0ae4f8',
762 '30c26513ff1eb8e5ce0e1c6b477ee5dc50e2f34b',
780 '30c26513ff1eb8e5ce0e1c6b477ee5dc50e2f34b',
763 'ac71e9503c2ca95542839af0ce7b64011b72ea7c',
781 'ac71e9503c2ca95542839af0ce7b64011b72ea7c',
764 '12669288fd13adba2a9b7dd5b870cc23ffab92d2',
782 '12669288fd13adba2a9b7dd5b870cc23ffab92d2',
765 '5a0c84f3e6fe3473e4c8427199d5a6fc71a9b382',
783 '5a0c84f3e6fe3473e4c8427199d5a6fc71a9b382',
766 '12f2f5e2b38e6ff3fbdb5d722efed9aa72ecb0d5',
784 '12f2f5e2b38e6ff3fbdb5d722efed9aa72ecb0d5',
767 '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
785 '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
768 'f50f42baeed5af6518ef4b0cb2f1423f3851a941',
786 'f50f42baeed5af6518ef4b0cb2f1423f3851a941',
769 'd7e390a45f6aa96f04f5e7f583ad4f867431aa25',
787 'd7e390a45f6aa96f04f5e7f583ad4f867431aa25',
770 'f15c21f97864b4f071cddfbf2750ec2e23859414',
788 'f15c21f97864b4f071cddfbf2750ec2e23859414',
771 'e906ef056cf539a4e4e5fc8003eaf7cf14dd8ade',
789 'e906ef056cf539a4e4e5fc8003eaf7cf14dd8ade',
772 'ea2b108b48aa8f8c9c4a941f66c1a03315ca1c3b',
790 'ea2b108b48aa8f8c9c4a941f66c1a03315ca1c3b',
773 '84dec09632a4458f79f50ddbbd155506c460b4f9',
791 '84dec09632a4458f79f50ddbbd155506c460b4f9',
774 '0115510b70c7229dbc5dc49036b32e7d91d23acd',
792 '0115510b70c7229dbc5dc49036b32e7d91d23acd',
775 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
793 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
776 '3bf1c5868e570e39569d094f922d33ced2fa3b2b',
794 '3bf1c5868e570e39569d094f922d33ced2fa3b2b',
777 'b8d04012574729d2c29886e53b1a43ef16dd00a1',
795 'b8d04012574729d2c29886e53b1a43ef16dd00a1',
778 '6970b057cffe4aab0a792aa634c89f4bebf01441',
796 '6970b057cffe4aab0a792aa634c89f4bebf01441',
779 'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
797 'dd80b0f6cf5052f17cc738c2951c4f2070200d7f',
780 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
798 'ff7ca51e58c505fec0dd2491de52c622bb7a806b',
781 ],
799 ],
782 'vcs/backends/git.py': [
800 'vcs/backends/git.py': [
783 '4cf116ad5a457530381135e2f4c453e68a1b0105',
801 '4cf116ad5a457530381135e2f4c453e68a1b0105',
784 '9a751d84d8e9408e736329767387f41b36935153',
802 '9a751d84d8e9408e736329767387f41b36935153',
785 'cb681fb539c3faaedbcdf5ca71ca413425c18f01',
803 'cb681fb539c3faaedbcdf5ca71ca413425c18f01',
786 '428f81bb652bcba8d631bce926e8834ff49bdcc6',
804 '428f81bb652bcba8d631bce926e8834ff49bdcc6',
787 '180ab15aebf26f98f714d8c68715e0f05fa6e1c7',
805 '180ab15aebf26f98f714d8c68715e0f05fa6e1c7',
788 '2b8e07312a2e89e92b90426ab97f349f4bce2a3a',
806 '2b8e07312a2e89e92b90426ab97f349f4bce2a3a',
789 '50e08c506174d8645a4bb517dd122ac946a0f3bf',
807 '50e08c506174d8645a4bb517dd122ac946a0f3bf',
790 '54000345d2e78b03a99d561399e8e548de3f3203',
808 '54000345d2e78b03a99d561399e8e548de3f3203',
791 ],
809 ],
792 }
810 }
793 for path, commit_ids in files.items():
811 for path, commit_ids in files.items():
794 node = self.repo.get_commit(commit_ids[0]).get_node(path)
812 node = self.repo.get_commit(commit_ids[0]).get_node(path)
795 node_ids = [commit.raw_id for commit in node.history]
813 node_ids = [commit.raw_id for commit in node.history]
796 assert set(commit_ids).issubset(set(node_ids)), (
814 assert set(commit_ids).issubset(set(node_ids)), (
797 "We assumed that %s is subset of commit_ids for which file %s "
815 "We assumed that %s is subset of commit_ids for which file %s "
798 "has been changed, and history of that node returned: %s"
816 "has been changed, and history of that node returned: %s"
799 % (commit_ids, path, node_ids))
817 % (commit_ids, path, node_ids))
800
818
801 def test_file_annotate(self):
819 def test_file_annotate(self):
802 files = {
820 files = {
803 'vcs/backends/__init__.py': {
821 'vcs/backends/__init__.py': {
804 'c1214f7e79e02fc37156ff215cd71275450cffc3': {
822 'c1214f7e79e02fc37156ff215cd71275450cffc3': {
805 'lines_no': 1,
823 'lines_no': 1,
806 'commits': [
824 'commits': [
807 'c1214f7e79e02fc37156ff215cd71275450cffc3',
825 'c1214f7e79e02fc37156ff215cd71275450cffc3',
808 ],
826 ],
809 },
827 },
810 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647': {
828 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647': {
811 'lines_no': 21,
829 'lines_no': 21,
812 'commits': [
830 'commits': [
813 '49d3fd156b6f7db46313fac355dca1a0b94a0017',
831 '49d3fd156b6f7db46313fac355dca1a0b94a0017',
814 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
832 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
815 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
833 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
816 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
834 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
817 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
835 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
818 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
836 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
819 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
837 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
820 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
838 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
821 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
839 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
822 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
840 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
823 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
841 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
824 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
842 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
825 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
843 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
826 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
844 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
827 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
845 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
828 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
846 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
829 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
847 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
830 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
848 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
831 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
849 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
832 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
850 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
833 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
851 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
834 ],
852 ],
835 },
853 },
836 'e29b67bd158580fc90fc5e9111240b90e6e86064': {
854 'e29b67bd158580fc90fc5e9111240b90e6e86064': {
837 'lines_no': 32,
855 'lines_no': 32,
838 'commits': [
856 'commits': [
839 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
857 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
840 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
858 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
841 '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
859 '5eab1222a7cd4bfcbabc218ca6d04276d4e27378',
842 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
860 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
843 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
861 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
844 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
862 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
845 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
863 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
846 '54000345d2e78b03a99d561399e8e548de3f3203',
864 '54000345d2e78b03a99d561399e8e548de3f3203',
847 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
865 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
848 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
866 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
849 '78c3f0c23b7ee935ec276acb8b8212444c33c396',
867 '78c3f0c23b7ee935ec276acb8b8212444c33c396',
850 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
868 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
851 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
869 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
852 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
870 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
853 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
871 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
854 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
872 '2a13f185e4525f9d4b59882791a2d397b90d5ddc',
855 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
873 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
856 '78c3f0c23b7ee935ec276acb8b8212444c33c396',
874 '78c3f0c23b7ee935ec276acb8b8212444c33c396',
857 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
875 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
858 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
876 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
859 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
877 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
860 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
878 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
861 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
879 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
862 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
880 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
863 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
881 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
864 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
882 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
865 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
883 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
866 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
884 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
867 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
885 '992f38217b979d0b0987d0bae3cc26dac85d9b19',
868 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
886 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
869 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
887 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
870 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
888 '16fba1ae9334d79b66d7afed2c2dfbfa2ae53647',
871 ],
889 ],
872 },
890 },
873 },
891 },
874 }
892 }
875
893
876 for fname, commit_dict in files.items():
894 for fname, commit_dict in files.items():
877 for commit_id, __ in commit_dict.items():
895 for commit_id, __ in commit_dict.items():
878 commit = self.repo.get_commit(commit_id)
896 commit = self.repo.get_commit(commit_id)
879
897
880 l1_1 = [x[1] for x in commit.get_file_annotate(fname)]
898 l1_1 = [x[1] for x in commit.get_file_annotate(fname)]
881 l1_2 = [x[2]().raw_id for x in commit.get_file_annotate(fname)]
899 l1_2 = [x[2]().raw_id for x in commit.get_file_annotate(fname)]
882 assert l1_1 == l1_2
900 assert l1_1 == l1_2
883 l1 = l1_1
901 l1 = l1_1
884 l2 = files[fname][commit_id]['commits']
902 l2 = files[fname][commit_id]['commits']
885 assert l1 == l2, (
903 assert l1 == l2, (
886 "The lists of commit_ids for %s@commit_id %s"
904 "The lists of commit_ids for %s@commit_id %s"
887 "from annotation list should match each other, "
905 "from annotation list should match each other, "
888 "got \n%s \nvs \n%s " % (fname, commit_id, l1, l2))
906 "got \n%s \nvs \n%s " % (fname, commit_id, l1, l2))
889
907
890 def test_files_state(self):
908 def test_files_state(self):
891 """
909 """
892 Tests state of FileNodes.
910 Tests state of FileNodes.
893 """
911 """
894 node = self.repo\
912 node = self.repo\
895 .get_commit('e6ea6d16e2f26250124a1f4b4fe37a912f9d86a0')\
913 .get_commit('e6ea6d16e2f26250124a1f4b4fe37a912f9d86a0')\
896 .get_node('vcs/utils/diffs.py')
914 .get_node('vcs/utils/diffs.py')
897 assert node.state, NodeState.ADDED
915 assert node.state, NodeState.ADDED
898 assert node.added
916 assert node.added
899 assert not node.changed
917 assert not node.changed
900 assert not node.not_changed
918 assert not node.not_changed
901 assert not node.removed
919 assert not node.removed
902
920
903 node = self.repo\
921 node = self.repo\
904 .get_commit('33fa3223355104431402a888fa77a4e9956feb3e')\
922 .get_commit('33fa3223355104431402a888fa77a4e9956feb3e')\
905 .get_node('.hgignore')
923 .get_node('.hgignore')
906 assert node.state, NodeState.CHANGED
924 assert node.state, NodeState.CHANGED
907 assert not node.added
925 assert not node.added
908 assert node.changed
926 assert node.changed
909 assert not node.not_changed
927 assert not node.not_changed
910 assert not node.removed
928 assert not node.removed
911
929
912 node = self.repo\
930 node = self.repo\
913 .get_commit('e29b67bd158580fc90fc5e9111240b90e6e86064')\
931 .get_commit('e29b67bd158580fc90fc5e9111240b90e6e86064')\
914 .get_node('setup.py')
932 .get_node('setup.py')
915 assert node.state, NodeState.NOT_CHANGED
933 assert node.state, NodeState.NOT_CHANGED
916 assert not node.added
934 assert not node.added
917 assert not node.changed
935 assert not node.changed
918 assert node.not_changed
936 assert node.not_changed
919 assert not node.removed
937 assert not node.removed
920
938
921 # If node has REMOVED state then trying to fetch it would raise
939 # If node has REMOVED state then trying to fetch it would raise
922 # CommitError exception
940 # CommitError exception
923 commit = self.repo.get_commit(
941 commit = self.repo.get_commit(
924 'fa6600f6848800641328adbf7811fd2372c02ab2')
942 'fa6600f6848800641328adbf7811fd2372c02ab2')
925 path = 'vcs/backends/BaseRepository.py'
943 path = 'vcs/backends/BaseRepository.py'
926 with pytest.raises(NodeDoesNotExistError):
944 with pytest.raises(NodeDoesNotExistError):
927 commit.get_node(path)
945 commit.get_node(path)
928 # but it would be one of ``removed`` (commit's attribute)
946 # but it would be one of ``removed`` (commit's attribute)
929 assert path in [rf.path for rf in commit.removed]
947 assert path in [rf.path for rf in commit.removed]
930
948
931 commit = self.repo.get_commit(
949 commit = self.repo.get_commit(
932 '54386793436c938cff89326944d4c2702340037d')
950 '54386793436c938cff89326944d4c2702340037d')
933 changed = [
951 changed = [
934 'setup.py', 'tests/test_nodes.py', 'vcs/backends/hg.py',
952 'setup.py', 'tests/test_nodes.py', 'vcs/backends/hg.py',
935 'vcs/nodes.py']
953 'vcs/nodes.py']
936 assert set(changed) == set([f.path for f in commit.changed])
954 assert set(changed) == set([f.path for f in commit.changed])
937
955
938 def test_unicode_branch_refs(self):
956 def test_unicode_branch_refs(self):
939 unicode_branches = {
957 unicode_branches = {
940 'refs/heads/unicode': '6c0ce52b229aa978889e91b38777f800e85f330b',
958 'refs/heads/unicode': '6c0ce52b229aa978889e91b38777f800e85f330b',
941 u'refs/heads/uniΓ§ΓΆβˆ‚e': 'ΓΌrl',
959 u'refs/heads/uniΓ§ΓΆβˆ‚e': 'ΓΌrl',
942 }
960 }
943 with mock.patch(
961 with mock.patch(
944 ("rhodecode.lib.vcs.backends.git.repository"
962 ("rhodecode.lib.vcs.backends.git.repository"
945 ".GitRepository._refs"),
963 ".GitRepository._refs"),
946 unicode_branches):
964 unicode_branches):
947 branches = self.repo.branches
965 branches = self.repo.branches
948
966
949 assert 'unicode' in branches
967 assert 'unicode' in branches
950 assert u'uniΓ§ΓΆβˆ‚e' in branches
968 assert u'uniΓ§ΓΆβˆ‚e' in branches
951
969
952 def test_unicode_tag_refs(self):
970 def test_unicode_tag_refs(self):
953 unicode_tags = {
971 unicode_tags = {
954 'refs/tags/unicode': '6c0ce52b229aa978889e91b38777f800e85f330b',
972 'refs/tags/unicode': '6c0ce52b229aa978889e91b38777f800e85f330b',
955 u'refs/tags/uniΓ§ΓΆβˆ‚e': '6c0ce52b229aa978889e91b38777f800e85f330b',
973 u'refs/tags/uniΓ§ΓΆβˆ‚e': '6c0ce52b229aa978889e91b38777f800e85f330b',
956 }
974 }
957 with mock.patch(
975 with mock.patch(
958 ("rhodecode.lib.vcs.backends.git.repository"
976 ("rhodecode.lib.vcs.backends.git.repository"
959 ".GitRepository._refs"),
977 ".GitRepository._refs"),
960 unicode_tags):
978 unicode_tags):
961 tags = self.repo.tags
979 tags = self.repo.tags
962
980
963 assert 'unicode' in tags
981 assert 'unicode' in tags
964 assert u'uniΓ§ΓΆβˆ‚e' in tags
982 assert u'uniΓ§ΓΆβˆ‚e' in tags
965
983
966 def test_commit_message_is_unicode(self):
984 def test_commit_message_is_unicode(self):
967 for commit in self.repo:
985 for commit in self.repo:
968 assert type(commit.message) == unicode
986 assert type(commit.message) == unicode
969
987
970 def test_commit_author_is_unicode(self):
988 def test_commit_author_is_unicode(self):
971 for commit in self.repo:
989 for commit in self.repo:
972 assert type(commit.author) == unicode
990 assert type(commit.author) == unicode
973
991
974 def test_repo_files_content_is_unicode(self):
992 def test_repo_files_content_is_unicode(self):
975 commit = self.repo.get_commit()
993 commit = self.repo.get_commit()
976 for node in commit.get_node('/'):
994 for node in commit.get_node('/'):
977 if node.is_file():
995 if node.is_file():
978 assert type(node.content) == unicode
996 assert type(node.content) == unicode
979
997
980 def test_wrong_path(self):
998 def test_wrong_path(self):
981 # There is 'setup.py' in the root dir but not there:
999 # There is 'setup.py' in the root dir but not there:
982 path = 'foo/bar/setup.py'
1000 path = 'foo/bar/setup.py'
983 tip = self.repo.get_commit()
1001 tip = self.repo.get_commit()
984 with pytest.raises(VCSError):
1002 with pytest.raises(VCSError):
985 tip.get_node(path)
1003 tip.get_node(path)
986
1004
987 @pytest.mark.parametrize("author_email, commit_id", [
1005 @pytest.mark.parametrize("author_email, commit_id", [
988 ('marcin@python-blog.com', 'c1214f7e79e02fc37156ff215cd71275450cffc3'),
1006 ('marcin@python-blog.com', 'c1214f7e79e02fc37156ff215cd71275450cffc3'),
989 ('lukasz.balcerzak@python-center.pl',
1007 ('lukasz.balcerzak@python-center.pl',
990 'ff7ca51e58c505fec0dd2491de52c622bb7a806b'),
1008 'ff7ca51e58c505fec0dd2491de52c622bb7a806b'),
991 ('none@none', '8430a588b43b5d6da365400117c89400326e7992'),
1009 ('none@none', '8430a588b43b5d6da365400117c89400326e7992'),
992 ])
1010 ])
993 def test_author_email(self, author_email, commit_id):
1011 def test_author_email(self, author_email, commit_id):
994 commit = self.repo.get_commit(commit_id)
1012 commit = self.repo.get_commit(commit_id)
995 assert author_email == commit.author_email
1013 assert author_email == commit.author_email
996
1014
997 @pytest.mark.parametrize("author, commit_id", [
1015 @pytest.mark.parametrize("author, commit_id", [
998 ('Marcin Kuzminski', 'c1214f7e79e02fc37156ff215cd71275450cffc3'),
1016 ('Marcin Kuzminski', 'c1214f7e79e02fc37156ff215cd71275450cffc3'),
999 ('Lukasz Balcerzak', 'ff7ca51e58c505fec0dd2491de52c622bb7a806b'),
1017 ('Lukasz Balcerzak', 'ff7ca51e58c505fec0dd2491de52c622bb7a806b'),
1000 ('marcink', '8430a588b43b5d6da365400117c89400326e7992'),
1018 ('marcink', '8430a588b43b5d6da365400117c89400326e7992'),
1001 ])
1019 ])
1002 def test_author_username(self, author, commit_id):
1020 def test_author_username(self, author, commit_id):
1003 commit = self.repo.get_commit(commit_id)
1021 commit = self.repo.get_commit(commit_id)
1004 assert author == commit.author_name
1022 assert author == commit.author_name
1005
1023
1006
1024
1007 class TestLargeFileRepo(object):
1025 class TestLargeFileRepo(object):
1008
1026
1009 def test_large_file(self, backend_git):
1027 def test_large_file(self, backend_git):
1010 conf = make_db_config()
1028 conf = make_db_config()
1011 repo = backend_git.create_test_repo('largefiles', conf)
1029 repo = backend_git.create_test_repo('largefiles', conf)
1012
1030
1013 tip = repo.scm_instance().get_commit()
1031 tip = repo.scm_instance().get_commit()
1014
1032
1015 # extract stored LF node into the origin cache
1033 # extract stored LF node into the origin cache
1016 lfs_store = os.path.join(repo.repo_path, repo.repo_name, 'lfs_store')
1034 lfs_store = os.path.join(repo.repo_path, repo.repo_name, 'lfs_store')
1017
1035
1018 oid = '7b331c02e313c7599d5a90212e17e6d3cb729bd2e1c9b873c302a63c95a2f9bf'
1036 oid = '7b331c02e313c7599d5a90212e17e6d3cb729bd2e1c9b873c302a63c95a2f9bf'
1019 oid_path = os.path.join(lfs_store, oid)
1037 oid_path = os.path.join(lfs_store, oid)
1020 oid_destination = os.path.join(
1038 oid_destination = os.path.join(
1021 conf.get('vcs_git_lfs', 'store_location'), oid)
1039 conf.get('vcs_git_lfs', 'store_location'), oid)
1022 shutil.copy(oid_path, oid_destination)
1040 shutil.copy(oid_path, oid_destination)
1023
1041
1024 node = tip.get_node('1MB.zip')
1042 node = tip.get_node('1MB.zip')
1025
1043
1026 lf_node = node.get_largefile_node()
1044 lf_node = node.get_largefile_node()
1027
1045
1028 assert lf_node.is_largefile() is True
1046 assert lf_node.is_largefile() is True
1029 assert lf_node.size == 1024000
1047 assert lf_node.size == 1024000
1030 assert lf_node.name == '1MB.zip'
1048 assert lf_node.name == '1MB.zip'
1031
1049
1032
1050
1033 @pytest.mark.usefixtures("vcs_repository_support")
1051 @pytest.mark.usefixtures("vcs_repository_support")
1034 class TestGitSpecificWithRepo(BackendTestMixin):
1052 class TestGitSpecificWithRepo(BackendTestMixin):
1035
1053
1036 @classmethod
1054 @classmethod
1037 def _get_commits(cls):
1055 def _get_commits(cls):
1038 return [
1056 return [
1039 {
1057 {
1040 'message': 'Initial',
1058 'message': 'Initial',
1041 'author': 'Joe Doe <joe.doe@example.com>',
1059 'author': 'Joe Doe <joe.doe@example.com>',
1042 'date': datetime.datetime(2010, 1, 1, 20),
1060 'date': datetime.datetime(2010, 1, 1, 20),
1043 'added': [
1061 'added': [
1044 FileNode('foobar/static/js/admin/base.js', content='base'),
1062 FileNode('foobar/static/js/admin/base.js', content='base'),
1045 FileNode(
1063 FileNode(
1046 'foobar/static/admin', content='admin',
1064 'foobar/static/admin', content='admin',
1047 mode=0120000), # this is a link
1065 mode=0120000), # this is a link
1048 FileNode('foo', content='foo'),
1066 FileNode('foo', content='foo'),
1049 ],
1067 ],
1050 },
1068 },
1051 {
1069 {
1052 'message': 'Second',
1070 'message': 'Second',
1053 'author': 'Joe Doe <joe.doe@example.com>',
1071 'author': 'Joe Doe <joe.doe@example.com>',
1054 'date': datetime.datetime(2010, 1, 1, 22),
1072 'date': datetime.datetime(2010, 1, 1, 22),
1055 'added': [
1073 'added': [
1056 FileNode('foo2', content='foo2'),
1074 FileNode('foo2', content='foo2'),
1057 ],
1075 ],
1058 },
1076 },
1059 ]
1077 ]
1060
1078
1061 def test_paths_slow_traversing(self):
1079 def test_paths_slow_traversing(self):
1062 commit = self.repo.get_commit()
1080 commit = self.repo.get_commit()
1063 assert commit.get_node('foobar').get_node('static').get_node('js')\
1081 assert commit.get_node('foobar').get_node('static').get_node('js')\
1064 .get_node('admin').get_node('base.js').content == 'base'
1082 .get_node('admin').get_node('base.js').content == 'base'
1065
1083
1066 def test_paths_fast_traversing(self):
1084 def test_paths_fast_traversing(self):
1067 commit = self.repo.get_commit()
1085 commit = self.repo.get_commit()
1068 assert (
1086 assert (
1069 commit.get_node('foobar/static/js/admin/base.js').content ==
1087 commit.get_node('foobar/static/js/admin/base.js').content ==
1070 'base')
1088 'base')
1071
1089
1072 def test_get_diff_runs_git_command_with_hashes(self):
1090 def test_get_diff_runs_git_command_with_hashes(self):
1073 self.repo.run_git_command = mock.Mock(return_value=['', ''])
1091 self.repo.run_git_command = mock.Mock(return_value=['', ''])
1074 self.repo.get_diff(self.repo[0], self.repo[1])
1092 self.repo.get_diff(self.repo[0], self.repo[1])
1075 self.repo.run_git_command.assert_called_once_with(
1093 self.repo.run_git_command.assert_called_once_with(
1076 ['diff', '-U3', '--full-index', '--binary', '-p', '-M',
1094 ['diff', '-U3', '--full-index', '--binary', '-p', '-M',
1077 '--abbrev=40', self.repo._get_commit_id(0),
1095 '--abbrev=40', self.repo._get_commit_id(0),
1078 self.repo._get_commit_id(1)])
1096 self.repo._get_commit_id(1)])
1079
1097
1080 def test_get_diff_runs_git_command_with_str_hashes(self):
1098 def test_get_diff_runs_git_command_with_str_hashes(self):
1081 self.repo.run_git_command = mock.Mock(return_value=['', ''])
1099 self.repo.run_git_command = mock.Mock(return_value=['', ''])
1082 self.repo.get_diff(self.repo.EMPTY_COMMIT, self.repo[1])
1100 self.repo.get_diff(self.repo.EMPTY_COMMIT, self.repo[1])
1083 self.repo.run_git_command.assert_called_once_with(
1101 self.repo.run_git_command.assert_called_once_with(
1084 ['show', '-U3', '--full-index', '--binary', '-p', '-M',
1102 ['show', '-U3', '--full-index', '--binary', '-p', '-M',
1085 '--abbrev=40', self.repo._get_commit_id(1)])
1103 '--abbrev=40', self.repo._get_commit_id(1)])
1086
1104
1087 def test_get_diff_runs_git_command_with_path_if_its_given(self):
1105 def test_get_diff_runs_git_command_with_path_if_its_given(self):
1088 self.repo.run_git_command = mock.Mock(return_value=['', ''])
1106 self.repo.run_git_command = mock.Mock(return_value=['', ''])
1089 self.repo.get_diff(self.repo[0], self.repo[1], 'foo')
1107 self.repo.get_diff(self.repo[0], self.repo[1], 'foo')
1090 self.repo.run_git_command.assert_called_once_with(
1108 self.repo.run_git_command.assert_called_once_with(
1091 ['diff', '-U3', '--full-index', '--binary', '-p', '-M',
1109 ['diff', '-U3', '--full-index', '--binary', '-p', '-M',
1092 '--abbrev=40', self.repo._get_commit_id(0),
1110 '--abbrev=40', self.repo._get_commit_id(0),
1093 self.repo._get_commit_id(1), '--', 'foo'])
1111 self.repo._get_commit_id(1), '--', 'foo'])
1094
1112
1095
1113
1096 @pytest.mark.usefixtures("vcs_repository_support")
1114 @pytest.mark.usefixtures("vcs_repository_support")
1097 class TestGitRegression(BackendTestMixin):
1115 class TestGitRegression(BackendTestMixin):
1098
1116
1099 @classmethod
1117 @classmethod
1100 def _get_commits(cls):
1118 def _get_commits(cls):
1101 return [
1119 return [
1102 {
1120 {
1103 'message': 'Initial',
1121 'message': 'Initial',
1104 'author': 'Joe Doe <joe.doe@example.com>',
1122 'author': 'Joe Doe <joe.doe@example.com>',
1105 'date': datetime.datetime(2010, 1, 1, 20),
1123 'date': datetime.datetime(2010, 1, 1, 20),
1106 'added': [
1124 'added': [
1107 FileNode('bot/__init__.py', content='base'),
1125 FileNode('bot/__init__.py', content='base'),
1108 FileNode('bot/templates/404.html', content='base'),
1126 FileNode('bot/templates/404.html', content='base'),
1109 FileNode('bot/templates/500.html', content='base'),
1127 FileNode('bot/templates/500.html', content='base'),
1110 ],
1128 ],
1111 },
1129 },
1112 {
1130 {
1113 'message': 'Second',
1131 'message': 'Second',
1114 'author': 'Joe Doe <joe.doe@example.com>',
1132 'author': 'Joe Doe <joe.doe@example.com>',
1115 'date': datetime.datetime(2010, 1, 1, 22),
1133 'date': datetime.datetime(2010, 1, 1, 22),
1116 'added': [
1134 'added': [
1117 FileNode('bot/build/migrations/1.py', content='foo2'),
1135 FileNode('bot/build/migrations/1.py', content='foo2'),
1118 FileNode('bot/build/migrations/2.py', content='foo2'),
1136 FileNode('bot/build/migrations/2.py', content='foo2'),
1119 FileNode(
1137 FileNode(
1120 'bot/build/static/templates/f.html', content='foo2'),
1138 'bot/build/static/templates/f.html', content='foo2'),
1121 FileNode(
1139 FileNode(
1122 'bot/build/static/templates/f1.html', content='foo2'),
1140 'bot/build/static/templates/f1.html', content='foo2'),
1123 FileNode('bot/build/templates/err.html', content='foo2'),
1141 FileNode('bot/build/templates/err.html', content='foo2'),
1124 FileNode('bot/build/templates/err2.html', content='foo2'),
1142 FileNode('bot/build/templates/err2.html', content='foo2'),
1125 ],
1143 ],
1126 },
1144 },
1127 ]
1145 ]
1128
1146
1129 @pytest.mark.parametrize("path, expected_paths", [
1147 @pytest.mark.parametrize("path, expected_paths", [
1130 ('bot', [
1148 ('bot', [
1131 'bot/build',
1149 'bot/build',
1132 'bot/templates',
1150 'bot/templates',
1133 'bot/__init__.py']),
1151 'bot/__init__.py']),
1134 ('bot/build', [
1152 ('bot/build', [
1135 'bot/build/migrations',
1153 'bot/build/migrations',
1136 'bot/build/static',
1154 'bot/build/static',
1137 'bot/build/templates']),
1155 'bot/build/templates']),
1138 ('bot/build/static', [
1156 ('bot/build/static', [
1139 'bot/build/static/templates']),
1157 'bot/build/static/templates']),
1140 ('bot/build/static/templates', [
1158 ('bot/build/static/templates', [
1141 'bot/build/static/templates/f.html',
1159 'bot/build/static/templates/f.html',
1142 'bot/build/static/templates/f1.html']),
1160 'bot/build/static/templates/f1.html']),
1143 ('bot/build/templates', [
1161 ('bot/build/templates', [
1144 'bot/build/templates/err.html',
1162 'bot/build/templates/err.html',
1145 'bot/build/templates/err2.html']),
1163 'bot/build/templates/err2.html']),
1146 ('bot/templates/', [
1164 ('bot/templates/', [
1147 'bot/templates/404.html',
1165 'bot/templates/404.html',
1148 'bot/templates/500.html']),
1166 'bot/templates/500.html']),
1149 ])
1167 ])
1150 def test_similar_paths(self, path, expected_paths):
1168 def test_similar_paths(self, path, expected_paths):
1151 commit = self.repo.get_commit()
1169 commit = self.repo.get_commit()
1152 paths = [n.path for n in commit.get_nodes(path)]
1170 paths = [n.path for n in commit.get_nodes(path)]
1153 assert paths == expected_paths
1171 assert paths == expected_paths
1154
1172
1155
1173
1156 class TestDiscoverGitVersion:
1174 class TestDiscoverGitVersion:
1157
1175
1158 def test_returns_git_version(self, baseapp):
1176 def test_returns_git_version(self, baseapp):
1159 version = discover_git_version()
1177 version = discover_git_version()
1160 assert version
1178 assert version
1161
1179
1162 def test_returns_empty_string_without_vcsserver(self):
1180 def test_returns_empty_string_without_vcsserver(self):
1163 mock_connection = mock.Mock()
1181 mock_connection = mock.Mock()
1164 mock_connection.discover_git_version = mock.Mock(
1182 mock_connection.discover_git_version = mock.Mock(
1165 side_effect=Exception)
1183 side_effect=Exception)
1166 with mock.patch('rhodecode.lib.vcs.connection.Git', mock_connection):
1184 with mock.patch('rhodecode.lib.vcs.connection.Git', mock_connection):
1167 version = discover_git_version()
1185 version = discover_git_version()
1168 assert version == ''
1186 assert version == ''
1169
1187
1170
1188
1171 class TestGetSubmoduleUrl(object):
1189 class TestGetSubmoduleUrl(object):
1172 def test_submodules_file_found(self):
1190 def test_submodules_file_found(self):
1173 commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
1191 commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
1174 node = mock.Mock()
1192 node = mock.Mock()
1175 with mock.patch.object(
1193 with mock.patch.object(
1176 commit, 'get_node', return_value=node) as get_node_mock:
1194 commit, 'get_node', return_value=node) as get_node_mock:
1177 node.content = (
1195 node.content = (
1178 '[submodule "subrepo1"]\n'
1196 '[submodule "subrepo1"]\n'
1179 '\tpath = subrepo1\n'
1197 '\tpath = subrepo1\n'
1180 '\turl = https://code.rhodecode.com/dulwich\n'
1198 '\turl = https://code.rhodecode.com/dulwich\n'
1181 )
1199 )
1182 result = commit._get_submodule_url('subrepo1')
1200 result = commit._get_submodule_url('subrepo1')
1183 get_node_mock.assert_called_once_with('.gitmodules')
1201 get_node_mock.assert_called_once_with('.gitmodules')
1184 assert result == 'https://code.rhodecode.com/dulwich'
1202 assert result == 'https://code.rhodecode.com/dulwich'
1185
1203
1186 def test_complex_submodule_path(self):
1204 def test_complex_submodule_path(self):
1187 commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
1205 commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
1188 node = mock.Mock()
1206 node = mock.Mock()
1189 with mock.patch.object(
1207 with mock.patch.object(
1190 commit, 'get_node', return_value=node) as get_node_mock:
1208 commit, 'get_node', return_value=node) as get_node_mock:
1191 node.content = (
1209 node.content = (
1192 '[submodule "complex/subrepo/path"]\n'
1210 '[submodule "complex/subrepo/path"]\n'
1193 '\tpath = complex/subrepo/path\n'
1211 '\tpath = complex/subrepo/path\n'
1194 '\turl = https://code.rhodecode.com/dulwich\n'
1212 '\turl = https://code.rhodecode.com/dulwich\n'
1195 )
1213 )
1196 result = commit._get_submodule_url('complex/subrepo/path')
1214 result = commit._get_submodule_url('complex/subrepo/path')
1197 get_node_mock.assert_called_once_with('.gitmodules')
1215 get_node_mock.assert_called_once_with('.gitmodules')
1198 assert result == 'https://code.rhodecode.com/dulwich'
1216 assert result == 'https://code.rhodecode.com/dulwich'
1199
1217
1200 def test_submodules_file_not_found(self):
1218 def test_submodules_file_not_found(self):
1201 commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
1219 commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
1202 with mock.patch.object(
1220 with mock.patch.object(
1203 commit, 'get_node', side_effect=NodeDoesNotExistError):
1221 commit, 'get_node', side_effect=NodeDoesNotExistError):
1204 result = commit._get_submodule_url('complex/subrepo/path')
1222 result = commit._get_submodule_url('complex/subrepo/path')
1205 assert result is None
1223 assert result is None
1206
1224
1207 def test_path_not_found(self):
1225 def test_path_not_found(self):
1208 commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
1226 commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
1209 node = mock.Mock()
1227 node = mock.Mock()
1210 with mock.patch.object(
1228 with mock.patch.object(
1211 commit, 'get_node', return_value=node) as get_node_mock:
1229 commit, 'get_node', return_value=node) as get_node_mock:
1212 node.content = (
1230 node.content = (
1213 '[submodule "subrepo1"]\n'
1231 '[submodule "subrepo1"]\n'
1214 '\tpath = subrepo1\n'
1232 '\tpath = subrepo1\n'
1215 '\turl = https://code.rhodecode.com/dulwich\n'
1233 '\turl = https://code.rhodecode.com/dulwich\n'
1216 )
1234 )
1217 result = commit._get_submodule_url('subrepo2')
1235 result = commit._get_submodule_url('subrepo2')
1218 get_node_mock.assert_called_once_with('.gitmodules')
1236 get_node_mock.assert_called_once_with('.gitmodules')
1219 assert result is None
1237 assert result is None
1220
1238
1221 def test_returns_cached_values(self):
1239 def test_returns_cached_values(self):
1222 commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
1240 commit = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
1223 node = mock.Mock()
1241 node = mock.Mock()
1224 with mock.patch.object(
1242 with mock.patch.object(
1225 commit, 'get_node', return_value=node) as get_node_mock:
1243 commit, 'get_node', return_value=node) as get_node_mock:
1226 node.content = (
1244 node.content = (
1227 '[submodule "subrepo1"]\n'
1245 '[submodule "subrepo1"]\n'
1228 '\tpath = subrepo1\n'
1246 '\tpath = subrepo1\n'
1229 '\turl = https://code.rhodecode.com/dulwich\n'
1247 '\turl = https://code.rhodecode.com/dulwich\n'
1230 )
1248 )
1231 for _ in range(3):
1249 for _ in range(3):
1232 commit._get_submodule_url('subrepo1')
1250 commit._get_submodule_url('subrepo1')
1233 get_node_mock.assert_called_once_with('.gitmodules')
1251 get_node_mock.assert_called_once_with('.gitmodules')
1234
1252
1235 def test_get_node_returns_a_link(self):
1253 def test_get_node_returns_a_link(self):
1236 repository = mock.Mock()
1254 repository = mock.Mock()
1237 repository.alias = 'git'
1255 repository.alias = 'git'
1238 commit = GitCommit(repository=repository, raw_id='abcdef12', idx=1)
1256 commit = GitCommit(repository=repository, raw_id='abcdef12', idx=1)
1239 submodule_url = 'https://code.rhodecode.com/dulwich'
1257 submodule_url = 'https://code.rhodecode.com/dulwich'
1240 get_id_patch = mock.patch.object(
1258 get_id_patch = mock.patch.object(
1241 commit, '_get_id_for_path', return_value=(1, 'link'))
1259 commit, '_get_id_for_path', return_value=(1, 'link'))
1242 get_submodule_patch = mock.patch.object(
1260 get_submodule_patch = mock.patch.object(
1243 commit, '_get_submodule_url', return_value=submodule_url)
1261 commit, '_get_submodule_url', return_value=submodule_url)
1244
1262
1245 with get_id_patch, get_submodule_patch as submodule_mock:
1263 with get_id_patch, get_submodule_patch as submodule_mock:
1246 node = commit.get_node('/abcde')
1264 node = commit.get_node('/abcde')
1247
1265
1248 submodule_mock.assert_called_once_with('/abcde')
1266 submodule_mock.assert_called_once_with('/abcde')
1249 assert type(node) == SubModuleNode
1267 assert type(node) == SubModuleNode
1250 assert node.url == submodule_url
1268 assert node.url == submodule_url
1251
1269
1252 def test_get_nodes_returns_links(self):
1270 def test_get_nodes_returns_links(self):
1253 repository = mock.MagicMock()
1271 repository = mock.MagicMock()
1254 repository.alias = 'git'
1272 repository.alias = 'git'
1255 repository._remote.tree_items.return_value = [
1273 repository._remote.tree_items.return_value = [
1256 ('subrepo', 'stat', 1, 'link')
1274 ('subrepo', 'stat', 1, 'link')
1257 ]
1275 ]
1258 commit = GitCommit(repository=repository, raw_id='abcdef12', idx=1)
1276 commit = GitCommit(repository=repository, raw_id='abcdef12', idx=1)
1259 submodule_url = 'https://code.rhodecode.com/dulwich'
1277 submodule_url = 'https://code.rhodecode.com/dulwich'
1260 get_id_patch = mock.patch.object(
1278 get_id_patch = mock.patch.object(
1261 commit, '_get_id_for_path', return_value=(1, 'tree'))
1279 commit, '_get_id_for_path', return_value=(1, 'tree'))
1262 get_submodule_patch = mock.patch.object(
1280 get_submodule_patch = mock.patch.object(
1263 commit, '_get_submodule_url', return_value=submodule_url)
1281 commit, '_get_submodule_url', return_value=submodule_url)
1264
1282
1265 with get_id_patch, get_submodule_patch as submodule_mock:
1283 with get_id_patch, get_submodule_patch as submodule_mock:
1266 nodes = commit.get_nodes('/abcde')
1284 nodes = commit.get_nodes('/abcde')
1267
1285
1268 submodule_mock.assert_called_once_with('/abcde/subrepo')
1286 submodule_mock.assert_called_once_with('/abcde/subrepo')
1269 assert len(nodes) == 1
1287 assert len(nodes) == 1
1270 assert type(nodes[0]) == SubModuleNode
1288 assert type(nodes[0]) == SubModuleNode
1271 assert nodes[0].url == submodule_url
1289 assert nodes[0].url == submodule_url
@@ -1,1180 +1,1183 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import os
21 import os
22
22
23 import mock
23 import mock
24 import pytest
24 import pytest
25
25
26 from rhodecode.lib.utils import make_db_config
26 from rhodecode.lib.utils import make_db_config
27 from rhodecode.lib.vcs import backends
27 from rhodecode.lib.vcs import backends
28 from rhodecode.lib.vcs.backends.base import (
28 from rhodecode.lib.vcs.backends.base import (
29 Reference, MergeResponse, MergeFailureReason)
29 Reference, MergeResponse, MergeFailureReason)
30 from rhodecode.lib.vcs.backends.hg import MercurialRepository, MercurialCommit
30 from rhodecode.lib.vcs.backends.hg import MercurialRepository, MercurialCommit
31 from rhodecode.lib.vcs.exceptions import (
31 from rhodecode.lib.vcs.exceptions import (
32 RepositoryError, VCSError, NodeDoesNotExistError, CommitDoesNotExistError)
32 RepositoryError, VCSError, NodeDoesNotExistError, CommitDoesNotExistError)
33 from rhodecode.lib.vcs.nodes import FileNode, NodeKind, NodeState
33 from rhodecode.lib.vcs.nodes import FileNode, NodeKind, NodeState
34 from rhodecode.tests import TEST_HG_REPO, TEST_HG_REPO_CLONE
34 from rhodecode.tests import TEST_HG_REPO, TEST_HG_REPO_CLONE
35
35
36
36
37 pytestmark = pytest.mark.backends("hg")
37 pytestmark = pytest.mark.backends("hg")
38
38
39
39
40 def repo_path_generator():
40 def repo_path_generator():
41 """
41 """
42 Return a different path to be used for cloning repos.
42 Return a different path to be used for cloning repos.
43 """
43 """
44 i = 0
44 i = 0
45 while True:
45 while True:
46 i += 1
46 i += 1
47 yield '%s-%d' % (TEST_HG_REPO_CLONE, i)
47 yield '%s-%d' % (TEST_HG_REPO_CLONE, i)
48
48
49
49
50 REPO_PATH_GENERATOR = repo_path_generator()
50 REPO_PATH_GENERATOR = repo_path_generator()
51
51
52
52
53 @pytest.fixture(scope='class', autouse=True)
53 @pytest.fixture(scope='class', autouse=True)
54 def repo(request, baseapp):
54 def repo(request, baseapp):
55 repo = MercurialRepository(TEST_HG_REPO)
55 repo = MercurialRepository(TEST_HG_REPO)
56 if request.cls:
56 if request.cls:
57 request.cls.repo = repo
57 request.cls.repo = repo
58 return repo
58 return repo
59
59
60
60
61 class TestMercurialRepository:
61 class TestMercurialRepository:
62
62
63 # pylint: disable=protected-access
63 # pylint: disable=protected-access
64
64
65 def get_clone_repo(self):
65 def get_clone_repo(self):
66 """
66 """
67 Return a clone of the base repo.
67 Return a clone of the base repo.
68 """
68 """
69 clone_path = next(REPO_PATH_GENERATOR)
69 clone_path = next(REPO_PATH_GENERATOR)
70 repo_clone = MercurialRepository(
70 repo_clone = MercurialRepository(
71 clone_path, create=True, src_url=self.repo.path)
71 clone_path, create=True, src_url=self.repo.path)
72
72
73 return repo_clone
73 return repo_clone
74
74
75 def get_empty_repo(self):
75 def get_empty_repo(self):
76 """
76 """
77 Return an empty repo.
77 Return an empty repo.
78 """
78 """
79 return MercurialRepository(next(REPO_PATH_GENERATOR), create=True)
79 return MercurialRepository(next(REPO_PATH_GENERATOR), create=True)
80
80
81 def test_wrong_repo_path(self):
81 def test_wrong_repo_path(self):
82 wrong_repo_path = '/tmp/errorrepo_hg'
82 wrong_repo_path = '/tmp/errorrepo_hg'
83 with pytest.raises(RepositoryError):
83 with pytest.raises(RepositoryError):
84 MercurialRepository(wrong_repo_path)
84 MercurialRepository(wrong_repo_path)
85
85
86 def test_unicode_path_repo(self):
86 def test_unicode_path_repo(self):
87 with pytest.raises(VCSError):
87 with pytest.raises(VCSError):
88 MercurialRepository(u'iShouldFail')
88 MercurialRepository(u'iShouldFail')
89
89
90 def test_unicode_commit_id(self):
90 def test_unicode_commit_id(self):
91 with pytest.raises(CommitDoesNotExistError):
91 with pytest.raises(CommitDoesNotExistError):
92 self.repo.get_commit(u'unicode-commit-id')
92 self.repo.get_commit(u'unicode-commit-id')
93 with pytest.raises(CommitDoesNotExistError):
93 with pytest.raises(CommitDoesNotExistError):
94 self.repo.get_commit(u'unΓ­cΓΈde-spéçial-chΓ€rΓ₯cter-commit-id')
94 self.repo.get_commit(u'unΓ­cΓΈde-spéçial-chΓ€rΓ₯cter-commit-id')
95
95
96 def test_unicode_bookmark(self):
96 def test_unicode_bookmark(self):
97 self.repo.bookmark(u'unicode-bookmark')
97 self.repo.bookmark(u'unicode-bookmark')
98 self.repo.bookmark(u'unΓ­cΓΈde-spéçial-chΓ€rΓ₯cter-bookmark')
98 self.repo.bookmark(u'unΓ­cΓΈde-spéçial-chΓ€rΓ₯cter-bookmark')
99
99
100 def test_unicode_branch(self):
100 def test_unicode_branch(self):
101 with pytest.raises(KeyError):
101 with pytest.raises(KeyError):
102 self.repo.branches[u'unicode-branch']
102 self.repo.branches[u'unicode-branch']
103 with pytest.raises(KeyError):
103 with pytest.raises(KeyError):
104 self.repo.branches[u'unΓ­cΓΈde-spéçial-chΓ€rΓ₯cter-branch']
104 self.repo.branches[u'unΓ­cΓΈde-spéçial-chΓ€rΓ₯cter-branch']
105
105
106 def test_repo_clone(self):
106 def test_repo_clone(self):
107 if os.path.exists(TEST_HG_REPO_CLONE):
107 if os.path.exists(TEST_HG_REPO_CLONE):
108 self.fail(
108 self.fail(
109 'Cannot test mercurial clone repo as location %s already '
109 'Cannot test mercurial clone repo as location %s already '
110 'exists. You should manually remove it first.'
110 'exists. You should manually remove it first.'
111 % TEST_HG_REPO_CLONE)
111 % TEST_HG_REPO_CLONE)
112
112
113 repo = MercurialRepository(TEST_HG_REPO)
113 repo = MercurialRepository(TEST_HG_REPO)
114 repo_clone = MercurialRepository(TEST_HG_REPO_CLONE,
114 repo_clone = MercurialRepository(TEST_HG_REPO_CLONE,
115 src_url=TEST_HG_REPO)
115 src_url=TEST_HG_REPO)
116 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
116 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
117 # Checking hashes of commits should be enough
117 # Checking hashes of commits should be enough
118 for commit in repo.get_commits():
118 for commit in repo.get_commits():
119 raw_id = commit.raw_id
119 raw_id = commit.raw_id
120 assert raw_id == repo_clone.get_commit(raw_id).raw_id
120 assert raw_id == repo_clone.get_commit(raw_id).raw_id
121
121
122 def test_repo_clone_with_update(self):
122 def test_repo_clone_with_update(self):
123 repo = MercurialRepository(TEST_HG_REPO)
123 repo = MercurialRepository(TEST_HG_REPO)
124 repo_clone = MercurialRepository(
124 repo_clone = MercurialRepository(
125 TEST_HG_REPO_CLONE + '_w_update',
125 TEST_HG_REPO_CLONE + '_w_update',
126 src_url=TEST_HG_REPO, update_after_clone=True)
126 src_url=TEST_HG_REPO, update_after_clone=True)
127 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
127 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
128
128
129 # check if current workdir was updated
129 # check if current workdir was updated
130 assert os.path.isfile(
130 assert os.path.isfile(
131 os.path.join(TEST_HG_REPO_CLONE + '_w_update', 'MANIFEST.in'))
131 os.path.join(TEST_HG_REPO_CLONE + '_w_update', 'MANIFEST.in'))
132
132
133 def test_repo_clone_without_update(self):
133 def test_repo_clone_without_update(self):
134 repo = MercurialRepository(TEST_HG_REPO)
134 repo = MercurialRepository(TEST_HG_REPO)
135 repo_clone = MercurialRepository(
135 repo_clone = MercurialRepository(
136 TEST_HG_REPO_CLONE + '_wo_update',
136 TEST_HG_REPO_CLONE + '_wo_update',
137 src_url=TEST_HG_REPO, update_after_clone=False)
137 src_url=TEST_HG_REPO, update_after_clone=False)
138 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
138 assert len(repo.commit_ids) == len(repo_clone.commit_ids)
139 assert not os.path.isfile(
139 assert not os.path.isfile(
140 os.path.join(TEST_HG_REPO_CLONE + '_wo_update', 'MANIFEST.in'))
140 os.path.join(TEST_HG_REPO_CLONE + '_wo_update', 'MANIFEST.in'))
141
141
142 def test_commit_ids(self):
142 def test_commit_ids(self):
143 # there are 21 commits at bitbucket now
143 # there are 21 commits at bitbucket now
144 # so we can assume they would be available from now on
144 # so we can assume they would be available from now on
145 subset = set([
145 subset = set([
146 'b986218ba1c9b0d6a259fac9b050b1724ed8e545',
146 'b986218ba1c9b0d6a259fac9b050b1724ed8e545',
147 '3d8f361e72ab303da48d799ff1ac40d5ac37c67e',
147 '3d8f361e72ab303da48d799ff1ac40d5ac37c67e',
148 '6cba7170863a2411822803fa77a0a264f1310b35',
148 '6cba7170863a2411822803fa77a0a264f1310b35',
149 '56349e29c2af3ac913b28bde9a2c6154436e615b',
149 '56349e29c2af3ac913b28bde9a2c6154436e615b',
150 '2dda4e345facb0ccff1a191052dd1606dba6781d',
150 '2dda4e345facb0ccff1a191052dd1606dba6781d',
151 '6fff84722075f1607a30f436523403845f84cd9e',
151 '6fff84722075f1607a30f436523403845f84cd9e',
152 '7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7',
152 '7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7',
153 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb',
153 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb',
154 'dc5d2c0661b61928834a785d3e64a3f80d3aad9c',
154 'dc5d2c0661b61928834a785d3e64a3f80d3aad9c',
155 'be90031137367893f1c406e0a8683010fd115b79',
155 'be90031137367893f1c406e0a8683010fd115b79',
156 'db8e58be770518cbb2b1cdfa69146e47cd481481',
156 'db8e58be770518cbb2b1cdfa69146e47cd481481',
157 '84478366594b424af694a6c784cb991a16b87c21',
157 '84478366594b424af694a6c784cb991a16b87c21',
158 '17f8e105dddb9f339600389c6dc7175d395a535c',
158 '17f8e105dddb9f339600389c6dc7175d395a535c',
159 '20a662e756499bde3095ffc9bc0643d1def2d0eb',
159 '20a662e756499bde3095ffc9bc0643d1def2d0eb',
160 '2e319b85e70a707bba0beff866d9f9de032aa4f9',
160 '2e319b85e70a707bba0beff866d9f9de032aa4f9',
161 '786facd2c61deb9cf91e9534735124fb8fc11842',
161 '786facd2c61deb9cf91e9534735124fb8fc11842',
162 '94593d2128d38210a2fcd1aabff6dda0d6d9edf8',
162 '94593d2128d38210a2fcd1aabff6dda0d6d9edf8',
163 'aa6a0de05b7612707db567078e130a6cd114a9a7',
163 'aa6a0de05b7612707db567078e130a6cd114a9a7',
164 'eada5a770da98ab0dd7325e29d00e0714f228d09'
164 'eada5a770da98ab0dd7325e29d00e0714f228d09'
165 ])
165 ])
166 assert subset.issubset(set(self.repo.commit_ids))
166 assert subset.issubset(set(self.repo.commit_ids))
167
167
168 # check if we have the proper order of commits
168 # check if we have the proper order of commits
169 org = [
169 org = [
170 'b986218ba1c9b0d6a259fac9b050b1724ed8e545',
170 'b986218ba1c9b0d6a259fac9b050b1724ed8e545',
171 '3d8f361e72ab303da48d799ff1ac40d5ac37c67e',
171 '3d8f361e72ab303da48d799ff1ac40d5ac37c67e',
172 '6cba7170863a2411822803fa77a0a264f1310b35',
172 '6cba7170863a2411822803fa77a0a264f1310b35',
173 '56349e29c2af3ac913b28bde9a2c6154436e615b',
173 '56349e29c2af3ac913b28bde9a2c6154436e615b',
174 '2dda4e345facb0ccff1a191052dd1606dba6781d',
174 '2dda4e345facb0ccff1a191052dd1606dba6781d',
175 '6fff84722075f1607a30f436523403845f84cd9e',
175 '6fff84722075f1607a30f436523403845f84cd9e',
176 '7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7',
176 '7d4bc8ec6be56c0f10425afb40b6fc315a4c25e7',
177 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb',
177 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb',
178 'dc5d2c0661b61928834a785d3e64a3f80d3aad9c',
178 'dc5d2c0661b61928834a785d3e64a3f80d3aad9c',
179 'be90031137367893f1c406e0a8683010fd115b79',
179 'be90031137367893f1c406e0a8683010fd115b79',
180 'db8e58be770518cbb2b1cdfa69146e47cd481481',
180 'db8e58be770518cbb2b1cdfa69146e47cd481481',
181 '84478366594b424af694a6c784cb991a16b87c21',
181 '84478366594b424af694a6c784cb991a16b87c21',
182 '17f8e105dddb9f339600389c6dc7175d395a535c',
182 '17f8e105dddb9f339600389c6dc7175d395a535c',
183 '20a662e756499bde3095ffc9bc0643d1def2d0eb',
183 '20a662e756499bde3095ffc9bc0643d1def2d0eb',
184 '2e319b85e70a707bba0beff866d9f9de032aa4f9',
184 '2e319b85e70a707bba0beff866d9f9de032aa4f9',
185 '786facd2c61deb9cf91e9534735124fb8fc11842',
185 '786facd2c61deb9cf91e9534735124fb8fc11842',
186 '94593d2128d38210a2fcd1aabff6dda0d6d9edf8',
186 '94593d2128d38210a2fcd1aabff6dda0d6d9edf8',
187 'aa6a0de05b7612707db567078e130a6cd114a9a7',
187 'aa6a0de05b7612707db567078e130a6cd114a9a7',
188 'eada5a770da98ab0dd7325e29d00e0714f228d09',
188 'eada5a770da98ab0dd7325e29d00e0714f228d09',
189 '2c1885c735575ca478bf9e17b0029dca68824458',
189 '2c1885c735575ca478bf9e17b0029dca68824458',
190 'd9bcd465040bf869799b09ad732c04e0eea99fe9',
190 'd9bcd465040bf869799b09ad732c04e0eea99fe9',
191 '469e9c847fe1f6f7a697b8b25b4bc5b48780c1a7',
191 '469e9c847fe1f6f7a697b8b25b4bc5b48780c1a7',
192 '4fb8326d78e5120da2c7468dcf7098997be385da',
192 '4fb8326d78e5120da2c7468dcf7098997be385da',
193 '62b4a097164940bd66030c4db51687f3ec035eed',
193 '62b4a097164940bd66030c4db51687f3ec035eed',
194 '536c1a19428381cfea92ac44985304f6a8049569',
194 '536c1a19428381cfea92ac44985304f6a8049569',
195 '965e8ab3c44b070cdaa5bf727ddef0ada980ecc4',
195 '965e8ab3c44b070cdaa5bf727ddef0ada980ecc4',
196 '9bb326a04ae5d98d437dece54be04f830cf1edd9',
196 '9bb326a04ae5d98d437dece54be04f830cf1edd9',
197 'f8940bcb890a98c4702319fbe36db75ea309b475',
197 'f8940bcb890a98c4702319fbe36db75ea309b475',
198 'ff5ab059786ebc7411e559a2cc309dfae3625a3b',
198 'ff5ab059786ebc7411e559a2cc309dfae3625a3b',
199 '6b6ad5f82ad5bb6190037671bd254bd4e1f4bf08',
199 '6b6ad5f82ad5bb6190037671bd254bd4e1f4bf08',
200 'ee87846a61c12153b51543bf860e1026c6d3dcba',
200 'ee87846a61c12153b51543bf860e1026c6d3dcba',
201 ]
201 ]
202 assert org == self.repo.commit_ids[:31]
202 assert org == self.repo.commit_ids[:31]
203
203
204 def test_iter_slice(self):
204 def test_iter_slice(self):
205 sliced = list(self.repo[:10])
205 sliced = list(self.repo[:10])
206 itered = list(self.repo)[:10]
206 itered = list(self.repo)[:10]
207 assert sliced == itered
207 assert sliced == itered
208
208
209 def test_slicing(self):
209 def test_slicing(self):
210 # 4 1 5 10 95
210 # 4 1 5 10 95
211 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
211 for sfrom, sto, size in [(0, 4, 4), (1, 2, 1), (10, 15, 5),
212 (10, 20, 10), (5, 100, 95)]:
212 (10, 20, 10), (5, 100, 95)]:
213 indexes = list(self.repo[sfrom:sto])
213 indexes = list(self.repo[sfrom:sto])
214 assert len(indexes) == size
214 assert len(indexes) == size
215 assert indexes[0] == self.repo.get_commit(commit_idx=sfrom)
215 assert indexes[0] == self.repo.get_commit(commit_idx=sfrom)
216 assert indexes[-1] == self.repo.get_commit(commit_idx=sto - 1)
216 assert indexes[-1] == self.repo.get_commit(commit_idx=sto - 1)
217
217
218 def test_branches(self):
218 def test_branches(self):
219 # TODO: Need more tests here
219 # TODO: Need more tests here
220
220
221 # active branches
221 # active branches
222 assert 'default' in self.repo.branches
222 assert 'default' in self.repo.branches
223 assert 'stable' in self.repo.branches
223 assert 'stable' in self.repo.branches
224
224
225 # closed
225 # closed
226 assert 'git' in self.repo._get_branches(closed=True)
226 assert 'git' in self.repo._get_branches(closed=True)
227 assert 'web' in self.repo._get_branches(closed=True)
227 assert 'web' in self.repo._get_branches(closed=True)
228
228
229 for name, id in self.repo.branches.items():
229 for name, id in self.repo.branches.items():
230 assert isinstance(self.repo.get_commit(id), MercurialCommit)
230 assert isinstance(self.repo.get_commit(id), MercurialCommit)
231
231
232 def test_tip_in_tags(self):
232 def test_tip_in_tags(self):
233 # tip is always a tag
233 # tip is always a tag
234 assert 'tip' in self.repo.tags
234 assert 'tip' in self.repo.tags
235
235
236 def test_tip_commit_in_tags(self):
236 def test_tip_commit_in_tags(self):
237 tip = self.repo.get_commit()
237 tip = self.repo.get_commit()
238 assert self.repo.tags['tip'] == tip.raw_id
238 assert self.repo.tags['tip'] == tip.raw_id
239
239
240 def test_initial_commit(self):
240 def test_initial_commit(self):
241 init_commit = self.repo.get_commit(commit_idx=0)
241 init_commit = self.repo.get_commit(commit_idx=0)
242 init_author = init_commit.author
242 init_author = init_commit.author
243
243
244 assert init_commit.message == 'initial import'
244 assert init_commit.message == 'initial import'
245 assert init_author == 'Marcin Kuzminski <marcin@python-blog.com>'
245 assert init_author == 'Marcin Kuzminski <marcin@python-blog.com>'
246 assert init_author == init_commit.committer
246 assert init_author == init_commit.committer
247 assert sorted(init_commit._file_paths) == sorted([
247 assert sorted(init_commit._file_paths) == sorted([
248 'vcs/__init__.py',
248 'vcs/__init__.py',
249 'vcs/backends/BaseRepository.py',
249 'vcs/backends/BaseRepository.py',
250 'vcs/backends/__init__.py',
250 'vcs/backends/__init__.py',
251 ])
251 ])
252 assert sorted(init_commit._dir_paths) == sorted(
252 assert sorted(init_commit._dir_paths) == sorted(
253 ['', 'vcs', 'vcs/backends'])
253 ['', 'vcs', 'vcs/backends'])
254
254
255 assert init_commit._dir_paths + init_commit._file_paths == \
255 assert init_commit._dir_paths + init_commit._file_paths == \
256 init_commit._paths
256 init_commit._paths
257
257
258 with pytest.raises(NodeDoesNotExistError):
258 with pytest.raises(NodeDoesNotExistError):
259 init_commit.get_node(path='foobar')
259 init_commit.get_node(path='foobar')
260
260
261 node = init_commit.get_node('vcs/')
261 node = init_commit.get_node('vcs/')
262 assert hasattr(node, 'kind')
262 assert hasattr(node, 'kind')
263 assert node.kind == NodeKind.DIR
263 assert node.kind == NodeKind.DIR
264
264
265 node = init_commit.get_node('vcs')
265 node = init_commit.get_node('vcs')
266 assert hasattr(node, 'kind')
266 assert hasattr(node, 'kind')
267 assert node.kind == NodeKind.DIR
267 assert node.kind == NodeKind.DIR
268
268
269 node = init_commit.get_node('vcs/__init__.py')
269 node = init_commit.get_node('vcs/__init__.py')
270 assert hasattr(node, 'kind')
270 assert hasattr(node, 'kind')
271 assert node.kind == NodeKind.FILE
271 assert node.kind == NodeKind.FILE
272
272
273 def test_not_existing_commit(self):
273 def test_not_existing_commit(self):
274 # rawid
274 # rawid
275 with pytest.raises(RepositoryError):
275 with pytest.raises(RepositoryError):
276 self.repo.get_commit('abcd' * 10)
276 self.repo.get_commit('abcd' * 10)
277 # shortid
277 # shortid
278 with pytest.raises(RepositoryError):
278 with pytest.raises(RepositoryError):
279 self.repo.get_commit('erro' * 4)
279 self.repo.get_commit('erro' * 4)
280 # numeric
280 # numeric
281 with pytest.raises(RepositoryError):
281 with pytest.raises(RepositoryError):
282 self.repo.get_commit(commit_idx=self.repo.count() + 1)
282 self.repo.get_commit(commit_idx=self.repo.count() + 1)
283
283
284 # Small chance we ever get to this one
284 # Small chance we ever get to this one
285 idx = pow(2, 30)
285 idx = pow(2, 30)
286 with pytest.raises(RepositoryError):
286 with pytest.raises(RepositoryError):
287 self.repo.get_commit(commit_idx=idx)
287 self.repo.get_commit(commit_idx=idx)
288
288
289 def test_commit10(self):
289 def test_commit10(self):
290 commit10 = self.repo.get_commit(commit_idx=10)
290 commit10 = self.repo.get_commit(commit_idx=10)
291 README = """===
291 README = """===
292 VCS
292 VCS
293 ===
293 ===
294
294
295 Various Version Control System management abstraction layer for Python.
295 Various Version Control System management abstraction layer for Python.
296
296
297 Introduction
297 Introduction
298 ------------
298 ------------
299
299
300 TODO: To be written...
300 TODO: To be written...
301
301
302 """
302 """
303 node = commit10.get_node('README.rst')
303 node = commit10.get_node('README.rst')
304 assert node.kind == NodeKind.FILE
304 assert node.kind == NodeKind.FILE
305 assert node.content == README
305 assert node.content == README
306
306
307 def test_local_clone(self):
307 def test_local_clone(self):
308 clone_path = next(REPO_PATH_GENERATOR)
308 clone_path = next(REPO_PATH_GENERATOR)
309 self.repo._local_clone(clone_path)
309 self.repo._local_clone(clone_path)
310 repo_clone = MercurialRepository(clone_path)
310 repo_clone = MercurialRepository(clone_path)
311
311
312 assert self.repo.commit_ids == repo_clone.commit_ids
312 assert self.repo.commit_ids == repo_clone.commit_ids
313
313
314 def test_local_clone_fails_if_target_exists(self):
314 def test_local_clone_fails_if_target_exists(self):
315 with pytest.raises(RepositoryError):
315 with pytest.raises(RepositoryError):
316 self.repo._local_clone(self.repo.path)
316 self.repo._local_clone(self.repo.path)
317
317
318 def test_update(self):
318 def test_update(self):
319 repo_clone = self.get_clone_repo()
319 repo_clone = self.get_clone_repo()
320 branches = repo_clone.branches
320 branches = repo_clone.branches
321
321
322 repo_clone._update('default')
322 repo_clone._update('default')
323 assert branches['default'] == repo_clone._identify()
323 assert branches['default'] == repo_clone._identify()
324 repo_clone._update('stable')
324 repo_clone._update('stable')
325 assert branches['stable'] == repo_clone._identify()
325 assert branches['stable'] == repo_clone._identify()
326
326
327 def test_local_pull_branch(self):
327 def test_local_pull_branch(self):
328 target_repo = self.get_empty_repo()
328 target_repo = self.get_empty_repo()
329 source_repo = self.get_clone_repo()
329 source_repo = self.get_clone_repo()
330
330
331 default = Reference(
331 default = Reference(
332 'branch', 'default', source_repo.branches['default'])
332 'branch', 'default', source_repo.branches['default'])
333 target_repo._local_pull(source_repo.path, default)
333 target_repo._local_pull(source_repo.path, default)
334 target_repo = MercurialRepository(target_repo.path)
334 target_repo = MercurialRepository(target_repo.path)
335 assert (target_repo.branches['default'] ==
335 assert (target_repo.branches['default'] ==
336 source_repo.branches['default'])
336 source_repo.branches['default'])
337
337
338 stable = Reference('branch', 'stable', source_repo.branches['stable'])
338 stable = Reference('branch', 'stable', source_repo.branches['stable'])
339 target_repo._local_pull(source_repo.path, stable)
339 target_repo._local_pull(source_repo.path, stable)
340 target_repo = MercurialRepository(target_repo.path)
340 target_repo = MercurialRepository(target_repo.path)
341 assert target_repo.branches['stable'] == source_repo.branches['stable']
341 assert target_repo.branches['stable'] == source_repo.branches['stable']
342
342
343 def test_local_pull_bookmark(self):
343 def test_local_pull_bookmark(self):
344 target_repo = self.get_empty_repo()
344 target_repo = self.get_empty_repo()
345 source_repo = self.get_clone_repo()
345 source_repo = self.get_clone_repo()
346
346
347 commits = list(source_repo.get_commits(branch_name='default'))
347 commits = list(source_repo.get_commits(branch_name='default'))
348 foo1_id = commits[-5].raw_id
348 foo1_id = commits[-5].raw_id
349 foo1 = Reference('book', 'foo1', foo1_id)
349 foo1 = Reference('book', 'foo1', foo1_id)
350 source_repo._update(foo1_id)
350 source_repo._update(foo1_id)
351 source_repo.bookmark('foo1')
351 source_repo.bookmark('foo1')
352
352
353 foo2_id = commits[-3].raw_id
353 foo2_id = commits[-3].raw_id
354 foo2 = Reference('book', 'foo2', foo2_id)
354 foo2 = Reference('book', 'foo2', foo2_id)
355 source_repo._update(foo2_id)
355 source_repo._update(foo2_id)
356 source_repo.bookmark('foo2')
356 source_repo.bookmark('foo2')
357
357
358 target_repo._local_pull(source_repo.path, foo1)
358 target_repo._local_pull(source_repo.path, foo1)
359 target_repo = MercurialRepository(target_repo.path)
359 target_repo = MercurialRepository(target_repo.path)
360 assert target_repo.branches['default'] == commits[-5].raw_id
360 assert target_repo.branches['default'] == commits[-5].raw_id
361
361
362 target_repo._local_pull(source_repo.path, foo2)
362 target_repo._local_pull(source_repo.path, foo2)
363 target_repo = MercurialRepository(target_repo.path)
363 target_repo = MercurialRepository(target_repo.path)
364 assert target_repo.branches['default'] == commits[-3].raw_id
364 assert target_repo.branches['default'] == commits[-3].raw_id
365
365
366 def test_local_pull_commit(self):
366 def test_local_pull_commit(self):
367 target_repo = self.get_empty_repo()
367 target_repo = self.get_empty_repo()
368 source_repo = self.get_clone_repo()
368 source_repo = self.get_clone_repo()
369
369
370 commits = list(source_repo.get_commits(branch_name='default'))
370 commits = list(source_repo.get_commits(branch_name='default'))
371 commit_id = commits[-5].raw_id
371 commit_id = commits[-5].raw_id
372 commit = Reference('rev', commit_id, commit_id)
372 commit = Reference('rev', commit_id, commit_id)
373 target_repo._local_pull(source_repo.path, commit)
373 target_repo._local_pull(source_repo.path, commit)
374 target_repo = MercurialRepository(target_repo.path)
374 target_repo = MercurialRepository(target_repo.path)
375 assert target_repo.branches['default'] == commit_id
375 assert target_repo.branches['default'] == commit_id
376
376
377 commit_id = commits[-3].raw_id
377 commit_id = commits[-3].raw_id
378 commit = Reference('rev', commit_id, commit_id)
378 commit = Reference('rev', commit_id, commit_id)
379 target_repo._local_pull(source_repo.path, commit)
379 target_repo._local_pull(source_repo.path, commit)
380 target_repo = MercurialRepository(target_repo.path)
380 target_repo = MercurialRepository(target_repo.path)
381 assert target_repo.branches['default'] == commit_id
381 assert target_repo.branches['default'] == commit_id
382
382
383 def test_local_pull_from_same_repo(self):
383 def test_local_pull_from_same_repo(self):
384 reference = Reference('branch', 'default', None)
384 reference = Reference('branch', 'default', None)
385 with pytest.raises(ValueError):
385 with pytest.raises(ValueError):
386 self.repo._local_pull(self.repo.path, reference)
386 self.repo._local_pull(self.repo.path, reference)
387
387
388 def test_validate_pull_reference_raises_on_missing_reference(
388 def test_validate_pull_reference_raises_on_missing_reference(
389 self, vcsbackend_hg):
389 self, vcsbackend_hg):
390 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
390 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
391 reference = Reference(
391 reference = Reference(
392 'book', 'invalid_reference', 'a' * 40)
392 'book', 'invalid_reference', 'a' * 40)
393
393
394 with pytest.raises(CommitDoesNotExistError):
394 with pytest.raises(CommitDoesNotExistError):
395 target_repo._validate_pull_reference(reference)
395 target_repo._validate_pull_reference(reference)
396
396
397 def test_heads(self):
397 def test_heads(self):
398 assert set(self.repo._heads()) == set(self.repo.branches.values())
398 assert set(self.repo._heads()) == set(self.repo.branches.values())
399
399
400 def test_ancestor(self):
400 def test_ancestor(self):
401 commits = [
401 commits = [
402 c.raw_id for c in self.repo.get_commits(branch_name='default')]
402 c.raw_id for c in self.repo.get_commits(branch_name='default')]
403 assert self.repo._ancestor(commits[-3], commits[-5]) == commits[-5]
403 assert self.repo._ancestor(commits[-3], commits[-5]) == commits[-5]
404 assert self.repo._ancestor(commits[-5], commits[-3]) == commits[-5]
404 assert self.repo._ancestor(commits[-5], commits[-3]) == commits[-5]
405
405
406 def test_local_push(self):
406 def test_local_push(self):
407 target_repo = self.get_empty_repo()
407 target_repo = self.get_empty_repo()
408
408
409 revisions = list(self.repo.get_commits(branch_name='default'))
409 revisions = list(self.repo.get_commits(branch_name='default'))
410 revision = revisions[-5].raw_id
410 revision = revisions[-5].raw_id
411 self.repo._local_push(revision, target_repo.path)
411 self.repo._local_push(revision, target_repo.path)
412
412
413 target_repo = MercurialRepository(target_repo.path)
413 target_repo = MercurialRepository(target_repo.path)
414
414
415 assert target_repo.branches['default'] == revision
415 assert target_repo.branches['default'] == revision
416
416
417 def test_hooks_can_be_enabled_for_local_push(self):
417 def test_hooks_can_be_enabled_for_local_push(self):
418 revision = 'deadbeef'
418 revision = 'deadbeef'
419 repo_path = 'test_group/test_repo'
419 repo_path = 'test_group/test_repo'
420 with mock.patch.object(self.repo, '_remote') as remote_mock:
420 with mock.patch.object(self.repo, '_remote') as remote_mock:
421 self.repo._local_push(revision, repo_path, enable_hooks=True)
421 self.repo._local_push(revision, repo_path, enable_hooks=True)
422 remote_mock.push.assert_called_once_with(
422 remote_mock.push.assert_called_once_with(
423 [revision], repo_path, hooks=True, push_branches=False)
423 [revision], repo_path, hooks=True, push_branches=False)
424
424
425 def test_local_merge(self, vcsbackend_hg):
425 def test_local_merge(self, vcsbackend_hg):
426 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
426 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
427 source_repo = vcsbackend_hg.clone_repo(target_repo)
427 source_repo = vcsbackend_hg.clone_repo(target_repo)
428 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
428 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
429 target_repo = MercurialRepository(target_repo.path)
429 target_repo = MercurialRepository(target_repo.path)
430 target_rev = target_repo.branches['default']
430 target_rev = target_repo.branches['default']
431 target_ref = Reference(
431 target_ref = Reference(
432 type='branch', name='default', commit_id=target_rev)
432 type='branch', name='default', commit_id=target_rev)
433 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
433 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
434 source_repo = MercurialRepository(source_repo.path)
434 source_repo = MercurialRepository(source_repo.path)
435 source_rev = source_repo.branches['default']
435 source_rev = source_repo.branches['default']
436 source_ref = Reference(
436 source_ref = Reference(
437 type='branch', name='default', commit_id=source_rev)
437 type='branch', name='default', commit_id=source_rev)
438
438
439 target_repo._local_pull(source_repo.path, source_ref)
439 target_repo._local_pull(source_repo.path, source_ref)
440
440
441 merge_message = 'Merge message\n\nDescription:...'
441 merge_message = 'Merge message\n\nDescription:...'
442 user_name = 'Albert Einstein'
442 user_name = 'Albert Einstein'
443 user_email = 'albert@einstein.com'
443 user_email = 'albert@einstein.com'
444 merge_commit_id, needs_push = target_repo._local_merge(
444 merge_commit_id, needs_push = target_repo._local_merge(
445 target_ref, merge_message, user_name, user_email, source_ref)
445 target_ref, merge_message, user_name, user_email, source_ref)
446 assert needs_push
446 assert needs_push
447
447
448 target_repo = MercurialRepository(target_repo.path)
448 target_repo = MercurialRepository(target_repo.path)
449 assert target_repo.commit_ids[-3] == target_rev
449 assert target_repo.commit_ids[-3] == target_rev
450 assert target_repo.commit_ids[-2] == source_rev
450 assert target_repo.commit_ids[-2] == source_rev
451 last_commit = target_repo.get_commit(merge_commit_id)
451 last_commit = target_repo.get_commit(merge_commit_id)
452 assert last_commit.message.strip() == merge_message
452 assert last_commit.message.strip() == merge_message
453 assert last_commit.author == '%s <%s>' % (user_name, user_email)
453 assert last_commit.author == '%s <%s>' % (user_name, user_email)
454
454
455 assert not os.path.exists(
455 assert not os.path.exists(
456 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
456 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
457
457
458 def test_local_merge_source_is_fast_forward(self, vcsbackend_hg):
458 def test_local_merge_source_is_fast_forward(self, vcsbackend_hg):
459 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
459 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
460 source_repo = vcsbackend_hg.clone_repo(target_repo)
460 source_repo = vcsbackend_hg.clone_repo(target_repo)
461 target_rev = target_repo.branches['default']
461 target_rev = target_repo.branches['default']
462 target_ref = Reference(
462 target_ref = Reference(
463 type='branch', name='default', commit_id=target_rev)
463 type='branch', name='default', commit_id=target_rev)
464 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
464 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
465 source_repo = MercurialRepository(source_repo.path)
465 source_repo = MercurialRepository(source_repo.path)
466 source_rev = source_repo.branches['default']
466 source_rev = source_repo.branches['default']
467 source_ref = Reference(
467 source_ref = Reference(
468 type='branch', name='default', commit_id=source_rev)
468 type='branch', name='default', commit_id=source_rev)
469
469
470 target_repo._local_pull(source_repo.path, source_ref)
470 target_repo._local_pull(source_repo.path, source_ref)
471
471
472 merge_message = 'Merge message\n\nDescription:...'
472 merge_message = 'Merge message\n\nDescription:...'
473 user_name = 'Albert Einstein'
473 user_name = 'Albert Einstein'
474 user_email = 'albert@einstein.com'
474 user_email = 'albert@einstein.com'
475 merge_commit_id, needs_push = target_repo._local_merge(
475 merge_commit_id, needs_push = target_repo._local_merge(
476 target_ref, merge_message, user_name, user_email, source_ref)
476 target_ref, merge_message, user_name, user_email, source_ref)
477 assert merge_commit_id == source_rev
477 assert merge_commit_id == source_rev
478 assert needs_push
478 assert needs_push
479
479
480 target_repo = MercurialRepository(target_repo.path)
480 target_repo = MercurialRepository(target_repo.path)
481 assert target_repo.commit_ids[-2] == target_rev
481 assert target_repo.commit_ids[-2] == target_rev
482 assert target_repo.commit_ids[-1] == source_rev
482 assert target_repo.commit_ids[-1] == source_rev
483
483
484 assert not os.path.exists(
484 assert not os.path.exists(
485 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
485 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
486
486
487 def test_local_merge_source_is_integrated(self, vcsbackend_hg):
487 def test_local_merge_source_is_integrated(self, vcsbackend_hg):
488 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
488 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
489 target_rev = target_repo.branches['default']
489 target_rev = target_repo.branches['default']
490 target_ref = Reference(
490 target_ref = Reference(
491 type='branch', name='default', commit_id=target_rev)
491 type='branch', name='default', commit_id=target_rev)
492
492
493 merge_message = 'Merge message\n\nDescription:...'
493 merge_message = 'Merge message\n\nDescription:...'
494 user_name = 'Albert Einstein'
494 user_name = 'Albert Einstein'
495 user_email = 'albert@einstein.com'
495 user_email = 'albert@einstein.com'
496 merge_commit_id, needs_push = target_repo._local_merge(
496 merge_commit_id, needs_push = target_repo._local_merge(
497 target_ref, merge_message, user_name, user_email, target_ref)
497 target_ref, merge_message, user_name, user_email, target_ref)
498 assert merge_commit_id == target_rev
498 assert merge_commit_id == target_rev
499 assert not needs_push
499 assert not needs_push
500
500
501 target_repo = MercurialRepository(target_repo.path)
501 target_repo = MercurialRepository(target_repo.path)
502 assert target_repo.commit_ids[-1] == target_rev
502 assert target_repo.commit_ids[-1] == target_rev
503
503
504 assert not os.path.exists(
504 assert not os.path.exists(
505 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
505 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
506
506
507 def test_local_merge_raises_exception_on_conflict(self, vcsbackend_hg):
507 def test_local_merge_raises_exception_on_conflict(self, vcsbackend_hg):
508 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
508 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
509 source_repo = vcsbackend_hg.clone_repo(target_repo)
509 source_repo = vcsbackend_hg.clone_repo(target_repo)
510 vcsbackend_hg.add_file(target_repo, 'README_MERGE', 'Version 1')
510 vcsbackend_hg.add_file(target_repo, 'README_MERGE', 'Version 1')
511 target_repo = MercurialRepository(target_repo.path)
511 target_repo = MercurialRepository(target_repo.path)
512 target_rev = target_repo.branches['default']
512 target_rev = target_repo.branches['default']
513 target_ref = Reference(
513 target_ref = Reference(
514 type='branch', name='default', commit_id=target_rev)
514 type='branch', name='default', commit_id=target_rev)
515 vcsbackend_hg.add_file(source_repo, 'README_MERGE', 'Version 2')
515 vcsbackend_hg.add_file(source_repo, 'README_MERGE', 'Version 2')
516 source_repo = MercurialRepository(source_repo.path)
516 source_repo = MercurialRepository(source_repo.path)
517 source_rev = source_repo.branches['default']
517 source_rev = source_repo.branches['default']
518 source_ref = Reference(
518 source_ref = Reference(
519 type='branch', name='default', commit_id=source_rev)
519 type='branch', name='default', commit_id=source_rev)
520
520
521 target_repo._local_pull(source_repo.path, source_ref)
521 target_repo._local_pull(source_repo.path, source_ref)
522 with pytest.raises(RepositoryError):
522 with pytest.raises(RepositoryError):
523 target_repo._local_merge(
523 target_repo._local_merge(
524 target_ref, 'merge_message', 'user name', 'user@name.com',
524 target_ref, 'merge_message', 'user name', 'user@name.com',
525 source_ref)
525 source_ref)
526
526
527 # Check we are not left in an intermediate merge state
527 # Check we are not left in an intermediate merge state
528 assert not os.path.exists(
528 assert not os.path.exists(
529 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
529 os.path.join(target_repo.path, '.hg', 'merge', 'state'))
530
530
531 def test_local_merge_of_two_branches_of_the_same_repo(self, backend_hg):
531 def test_local_merge_of_two_branches_of_the_same_repo(self, backend_hg):
532 commits = [
532 commits = [
533 {'message': 'a'},
533 {'message': 'a'},
534 {'message': 'b', 'branch': 'b'},
534 {'message': 'b', 'branch': 'b'},
535 ]
535 ]
536 repo = backend_hg.create_repo(commits)
536 repo = backend_hg.create_repo(commits)
537 commit_ids = backend_hg.commit_ids
537 commit_ids = backend_hg.commit_ids
538 target_ref = Reference(
538 target_ref = Reference(
539 type='branch', name='default', commit_id=commit_ids['a'])
539 type='branch', name='default', commit_id=commit_ids['a'])
540 source_ref = Reference(
540 source_ref = Reference(
541 type='branch', name='b', commit_id=commit_ids['b'])
541 type='branch', name='b', commit_id=commit_ids['b'])
542 merge_message = 'Merge message\n\nDescription:...'
542 merge_message = 'Merge message\n\nDescription:...'
543 user_name = 'Albert Einstein'
543 user_name = 'Albert Einstein'
544 user_email = 'albert@einstein.com'
544 user_email = 'albert@einstein.com'
545 vcs_repo = repo.scm_instance()
545 vcs_repo = repo.scm_instance()
546 merge_commit_id, needs_push = vcs_repo._local_merge(
546 merge_commit_id, needs_push = vcs_repo._local_merge(
547 target_ref, merge_message, user_name, user_email, source_ref)
547 target_ref, merge_message, user_name, user_email, source_ref)
548 assert merge_commit_id != source_ref.commit_id
548 assert merge_commit_id != source_ref.commit_id
549 assert needs_push is True
549 assert needs_push is True
550 commit = vcs_repo.get_commit(merge_commit_id)
550 commit = vcs_repo.get_commit(merge_commit_id)
551 assert commit.merge is True
551 assert commit.merge is True
552 assert commit.message == merge_message
552 assert commit.message == merge_message
553
553
554 def test_maybe_prepare_merge_workspace(self):
554 def test_maybe_prepare_merge_workspace(self):
555 workspace = self.repo._maybe_prepare_merge_workspace('pr2', 'unused')
555 workspace = self.repo._maybe_prepare_merge_workspace(
556 'pr2', 'unused', 'unused2')
556
557
557 assert os.path.isdir(workspace)
558 assert os.path.isdir(workspace)
558 workspace_repo = MercurialRepository(workspace)
559 workspace_repo = MercurialRepository(workspace)
559 assert workspace_repo.branches == self.repo.branches
560 assert workspace_repo.branches == self.repo.branches
560
561
561 # Calling it a second time should also succeed
562 # Calling it a second time should also succeed
562 workspace = self.repo._maybe_prepare_merge_workspace('pr2', 'unused')
563 workspace = self.repo._maybe_prepare_merge_workspace(
564 'pr2', 'unused', 'unused2')
563 assert os.path.isdir(workspace)
565 assert os.path.isdir(workspace)
564
566
565 def test_cleanup_merge_workspace(self):
567 def test_cleanup_merge_workspace(self):
566 workspace = self.repo._maybe_prepare_merge_workspace('pr3', 'unused')
568 workspace = self.repo._maybe_prepare_merge_workspace(
569 'pr3', 'unused', 'unused2')
567 self.repo.cleanup_merge_workspace('pr3')
570 self.repo.cleanup_merge_workspace('pr3')
568
571
569 assert not os.path.exists(workspace)
572 assert not os.path.exists(workspace)
570
573
571 def test_cleanup_merge_workspace_invalid_workspace_id(self):
574 def test_cleanup_merge_workspace_invalid_workspace_id(self):
572 # No assert: because in case of an inexistent workspace this function
575 # No assert: because in case of an inexistent workspace this function
573 # should still succeed.
576 # should still succeed.
574 self.repo.cleanup_merge_workspace('pr4')
577 self.repo.cleanup_merge_workspace('pr4')
575
578
576 def test_merge_target_is_bookmark(self, vcsbackend_hg):
579 def test_merge_target_is_bookmark(self, vcsbackend_hg):
577 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
580 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
578 source_repo = vcsbackend_hg.clone_repo(target_repo)
581 source_repo = vcsbackend_hg.clone_repo(target_repo)
579 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
582 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
580 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
583 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
581 imc = source_repo.in_memory_commit
584 imc = source_repo.in_memory_commit
582 imc.add(FileNode('file_x', content=source_repo.name))
585 imc.add(FileNode('file_x', content=source_repo.name))
583 imc.commit(
586 imc.commit(
584 message=u'Automatic commit from repo merge test',
587 message=u'Automatic commit from repo merge test',
585 author=u'Automatic')
588 author=u'Automatic')
586 target_commit = target_repo.get_commit()
589 target_commit = target_repo.get_commit()
587 source_commit = source_repo.get_commit()
590 source_commit = source_repo.get_commit()
588 default_branch = target_repo.DEFAULT_BRANCH_NAME
591 default_branch = target_repo.DEFAULT_BRANCH_NAME
589 bookmark_name = 'bookmark'
592 bookmark_name = 'bookmark'
590 target_repo._update(default_branch)
593 target_repo._update(default_branch)
591 target_repo.bookmark(bookmark_name)
594 target_repo.bookmark(bookmark_name)
592 target_ref = Reference('book', bookmark_name, target_commit.raw_id)
595 target_ref = Reference('book', bookmark_name, target_commit.raw_id)
593 source_ref = Reference('branch', default_branch, source_commit.raw_id)
596 source_ref = Reference('branch', default_branch, source_commit.raw_id)
594 workspace = 'test-merge'
597 workspace = 'test-merge'
595
598
596 merge_response = target_repo.merge(
599 merge_response = target_repo.merge(
597 target_ref, source_repo, source_ref, workspace,
600 target_ref, source_repo, source_ref, workspace,
598 'test user', 'test@rhodecode.com', 'merge message 1',
601 'test user', 'test@rhodecode.com', 'merge message 1',
599 dry_run=False)
602 dry_run=False)
600 expected_merge_response = MergeResponse(
603 expected_merge_response = MergeResponse(
601 True, True, merge_response.merge_ref,
604 True, True, merge_response.merge_ref,
602 MergeFailureReason.NONE)
605 MergeFailureReason.NONE)
603 assert merge_response == expected_merge_response
606 assert merge_response == expected_merge_response
604
607
605 target_repo = backends.get_backend(vcsbackend_hg.alias)(
608 target_repo = backends.get_backend(vcsbackend_hg.alias)(
606 target_repo.path)
609 target_repo.path)
607 target_commits = list(target_repo.get_commits())
610 target_commits = list(target_repo.get_commits())
608 commit_ids = [c.raw_id for c in target_commits[:-1]]
611 commit_ids = [c.raw_id for c in target_commits[:-1]]
609 assert source_ref.commit_id in commit_ids
612 assert source_ref.commit_id in commit_ids
610 assert target_ref.commit_id in commit_ids
613 assert target_ref.commit_id in commit_ids
611
614
612 merge_commit = target_commits[-1]
615 merge_commit = target_commits[-1]
613 assert merge_commit.raw_id == merge_response.merge_ref.commit_id
616 assert merge_commit.raw_id == merge_response.merge_ref.commit_id
614 assert merge_commit.message.strip() == 'merge message 1'
617 assert merge_commit.message.strip() == 'merge message 1'
615 assert merge_commit.author == 'test user <test@rhodecode.com>'
618 assert merge_commit.author == 'test user <test@rhodecode.com>'
616
619
617 # Check the bookmark was updated in the target repo
620 # Check the bookmark was updated in the target repo
618 assert (
621 assert (
619 target_repo.bookmarks[bookmark_name] ==
622 target_repo.bookmarks[bookmark_name] ==
620 merge_response.merge_ref.commit_id)
623 merge_response.merge_ref.commit_id)
621
624
622 def test_merge_source_is_bookmark(self, vcsbackend_hg):
625 def test_merge_source_is_bookmark(self, vcsbackend_hg):
623 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
626 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
624 source_repo = vcsbackend_hg.clone_repo(target_repo)
627 source_repo = vcsbackend_hg.clone_repo(target_repo)
625 imc = source_repo.in_memory_commit
628 imc = source_repo.in_memory_commit
626 imc.add(FileNode('file_x', content=source_repo.name))
629 imc.add(FileNode('file_x', content=source_repo.name))
627 imc.commit(
630 imc.commit(
628 message=u'Automatic commit from repo merge test',
631 message=u'Automatic commit from repo merge test',
629 author=u'Automatic')
632 author=u'Automatic')
630 target_commit = target_repo.get_commit()
633 target_commit = target_repo.get_commit()
631 source_commit = source_repo.get_commit()
634 source_commit = source_repo.get_commit()
632 default_branch = target_repo.DEFAULT_BRANCH_NAME
635 default_branch = target_repo.DEFAULT_BRANCH_NAME
633 bookmark_name = 'bookmark'
636 bookmark_name = 'bookmark'
634 target_ref = Reference('branch', default_branch, target_commit.raw_id)
637 target_ref = Reference('branch', default_branch, target_commit.raw_id)
635 source_repo._update(default_branch)
638 source_repo._update(default_branch)
636 source_repo.bookmark(bookmark_name)
639 source_repo.bookmark(bookmark_name)
637 source_ref = Reference('book', bookmark_name, source_commit.raw_id)
640 source_ref = Reference('book', bookmark_name, source_commit.raw_id)
638 workspace = 'test-merge'
641 workspace = 'test-merge'
639
642
640 merge_response = target_repo.merge(
643 merge_response = target_repo.merge(
641 target_ref, source_repo, source_ref, workspace,
644 target_ref, source_repo, source_ref, workspace,
642 'test user', 'test@rhodecode.com', 'merge message 1',
645 'test user', 'test@rhodecode.com', 'merge message 1',
643 dry_run=False)
646 dry_run=False)
644 expected_merge_response = MergeResponse(
647 expected_merge_response = MergeResponse(
645 True, True, merge_response.merge_ref,
648 True, True, merge_response.merge_ref,
646 MergeFailureReason.NONE)
649 MergeFailureReason.NONE)
647 assert merge_response == expected_merge_response
650 assert merge_response == expected_merge_response
648
651
649 target_repo = backends.get_backend(vcsbackend_hg.alias)(
652 target_repo = backends.get_backend(vcsbackend_hg.alias)(
650 target_repo.path)
653 target_repo.path)
651 target_commits = list(target_repo.get_commits())
654 target_commits = list(target_repo.get_commits())
652 commit_ids = [c.raw_id for c in target_commits]
655 commit_ids = [c.raw_id for c in target_commits]
653 assert source_ref.commit_id == commit_ids[-1]
656 assert source_ref.commit_id == commit_ids[-1]
654 assert target_ref.commit_id == commit_ids[-2]
657 assert target_ref.commit_id == commit_ids[-2]
655
658
656 def test_merge_target_has_multiple_heads(self, vcsbackend_hg):
659 def test_merge_target_has_multiple_heads(self, vcsbackend_hg):
657 target_repo = vcsbackend_hg.create_repo(number_of_commits=2)
660 target_repo = vcsbackend_hg.create_repo(number_of_commits=2)
658 source_repo = vcsbackend_hg.clone_repo(target_repo)
661 source_repo = vcsbackend_hg.clone_repo(target_repo)
659 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
662 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
660 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
663 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
661
664
662 # add an extra head to the target repo
665 # add an extra head to the target repo
663 imc = target_repo.in_memory_commit
666 imc = target_repo.in_memory_commit
664 imc.add(FileNode('file_x', content='foo'))
667 imc.add(FileNode('file_x', content='foo'))
665 commits = list(target_repo.get_commits())
668 commits = list(target_repo.get_commits())
666 imc.commit(
669 imc.commit(
667 message=u'Automatic commit from repo merge test',
670 message=u'Automatic commit from repo merge test',
668 author=u'Automatic', parents=commits[0:1])
671 author=u'Automatic', parents=commits[0:1])
669
672
670 target_commit = target_repo.get_commit()
673 target_commit = target_repo.get_commit()
671 source_commit = source_repo.get_commit()
674 source_commit = source_repo.get_commit()
672 default_branch = target_repo.DEFAULT_BRANCH_NAME
675 default_branch = target_repo.DEFAULT_BRANCH_NAME
673 target_repo._update(default_branch)
676 target_repo._update(default_branch)
674
677
675 target_ref = Reference('branch', default_branch, target_commit.raw_id)
678 target_ref = Reference('branch', default_branch, target_commit.raw_id)
676 source_ref = Reference('branch', default_branch, source_commit.raw_id)
679 source_ref = Reference('branch', default_branch, source_commit.raw_id)
677 workspace = 'test-merge'
680 workspace = 'test-merge'
678
681
679 assert len(target_repo._heads(branch='default')) == 2
682 assert len(target_repo._heads(branch='default')) == 2
680 expected_merge_response = MergeResponse(
683 expected_merge_response = MergeResponse(
681 False, False, None,
684 False, False, None,
682 MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS)
685 MergeFailureReason.HG_TARGET_HAS_MULTIPLE_HEADS)
683 merge_response = target_repo.merge(
686 merge_response = target_repo.merge(
684 target_ref, source_repo, source_ref, workspace,
687 target_ref, source_repo, source_ref, workspace,
685 'test user', 'test@rhodecode.com', 'merge message 1',
688 'test user', 'test@rhodecode.com', 'merge message 1',
686 dry_run=False)
689 dry_run=False)
687 assert merge_response == expected_merge_response
690 assert merge_response == expected_merge_response
688
691
689 def test_merge_rebase_source_is_updated_bookmark(self, vcsbackend_hg):
692 def test_merge_rebase_source_is_updated_bookmark(self, vcsbackend_hg):
690 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
693 target_repo = vcsbackend_hg.create_repo(number_of_commits=1)
691 source_repo = vcsbackend_hg.clone_repo(target_repo)
694 source_repo = vcsbackend_hg.clone_repo(target_repo)
692 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
695 vcsbackend_hg.add_file(target_repo, 'README_MERGE1', 'Version 1')
693 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
696 vcsbackend_hg.add_file(source_repo, 'README_MERGE2', 'Version 2')
694 imc = source_repo.in_memory_commit
697 imc = source_repo.in_memory_commit
695 imc.add(FileNode('file_x', content=source_repo.name))
698 imc.add(FileNode('file_x', content=source_repo.name))
696 imc.commit(
699 imc.commit(
697 message=u'Automatic commit from repo merge test',
700 message=u'Automatic commit from repo merge test',
698 author=u'Automatic')
701 author=u'Automatic')
699 target_commit = target_repo.get_commit()
702 target_commit = target_repo.get_commit()
700 source_commit = source_repo.get_commit()
703 source_commit = source_repo.get_commit()
701
704
702 vcsbackend_hg.add_file(source_repo, 'LICENSE', 'LICENSE Info')
705 vcsbackend_hg.add_file(source_repo, 'LICENSE', 'LICENSE Info')
703
706
704 default_branch = target_repo.DEFAULT_BRANCH_NAME
707 default_branch = target_repo.DEFAULT_BRANCH_NAME
705 bookmark_name = 'bookmark'
708 bookmark_name = 'bookmark'
706 source_repo._update(default_branch)
709 source_repo._update(default_branch)
707 source_repo.bookmark(bookmark_name)
710 source_repo.bookmark(bookmark_name)
708
711
709 target_ref = Reference('branch', default_branch, target_commit.raw_id)
712 target_ref = Reference('branch', default_branch, target_commit.raw_id)
710 source_ref = Reference('book', bookmark_name, source_commit.raw_id)
713 source_ref = Reference('book', bookmark_name, source_commit.raw_id)
711 workspace = 'test-merge'
714 workspace = 'test-merge'
712
715
713 merge_response = target_repo.merge(
716 merge_response = target_repo.merge(
714 target_ref, source_repo, source_ref, workspace,
717 target_ref, source_repo, source_ref, workspace,
715 'test user', 'test@rhodecode.com', 'merge message 1',
718 'test user', 'test@rhodecode.com', 'merge message 1',
716 dry_run=False, use_rebase=True)
719 dry_run=False, use_rebase=True)
717
720
718 expected_merge_response = MergeResponse(
721 expected_merge_response = MergeResponse(
719 True, True, merge_response.merge_ref,
722 True, True, merge_response.merge_ref,
720 MergeFailureReason.NONE)
723 MergeFailureReason.NONE)
721 assert merge_response == expected_merge_response
724 assert merge_response == expected_merge_response
722
725
723 target_repo = backends.get_backend(vcsbackend_hg.alias)(
726 target_repo = backends.get_backend(vcsbackend_hg.alias)(
724 target_repo.path)
727 target_repo.path)
725 last_commit = target_repo.get_commit()
728 last_commit = target_repo.get_commit()
726 assert last_commit.message == source_commit.message
729 assert last_commit.message == source_commit.message
727 assert last_commit.author == source_commit.author
730 assert last_commit.author == source_commit.author
728 # This checks that we effectively did a rebase
731 # This checks that we effectively did a rebase
729 assert last_commit.raw_id != source_commit.raw_id
732 assert last_commit.raw_id != source_commit.raw_id
730
733
731 # Check the target has only 4 commits: 2 were already in target and
734 # Check the target has only 4 commits: 2 were already in target and
732 # only two should have been added
735 # only two should have been added
733 assert len(target_repo.commit_ids) == 2 + 2
736 assert len(target_repo.commit_ids) == 2 + 2
734
737
735
738
736 class TestGetShadowInstance(object):
739 class TestGetShadowInstance(object):
737
740
738 @pytest.fixture
741 @pytest.fixture
739 def repo(self, vcsbackend_hg, monkeypatch):
742 def repo(self, vcsbackend_hg, monkeypatch):
740 repo = vcsbackend_hg.repo
743 repo = vcsbackend_hg.repo
741 monkeypatch.setattr(repo, 'config', mock.Mock())
744 monkeypatch.setattr(repo, 'config', mock.Mock())
742 monkeypatch.setattr('rhodecode.lib.vcs.connection.Hg', mock.Mock())
745 monkeypatch.setattr('rhodecode.lib.vcs.connection.Hg', mock.Mock())
743 return repo
746 return repo
744
747
745 def test_passes_config(self, repo):
748 def test_passes_config(self, repo):
746 shadow = repo._get_shadow_instance(repo.path)
749 shadow = repo._get_shadow_instance(repo.path)
747 assert shadow.config == repo.config.copy()
750 assert shadow.config == repo.config.copy()
748
751
749 def test_disables_hooks(self, repo):
752 def test_disables_hooks(self, repo):
750 shadow = repo._get_shadow_instance(repo.path)
753 shadow = repo._get_shadow_instance(repo.path)
751 shadow.config.clear_section.assert_called_once_with('hooks')
754 shadow.config.clear_section.assert_called_once_with('hooks')
752
755
753 def test_allows_to_keep_hooks(self, repo):
756 def test_allows_to_keep_hooks(self, repo):
754 shadow = repo._get_shadow_instance(repo.path, enable_hooks=True)
757 shadow = repo._get_shadow_instance(repo.path, enable_hooks=True)
755 assert not shadow.config.clear_section.called
758 assert not shadow.config.clear_section.called
756
759
757
760
758 class TestMercurialCommit(object):
761 class TestMercurialCommit(object):
759
762
760 def _test_equality(self, commit):
763 def _test_equality(self, commit):
761 idx = commit.idx
764 idx = commit.idx
762 assert commit == self.repo.get_commit(commit_idx=idx)
765 assert commit == self.repo.get_commit(commit_idx=idx)
763
766
764 def test_equality(self):
767 def test_equality(self):
765 indexes = [0, 10, 20]
768 indexes = [0, 10, 20]
766 commits = [self.repo.get_commit(commit_idx=idx) for idx in indexes]
769 commits = [self.repo.get_commit(commit_idx=idx) for idx in indexes]
767 for commit in commits:
770 for commit in commits:
768 self._test_equality(commit)
771 self._test_equality(commit)
769
772
770 def test_default_commit(self):
773 def test_default_commit(self):
771 tip = self.repo.get_commit('tip')
774 tip = self.repo.get_commit('tip')
772 assert tip == self.repo.get_commit()
775 assert tip == self.repo.get_commit()
773 assert tip == self.repo.get_commit(commit_id=None)
776 assert tip == self.repo.get_commit(commit_id=None)
774 assert tip == self.repo.get_commit(commit_idx=None)
777 assert tip == self.repo.get_commit(commit_idx=None)
775 assert tip == list(self.repo[-1:])[0]
778 assert tip == list(self.repo[-1:])[0]
776
779
777 def test_root_node(self):
780 def test_root_node(self):
778 tip = self.repo.get_commit('tip')
781 tip = self.repo.get_commit('tip')
779 assert tip.root is tip.get_node('')
782 assert tip.root is tip.get_node('')
780
783
781 def test_lazy_fetch(self):
784 def test_lazy_fetch(self):
782 """
785 """
783 Test if commit's nodes expands and are cached as we walk through
786 Test if commit's nodes expands and are cached as we walk through
784 the commit. This test is somewhat hard to write as order of tests
787 the commit. This test is somewhat hard to write as order of tests
785 is a key here. Written by running command after command in a shell.
788 is a key here. Written by running command after command in a shell.
786 """
789 """
787 commit = self.repo.get_commit(commit_idx=45)
790 commit = self.repo.get_commit(commit_idx=45)
788 assert len(commit.nodes) == 0
791 assert len(commit.nodes) == 0
789 root = commit.root
792 root = commit.root
790 assert len(commit.nodes) == 1
793 assert len(commit.nodes) == 1
791 assert len(root.nodes) == 8
794 assert len(root.nodes) == 8
792 # accessing root.nodes updates commit.nodes
795 # accessing root.nodes updates commit.nodes
793 assert len(commit.nodes) == 9
796 assert len(commit.nodes) == 9
794
797
795 docs = root.get_node('docs')
798 docs = root.get_node('docs')
796 # we haven't yet accessed anything new as docs dir was already cached
799 # we haven't yet accessed anything new as docs dir was already cached
797 assert len(commit.nodes) == 9
800 assert len(commit.nodes) == 9
798 assert len(docs.nodes) == 8
801 assert len(docs.nodes) == 8
799 # accessing docs.nodes updates commit.nodes
802 # accessing docs.nodes updates commit.nodes
800 assert len(commit.nodes) == 17
803 assert len(commit.nodes) == 17
801
804
802 assert docs is commit.get_node('docs')
805 assert docs is commit.get_node('docs')
803 assert docs is root.nodes[0]
806 assert docs is root.nodes[0]
804 assert docs is root.dirs[0]
807 assert docs is root.dirs[0]
805 assert docs is commit.get_node('docs')
808 assert docs is commit.get_node('docs')
806
809
807 def test_nodes_with_commit(self):
810 def test_nodes_with_commit(self):
808 commit = self.repo.get_commit(commit_idx=45)
811 commit = self.repo.get_commit(commit_idx=45)
809 root = commit.root
812 root = commit.root
810 docs = root.get_node('docs')
813 docs = root.get_node('docs')
811 assert docs is commit.get_node('docs')
814 assert docs is commit.get_node('docs')
812 api = docs.get_node('api')
815 api = docs.get_node('api')
813 assert api is commit.get_node('docs/api')
816 assert api is commit.get_node('docs/api')
814 index = api.get_node('index.rst')
817 index = api.get_node('index.rst')
815 assert index is commit.get_node('docs/api/index.rst')
818 assert index is commit.get_node('docs/api/index.rst')
816 assert index is commit.get_node(
819 assert index is commit.get_node(
817 'docs').get_node('api').get_node('index.rst')
820 'docs').get_node('api').get_node('index.rst')
818
821
819 def test_branch_and_tags(self):
822 def test_branch_and_tags(self):
820 commit0 = self.repo.get_commit(commit_idx=0)
823 commit0 = self.repo.get_commit(commit_idx=0)
821 assert commit0.branch == 'default'
824 assert commit0.branch == 'default'
822 assert commit0.tags == []
825 assert commit0.tags == []
823
826
824 commit10 = self.repo.get_commit(commit_idx=10)
827 commit10 = self.repo.get_commit(commit_idx=10)
825 assert commit10.branch == 'default'
828 assert commit10.branch == 'default'
826 assert commit10.tags == []
829 assert commit10.tags == []
827
830
828 commit44 = self.repo.get_commit(commit_idx=44)
831 commit44 = self.repo.get_commit(commit_idx=44)
829 assert commit44.branch == 'web'
832 assert commit44.branch == 'web'
830
833
831 tip = self.repo.get_commit('tip')
834 tip = self.repo.get_commit('tip')
832 assert 'tip' in tip.tags
835 assert 'tip' in tip.tags
833
836
834 def test_bookmarks(self):
837 def test_bookmarks(self):
835 commit0 = self.repo.get_commit(commit_idx=0)
838 commit0 = self.repo.get_commit(commit_idx=0)
836 assert commit0.bookmarks == []
839 assert commit0.bookmarks == []
837
840
838 def _test_file_size(self, idx, path, size):
841 def _test_file_size(self, idx, path, size):
839 node = self.repo.get_commit(commit_idx=idx).get_node(path)
842 node = self.repo.get_commit(commit_idx=idx).get_node(path)
840 assert node.is_file()
843 assert node.is_file()
841 assert node.size == size
844 assert node.size == size
842
845
843 def test_file_size(self):
846 def test_file_size(self):
844 to_check = (
847 to_check = (
845 (10, 'setup.py', 1068),
848 (10, 'setup.py', 1068),
846 (20, 'setup.py', 1106),
849 (20, 'setup.py', 1106),
847 (60, 'setup.py', 1074),
850 (60, 'setup.py', 1074),
848
851
849 (10, 'vcs/backends/base.py', 2921),
852 (10, 'vcs/backends/base.py', 2921),
850 (20, 'vcs/backends/base.py', 3936),
853 (20, 'vcs/backends/base.py', 3936),
851 (60, 'vcs/backends/base.py', 6189),
854 (60, 'vcs/backends/base.py', 6189),
852 )
855 )
853 for idx, path, size in to_check:
856 for idx, path, size in to_check:
854 self._test_file_size(idx, path, size)
857 self._test_file_size(idx, path, size)
855
858
856 def test_file_history_from_commits(self):
859 def test_file_history_from_commits(self):
857 node = self.repo[10].get_node('setup.py')
860 node = self.repo[10].get_node('setup.py')
858 commit_ids = [commit.raw_id for commit in node.history]
861 commit_ids = [commit.raw_id for commit in node.history]
859 assert ['3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == commit_ids
862 assert ['3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == commit_ids
860
863
861 node = self.repo[20].get_node('setup.py')
864 node = self.repo[20].get_node('setup.py')
862 node_ids = [commit.raw_id for commit in node.history]
865 node_ids = [commit.raw_id for commit in node.history]
863 assert ['eada5a770da98ab0dd7325e29d00e0714f228d09',
866 assert ['eada5a770da98ab0dd7325e29d00e0714f228d09',
864 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == node_ids
867 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == node_ids
865
868
866 # special case we check history from commit that has this particular
869 # special case we check history from commit that has this particular
867 # file changed this means we check if it's included as well
870 # file changed this means we check if it's included as well
868 node = self.repo.get_commit('eada5a770da98ab0dd7325e29d00e0714f228d09')\
871 node = self.repo.get_commit('eada5a770da98ab0dd7325e29d00e0714f228d09')\
869 .get_node('setup.py')
872 .get_node('setup.py')
870 node_ids = [commit.raw_id for commit in node.history]
873 node_ids = [commit.raw_id for commit in node.history]
871 assert ['eada5a770da98ab0dd7325e29d00e0714f228d09',
874 assert ['eada5a770da98ab0dd7325e29d00e0714f228d09',
872 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == node_ids
875 '3803844fdbd3b711175fc3da9bdacfcd6d29a6fb'] == node_ids
873
876
874 def test_file_history(self):
877 def test_file_history(self):
875 # we can only check if those commits are present in the history
878 # we can only check if those commits are present in the history
876 # as we cannot update this test every time file is changed
879 # as we cannot update this test every time file is changed
877 files = {
880 files = {
878 'setup.py': [7, 18, 45, 46, 47, 69, 77],
881 'setup.py': [7, 18, 45, 46, 47, 69, 77],
879 'vcs/nodes.py': [
882 'vcs/nodes.py': [
880 7, 8, 24, 26, 30, 45, 47, 49, 56, 57, 58, 59, 60, 61, 73, 76],
883 7, 8, 24, 26, 30, 45, 47, 49, 56, 57, 58, 59, 60, 61, 73, 76],
881 'vcs/backends/hg.py': [
884 'vcs/backends/hg.py': [
882 4, 5, 6, 11, 12, 13, 14, 15, 16, 21, 22, 23, 26, 27, 28, 30,
885 4, 5, 6, 11, 12, 13, 14, 15, 16, 21, 22, 23, 26, 27, 28, 30,
883 31, 33, 35, 36, 37, 38, 39, 40, 41, 44, 45, 47, 48, 49, 53, 54,
886 31, 33, 35, 36, 37, 38, 39, 40, 41, 44, 45, 47, 48, 49, 53, 54,
884 55, 58, 60, 61, 67, 68, 69, 70, 73, 77, 78, 79, 82],
887 55, 58, 60, 61, 67, 68, 69, 70, 73, 77, 78, 79, 82],
885 }
888 }
886 for path, indexes in files.items():
889 for path, indexes in files.items():
887 tip = self.repo.get_commit(commit_idx=indexes[-1])
890 tip = self.repo.get_commit(commit_idx=indexes[-1])
888 node = tip.get_node(path)
891 node = tip.get_node(path)
889 node_indexes = [commit.idx for commit in node.history]
892 node_indexes = [commit.idx for commit in node.history]
890 assert set(indexes).issubset(set(node_indexes)), (
893 assert set(indexes).issubset(set(node_indexes)), (
891 "We assumed that %s is subset of commits for which file %s "
894 "We assumed that %s is subset of commits for which file %s "
892 "has been changed, and history of that node returned: %s"
895 "has been changed, and history of that node returned: %s"
893 % (indexes, path, node_indexes))
896 % (indexes, path, node_indexes))
894
897
895 def test_file_annotate(self):
898 def test_file_annotate(self):
896 files = {
899 files = {
897 'vcs/backends/__init__.py': {
900 'vcs/backends/__init__.py': {
898 89: {
901 89: {
899 'lines_no': 31,
902 'lines_no': 31,
900 'commits': [
903 'commits': [
901 32, 32, 61, 32, 32, 37, 32, 32, 32, 44,
904 32, 32, 61, 32, 32, 37, 32, 32, 32, 44,
902 37, 37, 37, 37, 45, 37, 44, 37, 37, 37,
905 37, 37, 37, 37, 45, 37, 44, 37, 37, 37,
903 32, 32, 32, 32, 37, 32, 37, 37, 32,
906 32, 32, 32, 32, 37, 32, 37, 37, 32,
904 32, 32
907 32, 32
905 ]
908 ]
906 },
909 },
907 20: {
910 20: {
908 'lines_no': 1,
911 'lines_no': 1,
909 'commits': [4]
912 'commits': [4]
910 },
913 },
911 55: {
914 55: {
912 'lines_no': 31,
915 'lines_no': 31,
913 'commits': [
916 'commits': [
914 32, 32, 45, 32, 32, 37, 32, 32, 32, 44,
917 32, 32, 45, 32, 32, 37, 32, 32, 32, 44,
915 37, 37, 37, 37, 45, 37, 44, 37, 37, 37,
918 37, 37, 37, 37, 45, 37, 44, 37, 37, 37,
916 32, 32, 32, 32, 37, 32, 37, 37, 32,
919 32, 32, 32, 32, 37, 32, 37, 37, 32,
917 32, 32
920 32, 32
918 ]
921 ]
919 }
922 }
920 },
923 },
921 'vcs/exceptions.py': {
924 'vcs/exceptions.py': {
922 89: {
925 89: {
923 'lines_no': 18,
926 'lines_no': 18,
924 'commits': [
927 'commits': [
925 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
928 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
926 16, 16, 17, 16, 16, 18, 18, 18
929 16, 16, 17, 16, 16, 18, 18, 18
927 ]
930 ]
928 },
931 },
929 20: {
932 20: {
930 'lines_no': 18,
933 'lines_no': 18,
931 'commits': [
934 'commits': [
932 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
935 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
933 16, 16, 17, 16, 16, 18, 18, 18
936 16, 16, 17, 16, 16, 18, 18, 18
934 ]
937 ]
935 },
938 },
936 55: {
939 55: {
937 'lines_no': 18,
940 'lines_no': 18,
938 'commits': [
941 'commits': [
939 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
942 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
940 17, 16, 16, 18, 18, 18
943 17, 16, 16, 18, 18, 18
941 ]
944 ]
942 }
945 }
943 },
946 },
944 'MANIFEST.in': {
947 'MANIFEST.in': {
945 89: {
948 89: {
946 'lines_no': 5,
949 'lines_no': 5,
947 'commits': [7, 7, 7, 71, 71]
950 'commits': [7, 7, 7, 71, 71]
948 },
951 },
949 20: {
952 20: {
950 'lines_no': 3,
953 'lines_no': 3,
951 'commits': [7, 7, 7]
954 'commits': [7, 7, 7]
952 },
955 },
953 55: {
956 55: {
954 'lines_no': 3,
957 'lines_no': 3,
955 'commits': [7, 7, 7]
958 'commits': [7, 7, 7]
956 }
959 }
957 }
960 }
958 }
961 }
959
962
960 for fname, commit_dict in files.items():
963 for fname, commit_dict in files.items():
961 for idx, __ in commit_dict.items():
964 for idx, __ in commit_dict.items():
962 commit = self.repo.get_commit(commit_idx=idx)
965 commit = self.repo.get_commit(commit_idx=idx)
963 l1_1 = [x[1] for x in commit.get_file_annotate(fname)]
966 l1_1 = [x[1] for x in commit.get_file_annotate(fname)]
964 l1_2 = [x[2]().raw_id for x in commit.get_file_annotate(fname)]
967 l1_2 = [x[2]().raw_id for x in commit.get_file_annotate(fname)]
965 assert l1_1 == l1_2
968 assert l1_1 == l1_2
966 l1 = l1_2 = [
969 l1 = l1_2 = [
967 x[2]().idx for x in commit.get_file_annotate(fname)]
970 x[2]().idx for x in commit.get_file_annotate(fname)]
968 l2 = files[fname][idx]['commits']
971 l2 = files[fname][idx]['commits']
969 assert l1 == l2, (
972 assert l1 == l2, (
970 "The lists of commit for %s@commit_id%s"
973 "The lists of commit for %s@commit_id%s"
971 "from annotation list should match each other,"
974 "from annotation list should match each other,"
972 "got \n%s \nvs \n%s " % (fname, idx, l1, l2))
975 "got \n%s \nvs \n%s " % (fname, idx, l1, l2))
973
976
974 def test_commit_state(self):
977 def test_commit_state(self):
975 """
978 """
976 Tests which files have been added/changed/removed at particular commit
979 Tests which files have been added/changed/removed at particular commit
977 """
980 """
978
981
979 # commit_id 46ad32a4f974:
982 # commit_id 46ad32a4f974:
980 # hg st --rev 46ad32a4f974
983 # hg st --rev 46ad32a4f974
981 # changed: 13
984 # changed: 13
982 # added: 20
985 # added: 20
983 # removed: 1
986 # removed: 1
984 changed = set([
987 changed = set([
985 '.hgignore', 'README.rst', 'docs/conf.py', 'docs/index.rst',
988 '.hgignore', 'README.rst', 'docs/conf.py', 'docs/index.rst',
986 'setup.py', 'tests/test_hg.py', 'tests/test_nodes.py',
989 'setup.py', 'tests/test_hg.py', 'tests/test_nodes.py',
987 'vcs/__init__.py', 'vcs/backends/__init__.py',
990 'vcs/__init__.py', 'vcs/backends/__init__.py',
988 'vcs/backends/base.py', 'vcs/backends/hg.py', 'vcs/nodes.py',
991 'vcs/backends/base.py', 'vcs/backends/hg.py', 'vcs/nodes.py',
989 'vcs/utils/__init__.py'])
992 'vcs/utils/__init__.py'])
990
993
991 added = set([
994 added = set([
992 'docs/api/backends/hg.rst', 'docs/api/backends/index.rst',
995 'docs/api/backends/hg.rst', 'docs/api/backends/index.rst',
993 'docs/api/index.rst', 'docs/api/nodes.rst',
996 'docs/api/index.rst', 'docs/api/nodes.rst',
994 'docs/api/web/index.rst', 'docs/api/web/simplevcs.rst',
997 'docs/api/web/index.rst', 'docs/api/web/simplevcs.rst',
995 'docs/installation.rst', 'docs/quickstart.rst', 'setup.cfg',
998 'docs/installation.rst', 'docs/quickstart.rst', 'setup.cfg',
996 'vcs/utils/baseui_config.py', 'vcs/utils/web.py',
999 'vcs/utils/baseui_config.py', 'vcs/utils/web.py',
997 'vcs/web/__init__.py', 'vcs/web/exceptions.py',
1000 'vcs/web/__init__.py', 'vcs/web/exceptions.py',
998 'vcs/web/simplevcs/__init__.py', 'vcs/web/simplevcs/exceptions.py',
1001 'vcs/web/simplevcs/__init__.py', 'vcs/web/simplevcs/exceptions.py',
999 'vcs/web/simplevcs/middleware.py', 'vcs/web/simplevcs/models.py',
1002 'vcs/web/simplevcs/middleware.py', 'vcs/web/simplevcs/models.py',
1000 'vcs/web/simplevcs/settings.py', 'vcs/web/simplevcs/utils.py',
1003 'vcs/web/simplevcs/settings.py', 'vcs/web/simplevcs/utils.py',
1001 'vcs/web/simplevcs/views.py'])
1004 'vcs/web/simplevcs/views.py'])
1002
1005
1003 removed = set(['docs/api.rst'])
1006 removed = set(['docs/api.rst'])
1004
1007
1005 commit64 = self.repo.get_commit('46ad32a4f974')
1008 commit64 = self.repo.get_commit('46ad32a4f974')
1006 assert set((node.path for node in commit64.added)) == added
1009 assert set((node.path for node in commit64.added)) == added
1007 assert set((node.path for node in commit64.changed)) == changed
1010 assert set((node.path for node in commit64.changed)) == changed
1008 assert set((node.path for node in commit64.removed)) == removed
1011 assert set((node.path for node in commit64.removed)) == removed
1009
1012
1010 # commit_id b090f22d27d6:
1013 # commit_id b090f22d27d6:
1011 # hg st --rev b090f22d27d6
1014 # hg st --rev b090f22d27d6
1012 # changed: 13
1015 # changed: 13
1013 # added: 20
1016 # added: 20
1014 # removed: 1
1017 # removed: 1
1015 commit88 = self.repo.get_commit('b090f22d27d6')
1018 commit88 = self.repo.get_commit('b090f22d27d6')
1016 assert set((node.path for node in commit88.added)) == set()
1019 assert set((node.path for node in commit88.added)) == set()
1017 assert set((node.path for node in commit88.changed)) == \
1020 assert set((node.path for node in commit88.changed)) == \
1018 set(['.hgignore'])
1021 set(['.hgignore'])
1019 assert set((node.path for node in commit88.removed)) == set()
1022 assert set((node.path for node in commit88.removed)) == set()
1020
1023
1021 #
1024 #
1022 # 85:
1025 # 85:
1023 # added: 2 [
1026 # added: 2 [
1024 # 'vcs/utils/diffs.py', 'vcs/web/simplevcs/views/diffs.py']
1027 # 'vcs/utils/diffs.py', 'vcs/web/simplevcs/views/diffs.py']
1025 # changed: 4 ['vcs/web/simplevcs/models.py', ...]
1028 # changed: 4 ['vcs/web/simplevcs/models.py', ...]
1026 # removed: 1 ['vcs/utils/web.py']
1029 # removed: 1 ['vcs/utils/web.py']
1027 commit85 = self.repo.get_commit(commit_idx=85)
1030 commit85 = self.repo.get_commit(commit_idx=85)
1028 assert set((node.path for node in commit85.added)) == set([
1031 assert set((node.path for node in commit85.added)) == set([
1029 'vcs/utils/diffs.py',
1032 'vcs/utils/diffs.py',
1030 'vcs/web/simplevcs/views/diffs.py'])
1033 'vcs/web/simplevcs/views/diffs.py'])
1031 assert set((node.path for node in commit85.changed)) == set([
1034 assert set((node.path for node in commit85.changed)) == set([
1032 'vcs/web/simplevcs/models.py',
1035 'vcs/web/simplevcs/models.py',
1033 'vcs/web/simplevcs/utils.py',
1036 'vcs/web/simplevcs/utils.py',
1034 'vcs/web/simplevcs/views/__init__.py',
1037 'vcs/web/simplevcs/views/__init__.py',
1035 'vcs/web/simplevcs/views/repository.py',
1038 'vcs/web/simplevcs/views/repository.py',
1036 ])
1039 ])
1037 assert set((node.path for node in commit85.removed)) == \
1040 assert set((node.path for node in commit85.removed)) == \
1038 set(['vcs/utils/web.py'])
1041 set(['vcs/utils/web.py'])
1039
1042
1040 def test_files_state(self):
1043 def test_files_state(self):
1041 """
1044 """
1042 Tests state of FileNodes.
1045 Tests state of FileNodes.
1043 """
1046 """
1044 commit = self.repo.get_commit(commit_idx=85)
1047 commit = self.repo.get_commit(commit_idx=85)
1045 node = commit.get_node('vcs/utils/diffs.py')
1048 node = commit.get_node('vcs/utils/diffs.py')
1046 assert node.state, NodeState.ADDED
1049 assert node.state, NodeState.ADDED
1047 assert node.added
1050 assert node.added
1048 assert not node.changed
1051 assert not node.changed
1049 assert not node.not_changed
1052 assert not node.not_changed
1050 assert not node.removed
1053 assert not node.removed
1051
1054
1052 commit = self.repo.get_commit(commit_idx=88)
1055 commit = self.repo.get_commit(commit_idx=88)
1053 node = commit.get_node('.hgignore')
1056 node = commit.get_node('.hgignore')
1054 assert node.state, NodeState.CHANGED
1057 assert node.state, NodeState.CHANGED
1055 assert not node.added
1058 assert not node.added
1056 assert node.changed
1059 assert node.changed
1057 assert not node.not_changed
1060 assert not node.not_changed
1058 assert not node.removed
1061 assert not node.removed
1059
1062
1060 commit = self.repo.get_commit(commit_idx=85)
1063 commit = self.repo.get_commit(commit_idx=85)
1061 node = commit.get_node('setup.py')
1064 node = commit.get_node('setup.py')
1062 assert node.state, NodeState.NOT_CHANGED
1065 assert node.state, NodeState.NOT_CHANGED
1063 assert not node.added
1066 assert not node.added
1064 assert not node.changed
1067 assert not node.changed
1065 assert node.not_changed
1068 assert node.not_changed
1066 assert not node.removed
1069 assert not node.removed
1067
1070
1068 # If node has REMOVED state then trying to fetch it would raise
1071 # If node has REMOVED state then trying to fetch it would raise
1069 # CommitError exception
1072 # CommitError exception
1070 commit = self.repo.get_commit(commit_idx=2)
1073 commit = self.repo.get_commit(commit_idx=2)
1071 path = 'vcs/backends/BaseRepository.py'
1074 path = 'vcs/backends/BaseRepository.py'
1072 with pytest.raises(NodeDoesNotExistError):
1075 with pytest.raises(NodeDoesNotExistError):
1073 commit.get_node(path)
1076 commit.get_node(path)
1074 # but it would be one of ``removed`` (commit's attribute)
1077 # but it would be one of ``removed`` (commit's attribute)
1075 assert path in [rf.path for rf in commit.removed]
1078 assert path in [rf.path for rf in commit.removed]
1076
1079
1077 def test_commit_message_is_unicode(self):
1080 def test_commit_message_is_unicode(self):
1078 for cm in self.repo:
1081 for cm in self.repo:
1079 assert type(cm.message) == unicode
1082 assert type(cm.message) == unicode
1080
1083
1081 def test_commit_author_is_unicode(self):
1084 def test_commit_author_is_unicode(self):
1082 for cm in self.repo:
1085 for cm in self.repo:
1083 assert type(cm.author) == unicode
1086 assert type(cm.author) == unicode
1084
1087
1085 def test_repo_files_content_is_unicode(self):
1088 def test_repo_files_content_is_unicode(self):
1086 test_commit = self.repo.get_commit(commit_idx=100)
1089 test_commit = self.repo.get_commit(commit_idx=100)
1087 for node in test_commit.get_node('/'):
1090 for node in test_commit.get_node('/'):
1088 if node.is_file():
1091 if node.is_file():
1089 assert type(node.content) == unicode
1092 assert type(node.content) == unicode
1090
1093
1091 def test_wrong_path(self):
1094 def test_wrong_path(self):
1092 # There is 'setup.py' in the root dir but not there:
1095 # There is 'setup.py' in the root dir but not there:
1093 path = 'foo/bar/setup.py'
1096 path = 'foo/bar/setup.py'
1094 with pytest.raises(VCSError):
1097 with pytest.raises(VCSError):
1095 self.repo.get_commit().get_node(path)
1098 self.repo.get_commit().get_node(path)
1096
1099
1097 def test_author_email(self):
1100 def test_author_email(self):
1098 assert 'marcin@python-blog.com' == \
1101 assert 'marcin@python-blog.com' == \
1099 self.repo.get_commit('b986218ba1c9').author_email
1102 self.repo.get_commit('b986218ba1c9').author_email
1100 assert 'lukasz.balcerzak@python-center.pl' == \
1103 assert 'lukasz.balcerzak@python-center.pl' == \
1101 self.repo.get_commit('3803844fdbd3').author_email
1104 self.repo.get_commit('3803844fdbd3').author_email
1102 assert '' == self.repo.get_commit('84478366594b').author_email
1105 assert '' == self.repo.get_commit('84478366594b').author_email
1103
1106
1104 def test_author_username(self):
1107 def test_author_username(self):
1105 assert 'Marcin Kuzminski' == \
1108 assert 'Marcin Kuzminski' == \
1106 self.repo.get_commit('b986218ba1c9').author_name
1109 self.repo.get_commit('b986218ba1c9').author_name
1107 assert 'Lukasz Balcerzak' == \
1110 assert 'Lukasz Balcerzak' == \
1108 self.repo.get_commit('3803844fdbd3').author_name
1111 self.repo.get_commit('3803844fdbd3').author_name
1109 assert 'marcink' == \
1112 assert 'marcink' == \
1110 self.repo.get_commit('84478366594b').author_name
1113 self.repo.get_commit('84478366594b').author_name
1111
1114
1112
1115
1113 class TestLargeFileRepo(object):
1116 class TestLargeFileRepo(object):
1114
1117
1115 def test_large_file(self, backend_hg):
1118 def test_large_file(self, backend_hg):
1116 repo = backend_hg.create_test_repo('largefiles', make_db_config())
1119 repo = backend_hg.create_test_repo('largefiles', make_db_config())
1117
1120
1118 tip = repo.scm_instance().get_commit()
1121 tip = repo.scm_instance().get_commit()
1119 node = tip.get_node('.hglf/thisfileislarge')
1122 node = tip.get_node('.hglf/thisfileislarge')
1120
1123
1121 lf_node = node.get_largefile_node()
1124 lf_node = node.get_largefile_node()
1122
1125
1123 assert lf_node.is_largefile() is True
1126 assert lf_node.is_largefile() is True
1124 assert lf_node.size == 1024000
1127 assert lf_node.size == 1024000
1125 assert lf_node.name == '.hglf/thisfileislarge'
1128 assert lf_node.name == '.hglf/thisfileislarge'
1126
1129
1127
1130
1128 class TestGetBranchName(object):
1131 class TestGetBranchName(object):
1129 def test_returns_ref_name_when_type_is_branch(self):
1132 def test_returns_ref_name_when_type_is_branch(self):
1130 ref = self._create_ref('branch', 'fake-name')
1133 ref = self._create_ref('branch', 'fake-name')
1131 result = self.repo._get_branch_name(ref)
1134 result = self.repo._get_branch_name(ref)
1132 assert result == ref.name
1135 assert result == ref.name
1133
1136
1134 @pytest.mark.parametrize("type_", ("book", "tag"))
1137 @pytest.mark.parametrize("type_", ("book", "tag"))
1135 def test_queries_remote_when_type_is_not_branch(self, type_):
1138 def test_queries_remote_when_type_is_not_branch(self, type_):
1136 ref = self._create_ref(type_, 'wrong-fake-name')
1139 ref = self._create_ref(type_, 'wrong-fake-name')
1137 with mock.patch.object(self.repo, "_remote") as remote_mock:
1140 with mock.patch.object(self.repo, "_remote") as remote_mock:
1138 remote_mock.ctx_branch.return_value = "fake-name"
1141 remote_mock.ctx_branch.return_value = "fake-name"
1139 result = self.repo._get_branch_name(ref)
1142 result = self.repo._get_branch_name(ref)
1140 assert result == "fake-name"
1143 assert result == "fake-name"
1141 remote_mock.ctx_branch.assert_called_once_with(ref.commit_id)
1144 remote_mock.ctx_branch.assert_called_once_with(ref.commit_id)
1142
1145
1143 def _create_ref(self, type_, name):
1146 def _create_ref(self, type_, name):
1144 ref = mock.Mock()
1147 ref = mock.Mock()
1145 ref.type = type_
1148 ref.type = type_
1146 ref.name = 'wrong-fake-name'
1149 ref.name = 'wrong-fake-name'
1147 ref.commit_id = "deadbeef"
1150 ref.commit_id = "deadbeef"
1148 return ref
1151 return ref
1149
1152
1150
1153
1151 class TestIsTheSameBranch(object):
1154 class TestIsTheSameBranch(object):
1152 def test_returns_true_when_branches_are_equal(self):
1155 def test_returns_true_when_branches_are_equal(self):
1153 source_ref = mock.Mock(name="source-ref")
1156 source_ref = mock.Mock(name="source-ref")
1154 target_ref = mock.Mock(name="target-ref")
1157 target_ref = mock.Mock(name="target-ref")
1155 branch_name_patcher = mock.patch.object(
1158 branch_name_patcher = mock.patch.object(
1156 self.repo, "_get_branch_name", return_value="default")
1159 self.repo, "_get_branch_name", return_value="default")
1157 with branch_name_patcher as branch_name_mock:
1160 with branch_name_patcher as branch_name_mock:
1158 result = self.repo._is_the_same_branch(source_ref, target_ref)
1161 result = self.repo._is_the_same_branch(source_ref, target_ref)
1159
1162
1160 expected_calls = [mock.call(source_ref), mock.call(target_ref)]
1163 expected_calls = [mock.call(source_ref), mock.call(target_ref)]
1161 assert branch_name_mock.call_args_list == expected_calls
1164 assert branch_name_mock.call_args_list == expected_calls
1162 assert result is True
1165 assert result is True
1163
1166
1164 def test_returns_false_when_branches_are_not_equal(self):
1167 def test_returns_false_when_branches_are_not_equal(self):
1165 source_ref = mock.Mock(name="source-ref")
1168 source_ref = mock.Mock(name="source-ref")
1166 source_ref.name = "source-branch"
1169 source_ref.name = "source-branch"
1167 target_ref = mock.Mock(name="target-ref")
1170 target_ref = mock.Mock(name="target-ref")
1168 source_ref.name = "target-branch"
1171 source_ref.name = "target-branch"
1169
1172
1170 def side_effect(ref):
1173 def side_effect(ref):
1171 return ref.name
1174 return ref.name
1172
1175
1173 branch_name_patcher = mock.patch.object(
1176 branch_name_patcher = mock.patch.object(
1174 self.repo, "_get_branch_name", side_effect=side_effect)
1177 self.repo, "_get_branch_name", side_effect=side_effect)
1175 with branch_name_patcher as branch_name_mock:
1178 with branch_name_patcher as branch_name_mock:
1176 result = self.repo._is_the_same_branch(source_ref, target_ref)
1179 result = self.repo._is_the_same_branch(source_ref, target_ref)
1177
1180
1178 expected_calls = [mock.call(source_ref), mock.call(target_ref)]
1181 expected_calls = [mock.call(source_ref), mock.call(target_ref)]
1179 assert branch_name_mock.call_args_list == expected_calls
1182 assert branch_name_mock.call_args_list == expected_calls
1180 assert result is False
1183 assert result is False
@@ -1,183 +1,183 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import pytest
21 import pytest
22
22
23 from mock import call, patch
23 from mock import call, patch
24
24
25 from rhodecode.lib.vcs.backends.base import Reference
25 from rhodecode.lib.vcs.backends.base import Reference
26
26
27
27
28 class TestMercurialRemoteRepoInvalidation(object):
28 class TestMercurialRemoteRepoInvalidation(object):
29 """
29 """
30 If the VCSServer is running with multiple processes or/and instances.
30 If the VCSServer is running with multiple processes or/and instances.
31 Operations on repositories are potentially handled by different processes
31 Operations on repositories are potentially handled by different processes
32 in a random fashion. The mercurial repository objects used in the VCSServer
32 in a random fashion. The mercurial repository objects used in the VCSServer
33 are caching the commits of the repo. Therefore we have to invalidate the
33 are caching the commits of the repo. Therefore we have to invalidate the
34 VCSServer caching of these objects after a writing operation.
34 VCSServer caching of these objects after a writing operation.
35 """
35 """
36
36
37 # Default reference used as a dummy during tests.
37 # Default reference used as a dummy during tests.
38 default_ref = Reference('branch', 'default', None)
38 default_ref = Reference('branch', 'default', None)
39
39
40 # Methods of vcsserver.hg.HgRemote that are "writing" operations.
40 # Methods of vcsserver.hg.HgRemote that are "writing" operations.
41 writing_methods = [
41 writing_methods = [
42 'bookmark',
42 'bookmark',
43 'commit',
43 'commit',
44 'merge',
44 'merge',
45 'pull',
45 'pull',
46 'pull_cmd',
46 'pull_cmd',
47 'rebase',
47 'rebase',
48 'strip',
48 'strip',
49 'tag',
49 'tag',
50 ]
50 ]
51
51
52 @pytest.mark.parametrize('method_name, method_args', [
52 @pytest.mark.parametrize('method_name, method_args', [
53 ('_local_merge', [default_ref, None, None, None, default_ref]),
53 ('_local_merge', [default_ref, None, None, None, default_ref]),
54 ('_local_pull', ['', default_ref]),
54 ('_local_pull', ['', default_ref]),
55 ('bookmark', [None]),
55 ('bookmark', [None]),
56 ('pull', ['', default_ref]),
56 ('pull', ['', default_ref]),
57 ('remove_tag', ['mytag', None]),
57 ('remove_tag', ['mytag', None]),
58 ('strip', [None]),
58 ('strip', [None]),
59 ('tag', ['newtag', None]),
59 ('tag', ['newtag', None]),
60 ])
60 ])
61 def test_method_invokes_invalidate_on_remote_repo(
61 def test_method_invokes_invalidate_on_remote_repo(
62 self, method_name, method_args, backend_hg):
62 self, method_name, method_args, backend_hg):
63 """
63 """
64 Check that the listed methods are invalidating the VCSServer cache
64 Check that the listed methods are invalidating the VCSServer cache
65 after invoking a writing method of their remote repository object.
65 after invoking a writing method of their remote repository object.
66 """
66 """
67 tags = {'mytag': 'mytag-id'}
67 tags = {'mytag': 'mytag-id'}
68
68
69 def add_tag(name, raw_id, *args, **kwds):
69 def add_tag(name, raw_id, *args, **kwds):
70 tags[name] = raw_id
70 tags[name] = raw_id
71
71
72 repo = backend_hg.repo.scm_instance()
72 repo = backend_hg.repo.scm_instance()
73 with patch.object(repo, '_remote') as remote:
73 with patch.object(repo, '_remote') as remote:
74 remote.lookup.return_value = ('commit-id', 'commit-idx')
74 remote.lookup.return_value = ('commit-id', 'commit-idx')
75 remote.tags.return_value = tags
75 remote.tags.return_value = tags
76 remote._get_tags.return_value = tags
76 remote._get_tags.return_value = tags
77 remote.tag.side_effect = add_tag
77 remote.tag.side_effect = add_tag
78
78
79 # Invoke method.
79 # Invoke method.
80 method = getattr(repo, method_name)
80 method = getattr(repo, method_name)
81 method(*method_args)
81 method(*method_args)
82
82
83 # Assert that every "writing" method is followed by an invocation
83 # Assert that every "writing" method is followed by an invocation
84 # of the cache invalidation method.
84 # of the cache invalidation method.
85 for counter, method_call in enumerate(remote.method_calls):
85 for counter, method_call in enumerate(remote.method_calls):
86 call_name = method_call[0]
86 call_name = method_call[0]
87 if call_name in self.writing_methods:
87 if call_name in self.writing_methods:
88 next_call = remote.method_calls[counter + 1]
88 next_call = remote.method_calls[counter + 1]
89 assert next_call == call.invalidate_vcs_cache()
89 assert next_call == call.invalidate_vcs_cache()
90
90
91 def _prepare_shadow_repo(self, pull_request):
91 def _prepare_shadow_repo(self, pull_request):
92 """
92 """
93 Helper that creates a shadow repo that can be used to reproduce the
93 Helper that creates a shadow repo that can be used to reproduce the
94 CommitDoesNotExistError when pulling in from target and source
94 CommitDoesNotExistError when pulling in from target and source
95 references.
95 references.
96 """
96 """
97 from rhodecode.model.pull_request import PullRequestModel
97 from rhodecode.model.pull_request import PullRequestModel
98
98
99 target_vcs = pull_request.target_repo.scm_instance()
99 target_vcs = pull_request.target_repo.scm_instance()
100 target_ref = pull_request.target_ref_parts
100 target_ref = pull_request.target_ref_parts
101 source_ref = pull_request.source_ref_parts
101 source_ref = pull_request.source_ref_parts
102
102
103 # Create shadow repository.
103 # Create shadow repository.
104 pr = PullRequestModel()
104 pr = PullRequestModel()
105 workspace_id = pr._workspace_id(pull_request)
105 workspace_id = pr._workspace_id(pull_request)
106 shadow_repository_path = target_vcs._maybe_prepare_merge_workspace(
106 shadow_repository_path = target_vcs._maybe_prepare_merge_workspace(
107 workspace_id, target_ref)
107 workspace_id, target_ref, source_ref)
108 shadow_repo = target_vcs._get_shadow_instance(shadow_repository_path)
108 shadow_repo = target_vcs._get_shadow_instance(shadow_repository_path)
109
109
110 # This will populate the cache of the mercurial repository object
110 # This will populate the cache of the mercurial repository object
111 # inside of the VCSServer.
111 # inside of the VCSServer.
112 shadow_repo.get_commit()
112 shadow_repo.get_commit()
113
113
114 return shadow_repo, source_ref, target_ref
114 return shadow_repo, source_ref, target_ref
115
115
116 @pytest.mark.backends('hg')
116 @pytest.mark.backends('hg')
117 def test_commit_does_not_exist_error_happens(self, pr_util, app):
117 def test_commit_does_not_exist_error_happens(self, pr_util, app):
118 """
118 """
119 This test is somewhat special. It does not really test the system
119 This test is somewhat special. It does not really test the system
120 instead it is more or less a precondition for the
120 instead it is more or less a precondition for the
121 "test_commit_does_not_exist_error_does_not_happen". It deactivates the
121 "test_commit_does_not_exist_error_does_not_happen". It deactivates the
122 cache invalidation and asserts that the error occurs.
122 cache invalidation and asserts that the error occurs.
123 """
123 """
124 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
124 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
125
125
126 pull_request = pr_util.create_pull_request()
126 pull_request = pr_util.create_pull_request()
127 target_vcs = pull_request.target_repo.scm_instance()
127 target_vcs = pull_request.target_repo.scm_instance()
128 source_vcs = pull_request.source_repo.scm_instance()
128 source_vcs = pull_request.source_repo.scm_instance()
129 shadow_repo, source_ref, target_ref = self._prepare_shadow_repo(
129 shadow_repo, source_ref, target_ref = self._prepare_shadow_repo(
130 pull_request)
130 pull_request)
131
131
132 # Pull from target and source references but without invalidation of
132 # Pull from target and source references but without invalidation of
133 # RemoteRepo objects and without VCSServer caching of mercurial
133 # RemoteRepo objects and without VCSServer caching of mercurial
134 # repository objects.
134 # repository objects.
135 with patch.object(shadow_repo._remote, 'invalidate_vcs_cache'):
135 with patch.object(shadow_repo._remote, 'invalidate_vcs_cache'):
136 # NOTE: Do not use patch.dict() to disable the cache because it
136 # NOTE: Do not use patch.dict() to disable the cache because it
137 # restores the WHOLE dict and not only the patched keys.
137 # restores the WHOLE dict and not only the patched keys.
138 shadow_repo._remote._wire['cache'] = False
138 shadow_repo._remote._wire['cache'] = False
139 shadow_repo._local_pull(target_vcs.path, target_ref)
139 shadow_repo._local_pull(target_vcs.path, target_ref)
140 shadow_repo._local_pull(source_vcs.path, source_ref)
140 shadow_repo._local_pull(source_vcs.path, source_ref)
141 shadow_repo._remote._wire.pop('cache')
141 shadow_repo._remote._wire.pop('cache')
142
142
143 # Try to lookup the target_ref in shadow repo. This should work because
143 # Try to lookup the target_ref in shadow repo. This should work because
144 # the shadow repo is a clone of the target and always contains all off
144 # the shadow repo is a clone of the target and always contains all off
145 # it's commits in the initial cache.
145 # it's commits in the initial cache.
146 shadow_repo.get_commit(target_ref.commit_id)
146 shadow_repo.get_commit(target_ref.commit_id)
147
147
148 # If we try to lookup the source_ref it should fail because the shadow
148 # If we try to lookup the source_ref it should fail because the shadow
149 # repo commit cache doesn't get invalidated. (Due to patched
149 # repo commit cache doesn't get invalidated. (Due to patched
150 # invalidation and caching above).
150 # invalidation and caching above).
151 with pytest.raises(CommitDoesNotExistError):
151 with pytest.raises(CommitDoesNotExistError):
152 shadow_repo.get_commit(source_ref.commit_id)
152 shadow_repo.get_commit(source_ref.commit_id)
153
153
154 @pytest.mark.backends('hg')
154 @pytest.mark.backends('hg')
155 def test_commit_does_not_exist_error_does_not_happen(self, pr_util, app):
155 def test_commit_does_not_exist_error_does_not_happen(self, pr_util, app):
156 """
156 """
157 This test simulates a pull request merge in which the pull operations
157 This test simulates a pull request merge in which the pull operations
158 are handled by a different VCSServer process than all other operations.
158 are handled by a different VCSServer process than all other operations.
159 Without correct cache invalidation this leads to an error when
159 Without correct cache invalidation this leads to an error when
160 retrieving the pulled commits afterwards.
160 retrieving the pulled commits afterwards.
161 """
161 """
162
162
163 pull_request = pr_util.create_pull_request()
163 pull_request = pr_util.create_pull_request()
164 target_vcs = pull_request.target_repo.scm_instance()
164 target_vcs = pull_request.target_repo.scm_instance()
165 source_vcs = pull_request.source_repo.scm_instance()
165 source_vcs = pull_request.source_repo.scm_instance()
166 shadow_repo, source_ref, target_ref = self._prepare_shadow_repo(
166 shadow_repo, source_ref, target_ref = self._prepare_shadow_repo(
167 pull_request)
167 pull_request)
168
168
169 # Pull from target and source references without without VCSServer
169 # Pull from target and source references without without VCSServer
170 # caching of mercurial repository objects but with active invalidation
170 # caching of mercurial repository objects but with active invalidation
171 # of RemoteRepo objects.
171 # of RemoteRepo objects.
172 # NOTE: Do not use patch.dict() to disable the cache because it
172 # NOTE: Do not use patch.dict() to disable the cache because it
173 # restores the WHOLE dict and not only the patched keys.
173 # restores the WHOLE dict and not only the patched keys.
174 shadow_repo._remote._wire['cache'] = False
174 shadow_repo._remote._wire['cache'] = False
175 shadow_repo._local_pull(target_vcs.path, target_ref)
175 shadow_repo._local_pull(target_vcs.path, target_ref)
176 shadow_repo._local_pull(source_vcs.path, source_ref)
176 shadow_repo._local_pull(source_vcs.path, source_ref)
177 shadow_repo._remote._wire.pop('cache')
177 shadow_repo._remote._wire.pop('cache')
178
178
179 # Try to lookup the target and source references in shadow repo. This
179 # Try to lookup the target and source references in shadow repo. This
180 # should work because the RemoteRepo object gets invalidated during the
180 # should work because the RemoteRepo object gets invalidated during the
181 # above pull operations.
181 # above pull operations.
182 shadow_repo.get_commit(target_ref.commit_id)
182 shadow_repo.get_commit(target_ref.commit_id)
183 shadow_repo.get_commit(source_ref.commit_id)
183 shadow_repo.get_commit(source_ref.commit_id)
General Comments 0
You need to be logged in to leave comments. Login now