diff options
-rw-r--r-- | paramiko/client.py | 6 | ||||
-rw-r--r-- | tasks.py | 33 | ||||
-rw-r--r-- | tests/test_auth.py | 18 |
3 files changed, 45 insertions, 12 deletions
diff --git a/paramiko/client.py b/paramiko/client.py index 6f0cb847..de0a495e 100644 --- a/paramiko/client.py +++ b/paramiko/client.py @@ -463,6 +463,9 @@ class SSHClient (ClosingContextManager): Python :param int timeout: set command's channel timeout. See `.Channel.settimeout` + :param bool get_pty: + Request a pseudo-terminal from the server (default ``False``). + See `.Channel.get_pty` :param dict environment: a dict of shell environment variables, to be merged into the default environment that the remote command executes within. @@ -476,6 +479,9 @@ class SSHClient (ClosingContextManager): 3-tuple :raises: `.SSHException` -- if the server fails to execute the command + + .. versionchanged:: 1.10 + Added the ``get_pty`` kwarg. """ chan = self._transport.open_session(timeout=timeout) if get_pty: @@ -8,8 +8,21 @@ from invocations.packaging.release import ns as release_coll, publish from invocations.testing import count_errors +# TODO: this screams out for the invoke missing-feature of "I just wrap task X, +# assume its signature by default" (even if that is just **kwargs support) @task -def test(ctx, verbose=True, coverage=False, include_slow=False, opts=""): +def test( + ctx, + verbose=True, + color=True, + capture='sys', + module=None, + k=None, + x=False, + opts="", + coverage=False, + include_slow=False, +): """ Run unit tests via pytest. @@ -20,14 +33,28 @@ def test(ctx, verbose=True, coverage=False, include_slow=False, opts=""): """ if verbose and '--verbose' not in opts and '-v' not in opts: opts += " --verbose" + # TODO: forget why invocations.pytest added this; is it to force color when + # running headless? Probably? + if color: + opts += " --color=yes" + opts += ' --capture={0}'.format(capture) if '-m' not in opts and not include_slow: opts += " -m 'not slow'" + if k is not None and not ('-k' in opts if opts else False): + opts += ' -k {}'.format(k) + if x and not ('-x' in opts if opts else False): + opts += ' -x' + modstr = "" + if module is not None: + # NOTE: implicit test_ prefix as we're not on pytest-relaxed yet + modstr = " tests/test_{}.py".format(module) + # Switch runner depending on coverage or no coverage. + # TODO: get pytest's coverage plugin working, IIRC it has issues? runner = "pytest" if coverage: # Leverage how pytest can be run as 'python -m pytest', and then how # coverage can be told to run things in that manner instead of # expecting a literal .py file. - # TODO: get pytest's coverage plugin working, IIRC it has issues? runner = "coverage run --source=paramiko -m pytest" # Strip SSH_AUTH_SOCK from parent env to avoid pollution by interactive # users. @@ -37,7 +64,7 @@ def test(ctx, verbose=True, coverage=False, include_slow=False, opts=""): env = dict(os.environ) if 'SSH_AUTH_SOCK' in env: del env['SSH_AUTH_SOCK'] - cmd = "{} {}".format(runner, opts) + cmd = "{} {} {}".format(runner, opts, modstr) # NOTE: we have a pytest.ini and tend to use that over PYTEST_ADDOPTS. ctx.run(cmd, pty=True, env=env, replace_env=True) diff --git a/tests/test_auth.py b/tests/test_auth.py index 4eade610..dacdd654 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -133,7 +133,7 @@ class AuthTest (unittest.TestCase): self.assertTrue(self.event.is_set()) self.assertTrue(self.ts.is_active()) - def test_1_bad_auth_type(self): + def test_bad_auth_type(self): """ verify that we get the right exception when an unsupported auth type is requested. @@ -148,7 +148,7 @@ class AuthTest (unittest.TestCase): self.assertEqual(BadAuthenticationType, etype) self.assertEqual(['publickey'], evalue.allowed_types) - def test_2_bad_password(self): + def test_bad_password(self): """ verify that a bad password gets the right exception, and that a retry with the right password works. @@ -164,7 +164,7 @@ class AuthTest (unittest.TestCase): self.tc.auth_password(username='slowdive', password='pygmalion') self.verify_finished() - def test_3_multipart_auth(self): + def test_multipart_auth(self): """ verify that multipart auth works. """ @@ -177,7 +177,7 @@ class AuthTest (unittest.TestCase): self.assertEqual([], remain) self.verify_finished() - def test_4_interactive_auth(self): + def test_interactive_auth(self): """ verify keyboard-interactive auth works. """ @@ -195,7 +195,7 @@ class AuthTest (unittest.TestCase): self.assertEqual([], remain) self.verify_finished() - def test_5_interactive_auth_fallback(self): + def test_interactive_auth_fallback(self): """ verify that a password auth attempt will fallback to "interactive" if password auth isn't supported but interactive is. @@ -206,7 +206,7 @@ class AuthTest (unittest.TestCase): self.assertEqual([], remain) self.verify_finished() - def test_6_auth_utf8(self): + def test_auth_utf8(self): """ verify that utf-8 encoding happens in authentication. """ @@ -216,7 +216,7 @@ class AuthTest (unittest.TestCase): self.assertEqual([], remain) self.verify_finished() - def test_7_auth_non_utf8(self): + def test_auth_non_utf8(self): """ verify that non-utf-8 encoded passwords can be used for broken servers. @@ -227,7 +227,7 @@ class AuthTest (unittest.TestCase): self.assertEqual([], remain) self.verify_finished() - def test_8_auth_gets_disconnected(self): + def test_auth_gets_disconnected(self): """ verify that we catch a server disconnecting during auth, and report it as an auth failure. @@ -241,7 +241,7 @@ class AuthTest (unittest.TestCase): self.assertTrue(issubclass(etype, AuthenticationException)) @slow - def test_9_auth_non_responsive(self): + def test_auth_non_responsive(self): """ verify that authentication times out if server takes to long to respond (or never responds). |