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