##// END OF EJS Templates
tests: Skip test for Pyro4 connection and added doc strings.
Martin Bornhold -
r434:e4f441e2 default
parent child Browse files
Show More
@@ -1,159 +1,189 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2016 RhodeCode GmbH
3 # Copyright (C) 2016-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import pytest
21 import pytest
22
22
23 from mock import call, patch
23 from mock import call, patch
24
24
25 from rhodecode.lib.vcs.backends.base import Reference
25 from rhodecode.lib.vcs.backends.base import Reference
26
26
27
27
28 class TestMercurialRemoteRepoInvalidation(object):
28 class TestMercurialRemoteRepoInvalidation(object):
29 """
30 If the VCSServer is running with multiple processes or/and instances.
31 Operations on repositories are potentially handled by different processes
32 in a random fashion. The mercurial repository objects used in the VCSServer
33 are caching the commits of the repo. Therefore we have to invalidate the
34 VCSServer caching of these objects after a writing operation.
35 """
36
37 # Default reference used as a dummy during tests.
29 default_ref = Reference('branch', 'default', None)
38 default_ref = Reference('branch', 'default', None)
39
40 # Methods of vcsserver.hg.HgRemote that are "writing" operations.
30 writing_methods = [
41 writing_methods = [
31 'bookmark',
42 'bookmark',
32 'commit',
43 'commit',
33 'merge',
44 'merge',
34 'pull',
45 'pull',
35 'pull_cmd',
46 'pull_cmd',
36 'rebase',
47 'rebase',
37 'strip',
48 'strip',
38 'tag',
49 'tag',
39 ]
50 ]
40
51
41 @pytest.mark.parametrize('method_name, method_args', [
52 @pytest.mark.parametrize('method_name, method_args', [
42 ('_local_merge', [default_ref, None, None, None, default_ref]),
53 ('_local_merge', [default_ref, None, None, None, default_ref]),
43 ('_local_pull', ['', default_ref]),
54 ('_local_pull', ['', default_ref]),
44 ('bookmark', [None]),
55 ('bookmark', [None]),
45 ('pull', ['', default_ref]),
56 ('pull', ['', default_ref]),
46 ('remove_tag', ['mytag', None]),
57 ('remove_tag', ['mytag', None]),
47 ('strip', [None]),
58 ('strip', [None]),
48 ('tag', ['newtag', None]),
59 ('tag', ['newtag', None]),
49 ])
60 ])
50 def test_method_invokes_invalidate_on_remote_repo(
61 def test_method_invokes_invalidate_on_remote_repo(
51 self, method_name, method_args, backend_hg):
62 self, method_name, method_args, backend_hg):
52 """
63 """
53 Check that the listed methods are invalidating the VCSServer cache
64 Check that the listed methods are invalidating the VCSServer cache
54 after invoking a writing method of their remote repository object.
65 after invoking a writing method of their remote repository object.
55 """
66 """
56 tags = {'mytag': 'mytag-id'}
67 tags = {'mytag': 'mytag-id'}
57
68
58 def add_tag(name, raw_id, *args, **kwds):
69 def add_tag(name, raw_id, *args, **kwds):
59 tags[name] = raw_id
70 tags[name] = raw_id
60
71
61 repo = backend_hg.repo.scm_instance()
72 repo = backend_hg.repo.scm_instance()
62 with patch.object(repo, '_remote') as remote:
73 with patch.object(repo, '_remote') as remote:
63 remote.lookup.return_value = ('commit-id', 'commit-idx')
74 remote.lookup.return_value = ('commit-id', 'commit-idx')
64 remote.tags.return_value = tags
75 remote.tags.return_value = tags
65 remote._get_tags.return_value = tags
76 remote._get_tags.return_value = tags
66 remote.tag.side_effect = add_tag
77 remote.tag.side_effect = add_tag
67
78
68 # Invoke method.
79 # Invoke method.
69 method = getattr(repo, method_name)
80 method = getattr(repo, method_name)
70 method(*method_args)
81 method(*method_args)
71
82
72 # Assert that every "writing" method is followed by an invocation
83 # Assert that every "writing" method is followed by an invocation
73 # of the cache invalidation method.
84 # of the cache invalidation method.
74 for counter, method_call in enumerate(remote.method_calls):
85 for counter, method_call in enumerate(remote.method_calls):
75 call_name = method_call[0]
86 call_name = method_call[0]
76 if call_name in self.writing_methods:
87 if call_name in self.writing_methods:
77 next_call = remote.method_calls[counter + 1]
88 next_call = remote.method_calls[counter + 1]
78 assert next_call == call.invalidate_vcs_cache()
89 assert next_call == call.invalidate_vcs_cache()
79
90
80 def _prepare_shadow_repo(self, pull_request):
91 def _prepare_shadow_repo(self, pull_request):
81 """
92 """
82 Helper that creates a shadow repo that can be used to reproduce the
93 Helper that creates a shadow repo that can be used to reproduce the
83 CommitDoesNotExistError when pulling in from target and source
94 CommitDoesNotExistError when pulling in from target and source
84 references.
95 references.
85 """
96 """
86 from rhodecode.model.pull_request import PullRequestModel
97 from rhodecode.model.pull_request import PullRequestModel
87
98
88 target_vcs = pull_request.target_repo.scm_instance()
99 target_vcs = pull_request.target_repo.scm_instance()
89 target_ref = pull_request.target_ref_parts
100 target_ref = pull_request.target_ref_parts
90 source_ref = pull_request.source_ref_parts
101 source_ref = pull_request.source_ref_parts
91
102
92 # Create shadow repository.
103 # Create shadow repository.
93 pr = PullRequestModel()
104 pr = PullRequestModel()
94 workspace_id = pr._workspace_id(pull_request)
105 workspace_id = pr._workspace_id(pull_request)
95 shadow_repository_path = target_vcs._maybe_prepare_merge_workspace(
106 shadow_repository_path = target_vcs._maybe_prepare_merge_workspace(
96 workspace_id, target_ref)
107 workspace_id, target_ref)
97 shadow_repo = target_vcs._get_shadow_instance(shadow_repository_path)
108 shadow_repo = target_vcs._get_shadow_instance(shadow_repository_path)
98
109
99 # This will populate the cache of the mercurial repository object
110 # This will populate the cache of the mercurial repository object
100 # inside of the VCSServer.
111 # inside of the VCSServer.
101 shadow_repo.get_commit()
112 shadow_repo.get_commit()
102
113
103 return shadow_repo, source_ref, target_ref
114 return shadow_repo, source_ref, target_ref
104
115
105 @pytest.mark.backends('hg')
116 @pytest.mark.backends('hg')
106 def test_commit_does_not_exist_error_happens(self, pr_util):
117 def test_commit_does_not_exist_error_happens(self, pr_util, pylonsapp):
118 """
119 This test is somewhat special. It does not really test the system
120 instead it is more or less a precondition for the
121 "test_commit_does_not_exist_error_does_not_happen". It deactivates the
122 cache invalidation and asserts that the error occurs.
123 """
107 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
124 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
108
125
126 if pylonsapp.config['vcs.server.protocol'] != 'http':
127 pytest.skip('Test is intended for the HTTP protocol only.')
128
109 pull_request = pr_util.create_pull_request()
129 pull_request = pr_util.create_pull_request()
110 target_vcs = pull_request.target_repo.scm_instance()
130 target_vcs = pull_request.target_repo.scm_instance()
111 source_vcs = pull_request.source_repo.scm_instance()
131 source_vcs = pull_request.source_repo.scm_instance()
112 shadow_repo, source_ref, target_ref = self._prepare_shadow_repo(
132 shadow_repo, source_ref, target_ref = self._prepare_shadow_repo(
113 pull_request)
133 pull_request)
114
134
115 # Pull from target and source references but without invalidation of
135 # Pull from target and source references but without invalidation of
116 # RemoteRepo objects and without VCSServer caching of mercurial
136 # RemoteRepo objects and without VCSServer caching of mercurial
117 # repository objects.
137 # repository objects.
118 with patch.object(shadow_repo._remote, 'invalidate_vcs_cache'):
138 with patch.object(shadow_repo._remote, 'invalidate_vcs_cache'):
119 # NOTE: Do not use patch.dict() to disable the cache because it
139 # NOTE: Do not use patch.dict() to disable the cache because it
120 # restores the WHOLE dict and not only the patched keys.
140 # restores the WHOLE dict and not only the patched keys.
121 shadow_repo._remote._wire['cache'] = False
141 shadow_repo._remote._wire['cache'] = False
122 shadow_repo._local_pull(target_vcs.path, target_ref)
142 shadow_repo._local_pull(target_vcs.path, target_ref)
123 shadow_repo._local_pull(source_vcs.path, source_ref)
143 shadow_repo._local_pull(source_vcs.path, source_ref)
124 shadow_repo._remote._wire.pop('cache')
144 shadow_repo._remote._wire.pop('cache')
125
145
126 # Try to lookup the target_ref in shadow repo. This should work because
146 # Try to lookup the target_ref in shadow repo. This should work because
127 # the shadow repo is a clone of the target and always contains all off
147 # the shadow repo is a clone of the target and always contains all off
128 # it's commits in the initial cache.
148 # it's commits in the initial cache.
129 shadow_repo.get_commit(target_ref.commit_id)
149 shadow_repo.get_commit(target_ref.commit_id)
130
150
131 # If we try to lookup the source_ref it should fail because the shadow
151 # If we try to lookup the source_ref it should fail because the shadow
132 # repo commit cache doesn't get invalidated. (Due to patched
152 # repo commit cache doesn't get invalidated. (Due to patched
133 # invalidation and caching above).
153 # invalidation and caching above).
134 with pytest.raises(CommitDoesNotExistError):
154 with pytest.raises(CommitDoesNotExistError):
135 shadow_repo.get_commit(source_ref.commit_id)
155 shadow_repo.get_commit(source_ref.commit_id)
136
156
137 @pytest.mark.backends('hg')
157 @pytest.mark.backends('hg')
138 def test_commit_does_not_exist_error_does_not_happen(self, pr_util):
158 def test_commit_does_not_exist_error_does_not_happen(
159 self, pr_util, pylonsapp):
160 """
161 This test simulates a pull request merge in which the pull operations
162 are handled by a different VCSServer process than all other operations.
163 Without correct cache invalidation this leads to an error when
164 retrieving the pulled commits afterwards.
165 """
166 if pylonsapp.config['vcs.server.protocol'] != 'http':
167 pytest.skip('Test is intended for the HTTP protocol only.')
168
139 pull_request = pr_util.create_pull_request()
169 pull_request = pr_util.create_pull_request()
140 target_vcs = pull_request.target_repo.scm_instance()
170 target_vcs = pull_request.target_repo.scm_instance()
141 source_vcs = pull_request.source_repo.scm_instance()
171 source_vcs = pull_request.source_repo.scm_instance()
142 shadow_repo, source_ref, target_ref = self._prepare_shadow_repo(
172 shadow_repo, source_ref, target_ref = self._prepare_shadow_repo(
143 pull_request)
173 pull_request)
144
174
145 # Pull from target and source references without without VCSServer
175 # Pull from target and source references without without VCSServer
146 # caching of mercurial repository objects but with active invalidation
176 # caching of mercurial repository objects but with active invalidation
147 # of RemoteRepo objects.
177 # of RemoteRepo objects.
148 # NOTE: Do not use patch.dict() to disable the cache because it
178 # NOTE: Do not use patch.dict() to disable the cache because it
149 # restores the WHOLE dict and not only the patched keys.
179 # restores the WHOLE dict and not only the patched keys.
150 shadow_repo._remote._wire['cache'] = False
180 shadow_repo._remote._wire['cache'] = False
151 shadow_repo._local_pull(target_vcs.path, target_ref)
181 shadow_repo._local_pull(target_vcs.path, target_ref)
152 shadow_repo._local_pull(source_vcs.path, source_ref)
182 shadow_repo._local_pull(source_vcs.path, source_ref)
153 shadow_repo._remote._wire.pop('cache')
183 shadow_repo._remote._wire.pop('cache')
154
184
155 # Try to lookup the target and source references in shadow repo. This
185 # Try to lookup the target and source references in shadow repo. This
156 # should work because the RemoteRepo object gets invalidated during the
186 # should work because the RemoteRepo object gets invalidated during the
157 # above pull operations.
187 # above pull operations.
158 shadow_repo.get_commit(target_ref.commit_id)
188 shadow_repo.get_commit(target_ref.commit_id)
159 shadow_repo.get_commit(source_ref.commit_id)
189 shadow_repo.get_commit(source_ref.commit_id)
General Comments 0
You need to be logged in to leave comments. Login now