From 7059ae3408299453e1a0ee2c1c06517c19ddee1c Mon Sep 17 00:00:00 2001 From: khamutov Date: Sat, 4 May 2019 19:19:33 +0300 Subject: [PATCH 1/9] remote: add support for ssh config Fixes #1613 --- dvc/remote/ssh/__init__.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dvc/remote/ssh/__init__.py b/dvc/remote/ssh/__init__.py index 9a90065b44..0a827160a1 100644 --- a/dvc/remote/ssh/__init__.py +++ b/dvc/remote/ssh/__init__.py @@ -1,5 +1,6 @@ from __future__ import unicode_literals +import os import getpass import logging @@ -38,15 +39,27 @@ def __init__(self, repo, config): parsed = urlparse(self.url) self.host = parsed.hostname + + user_config_file = os.path.expanduser("~/.ssh/config") + user_ssh_config = dict() + if self.host: + if os.path.exists(user_config_file): + with open(user_config_file) as f: + ssh_config = paramiko.SSHConfig() + ssh_config.parse(f) + user_ssh_config = ssh_config.lookup(self.host) + self.user = ( config.get(Config.SECTION_REMOTE_USER) or parsed.username + or user_ssh_config.get("user") or getpass.getuser() ) self.prefix = parsed.path or "/" self.port = ( config.get(Config.SECTION_REMOTE_PORT) or parsed.port + or user_ssh_config.get("port") or self.DEFAULT_PORT ) self.keyfile = config.get(Config.SECTION_REMOTE_KEY_FILE, None) From ce9633458768511177f1d5b762ffaba0b673425a Mon Sep 17 00:00:00 2001 From: khamutov Date: Sun, 5 May 2019 13:20:28 +0300 Subject: [PATCH 2/9] extract ssh config parsing --- dvc/remote/ssh/__init__.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/dvc/remote/ssh/__init__.py b/dvc/remote/ssh/__init__.py index 0a827160a1..e58fec2a9d 100644 --- a/dvc/remote/ssh/__init__.py +++ b/dvc/remote/ssh/__init__.py @@ -40,14 +40,7 @@ def __init__(self, repo, config): parsed = urlparse(self.url) self.host = parsed.hostname - user_config_file = os.path.expanduser("~/.ssh/config") - user_ssh_config = dict() - if self.host: - if os.path.exists(user_config_file): - with open(user_config_file) as f: - ssh_config = paramiko.SSHConfig() - ssh_config.parse(f) - user_ssh_config = ssh_config.lookup(self.host) + user_ssh_config = self._load_user_ssh_config(self.host) self.user = ( config.get(Config.SECTION_REMOTE_USER) @@ -76,6 +69,17 @@ def __init__(self, repo, config): "port": self.port, } + @staticmethod + def _load_user_ssh_config(hostname): + user_config_file = os.path.expanduser("~/.ssh/config") + user_ssh_config = dict() + if hostname and os.path.exists(user_config_file): + with open(user_config_file) as f: + ssh_config = paramiko.SSHConfig() + ssh_config.parse(f) + user_ssh_config = ssh_config.lookup(hostname) + return user_ssh_config + def ssh(self, host=None, user=None, port=None, **kwargs): logger.debug( "Establishing ssh connection with '{host}' " From 0ac256cc9670d5ac3291d35fb092de858920c321 Mon Sep 17 00:00:00 2001 From: khamutov Date: Sun, 5 May 2019 19:28:05 +0300 Subject: [PATCH 3/9] add tests for ssh config --- dvc/remote/ssh/__init__.py | 21 ++++- tests/unit/remote/ssh/test_ssh.py | 128 ++++++++++++++++++++++-------- 2 files changed, 115 insertions(+), 34 deletions(-) diff --git a/dvc/remote/ssh/__init__.py b/dvc/remote/ssh/__init__.py index e58fec2a9d..557d5cff72 100644 --- a/dvc/remote/ssh/__init__.py +++ b/dvc/remote/ssh/__init__.py @@ -42,6 +42,7 @@ def __init__(self, repo, config): user_ssh_config = self._load_user_ssh_config(self.host) + self.host = user_ssh_config.get("hostname", self.host) self.user = ( config.get(Config.SECTION_REMOTE_USER) or parsed.username @@ -52,10 +53,12 @@ def __init__(self, repo, config): self.port = ( config.get(Config.SECTION_REMOTE_PORT) or parsed.port - or user_ssh_config.get("port") + or self._try_get_ssh_config_port(user_ssh_config) or self.DEFAULT_PORT ) - self.keyfile = config.get(Config.SECTION_REMOTE_KEY_FILE, None) + self.keyfile = config.get( + Config.SECTION_REMOTE_KEY_FILE + ) or self._try_get_ssh_config_keyfile(user_ssh_config) self.timeout = config.get(Config.SECTION_REMOTE_TIMEOUT, self.TIMEOUT) self.password = config.get(Config.SECTION_REMOTE_PASSWORD, None) self.ask_password = config.get( @@ -80,6 +83,20 @@ def _load_user_ssh_config(hostname): user_ssh_config = ssh_config.lookup(hostname) return user_ssh_config + @staticmethod + def _try_get_ssh_config_port(user_ssh_config): + try: + return int(user_ssh_config.get("port")) + except (ValueError, TypeError): + return None + + @staticmethod + def _try_get_ssh_config_keyfile(user_ssh_config): + identity_file = user_ssh_config.get("identityfile") + if identity_file and len(identity_file) > 0: + return identity_file[0] + return None + def ssh(self, host=None, user=None, port=None, **kwargs): logger.debug( "Establishing ssh connection with '{host}' " diff --git a/tests/unit/remote/ssh/test_ssh.py b/tests/unit/remote/ssh/test_ssh.py index 9afd9fe7df..2ff4a40f3f 100644 --- a/tests/unit/remote/ssh/test_ssh.py +++ b/tests/unit/remote/ssh/test_ssh.py @@ -1,28 +1,15 @@ import getpass +import os from unittest import TestCase +from mock import patch, mock_open +import pytest + from dvc.remote.ssh import RemoteSSH class TestRemoteSSH(TestCase): - def test_user(self): - url = "ssh://127.0.0.1:/path/to/dir" - config = {"url": url} - remote = RemoteSSH(None, config) - self.assertEqual(remote.user, getpass.getuser()) - - user = "test1" - url = "ssh://{}@127.0.0.1:/path/to/dir".format(user) - config = {"url": url} - remote = RemoteSSH(None, config) - self.assertEqual(remote.user, user) - - user = "test2" - config["user"] = user - remote = RemoteSSH(None, config) - self.assertEqual(remote.user, user) - def test_url(self): user = "test" host = "123.45.67.89" @@ -56,19 +43,96 @@ def test_no_path(self): remote = RemoteSSH(None, config) self.assertEqual(remote.prefix, "/") - def test_port(self): - url = "ssh://127.0.0.1/path/to/dir" - config = {"url": url} - remote = RemoteSSH(None, config) - self.assertEqual(remote.port, remote.DEFAULT_PORT) - - port = 1234 - url = "ssh://127.0.0.1:{}/path/to/dir".format(port) - config = {"url": url} - remote = RemoteSSH(None, config) - self.assertEqual(remote.port, port) - port = 4321 - config["port"] = port - remote = RemoteSSH(None, config) - self.assertEqual(remote.port, port) +mock_ssh_config = """ +Host example.com + User ubuntu + HostName 1.2.3.4 + Port 1234 + IdentityFile ~/.ssh/not_default.key +""" + + +@pytest.mark.parametrize( + "config,expected_host", + [ + ({"url": "ssh://example.com"}, "1.2.3.4"), + ({"url": "ssh://not_in_ssh_config.com"}, "not_in_ssh_config.com"), + ], +) +@patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) +def test_ssh_host_override_from_config(mock_file, config, expected_host): + remote = RemoteSSH(None, config) + + mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) + assert remote.host == expected_host + + +@pytest.mark.parametrize( + "config,expected_user", + [ + ({"url": "ssh://test1@example.com"}, "test1"), + ({"url": "ssh://example.com", "user": "test2"}, "test2"), + ({"url": "ssh://example.com"}, "ubuntu"), + ({"url": "ssh://test1@not_in_ssh_config.com"}, "test1"), + ( + {"url": "ssh://test1@not_in_ssh_config.com", "user": "test2"}, + "test2", + ), + ({"url": "ssh://not_in_ssh_config.com"}, getpass.getuser()), + ], +) +@patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) +def test_ssh_user(mock_file, config, expected_user): + remote = RemoteSSH(None, config) + + mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) + assert remote.user == expected_user + + +@pytest.mark.parametrize( + "config,expected_port", + [ + ({"url": "ssh://example.com:2222"}, 2222), + ({"url": "ssh://example.com"}, 1234), + ({"url": "ssh://example.com", "port": 4321}, 4321), + ({"url": "ssh://not_in_ssh_config.com"}, RemoteSSH.DEFAULT_PORT), + ({"url": "ssh://not_in_ssh_config.com:2222"}, 2222), + ({"url": "ssh://not_in_ssh_config.com:2222", "port": 4321}, 4321), + ], +) +@patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) +def test_ssh_port(mock_file, config, expected_port): + remote = RemoteSSH(None, config) + + mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) + assert remote.port == expected_port + + +@pytest.mark.parametrize( + "config,expected_keyfile", + [ + ( + {"url": "ssh://example.com", "keyfile": "dvc_config.key"}, + "dvc_config.key", + ), + ( + {"url": "ssh://example.com"}, + os.path.expanduser("~/.ssh/not_default.key"), + ), + ( + { + "url": "ssh://not_in_ssh_config.com", + "keyfile": "dvc_config.key", + }, + "dvc_config.key", + ), + ({"url": "ssh://not_in_ssh_config.com"}, None), + ], +) +@patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) +def test_ssh_keyfile(mock_file, config, expected_keyfile): + remote = RemoteSSH(None, config) + + mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) + assert remote.keyfile == expected_keyfile From 2f1d5d49b48248eaf536cd6d9ae292d06a0c9c3f Mon Sep 17 00:00:00 2001 From: khamutov Date: Sun, 5 May 2019 21:09:05 +0300 Subject: [PATCH 4/9] test: ssh: mock ssh config file exists check --- tests/unit/remote/ssh/test_ssh.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/unit/remote/ssh/test_ssh.py b/tests/unit/remote/ssh/test_ssh.py index 2ff4a40f3f..870b262f56 100644 --- a/tests/unit/remote/ssh/test_ssh.py +++ b/tests/unit/remote/ssh/test_ssh.py @@ -60,8 +60,11 @@ def test_no_path(self): ({"url": "ssh://not_in_ssh_config.com"}, "not_in_ssh_config.com"), ], ) +@patch("os.path.exists", return_value=True) @patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) -def test_ssh_host_override_from_config(mock_file, config, expected_host): +def test_ssh_host_override_from_config( + mock_exists, mock_file, config, expected_host +): remote = RemoteSSH(None, config) mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) @@ -82,8 +85,9 @@ def test_ssh_host_override_from_config(mock_file, config, expected_host): ({"url": "ssh://not_in_ssh_config.com"}, getpass.getuser()), ], ) +@patch("os.path.exists", return_value=True) @patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) -def test_ssh_user(mock_file, config, expected_user): +def test_ssh_user(mock_exists, mock_file, config, expected_user): remote = RemoteSSH(None, config) mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) @@ -101,8 +105,9 @@ def test_ssh_user(mock_file, config, expected_user): ({"url": "ssh://not_in_ssh_config.com:2222", "port": 4321}, 4321), ], ) +@patch("os.path.exists", return_value=True) @patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) -def test_ssh_port(mock_file, config, expected_port): +def test_ssh_port(mock_exists, mock_file, config, expected_port): remote = RemoteSSH(None, config) mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) @@ -130,9 +135,11 @@ def test_ssh_port(mock_file, config, expected_port): ({"url": "ssh://not_in_ssh_config.com"}, None), ], ) +@patch("os.path.exists", return_value=True) @patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) -def test_ssh_keyfile(mock_file, config, expected_keyfile): +def test_ssh_keyfile(mock_exists, mock_file, config, expected_keyfile): remote = RemoteSSH(None, config) + mock_exists.assert_called_with(os.path.expanduser("~/.ssh/config")) mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) assert remote.keyfile == expected_keyfile From 0afa99028ae639beaa50bacb9341ce7b25721f8c Mon Sep 17 00:00:00 2001 From: khamutov Date: Mon, 6 May 2019 09:05:39 +0300 Subject: [PATCH 5/9] test: ssh: fixes wrong order of mocks --- tests/unit/remote/ssh/test_ssh.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/unit/remote/ssh/test_ssh.py b/tests/unit/remote/ssh/test_ssh.py index 870b262f56..bb4008a845 100644 --- a/tests/unit/remote/ssh/test_ssh.py +++ b/tests/unit/remote/ssh/test_ssh.py @@ -63,10 +63,11 @@ def test_no_path(self): @patch("os.path.exists", return_value=True) @patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) def test_ssh_host_override_from_config( - mock_exists, mock_file, config, expected_host + mock_file, mock_exists, config, expected_host ): remote = RemoteSSH(None, config) + mock_exists.assert_called_with(os.path.expanduser("~/.ssh/config")) mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) assert remote.host == expected_host @@ -87,9 +88,10 @@ def test_ssh_host_override_from_config( ) @patch("os.path.exists", return_value=True) @patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) -def test_ssh_user(mock_exists, mock_file, config, expected_user): +def test_ssh_user(mock_file, mock_exists, config, expected_user): remote = RemoteSSH(None, config) + mock_exists.assert_called_with(os.path.expanduser("~/.ssh/config")) mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) assert remote.user == expected_user @@ -107,9 +109,10 @@ def test_ssh_user(mock_exists, mock_file, config, expected_user): ) @patch("os.path.exists", return_value=True) @patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) -def test_ssh_port(mock_exists, mock_file, config, expected_port): +def test_ssh_port(mock_file, mock_exists, config, expected_port): remote = RemoteSSH(None, config) + mock_exists.assert_called_with(os.path.expanduser("~/.ssh/config")) mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) assert remote.port == expected_port @@ -137,7 +140,7 @@ def test_ssh_port(mock_exists, mock_file, config, expected_port): ) @patch("os.path.exists", return_value=True) @patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) -def test_ssh_keyfile(mock_exists, mock_file, config, expected_keyfile): +def test_ssh_keyfile(mock_file, mock_exists, config, expected_keyfile): remote = RemoteSSH(None, config) mock_exists.assert_called_with(os.path.expanduser("~/.ssh/config")) From a4632092a5336a1c738f3a97d5e7bb01954d58cb Mon Sep 17 00:00:00 2001 From: khamutov Date: Mon, 6 May 2019 19:21:21 +0300 Subject: [PATCH 6/9] test: ssh: add mock_open compat version --- tests/unit/remote/ssh/test_ssh.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/unit/remote/ssh/test_ssh.py b/tests/unit/remote/ssh/test_ssh.py index bb4008a845..d13e779689 100644 --- a/tests/unit/remote/ssh/test_ssh.py +++ b/tests/unit/remote/ssh/test_ssh.py @@ -3,7 +3,8 @@ from unittest import TestCase -from mock import patch, mock_open +import mock +from mock import patch import pytest from dvc.remote.ssh import RemoteSSH @@ -44,14 +45,27 @@ def test_no_path(self): self.assertEqual(remote.prefix, "/") -mock_ssh_config = """ -Host example.com +mock_ssh_config = """Host example.com User ubuntu HostName 1.2.3.4 Port 1234 IdentityFile ~/.ssh/not_default.key """ +# compat version for mock library version 2 +# mock 2.0.0 can't iterate in mock_open +if mock.version_info[0] < 3: + + def mock_open_compat(*args, **kargs): + f_open = mock.mock_open(*args, **kargs) + f_open.return_value.__iter__ = lambda self: self + f_open.return_value.__next__ = lambda self: self.readline() + return f_open + + mock_open = mock_open_compat +else: + mock_open = mock.mock_open + @pytest.mark.parametrize( "config,expected_host", From 65fd7f9c8f62c9e5a242d7d37ac867b09e183954 Mon Sep 17 00:00:00 2001 From: khamutov Date: Mon, 6 May 2019 21:21:22 +0300 Subject: [PATCH 7/9] test: ssh: add support for python 2.7 in mocking --- tests/unit/remote/ssh/test_ssh.py | 41 +++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/tests/unit/remote/ssh/test_ssh.py b/tests/unit/remote/ssh/test_ssh.py index d13e779689..6193e44225 100644 --- a/tests/unit/remote/ssh/test_ssh.py +++ b/tests/unit/remote/ssh/test_ssh.py @@ -1,5 +1,6 @@ import getpass import os +import sys from unittest import TestCase @@ -45,7 +46,8 @@ def test_no_path(self): self.assertEqual(remote.prefix, "/") -mock_ssh_config = """Host example.com +mock_ssh_config = """ +Host example.com User ubuntu HostName 1.2.3.4 Port 1234 @@ -58,14 +60,23 @@ def test_no_path(self): def mock_open_compat(*args, **kargs): f_open = mock.mock_open(*args, **kargs) - f_open.return_value.__iter__ = lambda self: self - f_open.return_value.__next__ = lambda self: self.readline() + if sys.version_info.major == 3: + f_open.return_value.__iter__ = lambda self: self + f_open.return_value.__next__ = lambda self: self.readline() + else: + f_open.return_value.__iter__ = lambda self: iter(self.readline, "") + return f_open mock_open = mock_open_compat else: mock_open = mock.mock_open +if sys.version_info.major == 3: + builtin_module_name = "builtins" +else: + builtin_module_name = "__builtin__" + @pytest.mark.parametrize( "config,expected_host", @@ -75,7 +86,11 @@ def mock_open_compat(*args, **kargs): ], ) @patch("os.path.exists", return_value=True) -@patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) +@patch( + "{}.open".format(builtin_module_name), + new_callable=mock_open, + read_data=mock_ssh_config, +) def test_ssh_host_override_from_config( mock_file, mock_exists, config, expected_host ): @@ -101,7 +116,11 @@ def test_ssh_host_override_from_config( ], ) @patch("os.path.exists", return_value=True) -@patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) +@patch( + "{}.open".format(builtin_module_name), + new_callable=mock_open, + read_data=mock_ssh_config, +) def test_ssh_user(mock_file, mock_exists, config, expected_user): remote = RemoteSSH(None, config) @@ -122,7 +141,11 @@ def test_ssh_user(mock_file, mock_exists, config, expected_user): ], ) @patch("os.path.exists", return_value=True) -@patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) +@patch( + "{}.open".format(builtin_module_name), + new_callable=mock_open, + read_data=mock_ssh_config, +) def test_ssh_port(mock_file, mock_exists, config, expected_port): remote = RemoteSSH(None, config) @@ -153,7 +176,11 @@ def test_ssh_port(mock_file, mock_exists, config, expected_port): ], ) @patch("os.path.exists", return_value=True) -@patch("builtins.open", new_callable=mock_open, read_data=mock_ssh_config) +@patch( + "{}.open".format(builtin_module_name), + new_callable=mock_open, + read_data=mock_ssh_config, +) def test_ssh_keyfile(mock_file, mock_exists, config, expected_keyfile): remote = RemoteSSH(None, config) From 02eebd48eb9afa4579bf7e0be423a4208f25afc0 Mon Sep 17 00:00:00 2001 From: khamutov Date: Mon, 6 May 2019 21:47:58 +0300 Subject: [PATCH 8/9] test: ssh: add windows support for ssh config --- dvc/remote/ssh/__init__.py | 6 +++++- tests/unit/remote/ssh/test_ssh.py | 16 ++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/dvc/remote/ssh/__init__.py b/dvc/remote/ssh/__init__.py index 557d5cff72..0ef060efcf 100644 --- a/dvc/remote/ssh/__init__.py +++ b/dvc/remote/ssh/__init__.py @@ -72,9 +72,13 @@ def __init__(self, repo, config): "port": self.port, } + @staticmethod + def ssh_config_filename(): + return os.path.expanduser(os.path.join("~", ".ssh", "config")) + @staticmethod def _load_user_ssh_config(hostname): - user_config_file = os.path.expanduser("~/.ssh/config") + user_config_file = RemoteSSH.ssh_config_filename() user_ssh_config = dict() if hostname and os.path.exists(user_config_file): with open(user_config_file) as f: diff --git a/tests/unit/remote/ssh/test_ssh.py b/tests/unit/remote/ssh/test_ssh.py index 6193e44225..462c490cd4 100644 --- a/tests/unit/remote/ssh/test_ssh.py +++ b/tests/unit/remote/ssh/test_ssh.py @@ -96,8 +96,8 @@ def test_ssh_host_override_from_config( ): remote = RemoteSSH(None, config) - mock_exists.assert_called_with(os.path.expanduser("~/.ssh/config")) - mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) + mock_exists.assert_called_with(RemoteSSH.ssh_config_filename()) + mock_file.assert_called_with(RemoteSSH.ssh_config_filename()) assert remote.host == expected_host @@ -124,8 +124,8 @@ def test_ssh_host_override_from_config( def test_ssh_user(mock_file, mock_exists, config, expected_user): remote = RemoteSSH(None, config) - mock_exists.assert_called_with(os.path.expanduser("~/.ssh/config")) - mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) + mock_exists.assert_called_with(RemoteSSH.ssh_config_filename()) + mock_file.assert_called_with(RemoteSSH.ssh_config_filename()) assert remote.user == expected_user @@ -149,8 +149,8 @@ def test_ssh_user(mock_file, mock_exists, config, expected_user): def test_ssh_port(mock_file, mock_exists, config, expected_port): remote = RemoteSSH(None, config) - mock_exists.assert_called_with(os.path.expanduser("~/.ssh/config")) - mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) + mock_exists.assert_called_with(RemoteSSH.ssh_config_filename()) + mock_file.assert_called_with(RemoteSSH.ssh_config_filename()) assert remote.port == expected_port @@ -184,6 +184,6 @@ def test_ssh_port(mock_file, mock_exists, config, expected_port): def test_ssh_keyfile(mock_file, mock_exists, config, expected_keyfile): remote = RemoteSSH(None, config) - mock_exists.assert_called_with(os.path.expanduser("~/.ssh/config")) - mock_file.assert_called_with(os.path.expanduser("~/.ssh/config")) + mock_exists.assert_called_with(RemoteSSH.ssh_config_filename()) + mock_file.assert_called_with(RemoteSSH.ssh_config_filename()) assert remote.keyfile == expected_keyfile From 69a1d965e4c42b693b780235d646061e0994e1ef Mon Sep 17 00:00:00 2001 From: khamutov Date: Tue, 7 May 2019 11:28:50 +0300 Subject: [PATCH 9/9] test: ssh: update mock version to 3.0.0 min --- tests/requirements.txt | 2 +- tests/unit/remote/ssh/test_ssh.py | 21 +-------------------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/tests/requirements.txt b/tests/requirements.txt index fc290e9450..c7e1627afe 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -4,7 +4,7 @@ pytest-cov>=2.6.1 pytest-xdist>=1.26.1 pytest-mock>=1.10.4 flaky>=3.5.3 -mock>=2.0.0 +mock>=3.0.0 xmltodict>=0.11.0 awscli>=1.16.125 google-compute-engine diff --git a/tests/unit/remote/ssh/test_ssh.py b/tests/unit/remote/ssh/test_ssh.py index 462c490cd4..cc66b3adbf 100644 --- a/tests/unit/remote/ssh/test_ssh.py +++ b/tests/unit/remote/ssh/test_ssh.py @@ -4,8 +4,7 @@ from unittest import TestCase -import mock -from mock import patch +from mock import patch, mock_open import pytest from dvc.remote.ssh import RemoteSSH @@ -54,24 +53,6 @@ def test_no_path(self): IdentityFile ~/.ssh/not_default.key """ -# compat version for mock library version 2 -# mock 2.0.0 can't iterate in mock_open -if mock.version_info[0] < 3: - - def mock_open_compat(*args, **kargs): - f_open = mock.mock_open(*args, **kargs) - if sys.version_info.major == 3: - f_open.return_value.__iter__ = lambda self: self - f_open.return_value.__next__ = lambda self: self.readline() - else: - f_open.return_value.__iter__ = lambda self: iter(self.readline, "") - - return f_open - - mock_open = mock_open_compat -else: - mock_open = mock.mock_open - if sys.version_info.major == 3: builtin_module_name = "builtins" else: