Merge lp:~mbp/bzr/626679-strace into lp:bzr

Proposed by Martin Pool
Status: Merged
Approved by: Robert Collins
Approved revision: no longer in the source branch.
Merged at revision: 5402
Proposed branch: lp:~mbp/bzr/626679-strace
Merge into: lp:bzr
Diff against target: 184 lines (+54/-28)
3 files modified
NEWS (+4/-0)
bzrlib/strace.py (+22/-3)
bzrlib/tests/test_strace.py (+28/-25)
To merge this branch: bzr merge lp:~mbp/bzr/626679-strace
Reviewer Review Type Date Requested Status
Robert Collins (community) Approve
Review via email: mp+34157@code.launchpad.net

Commit message

disable strace tests broken under maverick

Description of the change

Ubuntu recently changed to stop users tracing their own processes by default as a security measure, which means that 'bzr selftest -s bt.test_strace' fails on maverick.

Unfortunately strace doesn't give you a clear error code to tell you that you hit this.

We don't actually use strace in any other tests at the moment, but it has been useful in the past for ad-hoc performance investigation.

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote :

+1

review: Approve
Revision history for this message
Martin Pool (mbp) wrote :

sent to pqm by email

Revision history for this message
Andrew Bennetts (spiv) wrote :

PQM seems to have hung while processing this. The circumstantial evidence from spm is that it was probably executing the strace tests at the time: there was an strace subprocess, and killing it caused another strace subprocess to be spawned. Hopefully some informative tracebacks/errors are on their way back to Martin from PQM.

Revision history for this message
Martin Pool (mbp) wrote :

Thanks.

That actually pushes me a bit more towards deleting/disabling the
tests, but leaving the facility. It's useful to have it, but it seems
silly to have test hangs for something that's not actively used other
than in the tests.

--
Martin

Revision history for this message
Andrew Bennetts (spiv) wrote :

Martin Pool wrote:
> Thanks.
>
> That actually pushes me a bit more towards deleting/disabling the
> tests, but leaving the facility. It's useful to have it, but it seems
> silly to have test hangs for something that's not actively used other
> than in the tests.

I think that's a reasonable compromise. Maybe leave the tests there but
skipped? It doesn't seem like something worth spending large amounts of
time on. The next person to work on the strace helpers can look at
fixing their tests if they like.

Revision history for this message
Martin Pool (mbp) wrote :

sent to pqm by email

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'NEWS'
--- NEWS 2010-09-01 08:02:42 +0000
+++ NEWS 2010-09-01 08:49:39 +0000
@@ -142,6 +142,10 @@
142 fetching from repositories with affected revisions.142 fetching from repositories with affected revisions.
143 (Andrew Bennetts, #522637)143 (Andrew Bennetts, #522637)
144144
145* strace test-helper tests cope with the new Ubuntu policy of not allowing
146 users to attach to their own processes by default.
147 (Martin Pool, #626679)
148
145* ``Transport.stat`` on a symlink, including a transport pointing directly149* ``Transport.stat`` on a symlink, including a transport pointing directly
146 to a symlink, now returns information about the symlink.150 to a symlink, now returns information about the symlink.
147 (Martin Pool)151 (Martin Pool)
148152
=== modified file 'bzrlib/strace.py'
--- bzrlib/strace.py 2009-03-23 14:59:43 +0000
+++ bzrlib/strace.py 2010-09-01 08:49:39 +0000
@@ -23,6 +23,9 @@
23import subprocess23import subprocess
24import tempfile24import tempfile
2525
26from bzrlib import errors
27
28
26# this is currently test-focused, so importing bzrlib.tests is ok. We might29# this is currently test-focused, so importing bzrlib.tests is ok. We might
27# want to move feature to its own module though.30# want to move feature to its own module though.
28from bzrlib.tests import Feature31from bzrlib.tests import Feature
@@ -46,14 +49,17 @@
46 # capture strace output to a file49 # capture strace output to a file
47 log_file = tempfile.NamedTemporaryFile()50 log_file = tempfile.NamedTemporaryFile()
48 log_file_fd = log_file.fileno()51 log_file_fd = log_file.fileno()
52 err_file = tempfile.NamedTemporaryFile()
49 pid = os.getpid()53 pid = os.getpid()
50 # start strace54 # start strace
51 strace_cmd = ['strace', '-r', '-tt', '-p', str(pid), '-o', log_file.name]55 strace_cmd = ['strace', '-r', '-tt', '-p', str(pid), '-o', log_file.name]
52 if follow_children:56 if follow_children:
53 strace_args.append('-f')57 strace_args.append('-f')
58 # need to catch both stdout and stderr to work around
59 # bug 627208
54 proc = subprocess.Popen(strace_cmd,60 proc = subprocess.Popen(strace_cmd,
55 stdout=subprocess.PIPE,61 stdout=subprocess.PIPE,
56 stderr=subprocess.STDOUT)62 stderr=err_file.fileno())
57 # Wait for strace to attach63 # Wait for strace to attach
58 attached_notice = proc.stdout.readline()64 attached_notice = proc.stdout.readline()
59 # Run the function to strace65 # Run the function to strace
@@ -65,18 +71,31 @@
65 log_file.seek(0)71 log_file.seek(0)
66 log = log_file.read()72 log = log_file.read()
67 log_file.close()73 log_file.close()
68 return result, StraceResult(log)74 # and stderr
75 err_file.seek(0)
76 err_messages = err_file.read()
77 err_file.close()
78 # and read any errors
79 if err_messages.startswith("attach: ptrace(PTRACE_ATTACH,"):
80 raise StraceError(err_messages=err_messages)
81 return result, StraceResult(log, err_messages)
82
83
84class StraceError(errors.BzrError):
85
86 _fmt = "strace failed: %(err_messages)s"
6987
7088
71class StraceResult(object):89class StraceResult(object):
72 """The result of stracing a function."""90 """The result of stracing a function."""
7391
74 def __init__(self, raw_log):92 def __init__(self, raw_log, err_messages):
75 """Create a StraceResult.93 """Create a StraceResult.
7694
77 :param raw_log: The output that strace created.95 :param raw_log: The output that strace created.
78 """96 """
79 self.raw_log = raw_log97 self.raw_log = raw_log
98 self.err_messages = err_messages
8099
81100
82class _StraceFeature(Feature):101class _StraceFeature(Feature):
83102
=== modified file 'bzrlib/tests/test_strace.py'
--- bzrlib/tests/test_strace.py 2009-03-23 14:59:43 +0000
+++ bzrlib/tests/test_strace.py 2010-09-01 08:49:39 +0000
@@ -1,5 +1,4 @@
1# Copyright (C) 2007 Canonical Ltd1# Copyright (C) 2007, 2010 Canonical Ltd
2# Authors: Robert Collins <robert.collins@canonical.com>
3#2#
4# This program is free software; you can redistribute it and/or modify3# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by4# it under the terms of the GNU General Public License as published by
@@ -22,34 +21,26 @@
22import threading21import threading
2322
24from bzrlib import (23from bzrlib import (
24 strace,
25 tests,25 tests,
26 )26 )
27from bzrlib.strace import StraceFeature, strace_detailed, StraceResult27from bzrlib.strace import StraceFeature, strace_detailed, StraceResult
2828
2929
30class TestStraceFeature(tests.TestCaseWithTransport):
31
32 def test_strace_detection(self):
33 """Strace is available if its runnable."""
34 try:
35 proc = subprocess.Popen(['strace'],
36 stderr=subprocess.PIPE,
37 stdout=subprocess.PIPE)
38 proc.communicate()
39 found_strace = True
40 except OSError, e:
41 if e.errno == errno.ENOENT:
42 # strace is not installed
43 found_strace = False
44 else:
45 raise
46 self.assertEqual(found_strace, StraceFeature.available())
47
48
49class TestStrace(tests.TestCaseWithTransport):30class TestStrace(tests.TestCaseWithTransport):
5031
51 _test_needs_features = [StraceFeature]32 _test_needs_features = [StraceFeature]
5233
34 def setUp(self):
35 # NB: see http://pad.lv/626679 and
36 # <https://code.launchpad.net/~mbp/bzr/626679-strace/+merge/34157>:
37 # testing strace by connecting to ourselves has repeatedly caused
38 # hangs in running the test suite; these are fixable given enough
39 # determination but given that strace is not used by any other tests
40 # at the moment and that it's only test-support code, we just leave it
41 # untested -- mbp 20100901
42 raise tests.TestSkipped("strace selftests are broken and disabled")
43
53 def _check_threads(self):44 def _check_threads(self):
54 # For bug #226769, it was decided that the strace tests should not be45 # For bug #226769, it was decided that the strace tests should not be
55 # run when more than one thread is active. A lot of tests are currently46 # run when more than one thread is active. A lot of tests are currently
@@ -61,14 +52,26 @@
61 raise tests.KnownFailure(52 raise tests.KnownFailure(
62 '%d active threads, bug #103133 needs to be fixed.' % active)53 '%d active threads, bug #103133 needs to be fixed.' % active)
6354
55 def strace_detailed_or_skip(self, *args, **kwargs):
56 """Run strace, but cope if it's not allowed"""
57 try:
58 return strace_detailed(*args, **kwargs)
59 except strace.StraceError, e:
60 if e.err_messages.startswith(
61 "attach: ptrace(PTRACE_ATTACH, ...): Operation not permitted"):
62 raise tests.TestSkipped("ptrace not permitted")
63 else:
64 raise
65
64 def test_strace_callable_is_called(self):66 def test_strace_callable_is_called(self):
65 self._check_threads()67 self._check_threads()
6668
67 output = []69 output = []
68 def function(positional, *args, **kwargs):70 def function(positional, *args, **kwargs):
69 output.append((positional, args, kwargs))71 output.append((positional, args, kwargs))
70 strace_detailed(function, ["a", "b"], {"c": "c"},72 self.strace_detailed_or_skip(
71 follow_children=False)73 function, ["a", "b"], {"c": "c"},
74 follow_children=False)
72 self.assertEqual([("a", ("b",), {"c":"c"})], output)75 self.assertEqual([("a", ("b",), {"c":"c"})], output)
7376
74 def test_strace_callable_result(self):77 def test_strace_callable_result(self):
@@ -76,7 +79,7 @@
7679
77 def function():80 def function():
78 return "foo"81 return "foo"
79 result, strace_result = strace_detailed(function,[], {},82 result, strace_result = self.strace_detailed_or_skip(function,[], {},
80 follow_children=False)83 follow_children=False)
81 self.assertEqual("foo", result)84 self.assertEqual("foo", result)
82 self.assertIsInstance(strace_result, StraceResult)85 self.assertIsInstance(strace_result, StraceResult)
@@ -87,6 +90,6 @@
8790
88 def function():91 def function():
89 self.build_tree(['myfile'])92 self.build_tree(['myfile'])
90 unused, result = strace_detailed(function, [], {},93 unused, result = self.strace_detailed_or_skip(function, [], {},
91 follow_children=False)94 follow_children=False)
92 self.assertContainsRe(result.raw_log, 'myfile')95 self.assertContainsRe(result.raw_log, 'myfile')