Rev 2374: Added ``bzrlib.strace.strace`` which will strace a single callable and in file:///home/robertc/source/baz/benchmark-strace/

Robert Collins robertc at robertcollins.net
Fri Mar 23 00:18:47 GMT 2007


At file:///home/robertc/source/baz/benchmark-strace/

------------------------------------------------------------
revno: 2374
revision-id: robertc at robertcollins.net-20070323001831-czc15dtustiat7j7
parent: robertc at robertcollins.net-20070322214342-58nmsg7pvh6ghc8b
committer: Robert Collins <robertc at robertcollins.net>
branch nick: benchmark-strace
timestamp: Fri 2007-03-23 11:18:31 +1100
message:
  Added ``bzrlib.strace.strace`` which will strace a single callable and
  return a StraceResult object which contains just the syscalls involved
  in running it. (Robert Collins)
added:
  bzrlib/strace.py               strace.py-20070323001526-6zquhhw8leb9m6j8-1
  bzrlib/tests/test_strace.py    test_strace.py-20070323001526-6zquhhw8leb9m6j8-2
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
=== added file 'bzrlib/strace.py'
--- a/bzrlib/strace.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/strace.py	2007-03-23 00:18:31 +0000
@@ -0,0 +1,87 @@
+# Copyright (C) 2007 Canonical Ltd
+#   Authors: Robert Collins <robert.collins at canonical.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Support for running strace against the current process."""
+
+import os
+import signal
+import subprocess
+import tempfile
+
+# this is currently test-focused, so importing bzrlib.tests is ok. We might
+# want to move feature to its own module though.
+from bzrlib.tests import Feature
+
+def strace(function, *args, **kwargs):
+    """Invoke strace on function.
+
+    :return: A StraceResult.
+    """
+    # capture strace output to a file
+    log_file = tempfile.TemporaryFile()
+    log_file_fd = log_file.fileno()
+    pid = os.getpid()
+    # start strace
+    proc = subprocess.Popen(['strace',
+        '-f', '-r', '-tt', '-p', str(pid),
+        ],
+        stderr=log_file_fd,
+        stdout=log_file_fd)
+    # TODO? confirm its started (test suite should be sufficient)
+    # (can loop on proc.pid, but that may not indicate started and attached.)
+    function(*args, **kwargs)
+    # stop strace
+    os.kill(proc.pid, signal.SIGQUIT)
+    proc.communicate()
+    # grab the log
+    log_file.seek(0)
+    log = log_file.read()
+    log_file.close()
+    return StraceResult(log)
+
+
+class StraceResult(object):
+    """The result of stracing a function."""
+
+    def __init__(self, raw_log):
+        """Create a StraceResult.
+
+        :param raw_log: The output that strace created.
+        """
+        self.raw_log = raw_log
+
+
+class _StraceFeature(Feature):
+
+    def _probe(self):
+        try:
+            proc = subprocess.Popen(['strace'],
+                stderr=subprocess.PIPE,
+                stdout=subprocess.PIPE)
+            proc.communicate()
+            return True
+        except OSError, e:
+            if e.errno == errno.ENOENT:
+                # strace is not installed
+                return False
+            else:
+                raise
+
+    def feature_name(self):
+        return 'strace'
+
+StraceFeature = _StraceFeature()

=== added file 'bzrlib/tests/test_strace.py'
--- a/bzrlib/tests/test_strace.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/test_strace.py	2007-03-23 00:18:31 +0000
@@ -0,0 +1,67 @@
+# Copyright (C) 2007 Canonical Ltd
+#   Authors: Robert Collins <robert.collins at canonical.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Tests for the strace-invoking support."""
+
+import subprocess
+
+from bzrlib.strace import StraceFeature, strace, StraceResult
+from bzrlib.tests import TestCaseWithTransport
+
+
+class TestStraceFeature(TestCaseWithTransport):
+
+    def test_strace_detection(self):
+        """Strace is available if its runnable."""
+        try:
+            proc = subprocess.Popen(['strace'],
+                stderr=subprocess.PIPE,
+                stdout=subprocess.PIPE)
+            proc.communicate()
+            found_strace = True
+        except OSError, e:
+            if e.errno == errno.ENOENT:
+                # strace is not installed
+                found_strace = False
+            else:
+                raise
+        self.assertEqual(found_strace, StraceFeature.available())
+
+
+class TestStrace(TestCaseWithTransport):
+
+    _test_needs_features = [StraceFeature]
+
+    def test_strace_callable_is_called(self):
+        output = []
+        def function(positional, *args, **kwargs):
+            output.append((positional, args, kwargs))
+        strace(function, "a", "b", c="c")
+        self.assertEqual([("a", ("b",), {"c":"c"})], output)
+
+    def test_strace_callable_gets_StraceResult(self):
+        def function():
+            pass
+        result = strace(function)
+        self.assertIsInstance(result, StraceResult)
+
+    def test_strace_result_has_raw_log(self):
+        """Checks that a reasonable raw strace log was found by strace."""
+        def function():
+            self.build_tree(['myfile'])
+        result = strace(function)
+        self.assertContainsRe(result.raw_log, 'myfile')

=== modified file 'NEWS'
--- a/NEWS	2007-03-21 04:28:02 +0000
+++ b/NEWS	2007-03-23 00:18:31 +0000
@@ -1,5 +1,11 @@
 IN DEVELOPMENT
 
+  TESTING:
+
+    * Added ``bzrlib.strace.strace`` which will strace a single callable and
+      return a StraceResult object which contains just the syscalls involved
+      in running it. (Robert Collins)
+
 bzr 0.15 (not finalised)
 
   INTERNALS:

=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2007-03-22 21:43:42 +0000
+++ b/bzrlib/tests/__init__.py	2007-03-23 00:18:31 +0000
@@ -2102,6 +2102,7 @@
                    'bzrlib.tests.test_ssh_transport',
                    'bzrlib.tests.test_status',
                    'bzrlib.tests.test_store',
+                   'bzrlib.tests.test_strace',
                    'bzrlib.tests.test_subsume',
                    'bzrlib.tests.test_symbol_versioning',
                    'bzrlib.tests.test_tag',



More information about the bazaar-commits mailing list