Mercurial > hg
comparison tests/run-tests.py @ 22104:70bdf59d27b6
run-tests: attempt to fix iolock handling
Ideally, when using -j and -i together, when a prompt comes up, we'd
like all other output to wait (but testing to continue!). This gets
other output to wait by adding back a bunch of the locking that
formerly existed. We switch to a recursive lock to deal with the
restructuring due to unittest compatibility.
Running tests continue to run, but now the scheduler doesn't schedule
any new tasks while waiting at a prompt because no task slots become
available due to result output happening in the thread and
blocking on the iolock.
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Mon, 11 Aug 2014 17:45:50 -0500 |
parents | 769198c6a62d |
children | 3b5cf39ffcc4 |
comparison
equal
deleted
inserted
replaced
22102:fff8e1cec90f | 22104:70bdf59d27b6 |
---|---|
1071 | 1071 |
1072 for s, r in replacements: | 1072 for s, r in replacements: |
1073 output = re.sub(s, r, output) | 1073 output = re.sub(s, r, output) |
1074 return ret, output.splitlines(True) | 1074 return ret, output.splitlines(True) |
1075 | 1075 |
1076 iolock = threading.Lock() | 1076 iolock = threading.RLock() |
1077 | 1077 |
1078 class SkipTest(Exception): | 1078 class SkipTest(Exception): |
1079 """Raised to indicate that a test is to be skipped.""" | 1079 """Raised to indicate that a test is to be skipped.""" |
1080 | 1080 |
1081 class IgnoreTest(Exception): | 1081 class IgnoreTest(Exception): |
1126 | 1126 |
1127 self.stream.write('!') | 1127 self.stream.write('!') |
1128 iolock.release() | 1128 iolock.release() |
1129 | 1129 |
1130 def addSuccess(self, test): | 1130 def addSuccess(self, test): |
1131 iolock.acquire() | |
1131 super(TestResult, self).addSuccess(test) | 1132 super(TestResult, self).addSuccess(test) |
1133 iolock.release() | |
1132 self.successes.append(test) | 1134 self.successes.append(test) |
1133 | 1135 |
1134 def addError(self, test, err): | 1136 def addError(self, test, err): |
1135 super(TestResult, self).addError(test, err) | 1137 super(TestResult, self).addError(test, err) |
1136 if self._options.first: | 1138 if self._options.first: |
1137 self.stop() | 1139 self.stop() |
1138 | 1140 |
1139 # Polyfill. | 1141 # Polyfill. |
1140 def addSkip(self, test, reason): | 1142 def addSkip(self, test, reason): |
1141 self.skipped.append((test, reason)) | 1143 self.skipped.append((test, reason)) |
1144 iolock.acquire() | |
1142 if self.showAll: | 1145 if self.showAll: |
1143 self.stream.writeln('skipped %s' % reason) | 1146 self.stream.writeln('skipped %s' % reason) |
1144 else: | 1147 else: |
1145 self.stream.write('s') | 1148 self.stream.write('s') |
1146 self.stream.flush() | 1149 self.stream.flush() |
1150 iolock.release() | |
1147 | 1151 |
1148 def addIgnore(self, test, reason): | 1152 def addIgnore(self, test, reason): |
1149 self.ignored.append((test, reason)) | 1153 self.ignored.append((test, reason)) |
1154 iolock.acquire() | |
1150 if self.showAll: | 1155 if self.showAll: |
1151 self.stream.writeln('ignored %s' % reason) | 1156 self.stream.writeln('ignored %s' % reason) |
1152 else: | 1157 else: |
1153 if reason != 'not retesting': | 1158 if reason != 'not retesting': |
1154 self.stream.write('i') | 1159 self.stream.write('i') |
1155 else: | 1160 else: |
1156 self.testsRun += 1 | 1161 self.testsRun += 1 |
1157 self.stream.flush() | 1162 self.stream.flush() |
1163 iolock.release() | |
1158 | 1164 |
1159 def addWarn(self, test, reason): | 1165 def addWarn(self, test, reason): |
1160 self.warned.append((test, reason)) | 1166 self.warned.append((test, reason)) |
1161 | 1167 |
1162 if self._options.first: | 1168 if self._options.first: |
1163 self.stop() | 1169 self.stop() |
1164 | 1170 |
1171 iolock.acquire() | |
1165 if self.showAll: | 1172 if self.showAll: |
1166 self.stream.writeln('warned %s' % reason) | 1173 self.stream.writeln('warned %s' % reason) |
1167 else: | 1174 else: |
1168 self.stream.write('~') | 1175 self.stream.write('~') |
1169 self.stream.flush() | 1176 self.stream.flush() |
1177 iolock.release() | |
1170 | 1178 |
1171 def addOutputMismatch(self, test, ret, got, expected): | 1179 def addOutputMismatch(self, test, ret, got, expected): |
1172 """Record a mismatch in test output for a particular test.""" | 1180 """Record a mismatch in test output for a particular test.""" |
1173 | 1181 |
1174 accepted = False | 1182 accepted = False |
1229 | 1237 |
1230 del self._started[test.name] | 1238 del self._started[test.name] |
1231 del self._stopped[test.name] | 1239 del self._stopped[test.name] |
1232 | 1240 |
1233 if interrupted: | 1241 if interrupted: |
1242 iolock.acquire() | |
1234 self.stream.writeln('INTERRUPTED: %s (after %d seconds)' % ( | 1243 self.stream.writeln('INTERRUPTED: %s (after %d seconds)' % ( |
1235 test.name, self.times[-1][3])) | 1244 test.name, self.times[-1][3])) |
1245 iolock.release() | |
1236 | 1246 |
1237 class TestSuite(unittest.TestSuite): | 1247 class TestSuite(unittest.TestSuite): |
1238 """Custom unitest TestSuite that knows how to execute Mercurial tests.""" | 1248 """Custom unitest TestSuite that knows how to execute Mercurial tests.""" |
1239 | 1249 |
1240 def __init__(self, testdir, jobs=1, whitelist=None, blacklist=None, | 1250 def __init__(self, testdir, jobs=1, whitelist=None, blacklist=None, |
1364 failed = len(result.failures) | 1374 failed = len(result.failures) |
1365 warned = len(result.warned) | 1375 warned = len(result.warned) |
1366 skipped = len(result.skipped) | 1376 skipped = len(result.skipped) |
1367 ignored = len(result.ignored) | 1377 ignored = len(result.ignored) |
1368 | 1378 |
1379 iolock.acquire() | |
1369 self.stream.writeln('') | 1380 self.stream.writeln('') |
1370 | 1381 |
1371 if not self._runner.options.noskips: | 1382 if not self._runner.options.noskips: |
1372 for test, msg in result.skipped: | 1383 for test, msg in result.skipped: |
1373 self.stream.writeln('Skipped %s: %s' % (test.name, msg)) | 1384 self.stream.writeln('Skipped %s: %s' % (test.name, msg)) |
1416 self.stream.writeln('python hash seed: %s' % | 1427 self.stream.writeln('python hash seed: %s' % |
1417 os.environ['PYTHONHASHSEED']) | 1428 os.environ['PYTHONHASHSEED']) |
1418 if self._runner.options.time: | 1429 if self._runner.options.time: |
1419 self.printtimes(result.times) | 1430 self.printtimes(result.times) |
1420 | 1431 |
1432 iolock.release() | |
1433 | |
1421 return result | 1434 return result |
1422 | 1435 |
1423 def printtimes(self, times): | 1436 def printtimes(self, times): |
1437 # iolock held by run | |
1424 self.stream.writeln('# Producing time report') | 1438 self.stream.writeln('# Producing time report') |
1425 times.sort(key=lambda t: (t[3])) | 1439 times.sort(key=lambda t: (t[3])) |
1426 cols = '%7.3f %7.3f %7.3f %s' | 1440 cols = '%7.3f %7.3f %7.3f %s' |
1427 self.stream.writeln('%-7s %-7s %-7s %s' % ('cuser', 'csys', 'real', | 1441 self.stream.writeln('%-7s %-7s %-7s %s' % ('cuser', 'csys', 'real', |
1428 'Test')) | 1442 'Test')) |