changeset 5384:e3a0c092b4e2

Allow tests to run in parallel.
author Bryan O'Sullivan <bos@serpentine.com>
date Fri, 05 Oct 2007 12:17:01 -0700
parents 7cdc896fdcd5
children caadfbc439c6
files tests/run-tests.py tests/test-archive tests/test-bad-pull tests/test-hgweb tests/test-http tests/test-http-clone-r tests/test-http-clone-r.out tests/test-http-proxy tests/test-http.out tests/test-incoming-outgoing tests/test-incoming-outgoing.out tests/test-non-interactive-wsgi tests/test-pull tests/test-pull.out tests/test-push-http tests/test-push-http.out tests/test-serve tests/test-serve.out tests/test-static-http tests/test-static-http.out tests/test-transplant tests/test-webraw
diffstat 22 files changed, 205 insertions(+), 121 deletions(-) [+]
line wrap: on
line diff
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -27,14 +27,20 @@ required_tools = ["python", "diff", "gre
 parser = optparse.OptionParser("%prog [options] [tests]")
 parser.add_option("-C", "--annotate", action="store_true",
     help="output files annotated with coverage")
+parser.add_option("--child", type="int",
+    help="run as child process, summary to given fd")
 parser.add_option("-c", "--cover", action="store_true",
     help="print a test coverage report")
 parser.add_option("-f", "--first", action="store_true",
     help="exit on the first test failure")
 parser.add_option("-i", "--interactive", action="store_true",
     help="prompt to accept changed output")
+parser.add_option("-j", "--jobs", type="int",
+    help="number of jobs to run in parallel")
 parser.add_option("-R", "--restart", action="store_true",
     help="restart at last error")
+parser.add_option("-p", "--port", type="int",
+    help="port on which servers should listen")
 parser.add_option("-r", "--retest", action="store_true",
     help="retest failed tests")
 parser.add_option("-s", "--cover_stdlib", action="store_true",
@@ -43,13 +49,22 @@ parser.add_option("-t", "--timeout", typ
     help="kill errant tests after TIMEOUT seconds")
 parser.add_option("-v", "--verbose", action="store_true",
     help="output verbose messages")
+parser.add_option("--with-hg", type="string",
+    help="test existing install at given location")
 
-parser.set_defaults(timeout=180)
+parser.set_defaults(jobs=1, port=20059, timeout=180)
 (options, args) = parser.parse_args()
 verbose = options.verbose
 coverage = options.cover or options.cover_stdlib or options.annotate
 python = sys.executable
 
+if options.jobs < 1:
+    print >> sys.stderr, 'ERROR: -j/--jobs must be positive'
+    sys.exit(1)
+if options.interactive and options.jobs > 1:
+    print >> sys.stderr, 'ERROR: cannot mix -interactive and --jobs > 1'
+    sys.exit(1)
+
 def vlog(*msg):
     if verbose:
         for m in msg:
@@ -368,10 +383,10 @@ def run_one(test):
         return None
     return ret == 0
 
+if not options.child:
+    os.umask(022)
 
-os.umask(022)
-
-check_required_tools()
+    check_required_tools()
 
 # Reset some environment variables to well-known values so that
 # the tests produce repeatable output.
@@ -380,28 +395,83 @@ os.environ['TZ'] = 'GMT'
 
 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
 HGTMP   = os.environ["HGTMP"]   = tempfile.mkdtemp("", "hgtests.")
-DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
-HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
+DAEMON_PIDS = None
+HGRCPATH = None
 
 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
 os.environ["HGMERGE"]  = ('python "%s" -L my -L other'
-                          % os.path.join(TESTDIR, os.path.pardir, 'contrib',
-                                         'simplemerge'))
+                          % os.path.join(TESTDIR, os.path.pardir,
+                                         'contrib', 'simplemerge'))
 os.environ["HGUSER"]   = "test"
 os.environ["HGENCODING"] = "ascii"
 os.environ["HGENCODINGMODE"] = "strict"
+os.environ["HGPORT"] = str(options.port)
+os.environ["HGPORT1"] = str(options.port + 1)
+os.environ["HGPORT2"] = str(options.port + 2)
 
-vlog("# Using TESTDIR", TESTDIR)
-vlog("# Using HGTMP", HGTMP)
-
-INST = os.path.join(HGTMP, "install")
+if options.with_hg:
+    INST = options.with_hg
+else:
+    INST = os.path.join(HGTMP, "install")
 BINDIR = os.path.join(INST, "bin")
 PYTHONDIR = os.path.join(INST, "lib", "python")
 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
 
-try:
+def run_children(tests):
+    if not options.with_hg:
+        install_hg()
+
+    optcopy = dict(options.__dict__)
+    optcopy['jobs'] = 1
+    optcopy['with_hg'] = INST
+    opts = []
+    for opt, value in optcopy.iteritems():
+        name = '--' + opt.replace('_', '-')
+        if value is True:
+            opts.append(name)
+        elif value is not None:
+            opts.append(name + '=' + str(value))
+
+    tests.reverse()
+    jobs = [[] for j in xrange(options.jobs)]
+    while tests:
+        for j in xrange(options.jobs):
+            if not tests: break
+            jobs[j].append(tests.pop())
+    fps = {}
+    for j in xrange(len(jobs)):
+        job = jobs[j]
+        if not job:
+            continue
+        rfd, wfd = os.pipe()
+        childopts = ['--child=%d' % wfd, '--port=%d' % (options.port + j * 3)]
+        cmdline = [python, sys.argv[0]] + opts + childopts + job
+        vlog(' '.join(cmdline))
+        fps[os.spawnvp(os.P_NOWAIT, cmdline[0], cmdline)] = os.fdopen(rfd, 'r')
+        os.close(wfd)
+    failures = 0
+    tested, skipped, failed = 0, 0, 0
+    while fps:
+        pid, status = os.wait()
+        fp = fps.pop(pid)
+        test, skip, fail = map(int, fp.read().splitlines())
+        tested += test
+        skipped += skip
+        failed += fail
+        vlog('pid %d exited, status %d' % (pid, status))
+        failures |= status
+    print "\n# Ran %d tests, %d skipped, %d failed." % (
+        tested, skipped, failed)
+    sys.exit(failures != 0)
+
+def run_tests(tests):
+    global DAEMON_PIDS, HGRCPATH
+    DAEMON_PIDS = os.environ["DAEMON_PIDS"] = os.path.join(HGTMP, 'daemon.pids')
+    HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
+
     try:
-        install_hg()
+        if not options.with_hg:
+            install_hg()
 
         if options.timeout > 0:
             try:
@@ -416,18 +486,6 @@ try:
         failed = 0
         skipped = 0
 
-        if len(args) == 0:
-            args = os.listdir(".")
-            args.sort()
-
-
-        tests = []
-        for test in args:
-            if (test.startswith("test-") and '~' not in test and
-                ('.' not in test or test.endswith('.py') or
-                 test.endswith('.bat'))):
-                tests.append(test)
-
         if options.restart:
             orig = list(tests)
             while tests:
@@ -458,15 +516,41 @@ try:
                     break
             tested += 1
 
-        print "\n# Ran %d tests, %d skipped, %d failed." % (tested, skipped,
-                                                            failed)
+        if options.child:
+            fp = os.fdopen(options.child, 'w')
+            fp.write('%d\n%d\n%d\n' % (tested, skipped, failed))
+            fp.close()
+        else:
+            print "\n# Ran %d tests, %d skipped, %d failed." % (
+                tested, skipped, failed)
+
         if coverage:
             output_coverage()
     except KeyboardInterrupt:
         failed = True
         print "\ninterrupted!"
+
+    if failed:
+        sys.exit(1)
+
+if len(args) == 0:
+    args = os.listdir(".")
+    args.sort()
+
+tests = []
+for test in args:
+    if (test.startswith("test-") and '~' not in test and
+        ('.' not in test or test.endswith('.py') or
+         test.endswith('.bat'))):
+        tests.append(test)
+
+vlog("# Using TESTDIR", TESTDIR)
+vlog("# Using HGTMP", HGTMP)
+
+try:
+    if len(tests) > 1 and options.jobs > 1:
+        run_children(tests)
+    else:
+        run_tests(tests)
 finally:
     cleanup_exit()
-
-if failed:
-    sys.exit(1)
--- a/tests/test-archive
+++ b/tests/test-archive
@@ -13,16 +13,16 @@ hg commit -Am 3 -d '1000000000 0'
 echo "[web]" >> .hg/hgrc
 echo "name = test-archive" >> .hg/hgrc
 echo "allow_archive = gz bz2, zip" >> .hg/hgrc
-hg serve -p 20059 -d --pid-file=hg.pid
+hg serve -p $HGPORT -d --pid-file=hg.pid
 cat hg.pid >> $DAEMON_PIDS
 
 TIP=`hg id -v | cut -f1 -d' '`
 QTIP=`hg id -q`
 cat > getarchive.py <<EOF
-import sys, urllib2
+import os, sys, urllib2
 node, archive = sys.argv[1:]
-f = urllib2.urlopen('http://127.0.0.1:20059/?cmd=archive;node=%s;type=%s'
-                    % (node, archive))
+f = urllib2.urlopen('http://127.0.0.1:%s/?cmd=archive;node=%s;type=%s'
+                    % (os.environ['HGPORT'], node, archive))
 sys.stdout.write(f.read())
 EOF
 http_proxy= python getarchive.py "$TIP" gz | gunzip | tar tf - | sed "s/$QTIP/TIP/"
--- a/tests/test-bad-pull
+++ b/tests/test-bad-pull
@@ -1,15 +1,15 @@
 #!/bin/sh
 
-hg clone http://localhost:20059/ copy
+hg clone http://localhost:$HGPORT/ copy
 echo $?
 test -d copy || echo copy: No such file or directory
 
 cat > dumb.py <<EOF
-import BaseHTTPServer, SimpleHTTPServer, signal
+import BaseHTTPServer, SimpleHTTPServer, os, signal
 
 def run(server_class=BaseHTTPServer.HTTPServer,
         handler_class=SimpleHTTPServer.SimpleHTTPRequestHandler):
-    server_address = ('localhost', 20059)
+    server_address = ('localhost', int(os.environ['HGPORT']))
     httpd = server_class(server_address, handler_class)
     httpd.serve_forever()
 
@@ -23,7 +23,7 @@ echo $! >> $DAEMON_PIDS
 # give the server some time to start running
 sleep 1
 
-http_proxy= hg clone http://localhost:20059/foo copy2 2>&1 | \
+http_proxy= hg clone http://localhost:$HGPORT/foo copy2 2>&1 | \
     sed -e 's/404.*/404/' -e 's/Date:.*/Date:/'
 echo $?
 
--- a/tests/test-hgweb
+++ b/tests/test-hgweb
@@ -6,8 +6,8 @@ mkdir da
 echo foo > da/foo
 echo foo > foo
 hg ci -Ambase -d '0 0'
-hg serve -p 20060 -d --pid-file=hg.pid
+hg serve -p $HGPORT -d --pid-file=hg.pid
 echo % manifest
-("$TESTDIR/get-with-headers.py" localhost:20060 '/file/tip/?style=raw')
-("$TESTDIR/get-with-headers.py" localhost:20060 '/file/tip/da?style=raw')
+("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/tip/?style=raw')
+("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/tip/da?style=raw')
 kill `cat hg.pid`
--- a/tests/test-http
+++ b/tests/test-http
@@ -6,23 +6,23 @@ hg init test
 cd test
 echo foo>foo
 hg commit -A -d '0 0' -m 1
-hg --config server.uncompressed=True serve -p 20059 -d --pid-file=../hg1.pid
-hg serve -p 20060 -d --pid-file=../hg2.pid
+hg --config server.uncompressed=True serve -p $HGPORT -d --pid-file=../hg1.pid
+hg serve -p $HGPORT1 -d --pid-file=../hg2.pid
 # Test server address cannot be reused
-hg serve -p 20060 2>&1 | sed -e 's/abort: cannot start server:.*/abort: cannot start server:/'
+hg serve -p $HGPORT1 2>&1 | sed -e 's/abort: cannot start server:.*/abort: cannot start server:/'
 cd ..
 cat hg1.pid hg2.pid >> $DAEMON_PIDS
 
 echo % clone via stream
-http_proxy= hg clone --uncompressed http://localhost:20059/ copy 2>&1 | \
+http_proxy= hg clone --uncompressed http://localhost:$HGPORT/ copy 2>&1 | \
   sed -e 's/[0-9][0-9.]*/XXX/g' -e 's/[KM]\(B\/sec\)/X\1/'
 hg verify -R copy
 
 echo % try to clone via stream, should use pull instead
-http_proxy= hg clone --uncompressed http://localhost:20060/ copy2
+http_proxy= hg clone --uncompressed http://localhost:$HGPORT1/ copy2
 
 echo % clone via pull
-http_proxy= hg clone http://localhost:20059/ copy-pull
+http_proxy= hg clone http://localhost:$HGPORT1/ copy-pull
 hg verify -R copy-pull
 
 cd test
@@ -34,5 +34,5 @@ echo % pull
 cd copy-pull
 echo '[hooks]' >> .hg/hgrc
 echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
-hg pull
+hg pull | sed -e 's,:[0-9][0-9]*/,/,'
 cd ..
--- a/tests/test-http-clone-r
+++ b/tests/test-http-clone-r
@@ -49,13 +49,13 @@ hg debugindex .hg/store/data/fred.i
 hg debugindex .hg/store/00manifest.i
 hg verify
 echo "# Starting server"
-hg serve -p 20061 -d --pid-file=../hg1.pid
+hg serve -p $HGPORT -d --pid-file=../hg1.pid
 cd ..
 cat hg1.pid >> $DAEMON_PIDS
 
 echo "# clone remote via stream"
 for i in 0 1 2 3 4 5 6 7 8; do
-   hg clone -r "$i" http://localhost:20061/ test-"$i" 2>&1
+   hg clone -r "$i" http://localhost:$HGPORT/ test-"$i" 2>&1
    if cd test-"$i"; then
       hg verify
       cd ..
@@ -66,13 +66,13 @@ hg pull ../test-7
 hg verify
 cd ..
 cd test-1
-hg pull -r 4 http://localhost:20061/ 2>&1
+hg pull -r 4 http://localhost:$HGPORT/ 2>&1 | sed -e 's,:[0-9][0-9]*/,/,'
 hg verify
-hg pull http://localhost:20061/ 2>&1
+hg pull http://localhost:$HGPORT/ 2>&1 | sed -e 's,:[0-9][0-9]*/,/,'
 cd ..
 cd test-2
-hg pull -r 5 http://localhost:20061/ 2>&1
+hg pull -r 5 http://localhost:$HGPORT/ 2>&1 | sed -e 's,:[0-9][0-9]*/,/,'
 hg verify
-hg pull http://localhost:20061/ 2>&1
+hg pull http://localhost:$HGPORT/ 2>&1 | sed -e 's,:[0-9][0-9]*/,/,'
 hg verify
 cd ..
--- a/tests/test-http-clone-r.out
+++ b/tests/test-http-clone-r.out
@@ -138,7 +138,7 @@ checking manifests
 crosschecking files in changesets and manifests
 checking files
 4 files, 9 changesets, 7 total revisions
-pulling from http://localhost:20061/
+pulling from http://localhost/
 searching for changes
 adding changesets
 adding manifests
@@ -150,14 +150,14 @@ checking manifests
 crosschecking files in changesets and manifests
 checking files
 1 files, 3 changesets, 2 total revisions
-pulling from http://localhost:20061/
+pulling from http://localhost/
 searching for changes
 adding changesets
 adding manifests
 adding file changes
 added 6 changesets with 5 changes to 4 files
 (run 'hg update' to get a working copy)
-pulling from http://localhost:20061/
+pulling from http://localhost/
 searching for changes
 adding changesets
 adding manifests
@@ -169,7 +169,7 @@ checking manifests
 crosschecking files in changesets and manifests
 checking files
 1 files, 5 changesets, 3 total revisions
-pulling from http://localhost:20061/
+pulling from http://localhost/
 searching for changes
 adding changesets
 adding manifests
--- a/tests/test-http-proxy
+++ b/tests/test-http-proxy
@@ -4,38 +4,38 @@ hg init a
 cd a
 echo a > a
 hg ci -Ama -d '1123456789 0'
-hg --config server.uncompressed=True serve -p 20059 -d --pid-file=hg.pid
+hg --config server.uncompressed=True serve -p $HGPORT -d --pid-file=hg.pid
 cat hg.pid >> $DAEMON_PIDS
 
 cd ..
-("$TESTDIR/tinyproxy.py" 20060 localhost >proxy.log 2>&1 </dev/null &
+("$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log 2>&1 </dev/null &
 echo $! > proxy.pid)
 cat proxy.pid >> $DAEMON_PIDS
 sleep 2
 
 echo %% url for proxy, stream
-http_proxy=http://localhost:20060/ hg --config http_proxy.always=True clone --uncompressed http://localhost:20059/ b | \
+http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone --uncompressed http://localhost:$HGPORT/ b | \
   sed -e 's/[0-9][0-9.]*/XXX/g' -e 's/[KM]\(B\/sec\)/X\1/'
 cd b
 hg verify
 cd ..
 
 echo %% url for proxy, pull
-http_proxy=http://localhost:20060/ hg --config http_proxy.always=True clone http://localhost:20059/ b-pull
+http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone http://localhost:$HGPORT/ b-pull
 cd b-pull
 hg verify
 cd ..
 
 echo %% host:port for proxy
-http_proxy=localhost:20060 hg clone --config http_proxy.always=True http://localhost:20059/ c
+http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ c
 
 echo %% proxy url with user name and password
-http_proxy=http://user:passwd@localhost:20060 hg clone --config http_proxy.always=True http://localhost:20059/ d
+http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ d
 
 echo %% url with user name and password
-http_proxy=http://user:passwd@localhost:20060 hg clone --config http_proxy.always=True http://user:passwd@localhost:20059/ e
+http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://user:passwd@localhost:$HGPORT/ e
 
 echo %% bad host:port for proxy
-http_proxy=localhost:20061 hg clone --config http_proxy.always=True http://localhost:20059/ f
+http_proxy=localhost:$HGPORT2 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ f
 
 exit 0
--- a/tests/test-http.out
+++ b/tests/test-http.out
@@ -31,8 +31,8 @@ checking files
 1 files, 1 changesets, 1 total revisions
 adding bar
 % pull
-changegroup hook: HG_NODE=cfbd11a1fa315300a080c3de8fe36b0fc5820acf HG_SOURCE=pull HG_URL=http://localhost:20059/ 
-pulling from http://localhost:20059/
+changegroup hook: HG_NODE=cfbd11a1fa315300a080c3de8fe36b0fc5820acf HG_SOURCE=pull HG_URL=http://localhost/ 
+pulling from http://localhost/
 searching for changes
 adding changesets
 adding manifests
--- a/tests/test-incoming-outgoing
+++ b/tests/test-incoming-outgoing
@@ -8,20 +8,20 @@ for i in 0 1 2 3 4 5 6 7 8; do
 	hg commit -A -m $i -d "1000000 0"
 done
 hg verify
-hg serve -p 20059 -d --pid-file=hg.pid
+hg serve -p $HGPORT -d --pid-file=hg.pid
 cat hg.pid >> $DAEMON_PIDS
 cd ..
 
 hg init new
 # http incoming
-http_proxy= hg -R new incoming http://localhost:20059/
-http_proxy= hg -R new incoming -r 4 http://localhost:20059/
+http_proxy= hg -R new incoming http://localhost:$HGPORT/ | sed -e 's,:[0-9][0-9]*/,/,'
+http_proxy= hg -R new incoming -r 4 http://localhost:$HGPORT/ | sed -e 's,:[0-9][0-9]*/,/,'
 # local incoming
 hg -R new incoming test
 hg -R new incoming -r 4 test
 
 # test with --bundle
-http_proxy= hg -R new incoming --bundle test.hg http://localhost:20059/
+http_proxy= hg -R new incoming --bundle test.hg http://localhost:$HGPORT/ | sed -e 's,:[0-9][0-9]*/,/,'
 hg -R new incoming --bundle test2.hg test
 
 # test the resulting bundles
@@ -44,5 +44,5 @@ done
 hg verify
 cd ..
 hg -R test-dev outgoing test
-http_proxy= hg -R test-dev outgoing http://localhost:20059/
-http_proxy= hg -R test-dev outgoing -r 11 http://localhost:20059/
+http_proxy= hg -R test-dev outgoing http://localhost:$HGPORT/ | sed -e 's,:[0-9][0-9]*/,/,'
+http_proxy= hg -R test-dev outgoing -r 11 http://localhost:$HGPORT/ | sed -e 's,:[0-9][0-9]*/,/,'
--- a/tests/test-incoming-outgoing.out
+++ b/tests/test-incoming-outgoing.out
@@ -4,7 +4,7 @@ checking manifests
 crosschecking files in changesets and manifests
 checking files
 1 files, 9 changesets, 9 total revisions
-comparing with http://localhost:20059/
+comparing with http://localhost/
 changeset:   0:9cb21d99fe27
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
@@ -51,7 +51,7 @@ user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
 summary:     8
 
-comparing with http://localhost:20059/
+comparing with http://localhost/
 changeset:   0:9cb21d99fe27
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
@@ -151,7 +151,7 @@ user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
 summary:     4
 
-comparing with http://localhost:20059/
+comparing with http://localhost/
 changeset:   0:9cb21d99fe27
 user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
@@ -301,7 +301,7 @@ user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
 summary:     13
 
-comparing with http://localhost:20059/
+comparing with http://localhost/
 searching for changes
 changeset:   9:3741c3ad1096
 user:        test
@@ -329,7 +329,7 @@ user:        test
 date:        Mon Jan 12 13:46:40 1970 +0000
 summary:     13
 
-comparing with http://localhost:20059/
+comparing with http://localhost/
 searching for changes
 changeset:   9:3741c3ad1096
 user:        test
--- a/tests/test-non-interactive-wsgi
+++ b/tests/test-non-interactive-wsgi
@@ -15,7 +15,7 @@ from mercurial.hgweb.request import _wsg
 from mercurial.ui import ui
 from mercurial import hg
 from StringIO import StringIO
-import sys
+import os, sys
 
 class FileLike(object):
     def __init__(self, real):
@@ -58,7 +58,7 @@ env = {
 	'PATH_INFO': '',
 	'QUERY_STRING': '',
 	'SERVER_NAME': '127.0.0.1',
-	'SERVER_PORT': '20059',
+	'SERVER_PORT': os.environ['HGPORT'],
 	'SERVER_PROTOCOL': 'HTTP/1.0'
 }
 
--- a/tests/test-pull
+++ b/tests/test-pull
@@ -7,17 +7,17 @@ hg init
 hg addremove
 hg commit -m 1
 hg verify
-hg serve -p 20059 -d --pid-file=hg.pid
+hg serve -p $HGPORT -d --pid-file=hg.pid
 cat hg.pid >> $DAEMON_PIDS
 cd ..
 
-http_proxy= hg clone --pull http://localhost:20059/ copy
+http_proxy= hg clone --pull http://localhost:$HGPORT/ copy | sed -e 's,:[0-9][0-9]*/,/,'
 cd copy
 hg verify
 hg co
 cat foo
 hg manifest --debug
-hg pull
+hg pull | sed -e 's,:[0-9][0-9]*/,/,'
 
 echo % issue 622
 cd ..
--- a/tests/test-pull.out
+++ b/tests/test-pull.out
@@ -18,7 +18,7 @@ 1 files, 1 changesets, 1 total revisions
 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
 foo
 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 foo
-pulling from http://localhost:20059/
+pulling from http://localhost/
 searching for changes
 no changes found
 % issue 622
--- a/tests/test-push-http
+++ b/tests/test-push-http
@@ -16,33 +16,33 @@ hg ci -mb -d '0 0'
 cd ../test
 
 echo % expect ssl error
-hg serve -p 20059 -d --pid-file=hg.pid
+hg serve -p $HGPORT -d --pid-file=hg.pid
 cat hg.pid >> $DAEMON_PIDS
-hg --cwd ../test2 push http://localhost:20059/
+hg --cwd ../test2 push http://localhost:$HGPORT/
 kill `cat hg.pid`
 
 echo % expect authorization error
 echo '[web]' > .hg/hgrc
 echo 'push_ssl = false' >> .hg/hgrc
-hg serve -p 20059 -d --pid-file=hg.pid
+hg serve -p $HGPORT -d --pid-file=hg.pid
 cat hg.pid >> $DAEMON_PIDS
-hg --cwd ../test2 push http://localhost:20059/
+hg --cwd ../test2 push http://localhost:$HGPORT/
 kill `cat hg.pid`
 
 echo % expect authorization error: must have authorized user
 echo 'allow_push = unperson' >> .hg/hgrc
-hg serve -p 20059 -d --pid-file=hg.pid
+hg serve -p $HGPORT -d --pid-file=hg.pid
 cat hg.pid >> $DAEMON_PIDS
-hg --cwd ../test2 push http://localhost:20059/
+hg --cwd ../test2 push http://localhost:$HGPORT/
 kill `cat hg.pid`
 
 echo % expect success
 echo 'allow_push = *' >> .hg/hgrc
 echo '[hooks]' >> .hg/hgrc
 echo 'changegroup = python ../printenv.py changegroup 0 ../urls' >> .hg/hgrc
-hg serve -p 20059 -d --pid-file=hg.pid
+hg serve -p $HGPORT -d --pid-file=hg.pid
 cat hg.pid >> $DAEMON_PIDS
-hg --cwd ../test2 push http://localhost:20059/
+hg --cwd ../test2 push http://localhost:$HGPORT/
 kill `cat hg.pid`
 hg rollback
 
@@ -52,14 +52,14 @@ echo % expect authorization error: all u
 echo '[web]' > .hg/hgrc
 echo 'push_ssl = false' >> .hg/hgrc
 echo 'deny_push = *' >> .hg/hgrc
-hg serve -p 20059 -d --pid-file=hg.pid
+hg serve -p $HGPORT -d --pid-file=hg.pid
 cat hg.pid >> $DAEMON_PIDS
-hg --cwd ../test2 push http://localhost:20059/
+hg --cwd ../test2 push http://localhost:$HGPORT/ | sed -e 's,:[0-9][0-9]*/,/,'
 kill `cat hg.pid`
 
 echo % expect authorization error: some users denied, users must be authenticated
 echo 'deny_push = unperson' >> .hg/hgrc
-hg serve -p 20059 -d --pid-file=hg.pid
+hg serve -p $HGPORT -d --pid-file=hg.pid
 cat hg.pid >> $DAEMON_PIDS
-hg --cwd ../test2 push http://localhost:20059/
+hg --cwd ../test2 push http://localhost:$HGPORT/ | sed -e 's,:[0-9][0-9]*/,/,'
 kill `cat hg.pid`
--- a/tests/test-push-http.out
+++ b/tests/test-push-http.out
@@ -1,19 +1,19 @@
 adding a
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 % expect ssl error
-pushing to http://localhost:20059/
+pushing to http://localhost:23451/
 searching for changes
 ssl required
 % expect authorization error
-pushing to http://localhost:20059/
+pushing to http://localhost:23451/
 searching for changes
 push not authorized
 % expect authorization error: must have authorized user
-pushing to http://localhost:20059/
+pushing to http://localhost:23451/
 searching for changes
 push not authorized
 % expect success
-pushing to http://localhost:20059/
+pushing to http://localhost:23451/
 searching for changes
 adding changesets
 adding manifests
@@ -22,10 +22,10 @@ added 1 changesets with 1 changes to 1 f
 rolling back last transaction
 changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_URL=remote:http 
 % expect authorization error: all users denied
-pushing to http://localhost:20059/
+pushing to http://localhost/
 searching for changes
 push not authorized
 % expect authorization error: some users denied, users must be authenticated
-pushing to http://localhost:20059/
+pushing to http://localhost/
 searching for changes
 push not authorized
--- a/tests/test-serve
+++ b/tests/test-serve
@@ -7,12 +7,12 @@ echo '[web]' > .hg/hgrc
 echo 'accesslog = access.log' >> .hg/hgrc
 
 echo % Without -v
-hg serve -a localhost -p 20063 -d --pid-file=hg.pid
+hg serve -a localhost -p $HGPORT -d --pid-file=hg.pid
 cat hg.pid >> "$DAEMON_PIDS"
 if [ -f access.log ]; then
     echo 'access log created - .hg/hgrc respected'
 fi
 
 echo % With -v
-hg serve -a localhost -p 20064 -d --pid-file=hg.pid -v
+hg serve -a localhost -p $HGPORT1 -d --pid-file=hg.pid -v | sed -e 's,:[0-9][0-9]*/,/,'
 cat hg.pid >> "$DAEMON_PIDS"
--- a/tests/test-serve.out
+++ b/tests/test-serve.out
@@ -1,4 +1,4 @@
 % Without -v
 access log created - .hg/hgrc respected
 % With -v
-listening at http://localhost:20064/
+listening at http://localhost/
--- a/tests/test-static-http
+++ b/tests/test-static-http
@@ -2,18 +2,18 @@
 
 cp "$TESTDIR"/printenv.py .
 
-http_proxy= hg clone static-http://localhost:20059/ copy
+http_proxy= hg clone static-http://localhost:$HGPORT/ copy
 echo $?
 test -d copy || echo copy: No such file or directory
 
 # This server doesn't do range requests so it's basically only good for
 # one pull
 cat > dumb.py <<EOF
-import BaseHTTPServer, SimpleHTTPServer, signal
+import BaseHTTPServer, SimpleHTTPServer, os, signal
 
 def run(server_class=BaseHTTPServer.HTTPServer,
         handler_class=SimpleHTTPServer.SimpleHTTPRequestHandler):
-    server_address = ('localhost', 20059)
+    server_address = ('localhost', int(os.environ['HGPORT']))
     httpd = server_class(server_address, handler_class)
     httpd.serve_forever()
 
@@ -34,7 +34,7 @@ hg tip
 
 cd ..
 
-http_proxy= hg clone static-http://localhost:20059/remote local
+http_proxy= hg clone static-http://localhost:$HGPORT/remote local | sed -e 's,:[0-9][0-9]*/,/,'
 
 cd local
 hg verify
@@ -47,7 +47,7 @@ hg commit -A -mtest2 -d '100000000 0'
 cd ../local
 echo '[hooks]' >> .hg/hgrc
 echo 'changegroup = python ../printenv.py changegroup' >> .hg/hgrc
-http_proxy= hg pull
+http_proxy= hg pull | sed -e 's,:[0-9][0-9]*/,/,'
 
 echo '% test with "/" URI (issue 747)'
 cd ..
@@ -56,11 +56,11 @@ echo a > a
 hg add a
 hg ci -ma
 
-http_proxy= hg clone static-http://localhost:20059/ local2
+http_proxy= hg clone static-http://localhost:$HGPORT/ local2 | sed -e 's,:[0-9][0-9]*/,/,'
 
 cd local2
 hg verify
 cat a
-hg paths
+hg paths | sed -e 's,:[0-9][0-9]*/,/,'
 
 kill $!
--- a/tests/test-static-http.out
+++ b/tests/test-static-http.out
@@ -20,8 +20,8 @@ checking files
 1 files, 1 changesets, 1 total revisions
 foo
 adding quux
-changegroup hook: HG_NODE=34401e0e9971e9720b613d9089ffa9a6eefb3d2d HG_SOURCE=pull HG_URL=static-http://localhost:20059/remote 
-pulling from static-http://localhost:20059/remote
+changegroup hook: HG_NODE=34401e0e9971e9720b613d9089ffa9a6eefb3d2d HG_SOURCE=pull HG_URL=static-http://localhost/remote 
+pulling from static-http://localhost/remote
 searching for changes
 adding changesets
 adding manifests
@@ -41,4 +41,4 @@ crosschecking files in changesets and ma
 checking files
 1 files, 1 changesets, 1 total revisions
 a
-default = static-http://localhost:20059/
+default = static-http://localhost/
--- a/tests/test-transplant
+++ b/tests/test-transplant
@@ -56,12 +56,12 @@ cd ../pullback
 hg transplant -s ../remote -a -b tip
 
 echo '% remote transplant with pull'
-hg -R ../t serve -p 20062 -d --pid-file=../t.pid
+hg -R ../t serve -p $HGPORT -d --pid-file=../t.pid
 cat ../t.pid >> $DAEMON_PIDS
 
 hg clone -r 0 ../t ../rp
 cd ../rp
-hg transplant -s http://localhost:20062/ 2 4
+hg transplant -s http://localhost:$HGPORT/ 2 4
 hg log --template '{rev} {parents} {desc}\n'
 
 echo '% transplant --continue'
--- a/tests/test-webraw
+++ b/tests/test-webraw
@@ -10,9 +10,9 @@ care about things like that.
 ENDSOME
 hg add sometext.txt
 hg commit -d "1 0" -m "Just some text"
-hg serve -p 20059 -A access.log -E error.log -d --pid-file=hg.pid
+hg serve -p $HGPORT -A access.log -E error.log -d --pid-file=hg.pid
 cat hg.pid >> $DAEMON_PIDS
-("$TESTDIR/get-with-headers.py" localhost:20059 '/?f=f165dc289438;file=sometext.txt;style=raw' content-type content-length content-disposition) >getoutput.txt &
+("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?f=f165dc289438;file=sometext.txt;style=raw' content-type content-length content-disposition) >getoutput.txt &
 
 sleep 5
 kill `cat hg.pid`