[zorg] r174138 - LitTestCommand: Fix some log parsing bugs.

Daniel Dunbar daniel at zuster.org
Thu Jan 31 17:39:53 PST 2013


Author: ddunbar
Date: Thu Jan 31 19:39:53 2013
New Revision: 174138

URL: http://llvm.org/viewvc/llvm-project?rev=174138&view=rev
Log:
LitTestCommand: Fix some log parsing bugs.

 - The last test failure would not get recorded properly.

 - The log names were wrong sometimes because of a variable shadowing bug.

 - Also, always parse verbose log info even if it isn't associated with a
   failing code.

Modified:
    zorg/trunk/zorg/buildbot/commands/LitTestCommand.py

Modified: zorg/trunk/zorg/buildbot/commands/LitTestCommand.py
URL: http://llvm.org/viewvc/llvm-project/zorg/trunk/zorg/buildbot/commands/LitTestCommand.py?rev=174138&r1=174137&r2=174138&view=diff
==============================================================================
--- zorg/trunk/zorg/buildbot/commands/LitTestCommand.py (original)
+++ zorg/trunk/zorg/buildbot/commands/LitTestCommand.py Thu Jan 31 19:39:53 2013
@@ -8,54 +8,93 @@ from buildbot.process.buildstep import L
 from buildbot.steps.shell import Test
 
 class LitLogObserver(LogLineObserver):
-  kTestLineRE = re.compile(r'([^ ]*): (.*) \(.*.*\)')
-  kTestFailureLogStartRE = re.compile(r"""\*{4,80} TEST '(.*)' .*""")
-  kTestFailureLogStopRE = re.compile(r"""\*{10,80}""")
+  # Regular expressions for a regular test line.
+  kTestLineRE = re.compile(r'([^ ]*): (.*) \(.*\)')
+
+  # Regular expressions for verbose log start and stop markers. Verbose log
+  # output always immediately follow a test.
+  kTestVerboseLogStartRE = re.compile(r"""\*{4,80} TEST '(.*)' .*""")
+  kTestVerboseLogStopRE = re.compile(r"""\*{10,80}""")
+
+  # These are the codes for which we will include the log output in the buildbot
+  # step results.
   failingCodes = set(['FAIL', 'XPASS', 'KPASS', 'UNRESOLVED'])
+
   def __init__(self):
     LogLineObserver.__init__(self)
     self.resultCounts = {}
-    self.inFailure = None
-    self.inFailureContext = False
+
+    # If non-null, a tuple of the last test code and name.
+    self.lastTestResult = None
+
+    # If non-null, a list of lines in the current log.
+    self.activeVerboseLog = None
 
   def hadFailure(self):
     for code in self.failingCodes:
       if self.resultCounts.get(code):
         return True
 
+  def handleVerboseLogLine(self, line):
+    # If this isn't a stop marker, just append it and continue.
+    if not self.kTestVerboseLogStopRE.match(line):
+      self.activeVerboseLog.append(line)
+      return
+
+    # Otherwise, the log and test info are finished.
+    self.testInfoFinished()
+
+  def testInfoFinished(self):
+    # We have finished getting information for one test, handle it.
+    code, name = self.lastTestResult
+
+    # If the test failed, add a log entry for it.
+    if code in self.failingCodes:
+      # If a verbose log was not provided, just add a one line description.
+      if self.activeVerboseLog is None:
+        self.activeVerboseLog = ['%s: %s' % (code, name)]
+
+      # Add the log to the build status.
+      self.step.addCompleteLog(name.replace('/', '__'),
+                               '\n'.join(self.activeVerboseLog))
+
+    # Reset the current state.
+    self.lastTestResult = None
+    self.activeVerboseLog = None
+
   def outLineReceived(self, line):
-    # See if we are inside a failure log.
-    if self.inFailureContext:
-      self.inFailure[1].append(line)
-      if self.kTestFailureLogStopRE.match(line):
-        self.inFailureContext = False
+    # If we are inside a verbose log, just accumulate lines until we reach the
+    # stop marker.
+    if self.activeVerboseLog is not None:
+      self.handleVerboseLogLine(line)
       return
 
-    line = line.strip()
-    if not line:
+    # Check for the test verbose log start marker.
+    m = self.kTestVerboseLogStartRE.match(line.strip())
+    if m:
+      self.activeVerboseLog = []
+      if m.group(1) != self.lastTestResult[1]:
+        # This is bogus, the verbose log test name doesn't match what we
+        # expect. Just note it in the log but otherwise accumulate as normal.
+        self.activeVerboseLog.append(
+          "error: verbose log output name didn't match expected test name")
       return
 
-    # Check for test failure logs.
-    m = self.kTestFailureLogStartRE.match(line)
-    if m and self.inFailure:
-      if m.group(1)==self.inFailure[0]:
-          self.inFailure[1].append(line)
-          self.inFailureContext = True
-          return
-      else:
-          msg = 'm[0]: %r\ninFailure[0]: %r' % (m.group(0), self.inFailure[0])
-          raise ValueError, msg
-    # Otherwise expect a test status line.
-    m = self.kTestLineRE.match(line)
+    # Otherwise, if we had any previous test consider it finished.
+    #
+    # FIXME: This assumes that we will always have at least one line following
+    # the last test result to properly record each test; we could fix this if
+    # buildbot provided us a hook for when the log is done.
+    if self.lastTestResult:
+      self.testInfoFinished()
+
+    # Check for a new test status line.
+    m = self.kTestLineRE.match(line.strip())
     if m:
-      code, name = m.groups()
-      if self.inFailure and name != self.inFailure[0]:
-        name,log = self.inFailure
-        self.step.addCompleteLog(name.replace('/', '__'), '\n'.join(log))
-        self.inFailure = None
-      if code in self.failingCodes:
-        self.inFailure = (name, [line])
+      # Remember the last test result and update the result counts.
+      self.lastTestResult = (code, name) = m.groups()
       self.resultCounts[code] = self.resultCounts.get(code, 0) + 1
+      return
 
 class LitTestCommand(Test):
   resultNames = {'FAIL':'unexpected failures',
@@ -124,7 +163,23 @@ PASS: test-three (3 of 3)
 """)
 
     self.assertEqual(obs.resultCounts, { 'FAIL' : 1, 'PASS' : 2 })
-    self.assertEqual(obs.step.logs, [('test-two', 'FAIL: test-two (2 of 3)')])
+    self.assertEqual(obs.step.logs, [('test-two', 'FAIL: test-two')])
+
+  def test_verbose_logs(self):
+    obs = self.parse_log("""
+FAIL: test-one (1 of 3)
+FAIL: test-two (2 of 3)
+**** TEST 'test-two' ****
+bla bla bla
+**********
+FAIL: test-three (3 of 3)
+""")
+
+    self.assertEqual(obs.resultCounts, { 'FAIL' : 3 })
+    self.assertEqual(obs.step.logs, [
+        ('test-one', 'FAIL: test-one'),
+        ('test-two', 'bla bla bla'),
+        ('test-three', 'FAIL: test-three')])
 
 class TestCommand(unittest.TestCase):
   def parse_log(self, text):





More information about the llvm-commits mailing list