Files
dvc/tests/unit/remote/ssh/test_ssh.py
T
Alexander Schepanovski d80293c44d dvc: path info refactoring
Replaced Path* dataclasses with PathInfo/URLInfo/CloudURLInfo, which
know how parse, serialize, stringify and join themselves. They also
provide useful accessors like part of an url or pathlib.Path like
.parent or .name.

Along the way two families of bugs where fixed and should never occur in
the future:
- paths not matched as strings anymore, e.g. using str.startswith()
- Output.path is eliminated as ambiguous

Both families might had caused undefined surprising behavior when local
and remote paths clash.
2019-06-11 19:19:17 +07:00

163 lines
4.6 KiB
Python

import getpass
import os
import sys
from unittest import TestCase
from mock import patch, mock_open
import pytest
from dvc.remote.ssh import RemoteSSH
class TestRemoteSSH(TestCase):
def test_url(self):
user = "test"
host = "123.45.67.89"
port = 1234
path = "/path/to/dir"
# URL ssh://[user@]host.xz[:port]/path
url = "ssh://{}@{}:{}{}".format(user, host, port, path)
config = {"url": url}
remote = RemoteSSH(None, config)
self.assertEqual(remote.path_info, url)
# SCP-like URL ssh://[user@]host.xz:/absolute/path
url = "ssh://{}@{}:{}".format(user, host, path)
config = {"url": url}
remote = RemoteSSH(None, config)
self.assertEqual(remote.path_info, url)
def test_no_path(self):
config = {"url": "ssh://127.0.0.1"}
remote = RemoteSSH(None, config)
self.assertEqual(remote.path_info.path, "")
mock_ssh_config = """
Host example.com
User ubuntu
HostName 1.2.3.4
Port 1234
IdentityFile ~/.ssh/not_default.key
"""
if sys.version_info.major == 3:
builtin_module_name = "builtins"
else:
builtin_module_name = "__builtin__"
@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("os.path.exists", return_value=True)
@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
):
remote = RemoteSSH(None, config)
mock_exists.assert_called_with(RemoteSSH.ssh_config_filename())
mock_file.assert_called_with(RemoteSSH.ssh_config_filename())
assert remote.path_info.host == expected_host
@pytest.mark.parametrize(
"config,expected_user",
[
({"url": "ssh://[email protected]"}, "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("os.path.exists", return_value=True)
@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)
mock_exists.assert_called_with(RemoteSSH.ssh_config_filename())
mock_file.assert_called_with(RemoteSSH.ssh_config_filename())
assert remote.path_info.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("os.path.exists", return_value=True)
@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)
mock_exists.assert_called_with(RemoteSSH.ssh_config_filename())
mock_file.assert_called_with(RemoteSSH.ssh_config_filename())
assert remote.path_info.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("os.path.exists", return_value=True)
@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)
mock_exists.assert_called_with(RemoteSSH.ssh_config_filename())
mock_file.assert_called_with(RemoteSSH.ssh_config_filename())
assert remote.keyfile == expected_keyfile