run-tests: redefine --with-hg so it takes the 'hg' script to run.
authorGreg Ward <greg-hg@gerg.ca>
Sun, 31 May 2009 15:20:31 -0400
changeset 8674 0941ee76489e
parent 8673 a8066f2fd1aa
child 8675 fb74e1e69da0
run-tests: redefine --with-hg so it takes the 'hg' script to run. - in parseargs(), check that --with-hg value is valid - add handy --local option for "--with-hg=../hg" - ensure that we always set PATH and PYTHONPATH (not just when doing a temporary install) - override any existing PYTHONPATH, so test success does not depend on whatever happens to be in the caller's environment - give tests a little more control by exporting $PYTHON to the environment; needed by test-convert and test-mergetool when they run hg with a stripped-down $PATH Also, add a big comment explaining all the corner cases to test for the next person who tries to modify this script.
tests/run-tests.py
tests/test-convert
tests/test-merge-tools
--- a/tests/run-tests.py	Fri May 29 22:18:16 2009 -0400
+++ b/tests/run-tests.py	Sun May 31 15:20:31 2009 -0400
@@ -7,6 +7,38 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2, incorporated herein by reference.
 
+# Modifying this script is tricky because it has many modes:
+#   - serial (default) vs parallel (-jN, N > 1)
+#   - no coverage (default) vs coverage (-c, -C, -s)
+#   - temp install (default) vs specific hg script (--with-hg, --local)
+#   - tests are a mix of shell scripts and Python scripts
+#
+# If you change this script, it is recommended that you ensure you
+# haven't broken it by running it in various modes with a representative
+# sample of test scripts.  For example:
+# 
+#  1) serial, no coverage, temp install:
+#      ./run-tests.py test-s*
+#  2) serial, no coverage, local hg:
+#      ./run-tests.py --local test-s*
+#  3) serial, coverage, temp install:
+#      ./run-tests.py -c test-s*
+#  4) serial, coverage, local hg:
+#      ./run-tests.py -c --local test-s*      # unsupported
+#  5) parallel, no coverage, temp install:
+#      ./run-tests.py -j2 test-s*
+#  6) parallel, no coverage, local hg:
+#      ./run-tests.py -j2 --local test-s*
+#  7) parallel, coverage, temp install:
+#      ./run-tests.py -j2 -c test-s*          # currently broken
+#  8) parallel, coverage, local install
+#      ./run-tests.py -j2 -c --local test-s*  # unsupported (and broken)
+#
+# (You could use any subset of the tests: test-s* happens to match
+# enough that it's worth doing parallel runs, few enough that it
+# completes fairly quickly, includes both shell and Python scripts, and
+# includes some scripts that run daemon processes.)
+
 import difflib
 import errno
 import optparse
@@ -34,7 +66,6 @@
 SKIPPED_PREFIX = 'skipped: '
 FAILED_PREFIX  = 'hghave check failed: '
 PYTHON = sys.executable
-hgpkg = None
 
 requiredtools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed"]
 
@@ -81,7 +112,11 @@
     parser.add_option("-n", "--nodiff", action="store_true",
         help="skip showing test changes")
     parser.add_option("--with-hg", type="string",
-        help="test existing install at given location")
+        metavar="HG",
+        help="test using specified hg script rather than a "
+             "temporary installation")
+    parser.add_option("--local", action="store_true",
+        help="shortcut for --with-hg=<testdir>/../hg")
     parser.add_option("--pure", action="store_true",
         help="use pure Python code instead of C extensions")
 
@@ -90,11 +125,32 @@
     parser.set_defaults(**defaults)
     (options, args) = parser.parse_args()
 
-    global vlog
+    if options.with_hg:
+        if not (os.path.isfile(options.with_hg) and
+                os.access(options.with_hg, os.X_OK)):
+            parser.error('--with-hg must specify an executable hg script')
+        if not os.path.basename(options.with_hg) == 'hg':
+            sys.stderr.write('warning: --with-hg should specify an hg script')
+    if options.local:
+        testdir = os.path.dirname(os.path.realpath(sys.argv[0]))
+        hgbin = os.path.join(os.path.dirname(testdir), 'hg')
+        if not os.access(hgbin, os.X_OK):
+            parser.error('--local specified, but %r not found or not executable'
+                         % hgbin)
+        options.with_hg = hgbin
+
     options.anycoverage = (options.cover or
                            options.cover_stdlib or
                            options.annotate)
 
+    if options.anycoverage and options.with_hg:
+        # I'm not sure if this is a fundamental limitation or just a
+        # bug.  But I don't want to waste people's time and energy doing
+        # test runs that don't give the results they want.
+        parser.error("sorry, coverage options do not work when --with-hg "
+                     "or --local specified")
+
+    global vlog
     if options.verbose:
         if options.jobs > 1 or options.child is not None:
             pid = "[%d]" % os.getpid()
@@ -227,16 +283,6 @@
         sys.exit(1)
     os.chdir(TESTDIR)
 
-    os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"])
-
-    pydir = os.pathsep.join([PYTHONDIR, TESTDIR])
-    pythonpath = os.environ.get("PYTHONPATH")
-    if pythonpath:
-        pythonpath = pydir + os.pathsep + pythonpath
-    else:
-        pythonpath = pydir
-    os.environ["PYTHONPATH"] = pythonpath
-
     usecorrectpython()
 
     vlog("# Installing dummy diffstat")
@@ -512,13 +558,14 @@
                          % (verb, actualhg, expecthg))
 
 def runchildren(options, tests):
-    if not options.with_hg:
+    if INST:
         installhg(options)
         _checkhglib("Testing")
 
     optcopy = dict(options.__dict__)
     optcopy['jobs'] = 1
-    optcopy['with_hg'] = INST
+    if optcopy['with_hg'] is None:
+        optcopy['with_hg'] = os.path.join(BINDIR, "hg")
     opts = []
     for opt, value in optcopy.iteritems():
         name = '--' + opt.replace('_', '-')
@@ -579,7 +626,7 @@
     HGRCPATH = os.environ["HGRCPATH"] = os.path.join(HGTMP, '.hgrc')
 
     try:
-        if not options.with_hg:
+        if INST:
             installhg(options)
             _checkhglib("Testing")
 
@@ -687,11 +734,31 @@
     os.environ["HGPORT2"] = str(options.port + 2)
 
     if options.with_hg:
-        INST = options.with_hg
+        INST = None
+        BINDIR = os.path.dirname(os.path.realpath(options.with_hg))
+
+        # This looks redundant with how Python initializes sys.path from
+        # the location of the script being executed.  Needed because the
+        # "hg" specified by --with-hg is not the only Python script
+        # executed in the test suite that needs to import 'mercurial'
+        # ... which means it's not really redundant at all.
+        PYTHONDIR = BINDIR
     else:
         INST = os.path.join(HGTMP, "install")
-    BINDIR = os.environ["BINDIR"] = os.path.join(INST, "bin")
-    PYTHONDIR = os.path.join(INST, "lib", "python")
+        BINDIR = os.environ["BINDIR"] = os.path.join(INST, "bin")
+        PYTHONDIR = os.path.join(INST, "lib", "python")
+
+    os.environ["BINDIR"] = BINDIR
+    os.environ["PYTHON"] = PYTHON
+
+    if not options.child:
+        path = [BINDIR] + os.environ["PATH"].split(os.pathsep)
+        os.environ["PATH"] = os.pathsep.join(path)
+
+        # Deliberately override existing PYTHONPATH: do not want success
+        # to depend on what happens to be in caller's environment.
+        os.environ["PYTHONPATH"] = PYTHONDIR
+
     COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
 
     if len(args) == 0:
@@ -710,6 +777,8 @@
 
     vlog("# Using TESTDIR", TESTDIR)
     vlog("# Using HGTMP", HGTMP)
+    vlog("# Using PATH", os.environ["PATH"])
+    vlog("# Using PYTHONPATH", os.environ["PYTHONPATH"])
 
     try:
         if len(tests) > 1 and options.jobs > 1:
--- a/tests/test-convert	Fri May 29 22:18:16 2009 -0400
+++ b/tests/test-convert	Sun May 31 15:20:31 2009 -0400
@@ -47,4 +47,6 @@
 
 echo % converting empty dir should fail "nicely"
 mkdir emptydir
-PATH=$BINDIR hg convert emptydir 2>&1 | sed 's,file://.*/emptydir,.../emptydir,g'
+# override $PATH to ensure p4 not visible; use $PYTHON in case we're
+# running from a devel copy, not a temp installation
+PATH=$BINDIR $PYTHON $BINDIR/hg convert emptydir 2>&1 | sed 's,file://.*/emptydir,.../emptydir,g'
--- a/tests/test-merge-tools	Fri May 29 22:18:16 2009 -0400
+++ b/tests/test-merge-tools	Sun May 31 15:20:31 2009 -0400
@@ -60,7 +60,9 @@
 echo "# default is internal merge:"
 beforemerge
 echo "# hg merge -r 2"
-PATH=$BINDIR hg merge -r 2
+# override $PATH to ensure hgmerge not visible; use $PYTHON in case we're
+# running from a devel copy, not a temp installation
+PATH=$BINDIR $PYTHON $BINDIR/hg merge -r 2
 aftermerge
 
 echo "# simplest hgrc using false for merge:"