Files
2026-07-13 13:17:40 +08:00

127 lines
3.8 KiB
Python

import uuid
import pytest
from ray.core.generated.export_train_state_pb2 import (
ExportTrainRunAttemptEventData as ProtoTrainRunAttempt,
ExportTrainRunEventData as ProtoTrainRun,
)
from ray.train._internal.state.export import (
train_run_info_to_proto_attempt,
train_run_info_to_proto_run,
)
from ray.train._internal.state.schema import (
ActorStatusEnum,
RunStatusEnum,
TrainRunInfo,
TrainWorkerInfo,
)
def create_mock_train_run_info(run_status=RunStatusEnum.RUNNING):
"""Create a minimal mock TrainRunInfo."""
worker = TrainWorkerInfo(
actor_id=uuid.uuid4().hex,
world_rank=0,
local_rank=0,
node_rank=0,
node_id=uuid.uuid4().hex,
node_ip="127.0.0.1",
pid=1234,
gpu_ids=[0],
status=ActorStatusEnum.ALIVE,
resources={"CPU": 1},
)
return TrainRunInfo(
name="test_run",
id=uuid.uuid4().hex,
job_id=uuid.uuid4().hex,
controller_actor_id=uuid.uuid4().hex,
workers=[worker],
datasets=[],
run_status=run_status,
status_detail="Error details" if run_status == RunStatusEnum.ERRORED else "",
start_time_ms=1000,
end_time_ms=2000
if run_status in [RunStatusEnum.FINISHED, RunStatusEnum.ERRORED]
else None,
resources=[{"CPU": 1}],
)
def test_train_run_info_to_proto_run():
"""Test that run info is correctly exported to proto run."""
run_info = create_mock_train_run_info()
proto_run = train_run_info_to_proto_run(run_info)
assert proto_run.ray_train_version == 1
assert proto_run.id == run_info.id
assert proto_run.name == run_info.name
assert proto_run.job_id == bytes.fromhex(run_info.job_id)
assert proto_run.status == ProtoTrainRun.RunStatus.RUNNING
def test_train_run_info_to_proto_attempt():
"""Test that run info is correctly exported to proto attempt."""
run_info = create_mock_train_run_info()
proto_attempt = train_run_info_to_proto_attempt(run_info)
assert proto_attempt.ray_train_version == 1
assert proto_attempt.run_id == run_info.id
assert proto_attempt.status == ProtoTrainRunAttempt.RunAttemptStatus.RUNNING
# Verify worker fields
assert len(proto_attempt.workers) == 1
proto_worker = proto_attempt.workers[0]
worker_info = run_info.workers[0]
assert proto_worker.world_rank == worker_info.world_rank
assert proto_worker.actor_id == bytes.fromhex(worker_info.actor_id)
def test_status_mapping():
"""Test that status is correctly mapped between schemas."""
status_pairs = [
(
RunStatusEnum.STARTED,
ProtoTrainRun.RunStatus.INITIALIZING,
ProtoTrainRunAttempt.RunAttemptStatus.PENDING,
),
(
RunStatusEnum.RUNNING,
ProtoTrainRun.RunStatus.RUNNING,
ProtoTrainRunAttempt.RunAttemptStatus.RUNNING,
),
(
RunStatusEnum.FINISHED,
ProtoTrainRun.RunStatus.FINISHED,
ProtoTrainRunAttempt.RunAttemptStatus.FINISHED,
),
(
RunStatusEnum.ERRORED,
ProtoTrainRun.RunStatus.ERRORED,
ProtoTrainRunAttempt.RunAttemptStatus.ERRORED,
),
(
RunStatusEnum.ABORTED,
ProtoTrainRun.RunStatus.ABORTED,
ProtoTrainRunAttempt.RunAttemptStatus.ABORTED,
),
]
for run_status, expected_run_status, expected_attempt_status in status_pairs:
run_info = create_mock_train_run_info(run_status=run_status)
proto_run = train_run_info_to_proto_run(run_info)
assert proto_run.status == expected_run_status
proto_attempt = train_run_info_to_proto_attempt(run_info)
assert proto_attempt.status == expected_attempt_status
if __name__ == "__main__":
import sys
sys.exit(pytest.main(["-v", "-x", __file__]))