Show More
@@ -0,0 +1,133 b'' | |||
|
1 | #!/usr/bin/env python | |
|
2 | ||
|
3 | # fsmonitor-run-tests.py - Run Mercurial tests with fsmonitor enabled | |
|
4 | # | |
|
5 | # Copyright 2017 Facebook, Inc. | |
|
6 | # | |
|
7 | # This software may be used and distributed according to the terms of the | |
|
8 | # GNU General Public License version 2 or any later version. | |
|
9 | # | |
|
10 | # This is a wrapper around run-tests.py that spins up an isolated instance of | |
|
11 | # Watchman and runs the Mercurial tests against it. This ensures that the global | |
|
12 | # version of Watchman isn't affected by anything this test does. | |
|
13 | ||
|
14 | from __future__ import absolute_import | |
|
15 | from __future__ import print_function | |
|
16 | ||
|
17 | import argparse | |
|
18 | import contextlib | |
|
19 | import json | |
|
20 | import os | |
|
21 | import shutil | |
|
22 | import subprocess | |
|
23 | import sys | |
|
24 | import tempfile | |
|
25 | import uuid | |
|
26 | ||
|
27 | osenvironb = getattr(os, 'environb', os.environ) | |
|
28 | ||
|
29 | if sys.version_info > (3, 5, 0): | |
|
30 | PYTHON3 = True | |
|
31 | xrange = range # we use xrange in one place, and we'd rather not use range | |
|
32 | def _bytespath(p): | |
|
33 | return p.encode('utf-8') | |
|
34 | ||
|
35 | elif sys.version_info >= (3, 0, 0): | |
|
36 | print('%s is only supported on Python 3.5+ and 2.7, not %s' % | |
|
37 | (sys.argv[0], '.'.join(str(v) for v in sys.version_info[:3]))) | |
|
38 | sys.exit(70) # EX_SOFTWARE from `man 3 sysexit` | |
|
39 | else: | |
|
40 | PYTHON3 = False | |
|
41 | ||
|
42 | # In python 2.x, path operations are generally done using | |
|
43 | # bytestrings by default, so we don't have to do any extra | |
|
44 | # fiddling there. We define the wrapper functions anyway just to | |
|
45 | # help keep code consistent between platforms. | |
|
46 | def _bytespath(p): | |
|
47 | return p | |
|
48 | ||
|
49 | def getparser(): | |
|
50 | """Obtain the argument parser used by the CLI.""" | |
|
51 | parser = argparse.ArgumentParser( | |
|
52 | description='Run tests with fsmonitor enabled.', | |
|
53 | epilog='Unrecognized options are passed to run-tests.py.') | |
|
54 | # - keep these sorted | |
|
55 | # - none of these options should conflict with any in run-tests.py | |
|
56 | parser.add_argument('--keep-fsmonitor-tmpdir', action='store_true', | |
|
57 | help='keep temporary directory with fsmonitor state') | |
|
58 | parser.add_argument('--watchman', | |
|
59 | help='location of watchman binary (default: watchman in PATH)', | |
|
60 | default='watchman') | |
|
61 | ||
|
62 | return parser | |
|
63 | ||
|
64 | @contextlib.contextmanager | |
|
65 | def watchman(args): | |
|
66 | basedir = tempfile.mkdtemp(prefix='hg-fsmonitor') | |
|
67 | try: | |
|
68 | # Much of this configuration is borrowed from Watchman's test harness. | |
|
69 | cfgfile = os.path.join(basedir, 'config.json') | |
|
70 | # TODO: allow setting a config | |
|
71 | with open(cfgfile, 'w') as f: | |
|
72 | f.write(json.dumps({})) | |
|
73 | ||
|
74 | logfile = os.path.join(basedir, 'log') | |
|
75 | clilogfile = os.path.join(basedir, 'cli-log') | |
|
76 | if os.name == 'nt': | |
|
77 | sockfile = '\\\\.\\pipe\\watchman-test-%s' % uuid.uuid4().hex | |
|
78 | else: | |
|
79 | sockfile = os.path.join(basedir, 'sock') | |
|
80 | pidfile = os.path.join(basedir, 'pid') | |
|
81 | statefile = os.path.join(basedir, 'state') | |
|
82 | ||
|
83 | argv = [ | |
|
84 | args.watchman, | |
|
85 | '--sockname', sockfile, | |
|
86 | '--logfile', logfile, | |
|
87 | '--pidfile', pidfile, | |
|
88 | '--statefile', statefile, | |
|
89 | '--foreground', | |
|
90 | '--log-level=2', # debug logging for watchman | |
|
91 | ] | |
|
92 | ||
|
93 | envb = osenvironb.copy() | |
|
94 | envb[b'WATCHMAN_CONFIG_FILE'] = _bytespath(cfgfile) | |
|
95 | with open(clilogfile, 'wb') as f: | |
|
96 | proc = subprocess.Popen( | |
|
97 | argv, env=envb, stdin=None, stdout=f, stderr=f) | |
|
98 | try: | |
|
99 | yield sockfile | |
|
100 | finally: | |
|
101 | proc.terminate() | |
|
102 | proc.kill() | |
|
103 | finally: | |
|
104 | if args.keep_fsmonitor_tmpdir: | |
|
105 | print('fsmonitor dir available at %s' % basedir) | |
|
106 | else: | |
|
107 | shutil.rmtree(basedir, ignore_errors=True) | |
|
108 | ||
|
109 | def run(): | |
|
110 | parser = getparser() | |
|
111 | args, runtestsargv = parser.parse_known_args() | |
|
112 | ||
|
113 | with watchman(args) as sockfile: | |
|
114 | osenvironb[b'WATCHMAN_SOCK'] = _bytespath(sockfile) | |
|
115 | # Indicate to hghave that we're running with fsmonitor enabled. | |
|
116 | osenvironb[b'HGFSMONITOR_TESTS'] = b'1' | |
|
117 | ||
|
118 | runtestdir = os.path.dirname(__file__) | |
|
119 | runtests = os.path.join(runtestdir, 'run-tests.py') | |
|
120 | blacklist = os.path.join(runtestdir, 'blacklists', 'fsmonitor') | |
|
121 | ||
|
122 | runtestsargv.insert(0, runtests) | |
|
123 | runtestsargv.extend([ | |
|
124 | '--extra-config', | |
|
125 | 'extensions.fsmonitor=', | |
|
126 | '--blacklist', | |
|
127 | blacklist, | |
|
128 | ]) | |
|
129 | ||
|
130 | return subprocess.call(runtestsargv) | |
|
131 | ||
|
132 | if __name__ == '__main__': | |
|
133 | sys.exit(run()) |
@@ -1,7 +1,5 b'' | |||
|
1 | 1 | # Blacklist for a full testsuite run with fsmonitor enabled. |
|
2 | # Use with | |
|
3 | # run-tests --blacklist=blacklists/fsmonitor \ | |
|
4 | # --extra-config="extensions.fsmonitor=" | |
|
2 | # Used by fsmonitor-run-tests. | |
|
5 | 3 | # The following tests all fail because they either use extensions that conflict |
|
6 | 4 | # with fsmonitor, use subrepositories, or don't anticipate the extra file in |
|
7 | 5 | # the .hg directory that fsmonitor adds. |
General Comments 0
You need to be logged in to leave comments.
Login now