Show More
@@ -0,0 +1,133 | |||||
|
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 | |||||
1 | # Blacklist for a full testsuite run with fsmonitor enabled. |
|
1 | # Blacklist for a full testsuite run with fsmonitor enabled. | |
2 | # Use with |
|
2 | # Used by fsmonitor-run-tests. | |
3 | # run-tests --blacklist=blacklists/fsmonitor \ |
|
|||
4 | # --extra-config="extensions.fsmonitor=" |
|
|||
5 | # The following tests all fail because they either use extensions that conflict |
|
3 | # The following tests all fail because they either use extensions that conflict | |
6 | # with fsmonitor, use subrepositories, or don't anticipate the extra file in |
|
4 | # with fsmonitor, use subrepositories, or don't anticipate the extra file in | |
7 | # the .hg directory that fsmonitor adds. |
|
5 | # the .hg directory that fsmonitor adds. |
General Comments 0
You need to be logged in to leave comments.
Login now