ceph/orchestra/test/test_run.py
Tommi Virtanen 0566de4979 Let callers specify that some arguments should not be quoted.
This lets you do things such as "test -e /foo && bar" or
"cd /tmp && blah". Remember that shell pipelines do not detect
errors in anything but the last command.
2011-05-24 13:38:05 -07:00

323 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)
def test_quote_simple():
got = run.quote(['a b', ' c', 'd e '])
eq(got, "'a b' ' c' 'd e '")
def test_quote_and_quote():
got = run.quote(['echo', 'this && is embedded', '&&', 'that was standalone'])
eq(got, "echo 'this && is embedded' '&&' 'that was standalone'")
def test_quote_and_raw():
got = run.quote(['true', run.Raw('&&'), 'echo', 'yay'])
eq(got, "true && echo yay")