]> git.apps.os.sepia.ceph.com Git - teuthology.git/commitdiff
Rewrite orchestra.run tests using mock
authorZack Cerza <zack@redhat.com>
Tue, 19 Jul 2016 21:25:48 +0000 (15:25 -0600)
committerZack Cerza <zack@redhat.com>
Wed, 20 Jul 2016 23:42:48 +0000 (17:42 -0600)
Signed-off-by: Zack Cerza <zack@redhat.com>
teuthology/orchestra/test/test_run.py

index 40464f19c69d33867a9c33e99b6561e77f1ad304..7d65e33475c248e5f0641e3067368c5fcfdc6f19 100644 (file)
 from cStringIO import StringIO
 
-import fudge
-import logging
 import socket
 
+from mock import MagicMock, patch
+from pytest import raises
+
 from .. import run
 from teuthology.exceptions import (CommandCrashedError, CommandFailedError,
                                    ConnectionLostError)
 
-from .util import assert_raises
-
 
 class TestRun(object):
-    @fudge.with_fakes
-    def test_run_log_simple(self):
-        fudge.clear_expectations()
-        ssh = fudge.Fake('SSHConnection')
-        transport = ssh.expects('get_transport').with_args().returns_fake()
-        transport.expects('getpeername').with_args().returns(('HOST', 22))
-        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_host = fudge.Fake('log_host')
-        logger.expects('getChild').with_args('HOST').returns(log_host)
-        log_err = fudge.Fake('log_err')
-        log_host.expects('getChild').with_args('stderr').returns(log_err)
-        log_err.expects('log').with_args(logging.INFO, 'bad')
-        log_out = fudge.Fake('log_out')
-        log_host.expects('getChild').with_args('stdout').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'],
-            )
-        assert r.exitstatus == 0
-
-    @fudge.with_fakes
-    def test_run_capture_stdout(self):
-        fudge.clear_expectations()
-        ssh = fudge.Fake('SSHConnection')
-        transport = ssh.expects('get_transport').with_args().returns_fake()
-        transport.expects('getpeername').with_args().returns(('HOST', 22))
-        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_host = fudge.Fake('log_host')
-        logger.expects('getChild').with_args('HOST').returns(log_host)
-        log_err = fudge.Fake('log_err')
-        log_host.expects('getChild').with_args('stderr').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,
+    def setup(self):
+        self.start_patchers()
+
+    def teardown(self):
+        self.stop_patchers()
+
+    def start_patchers(self):
+        self.m_remote_process = MagicMock(wraps=run.RemoteProcess)
+        self.patcher_remote_proc = patch(
+            'teuthology.orchestra.run.RemoteProcess',
+            self.m_remote_process,
+        )
+        self.m_channelfile = MagicMock(spec=run.ChannelFile)
+        self.m_ssh = MagicMock()
+        self.m_stdin_buf = self.m_channelfile()
+        self.m_stdout_buf = self.m_channelfile()
+        self.m_stderr_buf = self.m_channelfile()
+        self.m_ssh.exec_command.return_value = (
+            self.m_stdin_buf,
+            self.m_stdout_buf,
+            self.m_stderr_buf,
+        )
+        self.m_transport = MagicMock()
+        self.m_transport.getpeername.return_value = ('name', 22)
+        self.m_ssh.get_transport.return_value = self.m_transport
+        self.patcher_ssh = patch(
+            'teuthology.orchestra.connection.paramiko.SSHClient',
+            self.m_ssh,
+        )
+        self.patcher_ssh.start()
+        # Tests must start this if they wish to use it
+        # self.patcher_remote_proc.start()
+
+    def stop_patchers(self):
+        # If this patcher wasn't started, it's ok
+        try:
+            self.patcher_remote_proc.stop()
+        except RuntimeError:
+            pass
+        self.patcher_ssh.stop()
+
+    def test_exitstatus(self):
+        self.m_stdout_buf.channel.recv_exit_status.return_value = 0
+        proc = run.run(
+            client=self.m_ssh,
             args=['foo', 'bar baz'],
-            stdout=out_f,
+        )
+        assert proc.exitstatus == 0
+
+    def test_capture_stdout(self):
+        output = 'foo\nbar'
+
+        def m_copyfileobj(src, dest):
+            print output
+            print dest
+            dest.write(output)
+
+        self.m_stdout_buf.channel.recv_exit_status.return_value = 0
+        with patch(
+            'teuthology.orchestra.run.shutil.copyfileobj',
+            m_copyfileobj,
+        ):
+            proc = run.run(
+                client=self.m_ssh,
+                args=['foo', 'bar baz'],
+                stdout=StringIO(),
             )
-        assert r.exitstatus == 0
-        assert r.stdout is out_f
-        assert r.stdout.getvalue() == 'foo\nbar\n'
-
-    @fudge.with_fakes
-    def test_run_status_bad(self):
-        fudge.clear_expectations()
-        ssh = fudge.Fake('SSHConnection')
-        transport = ssh.expects('get_transport').with_args().returns_fake()
-        transport.expects('getpeername').with_args().returns(('HOST', 22))
-        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(
-            CommandFailedError,
-            run.run,
-            client=ssh,
-            logger=logger,
-            args=['foo'],
+        assert proc.stdout.getvalue() == output
+
+    def test_status_bad(self):
+        self.m_stdout_buf.channel.recv_exit_status.return_value = 42
+        with raises(CommandFailedError) as exc:
+            run.run(
+                client=self.m_ssh,
+                args=['foo'],
             )
-        assert e.command == 'foo'
-        assert e.exitstatus == 42
-        assert str(e) == "Command failed on HOST with status 42: 'foo'"
+        assert str(exc.value) == "Command failed on name with status 42: 'foo'"
 
-    @fudge.with_fakes
-    def test_run_status_bad_nocheck(self):
-        fudge.clear_expectations()
-        ssh = fudge.Fake('SSHConnection')
-        transport = ssh.expects('get_transport').with_args().returns_fake()
-        transport.expects('getpeername').with_args().returns(('HOST', 22))
-        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,
+    def test_status_bad_nocheck(self):
+        self.m_stdout_buf.channel.recv_exit_status.return_value = 42
+        proc = run.run(
+            client=self.m_ssh,
             args=['foo'],
             check_status=False,
+        )
+        assert proc.exitstatus == 42
+
+    def test_status_crash(self):
+        self.m_stdout_buf.channel.recv_exit_status.return_value = -1
+        with raises(CommandCrashedError) as exc:
+            run.run(
+                client=self.m_ssh,
+                args=['foo'],
             )
-        assert r.exitstatus == 42
-
-    @fudge.with_fakes
-    def test_run_status_crash(self):
-        fudge.clear_expectations()
-        ssh = fudge.Fake('SSHConnection')
-        transport = ssh.expects('get_transport').with_args().returns_fake()
-        transport.expects('getpeername').with_args().returns(('HOST', 22))
-        transport.expects('is_active').with_args().returns(True)
-        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)
-        e = assert_raises(
-            CommandCrashedError,
-            run.run,
-            client=ssh,
-            logger=logger,
-            args=['foo'],
-            )
-        assert e.command == 'foo'
-        assert str(e) == "Command crashed: 'foo'"
+        assert str(exc.value) == "Command crashed: 'foo'"
 
-    @fudge.with_fakes
-    def test_run_status_crash_nocheck(self):
-        fudge.clear_expectations()
-        ssh = fudge.Fake('SSHConnection')
-        transport = ssh.expects('get_transport').with_args().returns_fake()
-        transport.expects('getpeername').with_args().returns(('HOST', 22))
-        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,
+    def test_status_crash_nocheck(self):
+        self.m_stdout_buf.channel.recv_exit_status.return_value = -1
+        proc = run.run(
+            client=self.m_ssh,
             args=['foo'],
             check_status=False,
+        )
+        assert proc.exitstatus is None
+
+    def test_status_lost(self):
+        m_transport = MagicMock()
+        m_transport.getpeername.return_value = ('name', 22)
+        m_transport.is_active.return_value = False
+        self.m_stdout_buf.channel.recv_exit_status.return_value = -1
+        self.m_ssh.get_transport.return_value = m_transport
+        with raises(ConnectionLostError) as exc:
+            run.run(
+                client=self.m_ssh,
+                args=['foo'],
             )
-        assert r.exitstatus is None
-
-    @fudge.with_fakes
-    def test_run_status_lost(self):
-        fudge.clear_expectations()
-        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('getpeername').with_args().returns(('HOST', 22))
-        transport.expects('is_active').with_args().returns(False)
-        e = assert_raises(
-            ConnectionLostError,
-            run.run,
-            client=ssh,
-            logger=logger,
-            args=['foo'],
+        assert str(exc.value) == "SSH connection to name was lost: 'foo'"
+
+    def test_status_lost_socket(self):
+        m_transport = MagicMock()
+        m_transport.getpeername.side_effect = socket.error
+        self.m_ssh.get_transport.return_value = m_transport
+        with raises(ConnectionLostError) as exc:
+            run.run(
+                client=self.m_ssh,
+                args=['foo'],
             )
-
-        assert e.command == 'foo'
-        assert str(e) == "SSH connection to HOST was lost: 'foo'"
-
-    @fudge.with_fakes
-    def test_run_status_lost_socket(self):
-        fudge.clear_expectations()
-        ssh = fudge.Fake('SSHConnection')
-        out = fudge.Fake('ChannelFile').is_a_stub()
-        logger = fudge.Fake('logger').is_a_stub()
-        channel = fudge.Fake('channel')
-        out.has_attr(channel=channel)
-        transport = ssh.expects('get_transport').with_args().returns_fake()
-        transport.expects('getpeername').with_args().raises(socket.error)
-        e = assert_raises(
-            ConnectionLostError,
-            run.run,
-            client=ssh,
-            logger=logger,
-            args=['foo'],
-            )
-
-        assert e.command == 'foo'
-        assert str(e) == "SSH connection was lost: 'foo'"
-
-    @fudge.with_fakes
-    def test_run_status_lost_nocheck(self):
-        fudge.clear_expectations()
-        ssh = fudge.Fake('SSHConnection')
-        transport = ssh.expects('get_transport').with_args().returns_fake()
-        transport.expects('getpeername').with_args().returns(('HOST', 22))
-        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,
+        assert str(exc.value) == "SSH connection was lost: 'foo'"
+
+    def test_status_lost_nocheck(self):
+        m_transport = MagicMock()
+        m_transport.getpeername.return_value = ('name', 22)
+        m_transport.is_active.return_value = False
+        self.m_stdout_buf.channel.recv_exit_status.return_value = -1
+        self.m_ssh.get_transport.return_value = m_transport
+        proc = run.run(
+            client=self.m_ssh,
             args=['foo'],
             check_status=False,
-            )
-        assert r.exitstatus is None
+        )
+        assert proc.exitstatus is None
 
-    @fudge.with_fakes
-    def test_run_nowait(self):
-        fudge.clear_expectations()
-        ssh = fudge.Fake('SSHConnection')
-        transport = ssh.expects('get_transport').with_args().returns_fake()
-        transport.expects('getpeername').with_args().returns(('HOST', 22))
-        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,
+    def test_status_bad_nowait(self):
+        self.m_stdout_buf.channel.recv_exit_status.return_value = 42
+        proc = run.run(
+            client=self.m_ssh,
             args=['foo'],
             wait=False,
-            )
-        assert r.command == 'foo'
-        e = assert_raises(
-            CommandFailedError,
-            r.wait,
-            )
-        assert r.returncode == 42
-        assert str(e) == "Command failed on HOST with status 42: 'foo'"
-
-    @fudge.with_fakes
-    def test_run_stdin_pipe(self):
-        fudge.clear_expectations()
-        ssh = fudge.Fake('SSHConnection')
-        transport = ssh.expects('get_transport').with_args().returns_fake()
-        transport.expects('getpeername').with_args().returns(('HOST', 22))
-        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('exit_status_ready').with_args().returns(False)
-        channel.expects('recv_exit_status').with_args().returns(0)
-        r = run.run(
-            client=ssh,
-            logger=logger,
+        )
+        with raises(CommandFailedError) as exc:
+            proc.wait()
+        assert proc.returncode == 42
+        assert str(exc.value) == "Command failed on name with status 42: 'foo'"
+
+    def test_stdin_pipe(self):
+        self.m_stdout_buf.channel.recv_exit_status.return_value = 0
+        proc = run.run(
+            client=self.m_ssh,
             args=['foo'],
             stdin=run.PIPE,
-            wait=False,
-            )
-        r.stdin.write('bar')
-        assert r.command == 'foo'
-        assert r.poll() is None
-        got = r.wait()
-        assert isinstance(r.returncode, int)
-        assert got == 0
-
-    @fudge.with_fakes
-    def test_run_stdout_pipe(self):
-        fudge.clear_expectations()
-        ssh = fudge.Fake('SSHConnection')
-        transport = ssh.expects('get_transport').with_args().returns_fake()
-        transport.expects('getpeername').with_args().returns(('HOST', 22))
-        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('read').with_args().returns('one')
-        out.expects('read').with_args().returns('two')
-        out.expects('read').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('exit_status_ready').with_args().returns(False)
-        channel.expects('recv_exit_status').with_args().returns(0)
-        r = run.run(
-            client=ssh,
-            logger=logger,
+            wait=False
+        )
+        assert proc.poll() is None
+        code = proc.wait()
+        assert code == 0
+        assert proc.exitstatus == 0
+
+    def test_stdout_pipe(self):
+        self.m_stdout_buf.channel.recv_exit_status.return_value = 0
+        self.m_stdout_buf.read.side_effect = [
+            'one', 'two', '',
+        ]
+        proc = run.run(
+            client=self.m_ssh,
             args=['foo'],
             stdout=run.PIPE,
-            wait=False,
-            )
-        assert r.exitstatus is None
-        assert r.command == 'foo'
-        assert r.poll() is None
-        assert r.stdout.read() == 'one'
-        assert r.stdout.read() == 'two'
-        assert r.stdout.read() == ''
-        got = r.wait()
-        assert isinstance(r.exitstatus, int)
-        assert got == 0
-
-    @fudge.with_fakes
-    def test_run_stderr_pipe(self):
-        fudge.clear_expectations()
-        ssh = fudge.Fake('SSHConnection')
-        transport = ssh.expects('get_transport').with_args().returns_fake()
-        transport.expects('getpeername').with_args().returns(('HOST', 22))
-        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('read').with_args().returns('one')
-        err.expects('read').with_args().returns('two')
-        err.expects('read').with_args().returns('')
-        logger = fudge.Fake('logger').is_a_stub()
-        channel = fudge.Fake('channel')
-        out.has_attr(channel=channel)
-        channel.expects('exit_status_ready').with_args().returns(False)
-        channel.expects('recv_exit_status').with_args().returns(0)
-        r = run.run(
-            client=ssh,
-            logger=logger,
+            wait=False
+        )
+        assert proc.poll() is None
+        assert proc.stdout.read() == 'one'
+        assert proc.stdout.read() == 'two'
+        assert proc.stdout.read() == ''
+        code = proc.wait()
+        assert code == 0
+        assert proc.exitstatus == 0
+
+    def test_stderr_pipe(self):
+        self.m_stdout_buf.channel.recv_exit_status.return_value = 0
+        self.m_stderr_buf.read.side_effect = [
+            'one', 'two', '',
+        ]
+        proc = run.run(
+            client=self.m_ssh,
             args=['foo'],
             stderr=run.PIPE,
-            wait=False,
-            )
-        assert r.exitstatus is None
-        assert r.command == 'foo'
-        assert r.poll() is None
-        assert r.stderr.read() == 'one'
-        assert r.stderr.read() == 'two'
-        assert r.stderr.read() == ''
-        got = r.wait()
-        assert isinstance(r.exitstatus, int)
-        assert got == 0
-
+            wait=False
+        )
+        assert proc.poll() is None
+        assert proc.stderr.read() == 'one'
+        assert proc.stderr.read() == 'two'
+        assert proc.stderr.read() == ''
+        code = proc.wait()
+        assert code == 0
+        assert proc.exitstatus == 0
+
+
+class TestQuote(object):
     def test_quote_simple(self):
         got = run.quote(['a b', ' c', 'd e '])
         assert got == "'a b' ' c' 'd e '"