diff --git a/testsuite/expect/regression.py b/testsuite/expect/regression.py
new file mode 100755
index 0000000000000000000000000000000000000000..57dbcaadca98e7befbcb0302f20be6002290711f
--- /dev/null
+++ b/testsuite/expect/regression.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python
+############################################################################
+# Copyright (C) 2006 The Regents of the University of California.
+# Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+# Written by Christopher J. Morrone <morrone2@llnl.gov>
+# UCRL-CODE-217948.
+# 
+# This file is part of SLURM, a resource management program.
+# For details, see <http://www.llnl.gov/linux/slurm/>.
+#  
+# SLURM is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option)
+# any later version.
+# 
+# SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+# details.
+# 
+# You should have received a copy of the GNU General Public License along
+# with SLURM; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+############################################################################
+
+"""This script makes it easier to run the SLURM expect test scripts."""
+
+import os
+import re
+import sys
+import time
+from optparse import OptionParser
+from optparse import OptionValueError
+
+def main(argv=None):
+    try:
+        from subprocess import Popen
+    except:
+        Popen = poor_Popen_substitute
+
+    # "tests" is a list containing tuples of length 3 of the form
+    # (test major number, test minor number, test filename)
+    tests = []
+    failed_tests = []
+    passed_tests = []
+
+    # Handle command line parameters
+    if argv is None:
+        argv = sys.argv
+
+    parser = OptionParser()
+    parser.add_option('-t', '--time-individual', action='store_true',
+                      dest='time_individual', default=False)
+    parser.add_option('-e', '--exclude', type='string', dest='exclude_tests',
+                      action='callback', callback=test_parser,
+                      help='comma or space seperated string of tests to skip')
+    parser.add_option('-i', '--include', type='string', dest='include_tests',
+                      action='callback', callback=test_parser,
+                      help='comma or space seperated string of tests to include')
+    parser.add_option('-k', '--keep-logs', action='store_true', default=False)
+    (options, args) = parser.parse_args(args=argv)
+
+    # Sanity check
+    if not os.path.isfile('globals'):
+        print >>sys.stderr, 'ERROR: copy "globals.example" to "globals" and modify as needed'
+        return -1
+
+    # Read the current working directory and build a sorted list
+    # of the available tests.
+    test_re = re.compile('test(\d+)\.(\d+)$')
+    for filename in os.listdir('.'):
+        match = test_re.match(filename)
+        if match:
+            major = int(match.group(1))
+            minor = int(match.group(2))
+            if not test_in_list(major, minor, options.exclude_tests) \
+                   and (not options.include_tests
+                        or test_in_list(major, minor, options.include_tests)):
+                tests.append((major, minor, filename))
+    if not tests:
+        print >>sys.stderr, 'ERROR: no test files found in current working directory'
+        return -1
+    tests.sort(test_cmp)
+
+    # Now run the tests
+    start_time = time.time()
+    print >>sys.stdout, 'Started:', time.asctime(time.localtime(start_time))
+    sys.stdout.flush()
+    for test in tests:
+        sys.stdout.write('Running test %d.%d ' % (test[0],test[1]))
+        sys.stdout.flush()
+        testlog_name = 'test%d.%d.log' % (test[0],test[1])
+        try:
+            os.remove(testlog_name+'.failed')
+        except:
+            pass
+        testlog = file(testlog_name, 'w+')
+
+        if options.time_individual:
+            t1 = time.time()
+        retcode = Popen(('expect', test[2]), shell=False,
+                        stdout=testlog, stderr=testlog).wait()
+        if options.time_individual:
+            t2 = time.time()
+            minutes = int(t2-t1)/60
+            seconds = (t2-t1)%60
+            if minutes > 0:
+                sys.stdout.write('%d min '%(minutes))
+            sys.stdout.write('%.2f sec '%(seconds))
+
+        testlog.close()
+        if retcode == 0:
+            passed_tests.append(test)
+            sys.stdout.write('\n')
+            if not options.keep_logs:
+                os.remove(testlog_name)
+        else:
+            failed_tests.append(test)
+            os.rename(testlog_name, testlog_name+'.failed')
+            sys.stdout.write('FAILED!\n')
+        sys.stdout.flush()
+
+    end_time = time.time()
+    print >>sys.stdout, 'Ended:', time.asctime(time.localtime(end_time))
+    print >>sys.stdout, '\nTestsuite ran for %d minutes %d seconds'\
+          %((end_time-start_time)/60,(end_time-start_time)%60)
+    print >>sys.stdout
+    print >>sys.stdout, 'Completions  :', len(passed_tests)
+    print >>sys.stdout, 'Failures     :', len(failed_tests)
+    if len(failed_tests) > 0:
+        print >>sys.stdout, 'Failed tests : ',
+        first = True
+        for test in failed_tests:
+            if first:
+                first = False
+            else:
+                sys.stdout.write(', ')
+            sys.stdout.write('%d.%d'%(test[0], test[1]))
+        sys.stdout.write('\n')
+        sys.stdout.flush()
+
+def test_cmp(testA, testB):
+    if testA[0] < testB[0]:
+        return -1
+    elif testA[0] > testB[0]:
+        return 1
+    else:
+        if testA[1] < testB[1]:
+            return -1
+        elif testA[1] > testB[1]:
+            return 1
+        else:
+            return 0
+
+def test_in_list(major, minor, test_list):
+    if not test_list:
+        return False
+    for test in test_list:
+        if ((test[0] == '*' or test[0] == major)
+            and (test[1] == '*' or test[1] == minor)):
+            return True
+    return False
+
+def test_parser(option, opt_str, value, parser):
+    splitter = re.compile('[,\s]+')
+    # On error: raise OptionValueError
+    # parser.values.exclude
+    # setattr(parser.values, option.dest, 1)
+    if not hasattr(parser.values, option.dest):
+        setattr(parser.values, option.dest, [])
+    if getattr(parser.values, option.dest) is None:
+        setattr(parser.values, option.dest, [])
+    l = getattr(parser.values, option.dest)
+    val = splitter.split(value)
+    test_re = re.compile('(test)?((\d+)|\*)\.((\d+)|\*)$')
+    for v in val:
+        m = test_re.match(v)
+        if not m:
+            raise OptionValueError
+        major = m.group(2)
+        if major != '*':
+            major = int(major)
+        minor = m.group(4)
+        if minor != '*':
+            minor = int(minor)
+        l.append((major, minor))
+
+class poor_Popen_substitute:
+    def __init__(self, args, shell=False, stdout=None, stderr=None):
+        if shell is not False:
+            raise Exception("This substitute Popen only supports shell=True")
+        self.stdin = None
+        self.stdout = None
+        self.stderr = None
+        self.pid = None
+        self.returncode = None
+
+        pid = os.fork()
+        if pid > 0:
+            self.pid = pid
+            return
+        elif pid == 0:
+            if sys.stdout is not None:
+                os.dup2(stdout.fileno(), sys.stdout.fileno())
+                if sys.stdout == 'STDOUT':
+                    os.dup2(stdout.fileno(), sys.stderr.fileno())
+            if sys.stderr is not None:
+                os.dup2(stderr.fileno(), sys.stderr.fileno())
+
+            os.execvp(args[0], args)
+
+    def wait(self):
+        (pid, rc) = os.waitpid(self.pid, 0)
+        return rc
+
+if __name__ == "__main__":
+    sys.exit(main())