"""``ray_hook`` 中纯逻辑容器与 actor 句柄缓存的行为。""" from unittest.mock import MagicMock import pytest from kilostar.utils.ray_hook import ActorList def test_actor_list_attribute_set_get_delete(): actors = ActorList() actors.foo = "bar" assert actors.foo == "bar" del actors.foo with pytest.raises(AttributeError): _ = actors.foo def test_actor_list_missing_raises_attribute_error(): actors = ActorList() with pytest.raises(AttributeError): _ = actors.not_exist def test_actor_list_delete_missing_raises_attribute_error(): actors = ActorList() with pytest.raises(AttributeError): del actors.not_exist def test_ray_actor_hook_uses_fake_registry(fake_actors): """``ray_actor_hook`` 通过 fake registry 取 actor 并组装成 ActorList。""" handle = MagicMock() fake_actors.register("postgres_database", handle) from kilostar.utils.ray_hook import ray_actor_hook actors = ray_actor_hook("postgres_database") assert actors.postgres_database is handle def test_ray_actor_hook_unknown_actor_raises(fake_actors): from kilostar.utils.ray_hook import ray_actor_hook with pytest.raises(ValueError): ray_actor_hook("does_not_exist") def test_wait_for_actor_returns_immediately_when_ready(fake_actors): """actor 已就绪时 wait_for_actor 立刻返回,不进入轮询等待。""" handle = MagicMock() fake_actors.register("postgres_database", handle) from kilostar.utils.ray_hook import wait_for_actor got = wait_for_actor("postgres_database", timeout=5.0) assert got is handle def test_wait_for_actor_times_out_with_clear_error(fake_actors): """超时仍未就绪时抛 TimeoutError,并在 message 里带 actor 名。""" from kilostar.utils.ray_hook import wait_for_actor with pytest.raises(TimeoutError) as exc_info: wait_for_actor("never_ready", timeout=0.2, interval=0.05) assert "never_ready" in str(exc_info.value) def test_wait_for_actor_succeeds_after_delayed_registration(fake_actors): """actor 在第 N 次轮询时才注册,wait_for_actor 应在它就绪后返回。""" from kilostar.utils.ray_hook import wait_for_actor handle = MagicMock() calls = {"n": 0} original_get = fake_actors.get def delayed_get(name, namespace="kilostar"): calls["n"] += 1 if calls["n"] >= 3: return handle raise ValueError("not ready yet") fake_actors.get = delayed_get try: got = wait_for_actor("late_actor", timeout=2.0, interval=0.05) assert got is handle assert calls["n"] >= 3 finally: fake_actors.get = original_get def test_ray_actor_hook_with_timeout_waits(fake_actors): """ray_actor_hook(timeout>0) 会走 wait_for_actor 等待路径。""" from kilostar.utils.ray_hook import ray_actor_hook handle = MagicMock() calls = {"n": 0} def delayed_get(name, namespace="kilostar"): calls["n"] += 1 if calls["n"] >= 2: return handle raise ValueError("not ready yet") fake_actors.get = delayed_get actors = ray_actor_hook("slow_actor", timeout=2.0, interval=0.05) assert actors.slow_actor is handle