From d0af0a14351c92d9ebda50769e679586afefdf82 Mon Sep 17 00:00:00 2001 From: "brian.price" Date: Fri, 9 Aug 2019 12:41:13 -0500 Subject: [PATCH 1/6] Moving to requirements files, and setting up tox for local testing. --- .gitignore | 1 + requirements.txt | 4 ++ requirements/extras/requirements-credssp.txt | 1 + requirements/extras/requirements-kerberos.txt | 2 + requirements/requirements-testmin.txt | 13 +++++ setup.py | 33 +++++++++--- tox.ini | 52 +++++++++++++++++++ winrm/tests/test_transport.py | 22 ++++++++ 8 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 requirements.txt create mode 100644 requirements/extras/requirements-credssp.txt create mode 100644 requirements/extras/requirements-kerberos.txt create mode 100644 requirements/requirements-testmin.txt create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore index 7d6a3ec9..61a93d79 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ __pycache__ /winrm/tests/config.json .pytest_cache venv +.tox diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..c1a6340d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +xmltodict +requests>=2.9.1 +requests_ntlm>=0.3.0 +six>=1.7.0 \ No newline at end of file diff --git a/requirements/extras/requirements-credssp.txt b/requirements/extras/requirements-credssp.txt new file mode 100644 index 00000000..f6b73ec7 --- /dev/null +++ b/requirements/extras/requirements-credssp.txt @@ -0,0 +1 @@ +requests-credssp>=1.0.0 diff --git a/requirements/extras/requirements-kerberos.txt b/requirements/extras/requirements-kerberos.txt new file mode 100644 index 00000000..ede9cd09 --- /dev/null +++ b/requirements/extras/requirements-kerberos.txt @@ -0,0 +1,2 @@ +winkerberos>=0.5.0 ; sys_platform=="win32" +pykerberos>=1.2.1,<2.0.0 ; sys_platform!="win32" \ No newline at end of file diff --git a/requirements/requirements-testmin.txt b/requirements/requirements-testmin.txt new file mode 100644 index 00000000..4d5df065 --- /dev/null +++ b/requirements/requirements-testmin.txt @@ -0,0 +1,13 @@ +xmltodict==0.3.0 +requests==2.9.1 +requests_ntlm==0.3.0 +six==1.7.0 + +# credssp +requests-credssp==1.0.0 + +# kerberos +winkerberos==0.5.0 ; sys_platform=="win32" +pykerberos==1.2.1 ; sys_platform!="win32" + +-r requirements-test.txt \ No newline at end of file diff --git a/setup.py b/setup.py index b71ec2f2..f3e5ba86 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,5 @@ +import os + from setuptools import setup __version__ = '0.3.1.dev0' @@ -11,6 +13,29 @@ except ImportError: long_description = '' + +def install_deps(): + default = open('requirements/requirements.txt', 'r').readlines() + pkg_list = [] + for resource in default: + pkg_list.append(resource.strip()) + return pkg_list + + +def install_extras(): + extras = dict() + for filename in os.listdir('requirements/extras'): + extra_key = filename.replace('requirements-', '').replace('.txt', '') + extras[extra_key] = list() + with open(filename, 'r') as req_file: + for pkg_name in req_file.readlines(): + extras[extra_key].append(pkg_name) + return extras + + +req_deps_list = install_deps() +extras_deps = install_extras() + setup( name=project_name, version=__version__, @@ -23,12 +48,8 @@ license='MIT license', packages=('winrm', 'winrm.tests', 'winrm.vendor.requests_kerberos'), package_data={'winrm.tests': ['*.ps1']}, - install_requires=['xmltodict', 'requests>=2.9.1', 'requests_ntlm>=0.3.0', 'six'], - extras_require={ - 'credssp': ['requests-credssp>=1.0.0'], - 'kerberos:sys_platform=="win32"': ['winkerberos>=0.5.0'], - 'kerberos:sys_platform!="win32"': ['pykerberos>=1.2.1,<2.0.0'] - }, + install_requires=req_deps_list, + extras_require=extras_deps, classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Console', diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..75a57458 --- /dev/null +++ b/tox.ini @@ -0,0 +1,52 @@ +[tox] +envlist = py27,py35,py36,py37,py38,py27min,py37min,py27base,py37base +skip_missing_interpreters = True +skipsdist = True +sitepackages = False + +[testenv] +ignore_errors = False +deps = + -r{toxinidir}/requirements/requirements-test.txt + -r{toxinidir}/requirements/extras/requirements-credssp.txt + -r{toxinidir}/requirements/extras/requirements-kerberos.txt + -r{toxinidir}/requirements/requirements.txt +commands = + pytest -v --flake8 --cov=winrm --cov-report=term-missing winrm/tests/ +whitelist_externals = bash + +# Test the base install, without extras. +[testenv:py27base] +ignore_errors = False +deps = + -r{toxinidir}/requirements/requirements-test.txt + -r{toxinidir}/requirements/requirements.txt +commands = + pytest -v --flake8 --cov=winrm --cov-report=term-missing winrm/tests/ +whitelist_externals = bash + +[testenv:py37base] +ignore_errors = False +deps = + -r{toxinidir}/requirements/requirements-test.txt + -r{toxinidir}/requirements/requirements.txt +commands = + pytest -v --flake8 --cov=winrm --cov-report=term-missing winrm/tests/ +whitelist_externals = bash + +# Test the minimum requirements for the packages. +[testenv:py27min] +ignore_errors = False +deps = + -r{toxinidir}/requirements/requirements-testmin.txt +commands = + pytest -v --flake8 --cov=winrm --cov-report=term-missing winrm/tests/ +whitelist_externals = bash + +[testenv:py37min] +ignore_errors = False +deps = + -r{toxinidir}/requirements/requirements-testmin.txt +commands = + pytest -v --flake8 --cov=winrm --cov-report=term-missing winrm/tests/ +whitelist_externals = bash diff --git a/winrm/tests/test_transport.py b/winrm/tests/test_transport.py index cc451f3f..b0335d12 100644 --- a/winrm/tests/test_transport.py +++ b/winrm/tests/test_transport.py @@ -2,10 +2,14 @@ import os import mock import unittest +import requests +from distutils.version import StrictVersion from winrm import transport from winrm.exceptions import WinRMError, InvalidCredentialsError +REQUEST_VERSION = requests.__version__.split('.') + class TestTransport(unittest.TestCase): maxDiff = 2048 @@ -144,6 +148,24 @@ def test_build_session_cert_ignore_2(self): t_default.build_session() self.assertIs(False, t_default.session.verify) + # TODO: I am not sure in which version changed specifically, but this can be updated if we need to find out. + @unittest.skipIf(StrictVersion(requests.__version__) > StrictVersion('2.9.1'), reason="Skipping older version of requests.") + def test_build_session_proxy_none_old_request(self): + os.environ['HTTP_PROXY'] = 'random_proxy' + os.environ['HTTPS_PROXY'] = 'random_proxy_2' + + t_default = transport.Transport(endpoint="https://example.com", + server_cert_validation='validate', + username='test', + password='test', + auth_method='basic', + proxy=None + ) + + t_default.build_session() + self.assertEqual({'no_proxy': '*', 'http': 'random_proxy', 'https': 'random_proxy_2'}, t_default.session.proxies) + + @unittest.skipIf(StrictVersion(requests.__version__) <= StrictVersion('2.9.1'), reason="This test is for the latest requests.") def test_build_session_proxy_none(self): os.environ['HTTP_PROXY'] = 'random_proxy' os.environ['HTTPS_PROXY'] = 'random_proxy_2' From 4d4885cb384bfb00f7d73bf3f064620b321fc3cf Mon Sep 17 00:00:00 2001 From: "brian.price" Date: Fri, 9 Aug 2019 13:58:11 -0500 Subject: [PATCH 2/6] Setting up parent testing class, and fixing some bugs with the changes. --- requirements-test.txt | 1 + requirements/requirements-testmin.txt | 2 +- setup.py | 2 +- tox.ini | 27 +++++++--- winrm/tests/base.py | 68 +++++++++++++++++++++++++ winrm/tests/test_transport.py | 71 +++++++++++++++++++-------- 6 files changed, 142 insertions(+), 29 deletions(-) create mode 100644 winrm/tests/base.py diff --git a/requirements-test.txt b/requirements-test.txt index aa82eab0..ff85389b 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -4,3 +4,4 @@ pytest==4.4.2 pytest-cov==2.7.1 pytest-flake8==1.0.4 mock==3.0.5 +requests_mock==1.5.2 \ No newline at end of file diff --git a/requirements/requirements-testmin.txt b/requirements/requirements-testmin.txt index 4d5df065..c8d5f9e0 100644 --- a/requirements/requirements-testmin.txt +++ b/requirements/requirements-testmin.txt @@ -10,4 +10,4 @@ requests-credssp==1.0.0 winkerberos==0.5.0 ; sys_platform=="win32" pykerberos==1.2.1 ; sys_platform!="win32" --r requirements-test.txt \ No newline at end of file +-r ../requirements-test.txt \ No newline at end of file diff --git a/setup.py b/setup.py index f3e5ba86..6cd70ab0 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ def install_deps(): - default = open('requirements/requirements.txt', 'r').readlines() + default = open('requirements.txt', 'r').readlines() pkg_list = [] for resource in default: pkg_list.append(resource.strip()) diff --git a/tox.ini b/tox.ini index 75a57458..2bc61218 100644 --- a/tox.ini +++ b/tox.ini @@ -7,10 +7,13 @@ sitepackages = False [testenv] ignore_errors = False deps = - -r{toxinidir}/requirements/requirements-test.txt + -r{toxinidir}/requirements-test.txt -r{toxinidir}/requirements/extras/requirements-credssp.txt -r{toxinidir}/requirements/extras/requirements-kerberos.txt - -r{toxinidir}/requirements/requirements.txt + -r{toxinidir}/requirements.txt +setenv = + PYWINRM_TEST_CREDSSP=1 + PYWINRM_TEST_KERBEROS=1 commands = pytest -v --flake8 --cov=winrm --cov-report=term-missing winrm/tests/ whitelist_externals = bash @@ -19,8 +22,11 @@ whitelist_externals = bash [testenv:py27base] ignore_errors = False deps = - -r{toxinidir}/requirements/requirements-test.txt - -r{toxinidir}/requirements/requirements.txt + -r{toxinidir}/requirements-test.txt + -r{toxinidir}/requirements.txt +setenv = + PYWINRM_TEST_CREDSSP=0 + PYWINRM_TEST_KERBEROS=0 commands = pytest -v --flake8 --cov=winrm --cov-report=term-missing winrm/tests/ whitelist_externals = bash @@ -28,8 +34,11 @@ whitelist_externals = bash [testenv:py37base] ignore_errors = False deps = - -r{toxinidir}/requirements/requirements-test.txt - -r{toxinidir}/requirements/requirements.txt + -r{toxinidir}/requirements-test.txt + -r{toxinidir}/requirements.txt +setenv = + PYWINRM_TEST_CREDSSP=0 + PYWINRM_TEST_KERBEROS=0 commands = pytest -v --flake8 --cov=winrm --cov-report=term-missing winrm/tests/ whitelist_externals = bash @@ -39,6 +48,9 @@ whitelist_externals = bash ignore_errors = False deps = -r{toxinidir}/requirements/requirements-testmin.txt +setenv = + PYWINRM_TEST_CREDSSP=1 + PYWINRM_TEST_KERBEROS=1 commands = pytest -v --flake8 --cov=winrm --cov-report=term-missing winrm/tests/ whitelist_externals = bash @@ -47,6 +59,9 @@ whitelist_externals = bash ignore_errors = False deps = -r{toxinidir}/requirements/requirements-testmin.txt +setenv = + PYWINRM_TEST_CREDSSP=1 + PYWINRM_TEST_KERBEROS=1 commands = pytest -v --flake8 --cov=winrm --cov-report=term-missing winrm/tests/ whitelist_externals = bash diff --git a/winrm/tests/base.py b/winrm/tests/base.py new file mode 100644 index 00000000..4c1c968e --- /dev/null +++ b/winrm/tests/base.py @@ -0,0 +1,68 @@ +import os +import mock +import unittest +import requests_mock + +if os.environ.get('PYWINRM_TEST_CREDSSP') == '1': + EXPECT_CREDSSP = True +elif os.environ.get('PYWINRM_TEST_CREDSSP') == '0': + EXPECT_CREDSSP = False +else: + try: + from requests_credssp import HttpCredSSPAuth # NOQA + + EXPECT_CREDSSP = True + except ImportError as ie: + EXPECT_CREDSSP = False + +if os.environ.get('PYWINRM_TEST_KERBEROS') == '1': + EXPECT_KERBEROS = True +elif os.environ.get('PYWINRM_TEST_KERBEROS') == '0': + EXPECT_KERBEROS = False +else: + try: + from .vendor.requests_kerberos import HTTPKerberosAuth, REQUIRED # NOQA + + EXPECT_KERBEROS = True + except ImportError as ie: + EXPECT_KERBEROS = False + + +class BaseTest(unittest.TestCase): + maxDiff = 2048 + _old_env = None + + def setUp(self): + super(BaseTest, self).setUp() + self.mocked_request = requests_mock.Mocker() + self.mocked_request.start() + self._old_env = {} + os.environ.pop('REQUESTS_CA_BUNDLE', None) + os.environ.pop('TRAVIS_APT_PROXY', None) + os.environ.pop('CURL_CA_BUNDLE', None) + os.environ.pop('HTTPS_PROXY', None) + os.environ.pop('HTTP_PROXY', None) + os.environ.pop('NO_PROXY', None) + + def tearDown(self): + super(BaseTest, self).tearDown() + os.environ.pop('REQUESTS_CA_BUNDLE', None) + os.environ.pop('TRAVIS_APT_PROXY', None) + os.environ.pop('CURL_CA_BUNDLE', None) + os.environ.pop('HTTPS_PROXY', None) + os.environ.pop('HTTP_PROXY', None) + os.environ.pop('NO_PROXY', None) + self.mocked_request.stop() + + def auto_patch(self, to_patch, spec=True): + """ + Allow for mocking setup within setUp and tearDown in a single method. + + :param to_patch: Name of object to patch + :param spec: Whether mock should adhere to the spec + :return: The mock.Mock object. + """ + patcher = mock.patch(to_patch, spec=spec) + patched = patcher.start() + self.addCleanup(patcher.stop) + return patched diff --git a/winrm/tests/test_transport.py b/winrm/tests/test_transport.py index b0335d12..6ab15f55 100644 --- a/winrm/tests/test_transport.py +++ b/winrm/tests/test_transport.py @@ -3,6 +3,7 @@ import mock import unittest import requests +from . import base as base_test from distutils.version import StrictVersion from winrm import transport @@ -11,31 +12,13 @@ REQUEST_VERSION = requests.__version__.split('.') -class TestTransport(unittest.TestCase): - maxDiff = 2048 - _old_env = None +class TestTransport(base_test.BaseTest): def setUp(self): super(TestTransport, self).setUp() - self._old_env = {} - os.environ.pop('REQUESTS_CA_BUNDLE', None) - os.environ.pop('TRAVIS_APT_PROXY', None) - os.environ.pop('CURL_CA_BUNDLE', None) - os.environ.pop('HTTPS_PROXY', None) - os.environ.pop('HTTP_PROXY', None) - os.environ.pop('NO_PROXY', None) transport.DISPLAYED_PROXY_WARNING = False transport.DISPLAYED_CA_TRUST_WARNING = False - def tearDown(self): - super(TestTransport, self).tearDown() - os.environ.pop('REQUESTS_CA_BUNDLE', None) - os.environ.pop('TRAVIS_APT_PROXY', None) - os.environ.pop('CURL_CA_BUNDLE', None) - os.environ.pop('HTTPS_PROXY', None) - os.environ.pop('HTTP_PROXY', None) - os.environ.pop('NO_PROXY', None) - def test_build_session_cert_validate_default(self): t_default = transport.Transport(endpoint="https://example.com", username='test', @@ -149,7 +132,7 @@ def test_build_session_cert_ignore_2(self): self.assertIs(False, t_default.session.verify) # TODO: I am not sure in which version changed specifically, but this can be updated if we need to find out. - @unittest.skipIf(StrictVersion(requests.__version__) > StrictVersion('2.9.1'), reason="Skipping older version of requests.") + @unittest.skipIf(StrictVersion(requests.__version__) > StrictVersion('2.9.1'), reason="Skipping for versions 2.9.1 or older") def test_build_session_proxy_none_old_request(self): os.environ['HTTP_PROXY'] = 'random_proxy' os.environ['HTTPS_PROXY'] = 'random_proxy_2' @@ -165,7 +148,7 @@ def test_build_session_proxy_none_old_request(self): t_default.build_session() self.assertEqual({'no_proxy': '*', 'http': 'random_proxy', 'https': 'random_proxy_2'}, t_default.session.proxies) - @unittest.skipIf(StrictVersion(requests.__version__) <= StrictVersion('2.9.1'), reason="This test is for the latest requests.") + @unittest.skipIf(StrictVersion(requests.__version__) <= StrictVersion('2.9.1'), reason="Skipping for versions newer than 2.9.1") def test_build_session_proxy_none(self): os.environ['HTTP_PROXY'] = 'random_proxy' os.environ['HTTPS_PROXY'] = 'random_proxy_2' @@ -330,3 +313,49 @@ def test_close_session_not_built(self, mock_session): t_default.close_session() self.assertFalse(mock_session.return_value.close.called) self.assertIsNone(t_default.session) + + +class TestTransportCredSSP(base_test.BaseTest): + + @unittest.skipIf(base_test.EXPECT_CREDSSP is False, reason="Only testing when CredSSP is available") + def test_with_credssp(self): + t_default = transport.Transport(endpoint="https://example.com", + username='test', + password='test', + auth_method='credssp', + ) + t_default.build_session() + + @unittest.skipIf(base_test.EXPECT_CREDSSP is True, reason="Only testing when CredSSP is unavailable") + def test_without_credssp(self): + t_default = transport.Transport(endpoint="https://example.com", + username='test', + password='test', + auth_method='credssp', + ) + with self.assertRaises(WinRMError) as exc: + t_default.build_session() + self.assertEqual(str(exc.exception), 'requests auth method is credssp, but requests-credssp is not installed') + + +class TestTransportKerberos(base_test.BaseTest): + + @unittest.skipIf(base_test.EXPECT_KERBEROS is False, reason="Only testing when kerberos is available") + def test_with_kerberos(self): + t_default = transport.Transport(endpoint="https://example.com", + username='test', + password='test', + auth_method='kerberos', + ) + t_default.build_session() + + @unittest.skipIf(base_test.EXPECT_KERBEROS is True, reason="Only testing when kerberos is unavailable") + def test_without_kerberos(self): + t_default = transport.Transport(endpoint="https://example.com", + username='test', + password='test', + auth_method='kerberos', + ) + with self.assertRaises(WinRMError) as exc: + t_default.build_session() + self.assertEqual(str(exc.exception), 'requested auth method is kerberos, but requests_kerberos is not installed') From 8652a95a7b1297b5568618a5d140a0f7e4dd5274 Mon Sep 17 00:00:00 2001 From: "brian.price" Date: Fri, 9 Aug 2019 14:25:19 -0500 Subject: [PATCH 3/6] Fixing a bug with installs. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6cd70ab0..2aa44af6 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ def install_deps(): def install_extras(): extras = dict() for filename in os.listdir('requirements/extras'): - extra_key = filename.replace('requirements-', '').replace('.txt', '') + extra_key = filename.replace('requirements/extras/requirements-', '').replace('.txt', '') extras[extra_key] = list() with open(filename, 'r') as req_file: for pkg_name in req_file.readlines(): From 862abbd12ea88cd02b7939363c47f7294b26bf7e Mon Sep 17 00:00:00 2001 From: "brian.price" Date: Fri, 9 Aug 2019 14:27:31 -0500 Subject: [PATCH 4/6] Setting up parent testing class, and fixing some bugs with the changes. --- setup.py | 4 ++-- winrm/tests/winrm_responses/auth.py | 0 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 winrm/tests/winrm_responses/auth.py diff --git a/setup.py b/setup.py index 2aa44af6..05b59d05 100644 --- a/setup.py +++ b/setup.py @@ -25,9 +25,9 @@ def install_deps(): def install_extras(): extras = dict() for filename in os.listdir('requirements/extras'): - extra_key = filename.replace('requirements/extras/requirements-', '').replace('.txt', '') + extra_key = filename.replace('requirements-', '').replace('.txt', '') extras[extra_key] = list() - with open(filename, 'r') as req_file: + with open("requirements/extras/" + filename, 'r') as req_file: for pkg_name in req_file.readlines(): extras[extra_key].append(pkg_name) return extras diff --git a/winrm/tests/winrm_responses/auth.py b/winrm/tests/winrm_responses/auth.py new file mode 100644 index 00000000..e69de29b From acf14b31197e603efc197fac4c4602c4089cff1d Mon Sep 17 00:00:00 2001 From: "brian.price" Date: Fri, 9 Aug 2019 14:33:50 -0500 Subject: [PATCH 5/6] Fixing the CredSSP and Kerberos testing once again. --- winrm/tests/base.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/winrm/tests/base.py b/winrm/tests/base.py index 4c1c968e..06c64204 100644 --- a/winrm/tests/base.py +++ b/winrm/tests/base.py @@ -2,30 +2,21 @@ import mock import unittest import requests_mock +from winrm import transport if os.environ.get('PYWINRM_TEST_CREDSSP') == '1': EXPECT_CREDSSP = True elif os.environ.get('PYWINRM_TEST_CREDSSP') == '0': EXPECT_CREDSSP = False else: - try: - from requests_credssp import HttpCredSSPAuth # NOQA - - EXPECT_CREDSSP = True - except ImportError as ie: - EXPECT_CREDSSP = False + EXPECT_CREDSSP = transport.HAVE_CREDSSP if os.environ.get('PYWINRM_TEST_KERBEROS') == '1': EXPECT_KERBEROS = True elif os.environ.get('PYWINRM_TEST_KERBEROS') == '0': EXPECT_KERBEROS = False else: - try: - from .vendor.requests_kerberos import HTTPKerberosAuth, REQUIRED # NOQA - - EXPECT_KERBEROS = True - except ImportError as ie: - EXPECT_KERBEROS = False + EXPECT_KERBEROS = transport.HAVE_KERBEROS class BaseTest(unittest.TestCase): From f6913d41574cad484c4a9acb71b42c1fb08e4b11 Mon Sep 17 00:00:00 2001 From: "brian.price" Date: Fri, 9 Aug 2019 17:49:11 -0500 Subject: [PATCH 6/6] Started mocking the request and responses from winrm. --- winrm/tests/base.py | 14 -- winrm/tests/test_protocol.py | 34 ++++ .../winrm_responses/{auth.py => __init__.py} | 0 winrm/tests/winrm_responses/shells.py | 147 ++++++++++++++++++ 4 files changed, 181 insertions(+), 14 deletions(-) rename winrm/tests/winrm_responses/{auth.py => __init__.py} (100%) create mode 100644 winrm/tests/winrm_responses/shells.py diff --git a/winrm/tests/base.py b/winrm/tests/base.py index 06c64204..0eafc277 100644 --- a/winrm/tests/base.py +++ b/winrm/tests/base.py @@ -1,5 +1,4 @@ import os -import mock import unittest import requests_mock from winrm import transport @@ -44,16 +43,3 @@ def tearDown(self): os.environ.pop('HTTP_PROXY', None) os.environ.pop('NO_PROXY', None) self.mocked_request.stop() - - def auto_patch(self, to_patch, spec=True): - """ - Allow for mocking setup within setUp and tearDown in a single method. - - :param to_patch: Name of object to patch - :param spec: Whether mock should adhere to the spec - :return: The mock.Mock object. - """ - patcher = mock.patch(to_patch, spec=spec) - patched = patcher.start() - self.addCleanup(patcher.stop) - return patched diff --git a/winrm/tests/test_protocol.py b/winrm/tests/test_protocol.py index bcea47ea..98084ce6 100644 --- a/winrm/tests/test_protocol.py +++ b/winrm/tests/test_protocol.py @@ -1,8 +1,22 @@ import pytest +import copy +import xmltodict +from winrm.tests import base as base_test +from winrm.tests.winrm_responses import shells as shell_responses from winrm.protocol import Protocol +def convert_to_dict(ordered_dict): + new_dict = dict() + for name, value in ordered_dict.items(): + if isinstance(value, dict): + new_dict[name] = convert_to_dict(value) + else: + new_dict[name] = value + return new_dict + + def test_open_shell_and_close_shell(protocol_fake): shell_id = protocol_fake.open_shell() assert shell_id == '11111111-1111-1111-1111-111111111113' @@ -71,3 +85,23 @@ def test_fail_set_operation_timeout_as_sec(): operation_timeout_sec='29a') assert str(exc.value) == "failed to parse operation_timeout_sec as int: " \ "invalid literal for int() with base 10: '29a'" + + +class TestTransportShells(base_test.BaseTest): + + def test_open_shell(self): + self.mocked_request.post('https://example.com', text=shell_responses.OPEN_SHELL_RESPONSE) + server_conn = Protocol(endpoint="https://example.com", + username='test', + password='test', + ) + response = server_conn.open_shell() + self.assertEqual('5207F2DF-E6CA-4D10-8C7F-5380F01D6FDE', response) + + # MessageID will be dynamic, no need to compare + expected_shell_request = xmltodict.parse(copy.deepcopy(shell_responses.OPEN_SHELL_REQUEST)) + actual_shell_request = xmltodict.parse(copy.deepcopy(self.mocked_request.request_history[0].body)) + del expected_shell_request['env:Envelope']['env:Header']['a:MessageID'] + del actual_shell_request['env:Envelope']['env:Header']['a:MessageID'] + + self.assertEqual(convert_to_dict(expected_shell_request), convert_to_dict(actual_shell_request)) diff --git a/winrm/tests/winrm_responses/auth.py b/winrm/tests/winrm_responses/__init__.py similarity index 100% rename from winrm/tests/winrm_responses/auth.py rename to winrm/tests/winrm_responses/__init__.py diff --git a/winrm/tests/winrm_responses/shells.py b/winrm/tests/winrm_responses/shells.py new file mode 100644 index 00000000..bf24353d --- /dev/null +++ b/winrm/tests/winrm_responses/shells.py @@ -0,0 +1,147 @@ +OPEN_SHELL_REQUEST = """ + + + PT20S + http://windows-host:5985/wsman + + FALSE + 437 + + 153600 + http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd + http://schemas.xmlsoap.org/ws/2004/09/transfer/Create + + + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + + uuid:63acc10b-c16f-44e6-a1f8-45798c58f63d + + + + + stdin + stdout stderr + + + +""" + +OPEN_SHELL_RESPONSE = """ + + + http://schemas.xmlsoap.org/ws/2004/09/transfer/CreateResponse + uuid:BF99E0E5-4604-4FBE-A3F9-3C2251E2655E + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + uuid:63acc10b-c16f-44e6-a1f8-45798c58f63d + + + + http://windows-host:5985/wsman + + http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd + + 5207F2DF-E6CA-4D10-8C7F-5380F01D6FDE + + + + + 5207F2DF-E6CA-4D10-8C7F-5380F01D6FDE + http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd + SERVER-01\\Administrator + 192.168.0.1 + PT7200.000S + stdin + stdout stderr + P0DT0H0M0S + P0DT0H0M0S + + + +""" + +CLOSE_SHELL_REQUEST = """ + + + + PT20S + http://windows-host:5985/wsman + + B5235B70-E451-4378-BFB4-53C1ABACCAD2 + + 153600 + http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd + http://schemas.xmlsoap.org/ws/2004/09/transfer/Delete + + + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + + uuid:5fc69899-bbc7-4179-a7a2-f6bb62fe2860 + + + + +""" + +CLOSE_SHELL_RESPONSE = """ + + + http://schemas.xmlsoap.org/ws/2004/09/transfer/DeleteResponse + uuid:C20C16C3-D163-45B4-9821-8A11C4ED1E42 + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + uuid:5fc69899-bbc7-4179-a7a2-f6bb62fe2860 + + + +""" + +# Status code: 500 +CLOSE_SHELL_RESPONSE_ALREADY_CLOSED = """ + + + http://schemas.dmtf.org/wbem/wsman/1/wsman/fault + uuid:C0005351-7407-4B75-BE76-2A80BA45B7BF + http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous + uuid:fe945306-d7ce-4126-b168-c704bad7588c + + + + + s:Sender + + w:InvalidSelectors + + + + The WS-Management service cannot process the request because the request contained invalid selectors for the + resource. + + + + http://schemas.dmtf.org/wbem/wsman/1/wsman/faultDetail/UnexpectedSelectors + + The request for the Windows Remote Shell with ShellId B387C9DF-58ED-4E97-AE80-4117D8D12116 failed because the shell was not found + on the server. Possible causes are: the specified ShellId is incorrect or the shell no longer exists on the server. Provide the correct + ShellId or create a new shell and retry the operation. + + + + + + +"""