[PATCH] Add more annotations to QMTest runs

Nathaniel Smith njs at pobox.com
Wed Feb 11 20:45:31 UTC 2004


This patch, attached for review, adds more default annotations to
QMTest.  These are required for emulation of the TET[1] output format,
but are useful generally.

Also adds a few more calls to ExecutionEngine._Trace, and
rationalizes the early termination handling;
ExecutionEnginer._RunTests used to sometimes signal early termination
by just exiting, and sometimes by raising an exception; we now always
raise an exception of some form.

New annotations:
  qmtest.run.user: user who started the test run
  qmtest.run.version: version of QMTest used for this test run
  qmtest.run.uname: uname of the machine that started this test run
  qmtest.run.aborted: present with value "True" if test run was
    aborted early

Questions:
  - Currently the simple presence of qmtest.run.aborted signals an
    aborted run; should we instead always write this annotation with
    value either "True" or "False"?
  - Is there any documentation that should be added for these?  As far
    as I can tell, annotations aren't documentated at all ATM...

[1] http://tetworks.opengroup.org

-- Nathaniel

-- 
"If you can explain how you do something, then you're very very bad at it."
  -- John Hopfield
-------------- next part --------------
? foo
? results.qmr
? qm/external/__init__.pyc
? tests/regress/QMTest/regression_database.pyc
? tests/regress/QMTest/selftest.pyc
? tests/regress/env_context1/output.qmr
? tests/regress/exception_test/output.qmr
? tests/regress/gilles1/output.qmr
? tests/regress/nocycle1/output.qmr
? tests/regress/tuple1/QMTest/tuple_test.pyc
? tests/results_files/QMTest/results_file_database.pyc
? tests/results_files/QMTest/results_file_test.pyc
Index: ChangeLog
===================================================================
RCS file: /home/qm/Repository/qm/ChangeLog,v
retrieving revision 1.595
diff -u -r1.595 ChangeLog
--- ChangeLog	28 Jan 2004 19:50:51 -0000	1.595
+++ ChangeLog	11 Feb 2004 20:06:22 -0000
@@ -1,3 +1,18 @@
+2004-02-11  Nathaniel Smith  <njs at codesourcery.com>
+
+	* qm/common.py: Import getpass.  
+	(get_username): New function.
+	* qm/test/execution_engine.py
+	(ExecutionEngine._WriteInitialAnnotations): New method.
+	(ExecutionEngine.Run): Call it.
+	(TerminationRequested): New exception.
+	(ExecutionEngine._RunTests): Raise it when terminating.
+	(ExecutionEngine.Run): Check for exceptions in _RunTests.
+	
+	(ExecutionEngine.RequestTermination): More tracing.
+	(ExecutionEngine.Run): Likewise.
+	(ExecutionEngine._RunTests): Likewise.
+	
 2004-01-28  Mark Mitchell  <mark at codesourcery.com>
 
 	* qm/test/classes/explicit_suite.py (ExplicitSuite.is_implicit):
Index: qm/common.py
===================================================================
RCS file: /home/qm/Repository/qm/qm/common.py,v
retrieving revision 1.79
diff -u -r1.79 common.py
--- qm/common.py	24 Nov 2003 23:00:54 -0000	1.79
+++ qm/common.py	11 Feb 2004 20:06:22 -0000
@@ -39,6 +39,7 @@
 import time
 import traceback
 import types
+import getpass
 if sys.platform != "win32":
     import fcntl
     
@@ -872,6 +873,31 @@
         assignments[name] = value
 
     return assignments
+
+
+def get_username():
+    """Returns the current username as a string.
+
+    If the username cannot be found, raises a 'QMException'."""
+
+    # First try using the 'getpass' module.
+    try:
+        return getpass.getuser()
+    except:
+        pass
+
+    # 'getpass' doesn't necessarily work on Windows, so if that fails,
+    # try the win32 function.
+    try:
+        import win32api
+    except ImportError:
+        pass
+    else:
+        return win32api.GetUserName()
+
+    # And if none of that worked, give up.
+    raise QMException, "Cannot determine user name."
+
 
 ########################################################################
 # variables
Index: qm/test/execution_engine.py
===================================================================
RCS file: /home/qm/Repository/qm/qm/test/execution_engine.py,v
retrieving revision 1.25
diff -u -r1.25 execution_engine.py
--- qm/test/execution_engine.py	24 Nov 2003 06:35:01 -0000	1.25
+++ qm/test/execution_engine.py	11 Feb 2004 20:06:22 -0000
@@ -34,6 +34,13 @@
 # Classes
 ########################################################################
 
+class TerminationRequested(qm.common.QMException):
+    """A target requested termination of the test loop."""
+    
+    pass
+
+
+
 class ExecutionEngine:
     """A 'ExecutionEngine' executes tests.
 
@@ -232,6 +239,7 @@
         may take some time; tests that are already running will continue
         to run, for example."""
 
+        self._Trace("Test loop termination requested.")
         self.__terminated = 1
 
 
@@ -253,20 +261,27 @@
 
         returns -- True if any tests had unexpected outcomes."""
 
-        # Write out all the currently known annotations.
-        start_time_str = qm.common.format_time_iso(time.time())
-        for rs in self.__result_streams:
-            rs.WriteAllAnnotations(self.__context)
-            rs.WriteAnnotation("qmtest.run.start_time", start_time_str)
+        # Write out run metadata.
+        self._WriteInitialAnnotations()
 
         # Start all of the targets.
         for target in self.__targets:
             target.Start(self.__response_queue, self)
 
         # Run all of the tests.
+        self._Trace("Starting test loop")
         try:
-            self._RunTests()
+            try:
+                self._RunTests()
+            except:
+                self._Trace("Test loop exited with exception: %s"
+                            % str(sys.exc_info()))
+                for rs in self.__result_streams:
+                    rs.WriteAnnotation("qmtest.run.aborted", "True")
+                raise
         finally:
+            self._Trace("Test loop finished.")
+
             # Stop the targets.
             self._Trace("Stopping targets.")
             for target in self.__targets:
@@ -346,7 +361,9 @@
         while self.__num_tests_started < num_tests:
             # If the user interrupted QMTest, stop executing tests.
             if self._IsTerminationRequested():
-                break
+                self._Trace("Terminating test loop as requested.")
+                raise TerminationRequested, "Termination requested."
+
             # Process any responses and update the count of idle targets.
             while self.__CheckForResponse(wait=0):
                 pass
@@ -378,8 +395,9 @@
                     else:
                         self.__target_state[target] = self.__TARGET_BUSY
 
-        # Now all tests have been started; we just have wait for them
-        # all to finish.
+        # Now every test that we're going to start has started; we just
+        # have wait for them all to finish.
+        self._Trace("Waiting for remaining tests to finish.")
         while self.__running:
             self.__CheckForResponse(wait=1)
 
@@ -793,6 +811,31 @@
             tracer.Write(message, "exec")
 
     
+    def _WriteInitialAnnotations(self):
+
+        # Calculate annotations.
+        start_time_str = qm.common.format_time_iso(time.time())
+
+        try:
+            username = qm.common.get_username()
+        except:
+            username = None
+
+        try:
+            uname = " ".join(os.uname())
+        except:
+            uname = None
+
+        # Write them.
+        for rs in self.__result_streams:
+            rs.WriteAllAnnotations(self.__context)
+            rs.WriteAnnotation("qmtest.run.start_time", start_time_str)
+            if username is not None:
+                rs.WriteAnnotation("qmtest.run.user", username)
+            rs.WriteAnnotation("qmtest.run.version", qm.version)
+            rs.WriteAnnotation("qmtest.run.uname", uname)
+
+
 ########################################################################
 # Local Variables:
 # mode: python


More information about the qmtest mailing list