ceph/orchestra/test/test_run.py
Tommi Virtanen 073a4bbc18 Paramiko ChannelFile.close() didn't actually close the remote stdin.
Add a wrapper that does the calls shutdown on the channel itself,
to actually cause EOF. Add integration test using remote cat.

Move shuffling stdout bytes to background, so run.run returns before
seeing EOF on stdout, and thus actually making the stdin useful.
Similarly, don't wait for EOF on stderr before returning from run.run.
2011-05-24 13:06:00 -07:00

310 lines
10 KiB
Python

from nose.tools import eq_ as eq
from cStringIO import StringIO
import fudge
import gevent.event
import nose
import logging
from .. import run
from .util import assert_raises
@nose.with_setup(fudge.clear_expectations)
@fudge.with_fakes
def test_run_log_simple():
ssh = fudge.Fake('SSHConnection')
cmd = ssh.expects('exec_command')
cmd.with_args("foo 'bar baz'")
in_ = fudge.Fake('ChannelFile(stdin)')
out = fudge.Fake('ChannelFile(stdout)')
err = fudge.Fake('ChannelFile(stderr)')
cmd.returns((in_, out, err))
in_.expects('close').with_args()
in_chan = fudge.Fake('channel')
in_chan.expects('shutdown_write').with_args()
in_.has_attr(channel=in_chan)
out.expects('xreadlines').with_args().returns(['foo', 'bar'])
err.expects('xreadlines').with_args().returns(['bad'])
logger = fudge.Fake('logger')
log_err = fudge.Fake('log_err')
logger.expects('getChild').with_args('err').returns(log_err)
log_err.expects('log').with_args(logging.INFO, 'bad')
log_out = fudge.Fake('log_out')
logger.expects('getChild').with_args('out').returns(log_out)
log_out.expects('log').with_args(logging.INFO, 'foo')
log_out.expects('log').with_args(logging.INFO, 'bar')
channel = fudge.Fake('channel')
out.has_attr(channel=channel)
channel.expects('recv_exit_status').with_args().returns(0)
r = run.run(
client=ssh,
logger=logger,
args=['foo', 'bar baz'],
)
eq(r.exitstatus, 0)
@nose.with_setup(fudge.clear_expectations)
@fudge.with_fakes
def test_run_capture_stdout():
ssh = fudge.Fake('SSHConnection')
cmd = ssh.expects('exec_command')
cmd.with_args("foo 'bar baz'")
in_ = fudge.Fake('ChannelFile(stdin)')
out = fudge.Fake('ChannelFile(stdout)')
err = fudge.Fake('ChannelFile(stderr)')
cmd.returns((in_, out, err))
in_.expects('close').with_args()
in_chan = fudge.Fake('channel')
in_chan.expects('shutdown_write').with_args()
in_.has_attr(channel=in_chan)
out.remember_order()
out.expects('read').with_args().returns('foo\nb')
out.expects('read').with_args().returns('ar\n')
out.expects('read').with_args().returns('')
err.expects('xreadlines').with_args().returns(['bad'])
logger = fudge.Fake('logger')
log_err = fudge.Fake('log_err')
logger.expects('getChild').with_args('err').returns(log_err)
log_err.expects('log').with_args(logging.INFO, 'bad')
channel = fudge.Fake('channel')
out.has_attr(channel=channel)
channel.expects('recv_exit_status').with_args().returns(0)
out_f = StringIO()
r = run.run(
client=ssh,
logger=logger,
args=['foo', 'bar baz'],
stdout=out_f,
)
eq(r.exitstatus, 0)
assert r.stdout is out_f
eq(r.stdout.getvalue(), 'foo\nbar\n')
@nose.with_setup(fudge.clear_expectations)
@fudge.with_fakes
def test_run_status_bad():
ssh = fudge.Fake('SSHConnection')
cmd = ssh.expects('exec_command')
cmd.with_args("foo")
in_ = fudge.Fake('ChannelFile').is_a_stub()
out = fudge.Fake('ChannelFile').is_a_stub()
err = fudge.Fake('ChannelFile').is_a_stub()
cmd.returns((in_, out, err))
out.expects('xreadlines').with_args().returns([])
err.expects('xreadlines').with_args().returns([])
logger = fudge.Fake('logger').is_a_stub()
channel = fudge.Fake('channel')
out.has_attr(channel=channel)
channel.expects('recv_exit_status').with_args().returns(42)
e = assert_raises(
run.CommandFailedError,
run.run,
client=ssh,
logger=logger,
args=['foo'],
)
eq(e.command, 'foo')
eq(e.exitstatus, 42)
eq(str(e), "Command failed with status 42: 'foo'")
@nose.with_setup(fudge.clear_expectations)
@fudge.with_fakes
def test_run_status_bad_nocheck():
ssh = fudge.Fake('SSHConnection')
cmd = ssh.expects('exec_command')
cmd.with_args("foo")
in_ = fudge.Fake('ChannelFile').is_a_stub()
out = fudge.Fake('ChannelFile').is_a_stub()
err = fudge.Fake('ChannelFile').is_a_stub()
cmd.returns((in_, out, err))
out.expects('xreadlines').with_args().returns([])
err.expects('xreadlines').with_args().returns([])
logger = fudge.Fake('logger').is_a_stub()
channel = fudge.Fake('channel')
out.has_attr(channel=channel)
channel.expects('recv_exit_status').with_args().returns(42)
r = run.run(
client=ssh,
logger=logger,
args=['foo'],
check_status=False,
)
eq(r.exitstatus, 42)
@nose.with_setup(fudge.clear_expectations)
@fudge.with_fakes
def test_run_status_crash():
ssh = fudge.Fake('SSHConnection')
cmd = ssh.expects('exec_command')
cmd.with_args("foo")
in_ = fudge.Fake('ChannelFile').is_a_stub()
out = fudge.Fake('ChannelFile').is_a_stub()
err = fudge.Fake('ChannelFile').is_a_stub()
cmd.returns((in_, out, err))
out.expects('xreadlines').with_args().returns([])
err.expects('xreadlines').with_args().returns([])
logger = fudge.Fake('logger').is_a_stub()
channel = fudge.Fake('channel')
out.has_attr(channel=channel)
channel.expects('recv_exit_status').with_args().returns(-1)
transport = ssh.expects('get_transport').with_args().returns_fake()
transport.expects('is_active').with_args().returns(True)
e = assert_raises(
run.CommandCrashedError,
run.run,
client=ssh,
logger=logger,
args=['foo'],
)
eq(e.command, 'foo')
eq(str(e), "Command crashed: 'foo'")
@nose.with_setup(fudge.clear_expectations)
@fudge.with_fakes
def test_run_status_crash_nocheck():
ssh = fudge.Fake('SSHConnection')
cmd = ssh.expects('exec_command')
cmd.with_args("foo")
in_ = fudge.Fake('ChannelFile').is_a_stub()
out = fudge.Fake('ChannelFile').is_a_stub()
err = fudge.Fake('ChannelFile').is_a_stub()
cmd.returns((in_, out, err))
out.expects('xreadlines').with_args().returns([])
err.expects('xreadlines').with_args().returns([])
logger = fudge.Fake('logger').is_a_stub()
channel = fudge.Fake('channel')
out.has_attr(channel=channel)
channel.expects('recv_exit_status').with_args().returns(-1)
r = run.run(
client=ssh,
logger=logger,
args=['foo'],
check_status=False,
)
assert r.exitstatus is None
@nose.with_setup(fudge.clear_expectations)
@fudge.with_fakes
def test_run_status_lost():
ssh = fudge.Fake('SSHConnection')
cmd = ssh.expects('exec_command')
cmd.with_args("foo")
in_ = fudge.Fake('ChannelFile').is_a_stub()
out = fudge.Fake('ChannelFile').is_a_stub()
err = fudge.Fake('ChannelFile').is_a_stub()
cmd.returns((in_, out, err))
out.expects('xreadlines').with_args().returns([])
err.expects('xreadlines').with_args().returns([])
logger = fudge.Fake('logger').is_a_stub()
channel = fudge.Fake('channel')
out.has_attr(channel=channel)
channel.expects('recv_exit_status').with_args().returns(-1)
transport = ssh.expects('get_transport').with_args().returns_fake()
transport.expects('is_active').with_args().returns(False)
e = assert_raises(
run.ConnectionLostError,
run.run,
client=ssh,
logger=logger,
args=['foo'],
)
eq(e.command, 'foo')
eq(str(e), "SSH connection was lost: 'foo'")
@nose.with_setup(fudge.clear_expectations)
@fudge.with_fakes
def test_run_status_lost_nocheck():
ssh = fudge.Fake('SSHConnection')
cmd = ssh.expects('exec_command')
cmd.with_args("foo")
in_ = fudge.Fake('ChannelFile').is_a_stub()
out = fudge.Fake('ChannelFile').is_a_stub()
err = fudge.Fake('ChannelFile').is_a_stub()
cmd.returns((in_, out, err))
out.expects('xreadlines').with_args().returns([])
err.expects('xreadlines').with_args().returns([])
logger = fudge.Fake('logger').is_a_stub()
channel = fudge.Fake('channel')
out.has_attr(channel=channel)
channel.expects('recv_exit_status').with_args().returns(-1)
r = run.run(
client=ssh,
logger=logger,
args=['foo'],
check_status=False,
)
assert r.exitstatus is None
@nose.with_setup(fudge.clear_expectations)
@fudge.with_fakes
def test_run_nowait():
ssh = fudge.Fake('SSHConnection')
cmd = ssh.expects('exec_command')
cmd.with_args("foo")
in_ = fudge.Fake('ChannelFile').is_a_stub()
out = fudge.Fake('ChannelFile').is_a_stub()
err = fudge.Fake('ChannelFile').is_a_stub()
cmd.returns((in_, out, err))
out.expects('xreadlines').with_args().returns([])
err.expects('xreadlines').with_args().returns([])
logger = fudge.Fake('logger').is_a_stub()
channel = fudge.Fake('channel')
out.has_attr(channel=channel)
channel.expects('recv_exit_status').with_args().returns(42)
r = run.run(
client=ssh,
logger=logger,
args=['foo'],
wait=False,
)
eq(r.command, 'foo')
assert isinstance(r.exitstatus, gevent.event.AsyncResult)
e = assert_raises(
run.CommandFailedError,
r.exitstatus.get,
)
eq(e.exitstatus, 42)
eq(str(e), "Command failed with status 42: 'foo'")
@nose.with_setup(fudge.clear_expectations)
@fudge.with_fakes
def test_run_stdin_pipe():
ssh = fudge.Fake('SSHConnection')
cmd = ssh.expects('exec_command')
cmd.with_args("foo")
in_ = fudge.Fake('ChannelFile').is_a_stub()
out = fudge.Fake('ChannelFile').is_a_stub()
err = fudge.Fake('ChannelFile').is_a_stub()
cmd.returns((in_, out, err))
out.expects('xreadlines').with_args().returns([])
err.expects('xreadlines').with_args().returns([])
logger = fudge.Fake('logger').is_a_stub()
channel = fudge.Fake('channel')
out.has_attr(channel=channel)
channel.expects('recv_exit_status').with_args().returns(0)
r = run.run(
client=ssh,
logger=logger,
args=['foo'],
stdin=run.PIPE,
wait=False,
)
r.stdin.write('bar')
eq(r.command, 'foo')
assert isinstance(r.exitstatus, gevent.event.AsyncResult)
eq(r.exitstatus.ready(), False)
got = r.exitstatus.get()
eq(got, 0)