@@ -1118,6 +1118,135 @@ async def test_registers_service_replica_only_after_probes_pass(
11181118 assert not job .registered
11191119 assert not events
11201120
1121+ @pytest .mark .asyncio
1122+ @pytest .mark .parametrize ("test_db" , ["sqlite" , "postgres" ], indirect = True )
1123+ async def test_process_running_persists_runtime_data (
1124+ self , test_db , session : AsyncSession , tmp_path : Path
1125+ ):
1126+ project = await create_project (session = session )
1127+ user = await create_user (session = session )
1128+ repo = await create_repo (session = session , project_id = project .id )
1129+ run = await create_run (session = session , project = project , repo = repo , user = user )
1130+ instance = await create_instance (
1131+ session = session , project = project , status = InstanceStatus .BUSY
1132+ )
1133+ job = await create_job (
1134+ session = session ,
1135+ run = run ,
1136+ status = JobStatus .RUNNING ,
1137+ job_provisioning_data = get_job_provisioning_data (dockerized = False ),
1138+ job_runtime_data = get_job_runtime_data (),
1139+ instance = instance ,
1140+ instance_assigned = True ,
1141+ )
1142+ with (
1143+ patch ("dstack._internal.server.services.runner.ssh.SSHTunnel" ),
1144+ patch (
1145+ "dstack._internal.server.services.runner.client.RunnerClient"
1146+ ) as RunnerClientMock ,
1147+ patch .object (server_settings , "SERVER_DIR_PATH" , tmp_path ),
1148+ ):
1149+ runner_client_mock = RunnerClientMock .return_value
1150+ runner_client_mock .pull .return_value = PullResponse (
1151+ job_states = [],
1152+ job_logs = [],
1153+ runner_logs = [],
1154+ last_updated = 1 ,
1155+ working_dir = "/dstack/run" ,
1156+ username = "root" ,
1157+ )
1158+ await process_running_jobs ()
1159+ await session .refresh (job )
1160+ jrd = JobRuntimeData .__response__ .parse_raw (job .job_runtime_data )
1161+ assert jrd .working_dir == "/dstack/run"
1162+ assert jrd .username == "root"
1163+
1164+ @pytest .mark .asyncio
1165+ @pytest .mark .parametrize ("test_db" , ["sqlite" , "postgres" ], indirect = True )
1166+ async def test_process_running_does_not_overwrite_runtime_data (
1167+ self , test_db , session : AsyncSession , tmp_path : Path
1168+ ):
1169+ project = await create_project (session = session )
1170+ user = await create_user (session = session )
1171+ repo = await create_repo (session = session , project_id = project .id )
1172+ run = await create_run (session = session , project = project , repo = repo , user = user )
1173+ instance = await create_instance (
1174+ session = session , project = project , status = InstanceStatus .BUSY
1175+ )
1176+ job = await create_job (
1177+ session = session ,
1178+ run = run ,
1179+ status = JobStatus .RUNNING ,
1180+ job_provisioning_data = get_job_provisioning_data (dockerized = False ),
1181+ job_runtime_data = get_job_runtime_data (
1182+ working_dir = "/original/path" , username = "originaluser"
1183+ ),
1184+ instance = instance ,
1185+ instance_assigned = True ,
1186+ )
1187+ with (
1188+ patch ("dstack._internal.server.services.runner.ssh.SSHTunnel" ),
1189+ patch (
1190+ "dstack._internal.server.services.runner.client.RunnerClient"
1191+ ) as RunnerClientMock ,
1192+ patch .object (server_settings , "SERVER_DIR_PATH" , tmp_path ),
1193+ ):
1194+ runner_client_mock = RunnerClientMock .return_value
1195+ runner_client_mock .pull .return_value = PullResponse (
1196+ job_states = [],
1197+ job_logs = [],
1198+ runner_logs = [],
1199+ last_updated = 1 ,
1200+ working_dir = "/new/path" ,
1201+ username = "ubuntu" ,
1202+ )
1203+ await process_running_jobs ()
1204+ await session .refresh (job )
1205+ jrd = JobRuntimeData .__response__ .parse_raw (job .job_runtime_data )
1206+ assert jrd .working_dir == "/original/path"
1207+ assert jrd .username == "originaluser"
1208+
1209+ @pytest .mark .asyncio
1210+ @pytest .mark .parametrize ("test_db" , ["sqlite" , "postgres" ], indirect = True )
1211+ async def test_process_running_handles_old_runner_without_runtime_fields (
1212+ self , test_db , session : AsyncSession , tmp_path : Path
1213+ ):
1214+ project = await create_project (session = session )
1215+ user = await create_user (session = session )
1216+ repo = await create_repo (session = session , project_id = project .id )
1217+ run = await create_run (session = session , project = project , repo = repo , user = user )
1218+ instance = await create_instance (
1219+ session = session , project = project , status = InstanceStatus .BUSY
1220+ )
1221+ job = await create_job (
1222+ session = session ,
1223+ run = run ,
1224+ status = JobStatus .RUNNING ,
1225+ job_provisioning_data = get_job_provisioning_data (dockerized = False ),
1226+ job_runtime_data = get_job_runtime_data (),
1227+ instance = instance ,
1228+ instance_assigned = True ,
1229+ )
1230+ with (
1231+ patch ("dstack._internal.server.services.runner.ssh.SSHTunnel" ),
1232+ patch (
1233+ "dstack._internal.server.services.runner.client.RunnerClient"
1234+ ) as RunnerClientMock ,
1235+ patch .object (server_settings , "SERVER_DIR_PATH" , tmp_path ),
1236+ ):
1237+ runner_client_mock = RunnerClientMock .return_value
1238+ runner_client_mock .pull .return_value = PullResponse (
1239+ job_states = [],
1240+ job_logs = [],
1241+ runner_logs = [],
1242+ last_updated = 1 ,
1243+ )
1244+ await process_running_jobs ()
1245+ await session .refresh (job )
1246+ jrd = JobRuntimeData .__response__ .parse_raw (job .job_runtime_data )
1247+ assert jrd .working_dir is None
1248+ assert jrd .username is None
1249+
11211250
11221251class TestPatchBaseImageForAwsEfa :
11231252 @staticmethod
0 commit comments