Mercurial > hg
view tests/fsmonitor-run-tests.py @ 44667:b561f3a68e41 stable
discovery: avoid wrongly saying there are nothing to pull
We can get in a situation where a revision passed through `hg pull --rev REV`
are available on the server, but not a descendant of the advertised server
heads.
For example the server could lying be during heads advertisement, to hide some
pull request. Or obsolete/hidden content could be explicitly pulled.
So in this case the lookup associated to `REV` returned successfully, but the
normal discovery will find all advertised heads already known locally. This flip
a special boolean `anyinc` that will prevent any fetch attempt, preventing `REV`
to be pulled over.
We add three line of code to detect this case and make sure a pull actually
happens.
My main target is to make some third party extensions happy (I expect the
associated test to move upstream with the extension). However this fix already
make some of the `infinitepush` test happier.
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Mon, 06 Apr 2020 00:24:57 +0200 |
parents | 2372284d9457 |
children | 55c443fcb4fc |
line wrap: on
line source
#!/usr/bin/env python # fsmonitor-run-tests.py - Run Mercurial tests with fsmonitor enabled # # Copyright 2017 Facebook, Inc. # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. # # This is a wrapper around run-tests.py that spins up an isolated instance of # Watchman and runs the Mercurial tests against it. This ensures that the global # version of Watchman isn't affected by anything this test does. from __future__ import absolute_import from __future__ import print_function import argparse import contextlib import json import os import shutil import subprocess import sys import tempfile import uuid osenvironb = getattr(os, 'environb', os.environ) if sys.version_info > (3, 5, 0): PYTHON3 = True xrange = range # we use xrange in one place, and we'd rather not use range def _bytespath(p): return p.encode('utf-8') elif sys.version_info >= (3, 0, 0): print( '%s is only supported on Python 3.5+ and 2.7, not %s' % (sys.argv[0], '.'.join(str(v) for v in sys.version_info[:3])) ) sys.exit(70) # EX_SOFTWARE from `man 3 sysexit` else: PYTHON3 = False # In python 2.x, path operations are generally done using # bytestrings by default, so we don't have to do any extra # fiddling there. We define the wrapper functions anyway just to # help keep code consistent between platforms. def _bytespath(p): return p def getparser(): """Obtain the argument parser used by the CLI.""" parser = argparse.ArgumentParser( description='Run tests with fsmonitor enabled.', epilog='Unrecognized options are passed to run-tests.py.', ) # - keep these sorted # - none of these options should conflict with any in run-tests.py parser.add_argument( '--keep-fsmonitor-tmpdir', action='store_true', help='keep temporary directory with fsmonitor state', ) parser.add_argument( '--watchman', help='location of watchman binary (default: watchman in PATH)', default='watchman', ) return parser @contextlib.contextmanager def watchman(args): basedir = tempfile.mkdtemp(prefix='hg-fsmonitor') try: # Much of this configuration is borrowed from Watchman's test harness. cfgfile = os.path.join(basedir, 'config.json') # TODO: allow setting a config with open(cfgfile, 'w') as f: f.write(json.dumps({})) logfile = os.path.join(basedir, 'log') clilogfile = os.path.join(basedir, 'cli-log') if os.name == 'nt': sockfile = '\\\\.\\pipe\\watchman-test-%s' % uuid.uuid4().hex else: sockfile = os.path.join(basedir, 'sock') pidfile = os.path.join(basedir, 'pid') statefile = os.path.join(basedir, 'state') argv = [ args.watchman, '--sockname', sockfile, '--logfile', logfile, '--pidfile', pidfile, '--statefile', statefile, '--foreground', '--log-level=2', # debug logging for watchman ] envb = osenvironb.copy() envb[b'WATCHMAN_CONFIG_FILE'] = _bytespath(cfgfile) with open(clilogfile, 'wb') as f: proc = subprocess.Popen( argv, env=envb, stdin=None, stdout=f, stderr=f ) try: yield sockfile finally: proc.terminate() proc.kill() finally: if args.keep_fsmonitor_tmpdir: print('fsmonitor dir available at %s' % basedir) else: shutil.rmtree(basedir, ignore_errors=True) def run(): parser = getparser() args, runtestsargv = parser.parse_known_args() with watchman(args) as sockfile: osenvironb[b'WATCHMAN_SOCK'] = _bytespath(sockfile) # Indicate to hghave that we're running with fsmonitor enabled. osenvironb[b'HGFSMONITOR_TESTS'] = b'1' runtestdir = os.path.dirname(__file__) runtests = os.path.join(runtestdir, 'run-tests.py') blacklist = os.path.join(runtestdir, 'blacklists', 'fsmonitor') runtestsargv.insert(0, runtests) runtestsargv.extend( [ '--extra-config', 'extensions.fsmonitor=', # specify fsmonitor.mode=paranoid always in order to force # fsmonitor extension execute "paranoid" code path # # TODO: make fsmonitor-run-tests.py accept specific options '--extra-config', 'fsmonitor.mode=paranoid', '--blacklist', blacklist, ] ) return subprocess.call(runtestsargv) if __name__ == '__main__': sys.exit(run())