comparison tests/run-tests.py @ 21309:0b123e6a318c

run-tests: allow Test.run() to run multiple times Test.run() can now be executed multiple times on the same Test instance. This feature is currently unused and there are no plans to implement it. The main reason for this work was to refactor testtmp, replacements, and env to be run-time specific as opposed to Test instance specific.
author Gregory Szorc <gregory.szorc@gmail.com>
date Sat, 19 Apr 2014 14:47:34 -0700
parents 935ade207253
children af9a04951c69
comparison
equal deleted inserted replaced
21308:935ade207253 21309:0b123e6a318c
543 if not os.path.isdir(adir): 543 if not os.path.isdir(adir):
544 os.mkdir(adir) 544 os.mkdir(adir)
545 covrun('-i', '-a', '"--directory=%s"' % adir, '"--omit=%s"' % omit) 545 covrun('-i', '-a', '"--directory=%s"' % adir, '"--omit=%s"' % omit)
546 546
547 class Test(object): 547 class Test(object):
548 """Encapsulates a single, runnable test.""" 548 """Encapsulates a single, runnable test.
549
550 Test instances can be run multiple times via run(). However, multiple
551 runs cannot be run concurrently.
552 """
549 553
550 def __init__(self, path, options, count): 554 def __init__(self, path, options, count):
551 self._path = path 555 self._path = path
552 self._options = options 556 self._options = options
557 self._count = count
553 558
554 self.threadtmp = os.path.join(HGTMP, 'child%d' % count) 559 self.threadtmp = os.path.join(HGTMP, 'child%d' % count)
555 os.mkdir(self.threadtmp) 560 os.mkdir(self.threadtmp)
556 561
557 self._testtmp = os.path.join(self.threadtmp, os.path.basename(path))
558 os.mkdir(self._testtmp)
559
560 self._setreplacements(count)
561
562 def run(self, result, refpath): 562 def run(self, result, refpath):
563 env = self._getenv() 563 testtmp = os.path.join(self.threadtmp, os.path.basename(self._path))
564 os.mkdir(testtmp)
565 replacements, port = self._getreplacements(testtmp)
566 env = self._getenv(testtmp, port)
564 createhgrc(env['HGRCPATH'], self._options) 567 createhgrc(env['HGRCPATH'], self._options)
565 568
566 starttime = time.time() 569 starttime = time.time()
567 570
568 def updateduration(): 571 def updateduration():
569 result.duration = time.time() - starttime 572 result.duration = time.time() - starttime
570 573
571 try: 574 try:
572 ret, out = self._run(self._replacements, env) 575 ret, out = self._run(testtmp, replacements, env)
573 updateduration() 576 updateduration()
574 result.ret = ret 577 result.ret = ret
575 result.out = out 578 result.out = out
576 except KeyboardInterrupt: 579 except KeyboardInterrupt:
577 updateduration() 580 updateduration()
591 result.refout = f.read().splitlines(True) 594 result.refout = f.read().splitlines(True)
592 f.close() 595 f.close()
593 else: 596 else:
594 result.refout = [] 597 result.refout = []
595 598
596 def _run(self, replacements, env): 599 if not self._options.keep_tmpdir:
600 shutil.rmtree(testtmp)
601
602 def _run(self, testtmp, replacements, env):
597 raise NotImplemented('Subclasses must implement Test.run()') 603 raise NotImplemented('Subclasses must implement Test.run()')
598 604
599 def _setreplacements(self, count): 605 def _getreplacements(self, testtmp):
600 port = self._options.port + count * 3 606 port = self._options.port + self._count * 3
601 r = [ 607 r = [
602 (r':%s\b' % port, ':$HGPORT'), 608 (r':%s\b' % port, ':$HGPORT'),
603 (r':%s\b' % (port + 1), ':$HGPORT1'), 609 (r':%s\b' % (port + 1), ':$HGPORT1'),
604 (r':%s\b' % (port + 2), ':$HGPORT2'), 610 (r':%s\b' % (port + 2), ':$HGPORT2'),
605 ] 611 ]
606 612
607 if os.name == 'nt': 613 if os.name == 'nt':
608 r.append( 614 r.append(
609 (''.join(c.isalpha() and '[%s%s]' % (c.lower(), c.upper()) or 615 (''.join(c.isalpha() and '[%s%s]' % (c.lower(), c.upper()) or
610 c in '/\\' and r'[/\\]' or c.isdigit() and c or '\\' + c 616 c in '/\\' and r'[/\\]' or c.isdigit() and c or '\\' + c
611 for c in self._testtmp), '$TESTTMP')) 617 for c in testtmp), '$TESTTMP'))
612 else: 618 else:
613 r.append((re.escape(self._testtmp), '$TESTTMP')) 619 r.append((re.escape(testtmp), '$TESTTMP'))
614 620
615 self._replacements = r 621 return r, port
616 self._port = port 622
617 623 def _getenv(self, testtmp, port):
618 def _getenv(self):
619 env = os.environ.copy() 624 env = os.environ.copy()
620 env['TESTTMP'] = self._testtmp 625 env['TESTTMP'] = testtmp
621 env['HOME'] = self._testtmp 626 env['HOME'] = testtmp
622 env["HGPORT"] = str(self._port) 627 env["HGPORT"] = str(port)
623 env["HGPORT1"] = str(self._port + 1) 628 env["HGPORT1"] = str(port + 1)
624 env["HGPORT2"] = str(self._port + 2) 629 env["HGPORT2"] = str(port + 2)
625 env["HGRCPATH"] = os.path.join(self.threadtmp, '.hgrc') 630 env["HGRCPATH"] = os.path.join(self.threadtmp, '.hgrc')
626 env["DAEMON_PIDS"] = os.path.join(self.threadtmp, 'daemon.pids') 631 env["DAEMON_PIDS"] = os.path.join(self.threadtmp, 'daemon.pids')
627 env["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"' 632 env["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
628 env["HGMERGE"] = "internal:merge" 633 env["HGMERGE"] = "internal:merge"
629 env["HGUSER"] = "test" 634 env["HGUSER"] = "test"
674 replacements.append((r'\r\n', '\n')) 679 replacements.append((r'\r\n', '\n'))
675 return run(cmd, wd, options, replacements, env) 680 return run(cmd, wd, options, replacements, env)
676 681
677 class PythonTest(Test): 682 class PythonTest(Test):
678 """A Python-based test.""" 683 """A Python-based test."""
679 def _run(self, replacements, env): 684 def _run(self, testtmp, replacements, env):
680 return pytest(self._path, self._testtmp, self._options, replacements, 685 return pytest(self._path, testtmp, self._options, replacements,
681 env) 686 env)
682 687
683 needescape = re.compile(r'[\x00-\x08\x0b-\x1f\x7f-\xff]').search 688 needescape = re.compile(r'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
684 escapesub = re.compile(r'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub 689 escapesub = re.compile(r'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
685 escapemap = dict((chr(i), r'\x%02x' % i) for i in range(256)) 690 escapemap = dict((chr(i), r'\x%02x' % i) for i in range(256))
937 return exitcode, postout 942 return exitcode, postout
938 943
939 class TTest(Test): 944 class TTest(Test):
940 """A "t test" is a test backed by a .t file.""" 945 """A "t test" is a test backed by a .t file."""
941 946
942 def _run(self, replacements, env): 947 def _run(self, testtmp, replacements, env):
943 return tsttest(self._path, self._testtmp, self._options, replacements, 948 return tsttest(self._path, testtmp, self._options, replacements,
944 env) 949 env)
945 950
946 wifexited = getattr(os, "WIFEXITED", lambda x: False) 951 wifexited = getattr(os, "WIFEXITED", lambda x: False)
947 def run(cmd, wd, options, replacements, env): 952 def run(cmd, wd, options, replacements, env):
948 """Run command in a sub-process, capturing the output (stdout and stderr). 953 """Run command in a sub-process, capturing the output (stdout and stderr).