272 lines
7.2 KiB
Python
272 lines
7.2 KiB
Python
import sys
|
|
import time
|
|
|
|
import pytest
|
|
|
|
import ray
|
|
from ray._common.test_utils import run_string_as_driver
|
|
from ray._private import ray_constants
|
|
from ray._private.test_utils import (
|
|
get_error_message,
|
|
init_error_pubsub,
|
|
)
|
|
from ray.cluster_utils import Cluster
|
|
|
|
|
|
def test_isolation(shutdown_only):
|
|
info = ray.init(namespace="namespace")
|
|
|
|
address = info["address"]
|
|
|
|
# First param of template is the namespace. Second is the redis address.
|
|
driver_template = """
|
|
import ray
|
|
|
|
ray.init(address="{}", namespace="{}")
|
|
|
|
@ray.remote
|
|
class DetachedActor:
|
|
def ping(self):
|
|
return "pong from other job"
|
|
|
|
actor = DetachedActor.options(name="Pinger", lifetime="detached").remote()
|
|
ray.get(actor.ping.remote())
|
|
"""
|
|
|
|
# Start a detached actor in a different namespace.
|
|
run_string_as_driver(driver_template.format(address, "different"))
|
|
|
|
@ray.remote
|
|
class Actor:
|
|
def ping(self):
|
|
return "pong"
|
|
|
|
# Create an actor. This should succeed because the other actor is in a
|
|
# different namespace.
|
|
probe = Actor.options(name="Pinger").remote()
|
|
assert ray.get(probe.ping.remote()) == "pong"
|
|
del probe
|
|
|
|
# Wait for actor removal
|
|
actor_removed = False
|
|
for _ in range(50): # Timeout after 5s
|
|
try:
|
|
ray.get_actor("Pinger")
|
|
except ValueError:
|
|
actor_removed = True
|
|
# This means the actor was removed.
|
|
break
|
|
else:
|
|
time.sleep(0.1)
|
|
|
|
assert actor_removed, "This is an anti-flakey test measure"
|
|
|
|
with pytest.raises(ValueError, match="Failed to look up actor with name"):
|
|
ray.get_actor("Pinger")
|
|
|
|
# Now make the actor in this namespace, from a different job.
|
|
run_string_as_driver(driver_template.format(address, "namespace"))
|
|
|
|
detached_actor = ray.get_actor("Pinger")
|
|
assert ray.get(detached_actor.ping.remote()) == "pong from other job"
|
|
|
|
with pytest.raises(ValueError, match="The name .* is already taken"):
|
|
Actor.options(name="Pinger", lifetime="detached").remote()
|
|
|
|
|
|
def test_placement_groups(shutdown_only):
|
|
info = ray.init(namespace="namespace")
|
|
|
|
address = info["address"]
|
|
|
|
# First param of template is the namespace. Second is the redis address.
|
|
driver_template = """
|
|
import ray
|
|
|
|
ray.init(address="{}", namespace="{}")
|
|
|
|
pg = ray.util.placement_group(bundles=[dict(CPU=1)], name="hello",
|
|
lifetime="detached")
|
|
ray.get(pg.ready())
|
|
"""
|
|
|
|
# Start a detached placement group in a different namespace.
|
|
run_string_as_driver(driver_template.format(address, "different"))
|
|
|
|
# Create an actor. This should succeed because the other actor is in a
|
|
# different namespace.
|
|
probe = ray.util.placement_group(bundles=[{"CPU": 1}], name="hello")
|
|
ray.get(probe.ready())
|
|
ray.util.remove_placement_group(probe)
|
|
|
|
removed = False
|
|
for _ in range(50): # Timeout after 5s
|
|
try:
|
|
ray.util.get_placement_group("hello")
|
|
except ValueError:
|
|
removed = True
|
|
# This means the actor was removed.
|
|
break
|
|
else:
|
|
time.sleep(0.1)
|
|
|
|
assert removed, "This is an anti-flakey test measure"
|
|
|
|
# Now make the actor in this namespace, from a different job.
|
|
run_string_as_driver(driver_template.format(address, "namespace"))
|
|
|
|
|
|
def test_default_namespace(shutdown_only):
|
|
info = ray.init(namespace="namespace")
|
|
|
|
address = info["address"]
|
|
|
|
# First param of template is the namespace. Second is the redis address.
|
|
driver_template = """
|
|
import ray
|
|
|
|
ray.init(address="{}")
|
|
|
|
@ray.remote
|
|
class DetachedActor:
|
|
def ping(self):
|
|
return "pong from other job"
|
|
|
|
actor = DetachedActor.options(name="Pinger", lifetime="detached").remote()
|
|
ray.get(actor.ping.remote())
|
|
"""
|
|
|
|
# Each run of this script will create a detached actor. Since the drivers
|
|
# are in different namespaces, both scripts should succeed. If they were
|
|
# placed in the same namespace, the second call will throw an exception.
|
|
run_string_as_driver(driver_template.format(address))
|
|
run_string_as_driver(driver_template.format(address))
|
|
|
|
|
|
def test_namespace_in_job_config(shutdown_only):
|
|
# JobConfig isn't a public API, but we'll set it directly, instead of
|
|
# using the param in code paths like the ray client.
|
|
job_config = ray.job_config.JobConfig(ray_namespace="namespace")
|
|
info = ray.init(job_config=job_config)
|
|
|
|
address = info["address"]
|
|
|
|
# First param of template is the namespace. Second is the redis address.
|
|
driver_template = """
|
|
import ray
|
|
|
|
ray.init(address="{}", namespace="namespace")
|
|
|
|
@ray.remote
|
|
class DetachedActor:
|
|
def ping(self):
|
|
return "pong from other job"
|
|
|
|
actor = DetachedActor.options(name="Pinger", lifetime="detached").remote()
|
|
ray.get(actor.ping.remote())
|
|
"""
|
|
|
|
run_string_as_driver(driver_template.format(address))
|
|
|
|
act = ray.get_actor("Pinger")
|
|
assert ray.get(act.ping.remote()) == "pong from other job"
|
|
|
|
|
|
def test_detached_warning(shutdown_only):
|
|
ray.init()
|
|
|
|
@ray.remote
|
|
class DetachedActor:
|
|
def ping(self):
|
|
return "pong"
|
|
|
|
error_pubsub = init_error_pubsub()
|
|
actor = DetachedActor.options( # noqa: F841
|
|
name="Pinger", lifetime="detached"
|
|
).remote()
|
|
errors = get_error_message(error_pubsub, 1, None)
|
|
error = errors.pop()
|
|
assert error["type"] == ray_constants.DETACHED_ACTOR_ANONYMOUS_NAMESPACE_ERROR
|
|
|
|
|
|
def test_namespace_client():
|
|
cluster = Cluster()
|
|
cluster.add_node(num_cpus=4, ray_client_server_port=8080)
|
|
cluster.wait_for_nodes(1)
|
|
|
|
template = """
|
|
import ray
|
|
ray.util.connect("{address}", namespace="{namespace}")
|
|
|
|
@ray.remote
|
|
class DetachedActor:
|
|
def ping(self):
|
|
return "pong from other job"
|
|
|
|
actor = DetachedActor.options(name="Pinger", lifetime="detached").remote()
|
|
ray.get(actor.ping.remote())
|
|
print("Done!!!")
|
|
"""
|
|
|
|
print(
|
|
run_string_as_driver(
|
|
template.format(address="localhost:8080", namespace="test")
|
|
)
|
|
)
|
|
|
|
ray.util.connect("localhost:8080", namespace="test")
|
|
|
|
pinger = ray.get_actor("Pinger")
|
|
assert ray.get(pinger.ping.remote()) == "pong from other job"
|
|
|
|
ray.util.disconnect()
|
|
cluster.shutdown()
|
|
# This piece of cleanup doesn't seem to happen automatically.
|
|
ray._private.client_mode_hook._explicitly_disable_client_mode()
|
|
|
|
|
|
def test_runtime_context(shutdown_only):
|
|
ray.init(namespace="abc")
|
|
namespace = ray.get_runtime_context().namespace
|
|
assert namespace == "abc"
|
|
assert namespace == ray.get_runtime_context().get()["namespace"]
|
|
|
|
|
|
def test_namespace_validation(shutdown_only):
|
|
with pytest.raises(TypeError):
|
|
ray.init(namespace=123)
|
|
|
|
ray.shutdown()
|
|
|
|
with pytest.raises(ValueError):
|
|
ray.init(namespace="")
|
|
|
|
ray.shutdown()
|
|
|
|
ray.init(namespace="abc")
|
|
|
|
@ray.remote
|
|
class A:
|
|
pass
|
|
|
|
with pytest.raises(TypeError):
|
|
A.options(namespace=123).remote()
|
|
|
|
with pytest.raises(ValueError):
|
|
A.options(namespace="").remote()
|
|
|
|
A.options(name="a", namespace="test", lifetime="detached").remote()
|
|
|
|
with pytest.raises(TypeError):
|
|
ray.get_actor("a", namespace=123)
|
|
|
|
with pytest.raises(ValueError):
|
|
ray.get_actor("a", namespace="")
|
|
|
|
ray.get_actor("a", namespace="test")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
sys.exit(pytest.main(["-sv", __file__]))
|