On Mon, Feb 25, 2013 at 9:16 AM, jason pellerin <
jpel...@gmail.com> wrote:
> I'm using python3.3. from the deadsnakes PPA on ubuntu 12.04.
>
> It seems like some kind of output buffering problem to me -- I can also
> trigger it by read()ing from process.stderr -- if I make the read() amount
> big enough. "Big enough" varies by python version, what blocks on 3.3 (say,
> read(3000)) passes on 3.2.
So I was able to reproduce this in my Ubuntu 12.04 VM. It's
definitely the kind of issue you mention. I used the patch below, and
have managed to run just the mp keyboard interrupt tests 61 times in a
row now without an issue. This patch is not ready to incorporate yet.
Some of it could be structured better, and I want to make sure things
are getting cleaned up.
This gist has the patch too:
https://gist.github.com/jszakmeister/5078271. Do you mind giving it a
try and see if it fixes your issue. I may get some time tomorrow to
clean it up more.
One thing to note: without the extra sleep(0.1) before issuing the
SIGINT, I found that the test was often killed prematurely. I think
this is just another example of how racy these tests are. :-( What do
you think about having the test touch a file and check for the
existence of that as a busy-wait? I don't think waiting for the
existence of the logfile is good enough.
-John
diff --git a/functional_tests/test_multiprocessing/test_keyboardinterrupt.py
b/functional_tests/test_multiprocessing/test_keyboardinterrupt.py
index 8f07e54..86452a9 100644
--- a/functional_tests/test_multiprocessing/test_keyboardinterrupt.py
+++ b/functional_tests/test_multiprocessing/test_keyboardinterrupt.py
@@ -25,9 +25,12 @@ runner = os.path.join(support, 'fake_nosetest.py')
def keyboardinterrupt(case):
#os.setsid would create a process group so signals sent to the
#parent process will propogates to all children processes
- from tempfile import mktemp
+ from tempfile import mktemp, TemporaryFile
logfile = mktemp()
- process = Popen([sys.executable,runner,os.path.join(support,case),logfile],
preexec_fn=os.setsid, stdout=PIPE, stderr=PIPE, bufsize=-1)
+ tmpStdout = TemporaryFile()
+ tmpStderr = TemporaryFile()
+ process = Popen([sys.executable,runner,os.path.join(support,case),logfile],
+ preexec_fn=os.setsid, stdout=tmpStdout, stderr=tmpStderr)
#wait until logfile is created:
retry=100
@@ -37,8 +40,20 @@ def keyboardinterrupt(case):
if not retry:
raise Exception('Timeout while waiting for log file to be
created by fake_nosetest.py')
+ sleep(0.1)
os.killpg(process.pid, signal.SIGINT)
- return process, logfile
+
+ return (process, tmpStdout, tmpStderr), logfile
+
+def get_stdout_stderr(process):
+ process, tmpStdout, tmpStderr = process
+
+ retcode = process.wait()
+ tmpStdout.seek(0)
+ tmpStderr.seek(0)
+ stdout = tmpStdout.read().decode('utf-8')
+ stderr = tmpStderr.read().decode('utf-8')
+ return stdout, stderr
def get_log_content(logfile):
'''prefix = 'tempfile is: '
@@ -53,9 +68,14 @@ def get_log_content(logfile):
def test_keyboardinterrupt():
process, logfile = keyboardinterrupt('keyboardinterrupt.py')
- stdout, stderr = [s.decode('utf-8') for s in process.communicate(None)]
- print stderr
+ stdout, stderr = get_stdout_stderr(process)
log = get_log_content(logfile)
+ print "---- log ----"
+ print log
+ print "---- captured stdout ----"
+ print stdout
+ print "---- captured stderr ----"
+ print stderr
assert 'setup' in log
assert 'test_timeout' in log
assert 'test_timeout_finished' not in log
@@ -70,9 +90,15 @@ def test_keyboardinterrupt():
def test_keyboardinterrupt_twice():
process, logfile = keyboardinterrupt('keyboardinterrupt_twice.py')
sleep(0.5)
- os.killpg(process.pid, signal.SIGINT)
- stdout, stderr = [s.decode('utf-8') for s in process.communicate(None)]
+ os.killpg(process[0].pid, signal.SIGINT)
+ stdout, stderr = get_stdout_stderr(process)
log = get_log_content(logfile)
+ print "---- log ----"
+ print log
+ print "---- captured stdout ----"
+ print stdout
+ print "---- captured stderr ----"
+ print stderr
assert 'setup' in log
assert 'test_timeout' in log
assert 'test_timeout_finished' not in log