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'))