~bzr-pqm/bzr/bzr.dev

4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
1
# Copyright (C) 2006, 2007, 2009 Canonical Ltd
2423.3.7 by Martin Pool
Add BZR_SIGQUIT_PDB=0 option to disable breakin.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2423.3.7 by Martin Pool
Add BZR_SIGQUIT_PDB=0 option to disable breakin.
16
17
"""Blackbox tests for debugger breakin"""
18
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
19
try:
20
    import ctypes
21
    have_ctypes = True
22
except ImportError:
23
    have_ctypes = False
4168.1.4 by Vincent Ladeuil
More robust handling of test_breakin.
24
import errno
2423.3.7 by Martin Pool
Add BZR_SIGQUIT_PDB=0 option to disable breakin.
25
import os
26
import signal
27
import subprocess
28
import sys
29
import time
30
4168.1.4 by Vincent Ladeuil
More robust handling of test_breakin.
31
from bzrlib import (
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
32
    breakin,
4168.1.4 by Vincent Ladeuil
More robust handling of test_breakin.
33
    errors,
34
    tests,
35
    )
3815.2.3 by Martin Pool
merge fix for #293054, ssl on python2.6
36
37
38
class TestBreakin(tests.TestCase):
2423.3.7 by Martin Pool
Add BZR_SIGQUIT_PDB=0 option to disable breakin.
39
    # FIXME: If something is broken, these tests may just hang indefinitely in
40
    # wait() waiting for the child to exit when it's not going to.
41
42
    def setUp(self):
43
        super(TestBreakin, self).setUp()
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
44
        if breakin.determine_signal() is None:
45
            raise tests.TestSkipped('this platform is missing SIGQUIT'
46
                                    ' or SIGBREAK')
47
        if sys.platform == 'win32':
48
            # Windows doesn't have os.kill, and we catch the SIGBREAK signal.
49
            # We trigger SIGBREAK via a Console api so we need ctypes to access
50
            # the function
51
            if not have_ctypes:
52
                raise tests.UnavailableFeature('ctypes')
53
            self._send_signal = self._send_signal_win32
54
        else:
55
            self._send_signal = self._send_signal_via_kill
56
57
    def _send_signal_via_kill(self, pid, sig_type):
4578.1.2 by John Arbash Meinel
Fix a typo for the Linux code path.
58
        if sig_type == 'break':
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
59
            sig_num = signal.SIGQUIT
4578.1.2 by John Arbash Meinel
Fix a typo for the Linux code path.
60
        elif sig_type == 'kill':
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
61
            sig_num = signal.SIGKILL
62
        else:
63
            raise ValueError("unknown signal type: %s" % (sig_type,))
64
        os.kill(pid, sig_num)
65
66
    def _send_signal_win32(self, pid, sig_type):
67
        """Send a 'signal' on Windows.
68
69
        Windows doesn't really have signals in the same way. All it really
70
        supports is:
71
            1) Sending SIGINT to the *current* process group (so self, and all
72
                children of self)
73
            2) Sending SIGBREAK to a process that shares the current console,
74
                which can be in its own process group.
4578.1.4 by John Arbash Meinel
Fix some small comment bugs.
75
        So we have start_bzr_subprocess create a new process group for the
76
        spawned process (via a flag to Popen), and then we map
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
77
            SIGQUIT to GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT)
78
            SIGKILL to TerminateProcess
79
        """
80
        if sig_type == 'break':
81
            CTRL_BREAK_EVENT = 1
82
            # CTRL_C_EVENT = 0
83
            ret = ctypes.windll.kernel32.GenerateConsoleCtrlEvent(
84
                    CTRL_BREAK_EVENT, pid)
85
            if ret == 0: #error
86
                err = ctypes.FormatError()
87
                raise RuntimeError('failed to send CTRL_BREAK: %s'
88
                                   % (err,))
89
        elif sig_type == 'kill':
90
            # Does the exit code matter? For now we are just setting it to
91
            # something other than 0
92
            exit_code = breakin.determine_signal()
93
            ctypes.windll.kernel32.TerminateProcess(pid, exit_code)
94
95
    def _popen(self, *args, **kwargs):
96
        if sys.platform == 'win32':
97
            CREATE_NEW_PROCESS_GROUP = 512
98
            # This allows us to send a signal to the child, *without* also
99
            # sending it to ourselves
100
            kwargs['creationflags'] = CREATE_NEW_PROCESS_GROUP
101
        return super(TestBreakin, self)._popen(*args, **kwargs)
2423.3.7 by Martin Pool
Add BZR_SIGQUIT_PDB=0 option to disable breakin.
102
3815.2.3 by Martin Pool
merge fix for #293054, ssl on python2.6
103
    def _dont_SIGQUIT_on_darwin(self):
104
        if sys.platform == 'darwin':
105
            # At least on Leopard and with python 2.6, this test will raise a
106
            # popup window asking if the python failure should be reported to
107
            # Apple... That's not the point of the test :) Marking the test as
108
            # not applicable Until we find a way to disable that intrusive
109
            # behavior... --vila20080611
110
            raise tests.TestNotApplicable(
111
                '%s raises a popup on OSX' % self.id())
112
4168.1.4 by Vincent Ladeuil
More robust handling of test_breakin.
113
    def _wait_for_process(self, pid, sig=None):
114
        # We don't know quite how long waiting for the process 'pid' will take,
115
        # but if it's more than 10s then it's probably not going to work.
116
        for i in range(100):
117
            time.sleep(0.1)
118
            if sig is not None:
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
119
                self._send_signal(pid, sig)
4168.1.4 by Vincent Ladeuil
More robust handling of test_breakin.
120
            # Use WNOHANG to ensure we don't get blocked, doing so, we may
121
            # leave the process continue after *we* die...
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
122
            # Win32 doesn't support WNOHANG, so we just pass 0
123
            opts = getattr(os, 'WNOHANG', 0)
4168.1.4 by Vincent Ladeuil
More robust handling of test_breakin.
124
            try:
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
125
                # TODO: waitpid doesn't work well on windows, we might consider
126
                #       using WaitForSingleObject(proc._handle, TIMEOUT)
127
                #       instead. Most notably, the WNOHANG isn't allowed, so
128
                #       this can hang indefinitely.
129
                pid_killed, returncode = os.waitpid(pid, opts)
4168.1.4 by Vincent Ladeuil
More robust handling of test_breakin.
130
                if (pid_killed, returncode) != (0, 0):
131
                    if sig is not None:
132
                        # high bit in low byte says if core was dumped; we
133
                        # don't care
134
                        status, sig = (returncode >> 8, returncode & 0x7f)
135
                        return True, sig
136
            except OSError, e:
137
                if e.errno in (errno.ECHILD, errno.ESRCH):
138
                    # The process doesn't exist anymore
139
                    return True, None
140
                else:
141
                    raise
142
143
        return False, None
144
2423.3.7 by Martin Pool
Add BZR_SIGQUIT_PDB=0 option to disable breakin.
145
    # port 0 means to allocate any port
146
    _test_process_args = ['serve', '--port', 'localhost:0']
147
4168.1.2 by Vincent Ladeuil
Take Martin and John review comments into account and tighten the tests.
148
    def test_breakin(self):
149
        # Break in to a debugger while bzr is running
150
        # we need to test against a command that will wait for
151
        # a while -- bzr serve should do
152
        proc = self.start_bzr_subprocess(self._test_process_args,
153
                env_changes=dict(BZR_SIGQUIT_PDB=None))
154
        # wait for it to get started, and print the 'listening' line
155
        proc.stderr.readline()
156
        # first sigquit pops into debugger
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
157
        self._send_signal(proc.pid, 'break')
4168.1.2 by Vincent Ladeuil
Take Martin and John review comments into account and tighten the tests.
158
        # Wait for the debugger to acknowledge the signal reception
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
159
        # Note that it is possible for this to deadlock if the child doesn't
160
        # acknowlege the signal and write to stderr. Perhaps we should try
161
        # os.read(proc.stderr.fileno())?
4168.1.2 by Vincent Ladeuil
Take Martin and John review comments into account and tighten the tests.
162
        err = proc.stderr.readline()
163
        self.assertContainsRe(err, r'entering debugger')
164
        # Now that the debugger is entered, we can ask him to quit
165
        proc.stdin.write("q\n")
4168.1.4 by Vincent Ladeuil
More robust handling of test_breakin.
166
        # We wait a bit to let the child process handles our query and avoid
167
        # triggering deadlocks leading to hangs on multi-core hosts...
168
        dead, sig = self._wait_for_process(proc.pid)
169
        if not dead:
170
            # The process didn't finish, let's kill it before reporting failure
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
171
            dead, sig = self._wait_for_process(proc.pid, 'kill')
4168.1.4 by Vincent Ladeuil
More robust handling of test_breakin.
172
            if dead:
173
                raise tests.KnownFailure(
174
                    "subprocess wasn't terminated, it had to be killed")
175
            else:
176
                self.fail("subprocess %d wasn't terminated by repeated SIGKILL",
177
                          proc.pid)
4168.1.2 by Vincent Ladeuil
Take Martin and John review comments into account and tighten the tests.
178
4168.1.1 by Vincent Ladeuil
Commit fix in a new thread to handle review comments
179
    def test_breakin_harder(self):
4168.1.2 by Vincent Ladeuil
Take Martin and John review comments into account and tighten the tests.
180
        """SIGQUITting twice ends the process."""
4168.1.1 by Vincent Ladeuil
Commit fix in a new thread to handle review comments
181
        self._dont_SIGQUIT_on_darwin()
2423.3.7 by Martin Pool
Add BZR_SIGQUIT_PDB=0 option to disable breakin.
182
        proc = self.start_bzr_subprocess(self._test_process_args,
183
                env_changes=dict(BZR_SIGQUIT_PDB=None))
184
        # wait for it to get started, and print the 'listening' line
3955.1.7 by Jonathan Lange
Fix some tests that assumed the port was on stderr rather than stdout.
185
        proc.stderr.readline()
4168.1.1 by Vincent Ladeuil
Commit fix in a new thread to handle review comments
186
        # break into the debugger
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
187
        self._send_signal(proc.pid, 'break')
4168.1.2 by Vincent Ladeuil
Take Martin and John review comments into account and tighten the tests.
188
        # Wait for the debugger to acknowledge the signal reception (since we
189
        # want to send a second signal, we ensure it doesn't get lost by
190
        # validating the first get received and produce its effect).
2423.3.7 by Martin Pool
Add BZR_SIGQUIT_PDB=0 option to disable breakin.
191
        err = proc.stderr.readline()
192
        self.assertContainsRe(err, r'entering debugger')
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
193
        dead, sig = self._wait_for_process(proc.pid, 'break')
194
        self.assertTrue(dead)
195
        # Either the child was dead before we could read its status, or the
196
        # child was dead from the signal we sent it.
197
        self.assertTrue(sig in (None, breakin.determine_signal()))
2423.3.7 by Martin Pool
Add BZR_SIGQUIT_PDB=0 option to disable breakin.
198
199
    def test_breakin_disabled(self):
3815.2.3 by Martin Pool
merge fix for #293054, ssl on python2.6
200
        self._dont_SIGQUIT_on_darwin()
2423.3.7 by Martin Pool
Add BZR_SIGQUIT_PDB=0 option to disable breakin.
201
        proc = self.start_bzr_subprocess(self._test_process_args,
202
                env_changes=dict(BZR_SIGQUIT_PDB='0'))
203
        # wait for it to get started, and print the 'listening' line
3955.1.7 by Jonathan Lange
Fix some tests that assumed the port was on stderr rather than stdout.
204
        proc.stderr.readline()
2423.3.7 by Martin Pool
Add BZR_SIGQUIT_PDB=0 option to disable breakin.
205
        # first hit should just kill it
4578.1.1 by John Arbash Meinel
Update the breakin support to support CTRL-BREAK on Windows.
206
        self._send_signal(proc.pid, 'break')
2423.3.7 by Martin Pool
Add BZR_SIGQUIT_PDB=0 option to disable breakin.
207
        proc.wait()