@@ -398,10 +398,14 @@ def test_remote_file_copy_transfer_success(self):
398398 timeout = 30 ,
399399 )
400400 self .device .native_ssh .find_prompt .return_value = "host#"
401- self .device .native_ssh .send_command .return_value = "Copy complete"
401+ # Mock send_command to return success message that includes the prompt
402+ self .device .native_ssh .send_command .return_value = "Copy complete\n host#"
402403 with mock .patch .object (NXOSDevice , "verify_file" , side_effect = [False , True ]):
403404 self .device .remote_file_copy (src , file_system = "bootflash:" )
405+ # Verify send_command was called with expect_string parameter
404406 self .device .native_ssh .send_command .assert_called_once ()
407+ call_args = self .device .native_ssh .send_command .call_args
408+ self .assertIn ("expect_string" , call_args .kwargs )
405409
406410 def test_remote_file_copy_transfer_fails_verification (self ):
407411 src = FileCopyModel (
@@ -412,7 +416,8 @@ def test_remote_file_copy_transfer_fails_verification(self):
412416 timeout = 30 ,
413417 )
414418 self .device .native_ssh .find_prompt .return_value = "host#"
415- self .device .native_ssh .send_command .return_value = "Copy complete"
419+ # Mock send_command to return success message that includes the prompt
420+ self .device .native_ssh .send_command .return_value = "Copy complete\n host#"
416421 with mock .patch .object (NXOSDevice , "verify_file" , side_effect = [False , False ]):
417422 with self .assertRaises (FileTransferError ):
418423 self .device .remote_file_copy (src , file_system = "bootflash:" )
@@ -434,6 +439,58 @@ def test_remote_file_copy_raises_not_enough_free_space(self, mock_get_free_space
434439 self .device .remote_file_copy (src , file_system = "bootflash:" )
435440 self .device .native_ssh .send_command .assert_not_called ()
436441
442+ def test_remote_file_copy_with_vrf_prompt_handling (self ):
443+ """Test remote_file_copy handles VRF prompts correctly."""
444+ src = FileCopyModel (
445+ download_url = "ftp://example.com/nxos.bin" ,
446+ checksum = "abc123" ,
447+ file_name = "nxos.bin" ,
448+ hashing_algorithm = "md5" ,
449+ timeout = 30 ,
450+ username = "testuser" ,
451+ token = "testpass" ,
452+ vrf = "management" , # VRF specified for prompt response
453+ )
454+ self .device .native_ssh .find_prompt .return_value = "host#"
455+ # Mock send_command to return success message that includes the prompt
456+ self .device .native_ssh .send_command .return_value = "Copy complete\n host#"
457+ with mock .patch .object (NXOSDevice , "verify_file" , side_effect = [False , True ]):
458+ self .device .remote_file_copy (src , file_system = "bootflash:" )
459+
460+ # Verify send_command was called with VRF prompt handling
461+ self .device .native_ssh .send_command .assert_called_once ()
462+ call_args = self .device .native_ssh .send_command .call_args
463+ self .assertIn ("expect_string" , call_args .kwargs )
464+ # Verify the expect_string contains VRF prompt pattern
465+ expect_string = call_args .kwargs ["expect_string" ]
466+ self .assertIn ("Enter vrf" , expect_string )
467+
468+ def test_remote_file_copy_with_no_vrf_specified (self ):
469+ """Test remote_file_copy handles VRF prompts when no VRF is specified."""
470+ src = FileCopyModel (
471+ download_url = "ftp://example.com/nxos.bin" ,
472+ checksum = "abc123" ,
473+ file_name = "nxos.bin" ,
474+ hashing_algorithm = "md5" ,
475+ timeout = 30 ,
476+ username = "testuser" ,
477+ token = "testpass" ,
478+ # No VRF specified - should respond with empty string to VRF prompt
479+ )
480+ self .device .native_ssh .find_prompt .return_value = "host#"
481+ # Mock send_command to return success message that includes the prompt
482+ self .device .native_ssh .send_command .return_value = "Copy complete\n host#"
483+ with mock .patch .object (NXOSDevice , "verify_file" , side_effect = [False , True ]):
484+ self .device .remote_file_copy (src , file_system = "bootflash:" )
485+
486+ # Verify send_command was called with VRF prompt handling
487+ self .device .native_ssh .send_command .assert_called_once ()
488+ call_args = self .device .native_ssh .send_command .call_args
489+ self .assertIn ("expect_string" , call_args .kwargs )
490+ # Verify the expect_string contains VRF prompt pattern
491+ expect_string = call_args .kwargs ["expect_string" ]
492+ self .assertIn ("Enter vrf" , expect_string )
493+
437494 def test_remote_file_copy_invalid_scheme (self ):
438495 src = FileCopyModel (
439496 download_url = "smtp://example.com/nxos.bin" ,
@@ -493,6 +550,95 @@ def test_remote_file_copy_uses_ssh_for_filesystem_detection(self, scheme, hostna
493550 any ("dir" in str (call ) for call in ssh_calls ), "Expected SSH 'dir' command for filesystem detection"
494551 )
495552
553+ @mock .patch ("pyntc.devices.nxos_device.ConnectHandler" , create = True )
554+ @mock .patch ("pyntc.devices.nxos_device.NXOSNative" , autospec = True )
555+ def test_api_port_default (self , mock_device , mock_connect_handler ):
556+ """Test that api_port defaults to 80."""
557+ _ = NXOSDevice ("host" , "user" , "pass" )
558+
559+ # Verify NXOSNative was called with default api_port (80)
560+ mock_device .assert_called_with (
561+ "host" ,
562+ "user" ,
563+ "pass" ,
564+ transport = "http" ,
565+ timeout = 30 ,
566+ port = 80 , # Default api_port
567+ verify = True ,
568+ )
569+
570+ @mock .patch ("pyntc.devices.nxos_device.ConnectHandler" , create = True )
571+ @mock .patch ("pyntc.devices.nxos_device.NXOSNative" , autospec = True )
572+ def test_api_port_custom (self , mock_device , mock_connect_handler ):
573+ """Test that custom api_port is passed to NXOSNative."""
574+ _ = NXOSDevice ("host" , "user" , "pass" , api_port = 8080 )
575+
576+ # Verify NXOSNative was called with custom api_port
577+ mock_device .assert_called_with (
578+ "host" ,
579+ "user" ,
580+ "pass" ,
581+ transport = "http" ,
582+ timeout = 30 ,
583+ port = 8080 , # Custom api_port
584+ verify = True ,
585+ )
586+
587+ @mock .patch ("pyntc.devices.nxos_device.ConnectHandler" , create = True )
588+ @mock .patch ("pyntc.devices.nxos_device.NXOSNative" , autospec = True )
589+ def test_api_port_with_https (self , mock_device , mock_connect_handler ):
590+ """Test that api_port works with HTTPS transport."""
591+ _ = NXOSDevice ("host" , "user" , "pass" , transport = "https" , api_port = 8443 )
592+
593+ # Verify NXOSNative was called with HTTPS and custom api_port
594+ mock_device .assert_called_with (
595+ "host" ,
596+ "user" ,
597+ "pass" ,
598+ transport = "https" ,
599+ timeout = 30 ,
600+ port = 8443 , # Custom HTTPS api_port
601+ verify = True ,
602+ )
603+
604+ @mock .patch ("pyntc.devices.nxos_device.ConnectHandler" , create = True )
605+ @mock .patch ("pyntc.devices.nxos_device.NXOSNative" , autospec = True )
606+ def test_port_parameter_preserved (self , mock_device , mock_connect_handler ):
607+ """Test that the port parameter is preserved for future SSH port customization."""
608+ device = NXOSDevice ("host" , "user" , "pass" , api_port = 8080 , port = 2222 )
609+
610+ # Verify api_port is used for NXOSNative (NX-API)
611+ mock_device .assert_called_with (
612+ "host" ,
613+ "user" ,
614+ "pass" ,
615+ transport = "http" ,
616+ timeout = 30 ,
617+ port = 8080 , # api_port for NX-API
618+ verify = True ,
619+ )
620+
621+ # Verify port parameter is stored for future SSH use
622+ self .assertEqual (device .port , 2222 )
623+
624+ @mock .patch ("pyntc.devices.nxos_device.ConnectHandler" , create = True )
625+ @mock .patch ("pyntc.devices.nxos_device.NXOSNative" , autospec = True )
626+ def test_backward_compatibility_no_api_port (self , mock_device , mock_connect_handler ):
627+ """Test backward compatibility when api_port is not specified."""
628+ # Create device without specifying api_port
629+ _ = NXOSDevice ("host" , "user" , "pass" , transport = "http" )
630+
631+ # Should default to port 80 for HTTP
632+ mock_device .assert_called_with (
633+ "host" ,
634+ "user" ,
635+ "pass" ,
636+ transport = "http" ,
637+ timeout = 30 ,
638+ port = 80 , # Default api_port for HTTP
639+ verify = True ,
640+ )
641+
496642
497643if __name__ == "__main__" :
498644 unittest .main ()
0 commit comments