Patchwork D1830: test-run-tests: stabilize the test (issue5735)

login
register
mail settings
Submitter phabricator
Date Jan. 9, 2018, 1:07 a.m.
Message ID <differential-rev-PHID-DREV-rrzjpuw2xfyhc7wkqw4e-req@phab.mercurial-scm.org>
Download mbox | patch
Permalink /patch/26622/
State Superseded
Headers show

Comments

phabricator - Jan. 9, 2018, 1:07 a.m.
quark created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Previously there is a race condition because things happen in this order:
  
  1. Check shouldStop
  2. If shouldStop is false, print the diff
  3. Call fail() -> set shouldStop
  
  The check and set should really happen in a same critical section.
  
  This patch adds a lock to address the issue.

TEST PLAN
  Run `run-tests.py -l test-run-tests.t` 20 times on gcc112 and the race
  condition does not reproduce.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1830

AFFECTED FILES
  tests/run-tests.py

CHANGE DETAILS




To: quark, #hg-reviewers
Cc: mercurial-devel
phabricator - Jan. 10, 2018, 1:21 p.m.
yuja accepted this revision.
yuja added a comment.
This revision is now accepted and ready to land.


  Queued for stable. Thanks for fixing this issue.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1830

To: quark, #hg-reviewers, yuja
Cc: yuja, mercurial-devel
phabricator - Jan. 10, 2018, 11:28 p.m.
durin42 added a comment.


  As a note (re your test plan): there's a --runs-per-test flag on run-tests for exactly this kind of "did I fix a flaky test" debugging. I often set it to 100. :)

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D1830

To: quark, #hg-reviewers, yuja
Cc: durin42, yuja, mercurial-devel

Patch

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -670,6 +670,7 @@ 
 
     def __init__(self, path, outputdir, tmpdir, keeptmpdir=False,
                  debug=False,
+                 first=False,
                  timeout=None,
                  startport=None, extraconfigopts=None,
                  py3kwarnings=False, shell=None, hgcommand=None,
@@ -722,6 +723,7 @@ 
         self._threadtmp = tmpdir
         self._keeptmpdir = keeptmpdir
         self._debug = debug
+        self._first = first
         self._timeout = timeout
         self._slowtimeout = slowtimeout
         self._startport = startport
@@ -906,9 +908,13 @@ 
                         f.write(line)
 
             # The result object handles diff calculation for us.
-            if self._result.addOutputMismatch(self, ret, out, self._refout):
-                # change was accepted, skip failing
-                return
+            with firstlock:
+                if self._result.addOutputMismatch(self, ret, out, self._refout):
+                    # change was accepted, skip failing
+                    return
+                if self._first:
+                    global firsterror
+                    firsterror = True
 
             if ret:
                 msg = 'output changed and ' + describe(ret)
@@ -1637,6 +1643,8 @@ 
         return TTest.ESCAPESUB(TTest._escapef, s)
 
 iolock = threading.RLock()
+firstlock = threading.RLock()
+firsterror = False
 
 class TestResult(unittest._TextTestResult):
     """Holds results when executing via unittest."""
@@ -1722,7 +1730,7 @@ 
 
     def addOutputMismatch(self, test, ret, got, expected):
         """Record a mismatch in test output for a particular test."""
-        if self.shouldStop:
+        if self.shouldStop or firsterror:
             # don't print, some other test case already failed and
             # printed, we're just stale and probably failed due to our
             # temp dir getting cleaned up.
@@ -2700,6 +2708,7 @@ 
         t = testcls(refpath, self._outputdir, tmpdir,
                     keeptmpdir=self.options.keep_tmpdir,
                     debug=self.options.debug,
+                    first=self.options.first,
                     timeout=self.options.timeout,
                     startport=self._getport(count),
                     extraconfigopts=self.options.extra_config_opt,