Split ne_session_factory into templates, CLI hop detection, and connect paths.

Keep the facade for callers, retarget unit-test patches to ne_session_connect, and fix the ConnectHandler coverage case to use a non-Cisco device type.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-08-02 17:15:57 +08:00
parent 96b76294b4
commit 58cdbe6165
7 changed files with 994 additions and 904 deletions

View file

@ -73,8 +73,8 @@ class BastionTemplateTests(unittest.TestCase):
class BastionConnectRoutingTests(unittest.TestCase):
@patch("netx_api.ne_session_factory._connect_via_bastion")
@patch("netx_api.ne_session_factory._connect_direct")
@patch("netx_api.ne_session_connect._connect_via_bastion")
@patch("netx_api.ne_session_connect._connect_direct")
def test_open_routes_to_bastion_when_enabled(self, direct, bastion) -> None:
bastion.return_value = MagicMock()
creds = {"hop_enabled": True, "hop_vendor": "bastion"}
@ -82,8 +82,8 @@ class BastionConnectRoutingTests(unittest.TestCase):
bastion.assert_called_once()
direct.assert_not_called()
@patch("netx_api.ne_session_factory._connect_via_bastion")
@patch("netx_api.ne_session_factory._connect_via_linux_hop")
@patch("netx_api.ne_session_connect._connect_via_bastion")
@patch("netx_api.ne_session_connect._connect_via_linux_hop")
def test_open_routes_linux_not_bastion(self, linux, bastion) -> None:
linux.return_value = MagicMock()
creds = {"hop_enabled": True, "hop_vendor": "linux"}
@ -93,8 +93,8 @@ class BastionConnectRoutingTests(unittest.TestCase):
class BastionConnectImplTests(unittest.TestCase):
@patch("netx_api.ne_session_factory._netmiko_over_ssh_client")
@patch("netx_api.ne_session_factory._bastion_ssh_connect")
@patch("netx_api.ne_session_connect._netmiko_over_ssh_client")
@patch("netx_api.ne_session_connect._bastion_ssh_connect")
def test_bastion_managed_skips_secondary_auth(self, bastion_ssh, netmiko_wrap) -> None:
from netx_api.ne_session_factory import _connect_via_bastion
@ -132,10 +132,10 @@ class BastionConnectImplTests(unittest.TestCase):
self.assertEqual(wrap_kwargs["password"], "vault-pass")
conn.disconnect.assert_not_called()
@patch("netx_api.ne_session_factory._interactive_target_auth")
@patch("netx_api.ne_session_factory._read_channel")
@patch("netx_api.ne_session_factory._netmiko_over_ssh_client")
@patch("netx_api.ne_session_factory._bastion_ssh_connect")
@patch("netx_api.ne_session_connect._interactive_target_auth")
@patch("netx_api.ne_session_connect._read_channel")
@patch("netx_api.ne_session_connect._netmiko_over_ssh_client")
@patch("netx_api.ne_session_connect._bastion_ssh_connect")
def test_bastion_manual_invokes_secondary_auth(
self, bastion_ssh, netmiko_wrap, _read, interact
) -> None:

View file

@ -50,9 +50,9 @@ class CliHopReturnDetectionTests(unittest.TestCase):
self.assertFalse(should_close_cli_hop_session(text, "<HOP>", seen_other_prompt=False))
self.assertTrue(should_close_cli_hop_session(text, "<HOP>", seen_other_prompt=True))
@patch("netx_api.ne_session_factory._interactive_target_auth")
@patch("netx_api.ne_session_factory._read_channel")
@patch("netx_api.ne_session_factory.ConnectHandler")
@patch("netx_api.ne_session_connect._interactive_target_auth")
@patch("netx_api.ne_session_connect._read_channel")
@patch("netx_api.ne_session_connect.ConnectHandler")
def test_connect_attaches_cli_hop_guard(
self,
mock_ch: MagicMock,

View file

@ -20,10 +20,10 @@ class InteractiveNetmikoTests(unittest.TestCase):
def test_build_non_interactive_uses_connect_handler(self) -> None:
fake = MagicMock(name="conn")
with patch("netx_api.ne_session_factory.ConnectHandler", return_value=fake) as ch:
with patch("netx_api.ne_session_connect.ConnectHandler", return_value=fake) as ch:
out = _build_netmiko_connection(
{
"device_type": "cisco_ios",
"device_type": "linux",
"host": "1.1.1.1",
"username": "u",
"password": "p",
@ -42,7 +42,7 @@ class InteractiveNetmikoTests(unittest.TestCase):
"username": "u",
"password": "p",
}
with patch("netx_api.ne_session_factory._connect_direct") as direct:
with patch("netx_api.ne_session_connect._connect_direct") as direct:
direct.return_value = MagicMock()
open_netmiko_connection(creds, interactive=True)
direct.assert_called_once()