##// END OF EJS Templates
todos: all todos needs to be resolved for merge to happen....
todos: all todos needs to be resolved for merge to happen. This will prevent the outdated todos beeing automatically marked as solved becuase of bigger diff changes. It's better to mark commits quickly as resolved instead of potentially have unresolved todos hidden because of invlidation logic.

File last commit:

r1271:47a44c03 default
r1342:44fc3039 default
Show More
test_hg_vcsserver_cache_invalidation.py
189 lines | 8.0 KiB | text/x-python | PythonLexer
/ rhodecode / tests / vcs / test_hg_vcsserver_cache_invalidation.py
Martin Bornhold
tests: Add tests for hg invalidation of vcsserver cache.
r406 # -*- coding: utf-8 -*-
license: updated copyright year to 2017
r1271 # Copyright (C) 2016-2017 RhodeCode GmbH
Martin Bornhold
tests: Add tests for hg invalidation of vcsserver cache.
r406 #
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import pytest
Martin Bornhold
tests: Adapt tests to changes in mercurial vcs backend.
r408 from mock import call, patch
Martin Bornhold
tests: Add tests for hg invalidation of vcsserver cache.
r406
from rhodecode.lib.vcs.backends.base import Reference
class TestMercurialRemoteRepoInvalidation(object):
Martin Bornhold
tests: Skip test for Pyro4 connection and added doc strings.
r434 """
If the VCSServer is running with multiple processes or/and instances.
Operations on repositories are potentially handled by different processes
in a random fashion. The mercurial repository objects used in the VCSServer
are caching the commits of the repo. Therefore we have to invalidate the
VCSServer caching of these objects after a writing operation.
"""
# Default reference used as a dummy during tests.
Martin Bornhold
tests: Adapt tests to changes in mercurial vcs backend.
r408 default_ref = Reference('branch', 'default', None)
Martin Bornhold
tests: Skip test for Pyro4 connection and added doc strings.
r434
# Methods of vcsserver.hg.HgRemote that are "writing" operations.
Martin Bornhold
tests: Adapt tests to changes in mercurial vcs backend.
r408 writing_methods = [
Martin Bornhold
tests: Add tests for hg invalidation of vcsserver cache.
r406 'bookmark',
'commit',
Martin Bornhold
tests: Adapt tests to changes in mercurial vcs backend.
r408 'merge',
Martin Bornhold
tests: Add tests for hg invalidation of vcsserver cache.
r406 'pull',
'pull_cmd',
'rebase',
'strip',
Martin Bornhold
tests: Adapt tests to changes in mercurial vcs backend.
r408 'tag',
]
@pytest.mark.parametrize('method_name, method_args', [
('_local_merge', [default_ref, None, None, None, default_ref]),
('_local_pull', ['', default_ref]),
('bookmark', [None]),
('pull', ['', default_ref]),
('remove_tag', ['mytag', None]),
('strip', [None]),
('tag', ['newtag', None]),
Martin Bornhold
tests: Add tests for hg invalidation of vcsserver cache.
r406 ])
def test_method_invokes_invalidate_on_remote_repo(
Martin Bornhold
tests: Adapt tests to changes in mercurial vcs backend.
r408 self, method_name, method_args, backend_hg):
"""
Check that the listed methods are invalidating the VCSServer cache
after invoking a writing method of their remote repository object.
Martin Bornhold
tests: Add tests for hg invalidation of vcsserver cache.
r406 """
Martin Bornhold
tests: Adapt tests to changes in mercurial vcs backend.
r408 tags = {'mytag': 'mytag-id'}
def add_tag(name, raw_id, *args, **kwds):
tags[name] = raw_id
Martin Bornhold
tests: Add tests for hg invalidation of vcsserver cache.
r406 repo = backend_hg.repo.scm_instance()
Martin Bornhold
tests: Adapt tests to changes in mercurial vcs backend.
r408 with patch.object(repo, '_remote') as remote:
remote.lookup.return_value = ('commit-id', 'commit-idx')
remote.tags.return_value = tags
remote._get_tags.return_value = tags
remote.tag.side_effect = add_tag
# Invoke method.
method = getattr(repo, method_name)
method(*method_args)
# Assert that every "writing" method is followed by an invocation
# of the cache invalidation method.
for counter, method_call in enumerate(remote.method_calls):
call_name = method_call[0]
if call_name in self.writing_methods:
next_call = remote.method_calls[counter + 1]
assert next_call == call.invalidate_vcs_cache()
Martin Bornhold
tests: Add tests for hg invalidation of vcsserver cache.
r406
def _prepare_shadow_repo(self, pull_request):
"""
Helper that creates a shadow repo that can be used to reproduce the
CommitDoesNotExistError when pulling in from target and source
references.
"""
from rhodecode.model.pull_request import PullRequestModel
target_vcs = pull_request.target_repo.scm_instance()
target_ref = pull_request.target_ref_parts
source_ref = pull_request.source_ref_parts
# Create shadow repository.
pr = PullRequestModel()
workspace_id = pr._workspace_id(pull_request)
shadow_repository_path = target_vcs._maybe_prepare_merge_workspace(
workspace_id, target_ref)
shadow_repo = target_vcs._get_shadow_instance(shadow_repository_path)
# This will populate the cache of the mercurial repository object
# inside of the VCSServer.
shadow_repo.get_commit()
return shadow_repo, source_ref, target_ref
@pytest.mark.backends('hg')
Martin Bornhold
tests: Skip test for Pyro4 connection and added doc strings.
r434 def test_commit_does_not_exist_error_happens(self, pr_util, pylonsapp):
"""
This test is somewhat special. It does not really test the system
instead it is more or less a precondition for the
"test_commit_does_not_exist_error_does_not_happen". It deactivates the
cache invalidation and asserts that the error occurs.
"""
Martin Bornhold
tests: Add tests for hg invalidation of vcsserver cache.
r406 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
Martin Bornhold
tests: Only skip test if protocol is 'pyro4'
r435 if pylonsapp.config['vcs.server.protocol'] == 'pyro4':
Martin Bornhold
tests: Skip test for Pyro4 connection and added doc strings.
r434 pytest.skip('Test is intended for the HTTP protocol only.')
Martin Bornhold
tests: Add tests for hg invalidation of vcsserver cache.
r406 pull_request = pr_util.create_pull_request()
target_vcs = pull_request.target_repo.scm_instance()
source_vcs = pull_request.source_repo.scm_instance()
shadow_repo, source_ref, target_ref = self._prepare_shadow_repo(
pull_request)
# Pull from target and source references but without invalidation of
# RemoteRepo objects and without VCSServer caching of mercurial
# repository objects.
with patch.object(shadow_repo._remote, 'invalidate_vcs_cache'):
# NOTE: Do not use patch.dict() to disable the cache because it
# restores the WHOLE dict and not only the patched keys.
shadow_repo._remote._wire['cache'] = False
shadow_repo._local_pull(target_vcs.path, target_ref)
shadow_repo._local_pull(source_vcs.path, source_ref)
shadow_repo._remote._wire.pop('cache')
# Try to lookup the target_ref in shadow repo. This should work because
# the shadow repo is a clone of the target and always contains all off
# it's commits in the initial cache.
shadow_repo.get_commit(target_ref.commit_id)
# If we try to lookup the source_ref it should fail because the shadow
# repo commit cache doesn't get invalidated. (Due to patched
# invalidation and caching above).
with pytest.raises(CommitDoesNotExistError):
shadow_repo.get_commit(source_ref.commit_id)
@pytest.mark.backends('hg')
Martin Bornhold
tests: Skip test for Pyro4 connection and added doc strings.
r434 def test_commit_does_not_exist_error_does_not_happen(
self, pr_util, pylonsapp):
"""
This test simulates a pull request merge in which the pull operations
are handled by a different VCSServer process than all other operations.
Without correct cache invalidation this leads to an error when
retrieving the pulled commits afterwards.
"""
Martin Bornhold
tests: Only skip test if protocol is 'pyro4'
r435 if pylonsapp.config['vcs.server.protocol'] == 'pyro4':
Martin Bornhold
tests: Skip test for Pyro4 connection and added doc strings.
r434 pytest.skip('Test is intended for the HTTP protocol only.')
Martin Bornhold
tests: Add tests for hg invalidation of vcsserver cache.
r406 pull_request = pr_util.create_pull_request()
target_vcs = pull_request.target_repo.scm_instance()
source_vcs = pull_request.source_repo.scm_instance()
shadow_repo, source_ref, target_ref = self._prepare_shadow_repo(
pull_request)
# Pull from target and source references without without VCSServer
# caching of mercurial repository objects but with active invalidation
# of RemoteRepo objects.
# NOTE: Do not use patch.dict() to disable the cache because it
# restores the WHOLE dict and not only the patched keys.
shadow_repo._remote._wire['cache'] = False
shadow_repo._local_pull(target_vcs.path, target_ref)
shadow_repo._local_pull(source_vcs.path, source_ref)
shadow_repo._remote._wire.pop('cache')
# Try to lookup the target and source references in shadow repo. This
# should work because the RemoteRepo object gets invalidated during the
# above pull operations.
shadow_repo.get_commit(target_ref.commit_id)
shadow_repo.get_commit(source_ref.commit_id)