@@ -693,57 +693,14 @@ def test_launch_script_with_pre_launch_commands(self):
693693 expected_pre_launch = "echo 'Custom setup'\n export MY_VAR=test\n "
694694 assert pre_launch_section_with_commands == expected_pre_launch
695695
696- @patch ("nemo_run.core.execution.lepton.LeptonExecutor._validate_mounts" )
697- @patch ("nemo_run.core.execution.lepton.LeptonExecutor.move_data" )
698- @patch ("nemo_run.core.execution.lepton.LeptonExecutor.create_lepton_job" )
699- @patch ("nemo_run.core.execution.lepton.LeptonExecutor.status" )
700- @patch ("builtins.open" , new_callable = mock_open )
701- @patch ("os.path.join" )
702- def test_launch_method_name_validation (
703- self ,
704- mock_join ,
705- mock_file ,
706- mock_status ,
707- mock_create_job ,
708- mock_move_data ,
709- mock_validate_mounts ,
710- ):
711- """Test the launch method's name validation and transformation logic."""
712- # Setup mocks
713- mock_job = MagicMock ()
714- mock_job .metadata .id_ = "test-job-id"
715- mock_create_job .return_value = mock_job
716- mock_status .return_value = LeptonJobState .Running
717- mock_join .return_value = "/fake/path/launch_script.sh"
718-
719- executor = LeptonExecutor (
720- container_image = "test-image" ,
721- nemo_run_dir = "/test/path" ,
722- )
723- executor .job_dir = "/fake/job/dir"
724- executor .lepton_job_dir = "/fake/lepton/job/dir"
725-
726- # Test normal name (no transformation needed)
727- job_id , status = executor .launch ("short-name" , ["python" , "script.py" ])
728- assert job_id == "test-job-id"
729- assert status == LeptonJobState .Running
730-
731- # Test name with underscores and dots (should be replaced)
732- job_id , status = executor .launch ("test_job.name" , ["python" , "script.py" ])
733- assert job_id == "test-job-id"
734-
735- # Test uppercase name (should be lowercased)
736- job_id , status = executor .launch ("UPPERCASE" , ["python" , "script.py" ])
737- assert job_id == "test-job-id"
738-
739696 @patch ("nemo_run.core.execution.lepton.LeptonExecutor._validate_mounts" )
740697 @patch ("nemo_run.core.execution.lepton.LeptonExecutor.move_data" )
741698 @patch ("nemo_run.core.execution.lepton.LeptonExecutor.create_lepton_job" )
742699 @patch ("nemo_run.core.execution.lepton.LeptonExecutor.status" )
743700 @patch ("builtins.open" , new_callable = mock_open )
744701 @patch ("os.path.join" )
745702 @patch ("nemo_run.core.execution.lepton.logger" )
746- def test_launch_method_long_name_truncation (
703+ def test_launch_method_comprehensive (
747704 self ,
748705 mock_logger ,
749706 mock_join ,
@@ -753,200 +710,34 @@ def test_launch_method_long_name_truncation(
753710 mock_move_data ,
754711 mock_validate_mounts ,
755712 ):
756- """Test that long names are properly truncated and warning is logged."""
757- # Setup mocks
758- mock_job = MagicMock ()
759- mock_job .metadata .id_ = "test-job-id"
760- mock_create_job .return_value = mock_job
761- mock_status .return_value = LeptonJobState .Running
762- mock_join .return_value = "/fake/path/launch_script.sh"
763-
713+ """Test launch method name validation, pre_launch_commands, and script generation."""
714+ # Setup
764715 executor = LeptonExecutor (
765- container_image = "test-image" ,
766- nemo_run_dir = "/test/path" ,
767- )
768- executor .job_dir = "/fake/job/dir"
769- executor .lepton_job_dir = "/fake/lepton/job/dir"
770-
771- # Test long name (should be truncated and logged)
772- long_name = "this-is-a-very-long-name-that-exceeds-thirty-five-characters"
773- job_id , status = executor .launch (long_name , ["python" , "script.py" ])
774-
775- # Verify warning was logged
776- mock_logger .warning .assert_called_with (
777- "length of name exceeds 35 characters. Shortening..."
716+ container_image = "test-image" , nemo_run_dir = "/test" , pre_launch_commands = ["echo setup" ]
778717 )
779- assert job_id == "test-job-id"
780- assert status == LeptonJobState .Running
781-
782- @patch ("nemo_run.core.execution.lepton.LeptonExecutor._validate_mounts" )
783- @patch ("nemo_run.core.execution.lepton.LeptonExecutor.move_data" )
784- @patch ("nemo_run.core.execution.lepton.LeptonExecutor.create_lepton_job" )
785- @patch ("nemo_run.core.execution.lepton.LeptonExecutor.status" )
786- @patch ("builtins.open" , new_callable = mock_open )
787- @patch ("os.path.join" )
788- def test_launch_method_with_pre_launch_commands (
789- self ,
790- mock_join ,
791- mock_file ,
792- mock_status ,
793- mock_create_job ,
794- mock_move_data ,
795- mock_validate_mounts ,
796- ):
797- """Test the launch method properly includes pre_launch_commands in the script."""
798- # Setup mocks
718+ executor .job_dir = executor .lepton_job_dir = "/fake"
719+ mock_join .return_value = "/fake/script.sh"
799720 mock_job = MagicMock ()
800- mock_job .metadata .id_ = "test-job-id"
801- mock_create_job .return_value = mock_job
802- mock_status .return_value = LeptonJobState .Running
803- mock_join .return_value = "/fake/path/launch_script.sh"
804-
805- # Test with pre_launch_commands
806- commands = ["echo 'Setting up environment'" , "export TEST_VAR=value" , "mkdir -p /workspace" ]
807- executor = LeptonExecutor (
808- container_image = "test-image" ,
809- nemo_run_dir = "/test/path" ,
810- pre_launch_commands = commands ,
811- )
812- executor .job_dir = "/fake/job/dir"
813- executor .lepton_job_dir = "/fake/lepton/job/dir"
814-
815- job_id , status = executor .launch ("test-job" , ["python" , "train.py" ])
816-
817- # Verify launch script was written with pre_launch_commands
818- mock_file .assert_called_once_with ("/fake/path/launch_script.sh" , "w+" )
819- handle = mock_file .return_value .__enter__ .return_value
820- written_content = handle .write .call_args [0 ][0 ]
821-
822- # Verify pre_launch_commands are included at the beginning
823- assert "echo 'Setting up environment'" in written_content
824- assert "export TEST_VAR=value" in written_content
825- assert "mkdir -p /workspace" in written_content
826-
827- # Verify the script structure
828- assert "wget -O init.sh" in written_content
829- assert "chmod +x init.sh" in written_content
830- assert "source init.sh" in written_content
831- assert "ln -s /fake/lepton/job/dir/ /nemo_run" in written_content
832- assert "cd /nemo_run/code" in written_content
833- assert "python train.py" in written_content
834-
835- assert job_id == "test-job-id"
836- assert status == LeptonJobState .Running
837-
838- @patch ("nemo_run.core.execution.lepton.LeptonExecutor._validate_mounts" )
839- @patch ("nemo_run.core.execution.lepton.LeptonExecutor.move_data" )
840- @patch ("nemo_run.core.execution.lepton.LeptonExecutor.create_lepton_job" )
841- @patch ("nemo_run.core.execution.lepton.LeptonExecutor.status" )
842- @patch ("builtins.open" , new_callable = mock_open )
843- @patch ("os.path.join" )
844- def test_launch_method_without_pre_launch_commands (
845- self ,
846- mock_join ,
847- mock_file ,
848- mock_status ,
849- mock_create_job ,
850- mock_move_data ,
851- mock_validate_mounts ,
852- ):
853- """Test the launch method works correctly without pre_launch_commands."""
854- # Setup mocks
855- mock_job = MagicMock ()
856- mock_job .metadata .id_ = "test-job-id"
721+ mock_job .metadata .id_ = "job-id"
857722 mock_create_job .return_value = mock_job
858723 mock_status .return_value = LeptonJobState .Running
859- mock_join .return_value = "/fake/path/launch_script.sh"
860724
861- # Test without pre_launch_commands (default empty list)
862- executor = LeptonExecutor (
863- container_image = "test-image" ,
864- nemo_run_dir = "/test/path" ,
865- )
866- executor .job_dir = "/fake/job/dir"
867- executor .lepton_job_dir = "/fake/lepton/job/dir"
868-
869- job_id , status = executor .launch ("test-job" , ["python" , "script.py" ])
725+ # Test name transformation and pre_launch_commands
726+ job_id , status = executor .launch ("Test_Job.Name" , ["python" , "script.py" ])
727+ assert job_id == "job-id"
870728
871- # Verify launch script was written without pre_launch_commands
872- mock_file .assert_called_once_with ("/fake/path/launch_script.sh" , "w+" )
729+ # Verify script content includes pre_launch_commands
873730 handle = mock_file .return_value .__enter__ .return_value
874731 written_content = handle .write .call_args [0 ][0 ]
875-
876- # Verify no pre_launch_commands section
877- lines = written_content .split ("\n " )
878- # First non-empty line should be the wget command
879- first_command_line = next (line for line in lines if line .strip ())
880- assert first_command_line .strip ().startswith ("wget -O init.sh" )
881-
882- # Verify the standard script structure is still there
883- assert "wget -O init.sh" in written_content
884- assert "chmod +x init.sh" in written_content
885- assert "source init.sh" in written_content
886- assert "ln -s /fake/lepton/job/dir/ /nemo_run" in written_content
887- assert "cd /nemo_run/code" in written_content
732+ assert "echo setup\n " in written_content
888733 assert "python script.py" in written_content
889734
890- assert job_id == "test-job-id"
891- assert status == LeptonJobState .Running
892-
893- @patch ("nemo_run.core.execution.lepton.LeptonExecutor._validate_mounts" )
894- @patch ("nemo_run.core.execution.lepton.LeptonExecutor.move_data" )
895- @patch ("nemo_run.core.execution.lepton.LeptonExecutor.create_lepton_job" )
896- @patch ("nemo_run.core.execution.lepton.LeptonExecutor.status" )
897- @patch ("builtins.open" , new_callable = mock_open )
898- @patch ("os.path.join" )
899- def test_launch_method_edge_cases (
900- self ,
901- mock_join ,
902- mock_file ,
903- mock_status ,
904- mock_create_job ,
905- mock_move_data ,
906- mock_validate_mounts ,
907- ):
908- """Test edge cases for the launch method."""
909- # Setup mocks
910- mock_job = MagicMock ()
911- mock_job .metadata .id_ = "test-job-id"
912- mock_create_job .return_value = mock_job
913- mock_status .return_value = LeptonJobState .Running
914- mock_join .return_value = "/fake/path/launch_script.sh"
915-
916- executor = LeptonExecutor (
917- container_image = "test-image" ,
918- nemo_run_dir = "/test/path" ,
735+ # Test long name truncation
736+ long_name = "a" * 50
737+ executor .launch (long_name , ["cmd" ])
738+ mock_logger .warning .assert_called_with (
739+ "length of name exceeds 35 characters. Shortening..."
919740 )
920- executor .job_dir = "/fake/job/dir"
921- executor .lepton_job_dir = "/fake/lepton/job/dir"
922-
923- # Test with exactly 35 characters (should be truncated)
924- name_35_chars = "a" * 35
925- job_id , status = executor .launch (name_35_chars , ["python" , "script.py" ])
926- assert job_id == "test-job-id"
927-
928- # Test with empty command list
929- job_id , status = executor .launch ("test-job" , [])
930- assert job_id == "test-job-id"
931-
932- # Test with complex command
933- complex_cmd = [
934- "python" ,
935- "-m" ,
936- "torch.distributed.launch" ,
937- "--nproc_per_node=8" ,
938- "train.py" ,
939- "--config" ,
940- "config.yaml" ,
941- ]
942- job_id , status = executor .launch ("complex-job" , complex_cmd )
943- assert job_id == "test-job-id"
944-
945- # Verify complex command is properly joined in script
946- handle = mock_file .return_value .__enter__ .return_value
947- written_content = handle .write .call_args [0 ][0 ]
948- expected_cmd = " " .join (complex_cmd )
949- assert expected_cmd in written_content
950741
951742 @patch ("nemo_run.core.execution.lepton.LeptonExecutor._validate_mounts" )
952743 @patch ("nemo_run.core.execution.lepton.LeptonExecutor.move_data" )
0 commit comments