From 0f5bd2be5b1718fc6cfb5e15b18e68cb0b60a3f1 Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sat, 8 Nov 2025 22:51:06 +0100 Subject: [PATCH 01/17] check in initial pyproject.toml --- src/services/ray/pyproject.toml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/services/ray/pyproject.toml diff --git a/src/services/ray/pyproject.toml b/src/services/ray/pyproject.toml new file mode 100644 index 00000000..edc0fcd5 --- /dev/null +++ b/src/services/ray/pyproject.toml @@ -0,0 +1,28 @@ +# +[build-system] +requires = ["setuptools>=68", "wheel"] + +[project] +name = "ndif-tests" +version = "0.0.1" + +[tool.pytest.ini_options] +minversion = "8.2" +addopts = "-ra -q" +testpaths = ["tests"] +pythonpath = ["src/services/ray/src"] +markers = [ + "raymock: uses mocked external Ray APIs (fast)", + "integration: requires real Ray runtime (slow)" +] +filterwarnings = [ + "ignore::DeprecationWarning" +] + +[tool.coverage.run] +source = [ + "src/services/ray/src/ray/deployments", + "src/services/ray/src/ray/distributed", + "src/services/ray/src/ray/nn" +] +branch = true From 6a40a0203e42a11d51b78acd72fc96755ae3b3a5 Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sat, 8 Nov 2025 23:19:16 +0100 Subject: [PATCH 02/17] check error-free pyproject.toml --- src/services/ray/pyproject.toml | 39 ++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/services/ray/pyproject.toml b/src/services/ray/pyproject.toml index edc0fcd5..f36218c5 100644 --- a/src/services/ray/pyproject.toml +++ b/src/services/ray/pyproject.toml @@ -3,14 +3,41 @@ requires = ["setuptools>=68", "wheel"] [project] -name = "ndif-tests" +name = "ndif-ray-tests" version = "0.0.1" +[tool.coverage.run] +source = [ + "src/services/ray/src/ray/deployments", + "src/services/ray/src/ray/distributed", + "src/services/ray/src/ray/nn" +] +branch = true + [tool.pytest.ini_options] minversion = "8.2" -addopts = "-ra -q" +#addopts = "-ra -q" +addopts = "-ra -q --ignore=src/services/api --ignore=src/services/queue --ignore=src/services/base --ignore=src/common --ignore=src/ndif" + +# ✅ pytest will look only here for test files testpaths = ["tests"] + +# ✅ pytest will treat only your internal Ray tree as the import root pythonpath = ["src/services/ray/src"] + +# ✅ Ignore every other NDIF directory so tests there are never even collected +norecursedirs = [ + "src/common", + "src/ndif", + "src/services/api", + "src/services/base", + "src/services/queue", + "src/services/*/tests", + "node_modules", + ".venv", + "__pycache__" +] + markers = [ "raymock: uses mocked external Ray APIs (fast)", "integration: requires real Ray runtime (slow)" @@ -18,11 +45,3 @@ markers = [ filterwarnings = [ "ignore::DeprecationWarning" ] - -[tool.coverage.run] -source = [ - "src/services/ray/src/ray/deployments", - "src/services/ray/src/ray/distributed", - "src/services/ray/src/ray/nn" -] -branch = true From 5b2b3c96483e8917fd8f70fcfba4888368e52f36 Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 00:02:33 +0100 Subject: [PATCH 03/17] mock ray package --- src/services/ray/tests/conftest.py | 93 ++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/services/ray/tests/conftest.py diff --git a/src/services/ray/tests/conftest.py b/src/services/ray/tests/conftest.py new file mode 100644 index 00000000..25be75f2 --- /dev/null +++ b/src/services/ray/tests/conftest.py @@ -0,0 +1,93 @@ +# ndif/src/services/ray/tests/conftest.py +import sys +import importlib +from pathlib import Path +import types +import pytest + +def _put_internal_src_on_path(): + here = Path(__file__).resolve() + candidates = [ + here.parents[1] / "src", # .../services/ray/tests -> .../services/ray/src + Path.cwd() / "src", # if running from the service root + ] + for c in candidates: + if (c / "ray" / "__init__.py").exists(): + sys.path.insert(0, str(c)) + return str(c) + return None + +_src = _put_internal_src_on_path() + +def _ensure_pkg(dotted: str) -> types.ModuleType: + """ + Ensure a dotted module path exists in sys.modules as a *package* at each level. + Each created module gets __path__ so that submodule imports work. + """ + parts = dotted.split(".") + cur = None + path = [] + for part in parts: + path.append(part) + name = ".".join(path) + mod = sys.modules.get(name) + if mod is None: + mod = types.ModuleType(name) + # mark as package so children like name.sub import work + mod.__path__ = [] # type: ignore[attr-defined] + sys.modules[name] = mod + if cur is not None: + setattr(cur, part, mod) + cur = mod + return cur + +# --- Create stubs BEFORE importing your modules ------------------------------ + +# 1) ray package (top-level) +ray_pkg = _ensure_pkg("ray") + +# Provide minimal top-level APIs; tests will monkeypatch as needed. +if not hasattr(ray_pkg, "get_actor"): + ray_pkg.get_actor = lambda *a, **k: None +if not hasattr(ray_pkg, "kill"): + ray_pkg.kill = lambda *a, **k: None + +# 2) ray._private and ray._private.state as *packages* +rp = _ensure_pkg("ray._private") +rp_state = _ensure_pkg("ray._private.state") + + +# Optional: add minimal symbols some code imports +if not hasattr(rp, "services"): + rp.services = types.SimpleNamespace(get_node_ip_address=lambda *a, **k: "127.0.0.1") +# Leave rp_state mostly empty unless your code needs specific names. + +# 3) Dashboard Serve SDK import path used by your code +sdk = _ensure_pkg("ray.dashboard.modules.serve.sdk") +if not hasattr(sdk, "ServeSubmissionClient"): + class _FakeClient: + def __init__(self, *a, **k): ... + def deploy_app(self, *a, **k): return {"ok": True} + sdk.ServeSubmissionClient = _FakeClient + +# ---- Safety: ensure we loaded the *internal* ray, not external wheel -------- +try: + real_ray = importlib.import_module("ray") +except Exception as e: + raise RuntimeError( + "Could not import internal 'ray'. Ensure ./src/ray exists and run pytest from " + "ndif/src/services/ray/ or below." + ) from e + +if "site-packages" in (getattr(real_ray, "__file__", "") or ""): + raise RuntimeError( + f"Loaded external Ray instead of internal one: {real_ray.__file__}\n" + f"sys.path included: {_src}" + ) + +# ---- Utilities available to tests ------------------------------------------ + +@pytest.fixture +def freeze_time(monkeypatch): + import time as _time + monkeypatch.setattr(_time, "time", lambda: 1_000.0, raising=True) From 41ad11690e57055499aa60b37073d1f3551cedac Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 00:08:25 +0100 Subject: [PATCH 04/17] fix external ray package not found error --- src/services/ray/tests/conftest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/ray/tests/conftest.py b/src/services/ray/tests/conftest.py index 25be75f2..01895d30 100644 --- a/src/services/ray/tests/conftest.py +++ b/src/services/ray/tests/conftest.py @@ -55,6 +55,7 @@ def _ensure_pkg(dotted: str) -> types.ModuleType: # 2) ray._private and ray._private.state as *packages* rp = _ensure_pkg("ray._private") rp_state = _ensure_pkg("ray._private.state") +rp_deployment = _ensure_pkg("ray.deployments") # Optional: add minimal symbols some code imports From e4a5fa557fe4c112fbfab4117a8255955f5df15d Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 00:20:39 +0100 Subject: [PATCH 05/17] rename ndif internal ray package dir to ndif_ray --- src/services/ray/src/{ray => ndif_ray}/__init__.py | 0 src/services/ray/src/{ray => ndif_ray}/config/ray_config.yml | 0 src/services/ray/src/{ray => ndif_ray}/deployments/__init__.py | 0 .../ray/src/{ray => ndif_ray}/deployments/controller/__init__.py | 0 .../{ray => ndif_ray}/deployments/controller/cluster/__init__.py | 0 .../{ray => ndif_ray}/deployments/controller/cluster/cluster.py | 0 .../deployments/controller/cluster/deployment.py | 0 .../{ray => ndif_ray}/deployments/controller/cluster/evaluator.py | 0 .../src/{ray => ndif_ray}/deployments/controller/cluster/node.py | 0 .../src/{ray => ndif_ray}/deployments/controller/controller.py | 0 .../src/{ray => ndif_ray}/deployments/controller/gcal/__init__.py | 0 .../{ray => ndif_ray}/deployments/controller/gcal/controller.py | 0 .../{ray => ndif_ray}/deployments/controller/gcal/scheduler.py | 0 .../ray/src/{ray => ndif_ray}/deployments/modeling/__init__.py | 0 .../ray/src/{ray => ndif_ray}/deployments/modeling/base.py | 0 .../ray/src/{ray => ndif_ray}/deployments/modeling/model.py | 0 .../ray/src/{ray => ndif_ray}/deployments/modeling/util.py | 0 src/services/ray/src/{ray => ndif_ray}/distributed/__init__.py | 0 .../ray/src/{ray => ndif_ray}/distributed/parallel_dims.py | 0 .../{ray => ndif_ray}/distributed/tensor_parallelism/__init__.py | 0 .../distributed/tensor_parallelism/plans/__init__.py | 0 .../distributed/tensor_parallelism/plans/llama.py | 0 .../src/{ray => ndif_ray}/distributed/tensor_parallelism/test.py | 0 src/services/ray/src/{ray => ndif_ray}/distributed/util.py | 0 src/services/ray/src/{ray => ndif_ray}/nn/__init__.py | 0 src/services/ray/src/{ray => ndif_ray}/nn/backend.py | 0 src/services/ray/src/{ray => ndif_ray}/nn/ops.py | 0 src/services/ray/src/{ray => ndif_ray}/nn/sandbox.py | 0 src/services/ray/src/{ray => ndif_ray}/nn/security/__init__.py | 0 .../src/{ray => ndif_ray}/nn/security/protected_environment.py | 0 .../ray/src/{ray => ndif_ray}/nn/security/protected_objects.py | 0 src/services/ray/src/{ray => ndif_ray}/resources.py | 0 32 files changed, 0 insertions(+), 0 deletions(-) rename src/services/ray/src/{ray => ndif_ray}/__init__.py (100%) rename src/services/ray/src/{ray => ndif_ray}/config/ray_config.yml (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/__init__.py (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/controller/__init__.py (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/controller/cluster/__init__.py (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/controller/cluster/cluster.py (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/controller/cluster/deployment.py (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/controller/cluster/evaluator.py (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/controller/cluster/node.py (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/controller/controller.py (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/controller/gcal/__init__.py (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/controller/gcal/controller.py (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/controller/gcal/scheduler.py (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/modeling/__init__.py (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/modeling/base.py (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/modeling/model.py (100%) rename src/services/ray/src/{ray => ndif_ray}/deployments/modeling/util.py (100%) rename src/services/ray/src/{ray => ndif_ray}/distributed/__init__.py (100%) rename src/services/ray/src/{ray => ndif_ray}/distributed/parallel_dims.py (100%) rename src/services/ray/src/{ray => ndif_ray}/distributed/tensor_parallelism/__init__.py (100%) rename src/services/ray/src/{ray => ndif_ray}/distributed/tensor_parallelism/plans/__init__.py (100%) rename src/services/ray/src/{ray => ndif_ray}/distributed/tensor_parallelism/plans/llama.py (100%) rename src/services/ray/src/{ray => ndif_ray}/distributed/tensor_parallelism/test.py (100%) rename src/services/ray/src/{ray => ndif_ray}/distributed/util.py (100%) rename src/services/ray/src/{ray => ndif_ray}/nn/__init__.py (100%) rename src/services/ray/src/{ray => ndif_ray}/nn/backend.py (100%) rename src/services/ray/src/{ray => ndif_ray}/nn/ops.py (100%) rename src/services/ray/src/{ray => ndif_ray}/nn/sandbox.py (100%) rename src/services/ray/src/{ray => ndif_ray}/nn/security/__init__.py (100%) rename src/services/ray/src/{ray => ndif_ray}/nn/security/protected_environment.py (100%) rename src/services/ray/src/{ray => ndif_ray}/nn/security/protected_objects.py (100%) rename src/services/ray/src/{ray => ndif_ray}/resources.py (100%) diff --git a/src/services/ray/src/ray/__init__.py b/src/services/ray/src/ndif_ray/__init__.py similarity index 100% rename from src/services/ray/src/ray/__init__.py rename to src/services/ray/src/ndif_ray/__init__.py diff --git a/src/services/ray/src/ray/config/ray_config.yml b/src/services/ray/src/ndif_ray/config/ray_config.yml similarity index 100% rename from src/services/ray/src/ray/config/ray_config.yml rename to src/services/ray/src/ndif_ray/config/ray_config.yml diff --git a/src/services/ray/src/ray/deployments/__init__.py b/src/services/ray/src/ndif_ray/deployments/__init__.py similarity index 100% rename from src/services/ray/src/ray/deployments/__init__.py rename to src/services/ray/src/ndif_ray/deployments/__init__.py diff --git a/src/services/ray/src/ray/deployments/controller/__init__.py b/src/services/ray/src/ndif_ray/deployments/controller/__init__.py similarity index 100% rename from src/services/ray/src/ray/deployments/controller/__init__.py rename to src/services/ray/src/ndif_ray/deployments/controller/__init__.py diff --git a/src/services/ray/src/ray/deployments/controller/cluster/__init__.py b/src/services/ray/src/ndif_ray/deployments/controller/cluster/__init__.py similarity index 100% rename from src/services/ray/src/ray/deployments/controller/cluster/__init__.py rename to src/services/ray/src/ndif_ray/deployments/controller/cluster/__init__.py diff --git a/src/services/ray/src/ray/deployments/controller/cluster/cluster.py b/src/services/ray/src/ndif_ray/deployments/controller/cluster/cluster.py similarity index 100% rename from src/services/ray/src/ray/deployments/controller/cluster/cluster.py rename to src/services/ray/src/ndif_ray/deployments/controller/cluster/cluster.py diff --git a/src/services/ray/src/ray/deployments/controller/cluster/deployment.py b/src/services/ray/src/ndif_ray/deployments/controller/cluster/deployment.py similarity index 100% rename from src/services/ray/src/ray/deployments/controller/cluster/deployment.py rename to src/services/ray/src/ndif_ray/deployments/controller/cluster/deployment.py diff --git a/src/services/ray/src/ray/deployments/controller/cluster/evaluator.py b/src/services/ray/src/ndif_ray/deployments/controller/cluster/evaluator.py similarity index 100% rename from src/services/ray/src/ray/deployments/controller/cluster/evaluator.py rename to src/services/ray/src/ndif_ray/deployments/controller/cluster/evaluator.py diff --git a/src/services/ray/src/ray/deployments/controller/cluster/node.py b/src/services/ray/src/ndif_ray/deployments/controller/cluster/node.py similarity index 100% rename from src/services/ray/src/ray/deployments/controller/cluster/node.py rename to src/services/ray/src/ndif_ray/deployments/controller/cluster/node.py diff --git a/src/services/ray/src/ray/deployments/controller/controller.py b/src/services/ray/src/ndif_ray/deployments/controller/controller.py similarity index 100% rename from src/services/ray/src/ray/deployments/controller/controller.py rename to src/services/ray/src/ndif_ray/deployments/controller/controller.py diff --git a/src/services/ray/src/ray/deployments/controller/gcal/__init__.py b/src/services/ray/src/ndif_ray/deployments/controller/gcal/__init__.py similarity index 100% rename from src/services/ray/src/ray/deployments/controller/gcal/__init__.py rename to src/services/ray/src/ndif_ray/deployments/controller/gcal/__init__.py diff --git a/src/services/ray/src/ray/deployments/controller/gcal/controller.py b/src/services/ray/src/ndif_ray/deployments/controller/gcal/controller.py similarity index 100% rename from src/services/ray/src/ray/deployments/controller/gcal/controller.py rename to src/services/ray/src/ndif_ray/deployments/controller/gcal/controller.py diff --git a/src/services/ray/src/ray/deployments/controller/gcal/scheduler.py b/src/services/ray/src/ndif_ray/deployments/controller/gcal/scheduler.py similarity index 100% rename from src/services/ray/src/ray/deployments/controller/gcal/scheduler.py rename to src/services/ray/src/ndif_ray/deployments/controller/gcal/scheduler.py diff --git a/src/services/ray/src/ray/deployments/modeling/__init__.py b/src/services/ray/src/ndif_ray/deployments/modeling/__init__.py similarity index 100% rename from src/services/ray/src/ray/deployments/modeling/__init__.py rename to src/services/ray/src/ndif_ray/deployments/modeling/__init__.py diff --git a/src/services/ray/src/ray/deployments/modeling/base.py b/src/services/ray/src/ndif_ray/deployments/modeling/base.py similarity index 100% rename from src/services/ray/src/ray/deployments/modeling/base.py rename to src/services/ray/src/ndif_ray/deployments/modeling/base.py diff --git a/src/services/ray/src/ray/deployments/modeling/model.py b/src/services/ray/src/ndif_ray/deployments/modeling/model.py similarity index 100% rename from src/services/ray/src/ray/deployments/modeling/model.py rename to src/services/ray/src/ndif_ray/deployments/modeling/model.py diff --git a/src/services/ray/src/ray/deployments/modeling/util.py b/src/services/ray/src/ndif_ray/deployments/modeling/util.py similarity index 100% rename from src/services/ray/src/ray/deployments/modeling/util.py rename to src/services/ray/src/ndif_ray/deployments/modeling/util.py diff --git a/src/services/ray/src/ray/distributed/__init__.py b/src/services/ray/src/ndif_ray/distributed/__init__.py similarity index 100% rename from src/services/ray/src/ray/distributed/__init__.py rename to src/services/ray/src/ndif_ray/distributed/__init__.py diff --git a/src/services/ray/src/ray/distributed/parallel_dims.py b/src/services/ray/src/ndif_ray/distributed/parallel_dims.py similarity index 100% rename from src/services/ray/src/ray/distributed/parallel_dims.py rename to src/services/ray/src/ndif_ray/distributed/parallel_dims.py diff --git a/src/services/ray/src/ray/distributed/tensor_parallelism/__init__.py b/src/services/ray/src/ndif_ray/distributed/tensor_parallelism/__init__.py similarity index 100% rename from src/services/ray/src/ray/distributed/tensor_parallelism/__init__.py rename to src/services/ray/src/ndif_ray/distributed/tensor_parallelism/__init__.py diff --git a/src/services/ray/src/ray/distributed/tensor_parallelism/plans/__init__.py b/src/services/ray/src/ndif_ray/distributed/tensor_parallelism/plans/__init__.py similarity index 100% rename from src/services/ray/src/ray/distributed/tensor_parallelism/plans/__init__.py rename to src/services/ray/src/ndif_ray/distributed/tensor_parallelism/plans/__init__.py diff --git a/src/services/ray/src/ray/distributed/tensor_parallelism/plans/llama.py b/src/services/ray/src/ndif_ray/distributed/tensor_parallelism/plans/llama.py similarity index 100% rename from src/services/ray/src/ray/distributed/tensor_parallelism/plans/llama.py rename to src/services/ray/src/ndif_ray/distributed/tensor_parallelism/plans/llama.py diff --git a/src/services/ray/src/ray/distributed/tensor_parallelism/test.py b/src/services/ray/src/ndif_ray/distributed/tensor_parallelism/test.py similarity index 100% rename from src/services/ray/src/ray/distributed/tensor_parallelism/test.py rename to src/services/ray/src/ndif_ray/distributed/tensor_parallelism/test.py diff --git a/src/services/ray/src/ray/distributed/util.py b/src/services/ray/src/ndif_ray/distributed/util.py similarity index 100% rename from src/services/ray/src/ray/distributed/util.py rename to src/services/ray/src/ndif_ray/distributed/util.py diff --git a/src/services/ray/src/ray/nn/__init__.py b/src/services/ray/src/ndif_ray/nn/__init__.py similarity index 100% rename from src/services/ray/src/ray/nn/__init__.py rename to src/services/ray/src/ndif_ray/nn/__init__.py diff --git a/src/services/ray/src/ray/nn/backend.py b/src/services/ray/src/ndif_ray/nn/backend.py similarity index 100% rename from src/services/ray/src/ray/nn/backend.py rename to src/services/ray/src/ndif_ray/nn/backend.py diff --git a/src/services/ray/src/ray/nn/ops.py b/src/services/ray/src/ndif_ray/nn/ops.py similarity index 100% rename from src/services/ray/src/ray/nn/ops.py rename to src/services/ray/src/ndif_ray/nn/ops.py diff --git a/src/services/ray/src/ray/nn/sandbox.py b/src/services/ray/src/ndif_ray/nn/sandbox.py similarity index 100% rename from src/services/ray/src/ray/nn/sandbox.py rename to src/services/ray/src/ndif_ray/nn/sandbox.py diff --git a/src/services/ray/src/ray/nn/security/__init__.py b/src/services/ray/src/ndif_ray/nn/security/__init__.py similarity index 100% rename from src/services/ray/src/ray/nn/security/__init__.py rename to src/services/ray/src/ndif_ray/nn/security/__init__.py diff --git a/src/services/ray/src/ray/nn/security/protected_environment.py b/src/services/ray/src/ndif_ray/nn/security/protected_environment.py similarity index 100% rename from src/services/ray/src/ray/nn/security/protected_environment.py rename to src/services/ray/src/ndif_ray/nn/security/protected_environment.py diff --git a/src/services/ray/src/ray/nn/security/protected_objects.py b/src/services/ray/src/ndif_ray/nn/security/protected_objects.py similarity index 100% rename from src/services/ray/src/ray/nn/security/protected_objects.py rename to src/services/ray/src/ndif_ray/nn/security/protected_objects.py diff --git a/src/services/ray/src/ray/resources.py b/src/services/ray/src/ndif_ray/resources.py similarity index 100% rename from src/services/ray/src/ray/resources.py rename to src/services/ray/src/ndif_ray/resources.py From ac071d9be2fc187380ab0536f4e5c0c99dbecbbf Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 01:27:13 +0100 Subject: [PATCH 06/17] updates after renaming ray to ndif_ray --- src/services/ray/pyproject.toml | 6 +- src/services/ray/tests/conftest.py | 92 +----------------------------- 2 files changed, 5 insertions(+), 93 deletions(-) diff --git a/src/services/ray/pyproject.toml b/src/services/ray/pyproject.toml index f36218c5..5a80e3b6 100644 --- a/src/services/ray/pyproject.toml +++ b/src/services/ray/pyproject.toml @@ -8,9 +8,9 @@ version = "0.0.1" [tool.coverage.run] source = [ - "src/services/ray/src/ray/deployments", - "src/services/ray/src/ray/distributed", - "src/services/ray/src/ray/nn" + "src/services/ray/src/ndif_ray/deployments", + "src/services/ray/src/ndif_ray/distributed", + "src/services/ray/src/ndif_ray/nn" ] branch = true diff --git a/src/services/ray/tests/conftest.py b/src/services/ray/tests/conftest.py index 01895d30..d73b110c 100644 --- a/src/services/ray/tests/conftest.py +++ b/src/services/ray/tests/conftest.py @@ -1,94 +1,6 @@ # ndif/src/services/ray/tests/conftest.py import sys -import importlib from pathlib import Path -import types -import pytest -def _put_internal_src_on_path(): - here = Path(__file__).resolve() - candidates = [ - here.parents[1] / "src", # .../services/ray/tests -> .../services/ray/src - Path.cwd() / "src", # if running from the service root - ] - for c in candidates: - if (c / "ray" / "__init__.py").exists(): - sys.path.insert(0, str(c)) - return str(c) - return None - -_src = _put_internal_src_on_path() - -def _ensure_pkg(dotted: str) -> types.ModuleType: - """ - Ensure a dotted module path exists in sys.modules as a *package* at each level. - Each created module gets __path__ so that submodule imports work. - """ - parts = dotted.split(".") - cur = None - path = [] - for part in parts: - path.append(part) - name = ".".join(path) - mod = sys.modules.get(name) - if mod is None: - mod = types.ModuleType(name) - # mark as package so children like name.sub import work - mod.__path__ = [] # type: ignore[attr-defined] - sys.modules[name] = mod - if cur is not None: - setattr(cur, part, mod) - cur = mod - return cur - -# --- Create stubs BEFORE importing your modules ------------------------------ - -# 1) ray package (top-level) -ray_pkg = _ensure_pkg("ray") - -# Provide minimal top-level APIs; tests will monkeypatch as needed. -if not hasattr(ray_pkg, "get_actor"): - ray_pkg.get_actor = lambda *a, **k: None -if not hasattr(ray_pkg, "kill"): - ray_pkg.kill = lambda *a, **k: None - -# 2) ray._private and ray._private.state as *packages* -rp = _ensure_pkg("ray._private") -rp_state = _ensure_pkg("ray._private.state") -rp_deployment = _ensure_pkg("ray.deployments") - - -# Optional: add minimal symbols some code imports -if not hasattr(rp, "services"): - rp.services = types.SimpleNamespace(get_node_ip_address=lambda *a, **k: "127.0.0.1") -# Leave rp_state mostly empty unless your code needs specific names. - -# 3) Dashboard Serve SDK import path used by your code -sdk = _ensure_pkg("ray.dashboard.modules.serve.sdk") -if not hasattr(sdk, "ServeSubmissionClient"): - class _FakeClient: - def __init__(self, *a, **k): ... - def deploy_app(self, *a, **k): return {"ok": True} - sdk.ServeSubmissionClient = _FakeClient - -# ---- Safety: ensure we loaded the *internal* ray, not external wheel -------- -try: - real_ray = importlib.import_module("ray") -except Exception as e: - raise RuntimeError( - "Could not import internal 'ray'. Ensure ./src/ray exists and run pytest from " - "ndif/src/services/ray/ or below." - ) from e - -if "site-packages" in (getattr(real_ray, "__file__", "") or ""): - raise RuntimeError( - f"Loaded external Ray instead of internal one: {real_ray.__file__}\n" - f"sys.path included: {_src}" - ) - -# ---- Utilities available to tests ------------------------------------------ - -@pytest.fixture -def freeze_time(monkeypatch): - import time as _time - monkeypatch.setattr(_time, "time", lambda: 1_000.0, raising=True) +# ensure src/ is on path so ndif_ray is importable +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) From 1c480e53fce6e13c2c97abcc9e4189a35ed9b919 Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 12:05:52 +0100 Subject: [PATCH 07/17] stub 'logging_loki' so internal logger module can import it --- src/services/ray/tests/conftest.py | 32 +++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/services/ray/tests/conftest.py b/src/services/ray/tests/conftest.py index d73b110c..53fd2cbb 100644 --- a/src/services/ray/tests/conftest.py +++ b/src/services/ray/tests/conftest.py @@ -1,6 +1,36 @@ # ndif/src/services/ray/tests/conftest.py import sys +import importlib from pathlib import Path +import types +import pytest # ensure src/ is on path so ndif_ray is importable -sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) +#sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) + +# 1) Put the *service* src on sys.path so ndif_ray is importable +SERVICE_SRC = Path(__file__).resolve().parents[1] / "src" # .../services/ray/src +sys.path.insert(0, str(SERVICE_SRC)) + +# 2) Force stdlib 'logging' (avoid shadowing by ./src/logging) +stdlib_logging = importlib.import_module("logging") # stdlib +sys.modules["logging"] = stdlib_logging # lock it before any project import + +# 3) Stub 'logging_loki' so your internal logger module can import it +if "logging_loki" not in sys.modules: + logging_loki = types.ModuleType("logging_loki") + # Provide a minimal LokiHandler to satisfy imports + class LokiHandler(stdlib_logging.Handler): + def __init__(self, *a, **k): super().__init__() + def emit(self, record): pass + logging_loki.LokiHandler = LokiHandler + sys.modules["logging_loki"] = logging_loki + +# 4) (Only if you still import any ray internals later — usually not needed after renaming to ndif_ray) +# You can add targeted stubs similarly with sys.modules if something else pops up. + +@pytest.fixture +def freeze_time(monkeypatch): + import time + monkeypatch.setattr(time, "time", lambda: 1_000.0, raising=True) + From a94a73635e325057fa557204b732f68b46e299b0 Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 12:07:59 +0100 Subject: [PATCH 08/17] add stub for external ray library --- src/services/ray/tests/conftest.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/services/ray/tests/conftest.py b/src/services/ray/tests/conftest.py index 53fd2cbb..a59f94d2 100644 --- a/src/services/ray/tests/conftest.py +++ b/src/services/ray/tests/conftest.py @@ -5,9 +5,6 @@ import types import pytest -# ensure src/ is on path so ndif_ray is importable -#sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) - # 1) Put the *service* src on sys.path so ndif_ray is importable SERVICE_SRC = Path(__file__).resolve().parents[1] / "src" # .../services/ray/src sys.path.insert(0, str(SERVICE_SRC)) @@ -19,18 +16,30 @@ # 3) Stub 'logging_loki' so your internal logger module can import it if "logging_loki" not in sys.modules: logging_loki = types.ModuleType("logging_loki") - # Provide a minimal LokiHandler to satisfy imports class LokiHandler(stdlib_logging.Handler): def __init__(self, *a, **k): super().__init__() def emit(self, record): pass logging_loki.LokiHandler = LokiHandler sys.modules["logging_loki"] = logging_loki -# 4) (Only if you still import any ray internals later — usually not needed after renaming to ndif_ray) -# You can add targeted stubs similarly with sys.modules if something else pops up. +# 4) Stub the EXTERNAL ray library (your internal package is now ndif_ray) +# deployment.py does `import ray` to call get_actor/kill; we provide a tiny fake. +if "ray" not in sys.modules: + ray_stub = types.ModuleType("ray") + + # Default behavior: act like "actor not found" so tests can assert error-path logging. + def _default_get_actor(*a, **k): + raise RuntimeError("actor not found (stubbed)") + + ray_stub.get_actor = _default_get_actor + ray_stub.kill = lambda *a, **k: None + + # If other tests later need more symbols, you can add them here + # e.g., ray_stub.util = types.SimpleNamespace(placement_group=lambda *a, **k: None) + + sys.modules["ray"] = ray_stub @pytest.fixture def freeze_time(monkeypatch): import time monkeypatch.setattr(time, "time", lambda: 1_000.0, raising=True) - From e1873a6d84a18f8d30e7e7f94d984d18c93bcb44 Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 12:54:14 +0100 Subject: [PATCH 09/17] add stub for GlobalState in ray._private.state --- src/services/ray/tests/conftest.py | 83 ++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 16 deletions(-) diff --git a/src/services/ray/tests/conftest.py b/src/services/ray/tests/conftest.py index a59f94d2..e883371e 100644 --- a/src/services/ray/tests/conftest.py +++ b/src/services/ray/tests/conftest.py @@ -5,15 +5,15 @@ import types import pytest -# 1) Put the *service* src on sys.path so ndif_ray is importable +# 1) Put the service src on sys.path so ndif_ray is importable SERVICE_SRC = Path(__file__).resolve().parents[1] / "src" # .../services/ray/src sys.path.insert(0, str(SERVICE_SRC)) # 2) Force stdlib 'logging' (avoid shadowing by ./src/logging) -stdlib_logging = importlib.import_module("logging") # stdlib -sys.modules["logging"] = stdlib_logging # lock it before any project import +stdlib_logging = importlib.import_module("logging") +sys.modules["logging"] = stdlib_logging -# 3) Stub 'logging_loki' so your internal logger module can import it +# 3) Stub 'logging_loki' so your internal logger can import it if "logging_loki" not in sys.modules: logging_loki = types.ModuleType("logging_loki") class LokiHandler(stdlib_logging.Handler): @@ -22,23 +22,74 @@ def emit(self, record): pass logging_loki.LokiHandler = LokiHandler sys.modules["logging_loki"] = logging_loki -# 4) Stub the EXTERNAL ray library (your internal package is now ndif_ray) -# deployment.py does `import ray` to call get_actor/kill; we provide a tiny fake. -if "ray" not in sys.modules: - ray_stub = types.ModuleType("ray") +# 4) Robust Ray stub: make 'ray' a *package* and add subpackages you need +def _ensure_pkg(dotted: str) -> types.ModuleType: + """ + Ensure a dotted module path exists in sys.modules as a *package* at each level + (i.e., has __path__), so that child imports work (e.g., ray._private.state). + """ + parts = dotted.split(".") + cur_name = "" + parent = None + for p in parts: + cur_name = f"{cur_name+'.' if cur_name else ''}{p}" + mod = sys.modules.get(cur_name) + if mod is None: + mod = types.ModuleType(cur_name) + mod.__path__ = [] # mark as package + sys.modules[cur_name] = mod + if parent: + setattr(parent, p, mod) + parent = mod + return sys.modules[dotted] - # Default behavior: act like "actor not found" so tests can assert error-path logging. - def _default_get_actor(*a, **k): - raise RuntimeError("actor not found (stubbed)") +# Create 'ray' as a package and provide APIs used by your code under test +ray_pkg = _ensure_pkg("ray") - ray_stub.get_actor = _default_get_actor - ray_stub.kill = lambda *a, **k: None +# Minimal functions used in deployment.py +def _default_get_actor(*a, **k): + raise RuntimeError("actor not found (stubbed)") +if not hasattr(ray_pkg, "get_actor"): + ray_pkg.get_actor = _default_get_actor +if not hasattr(ray_pkg, "kill"): + ray_pkg.kill = lambda *a, **k: None - # If other tests later need more symbols, you can add them here - # e.g., ray_stub.util = types.SimpleNamespace(placement_group=lambda *a, **k: None) +# Subpackages some of your modules import +rp = _ensure_pkg("ray._private") +rp_state = _ensure_pkg("ray._private.state") - sys.modules["ray"] = ray_stub +# Provide the exact attribute your code imports: from ray._private import services +if not hasattr(rp, "services"): + rp.services = types.SimpleNamespace( + get_node_ip_address=lambda *a, **k: "127.0.0.1" + ) + +# 👉 Provide GlobalState in ray._private.state +if not hasattr(rp_state, "GlobalState"): + class GlobalState: + def __init__(self, *a, **k): pass + # Ray versions differ; expose both names just in case + def initialize_global_state(self, *a, **k): pass + def _initialize_global_state(self, *a, **k): pass + def disconnect(self, *a, **k): pass + # Common query helpers some code calls; return safe defaults + def node_table(self, *a, **k): return [] + def job_table(self, *a, **k): return [] + def cluster_resources(self, *a, **k): return {} + def available_resources(self, *a, **k): return {} + rp_state.GlobalState = GlobalState +# If anything references the dashboard Serve SDK, stub that too +sdk = _ensure_pkg("ray.dashboard.modules.serve.sdk") +if not hasattr(sdk, "ServeSubmissionClient"): + class _FakeClient: + def __init__(self, *a, **k): ... + def deploy_app(self, *a, **k): return {"ok": True} + sdk.ServeSubmissionClient = _FakeClient + +#end of ray stub + +# Utility fixture you already had @pytest.fixture def freeze_time(monkeypatch): import time From bec32405d42f152fa3cf7dec8bdb180babd00a0e Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 15:19:49 +0100 Subject: [PATCH 10/17] add stubs for all external ray related components that are imported in internal ray service --- src/services/ray/tests/conftest.py | 81 ++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/services/ray/tests/conftest.py b/src/services/ray/tests/conftest.py index e883371e..f5cc3fb3 100644 --- a/src/services/ray/tests/conftest.py +++ b/src/services/ray/tests/conftest.py @@ -22,6 +22,7 @@ def emit(self, record): pass logging_loki.LokiHandler = LokiHandler sys.modules["logging_loki"] = logging_loki +''' # 4) Robust Ray stub: make 'ray' a *package* and add subpackages you need def _ensure_pkg(dotted: str) -> types.ModuleType: """ @@ -88,6 +89,86 @@ def deploy_app(self, *a, **k): return {"ok": True} sdk.ServeSubmissionClient = _FakeClient #end of ray stub +''' + +# --- Robust Ray stub for unit tests ------------------------------------------ +import sys, types + +def _ensure_pkg(dotted: str) -> types.ModuleType: + """Ensure a dotted path exists in sys.modules as a *package* at each level.""" + parts = dotted.split(".") + cur = None + path = [] + for seg in parts: + path.append(seg) + name = ".".join(path) + mod = sys.modules.get(name) + if mod is None: + mod = types.ModuleType(name) + mod.__path__ = [] # make it a package so children can import + sys.modules[name] = mod + if cur is not None: + setattr(cur, seg, mod) + cur = mod + return cur + +# 1) Top-level package 'ray' +ray_pkg = _ensure_pkg("ray") + +# minimal functions you actually use in deployment.py +if not hasattr(ray_pkg, "get_actor"): + def _default_get_actor(*a, **k): # default: simulate "not found" + raise RuntimeError("actor not found (stub)") + ray_pkg.get_actor = _default_get_actor +if not hasattr(ray_pkg, "kill"): + ray_pkg.kill = lambda *a, **k: None + +# 2) Private internals your code imports +# 2a) ray._private and ray._private.services +rp = _ensure_pkg("ray._private") +if not hasattr(rp, "services"): + rp.services = types.SimpleNamespace( + get_node_ip_address=lambda *a, **k: "127.0.0.1", + ) + +# 2b) ray._private.state.GlobalState +rp_state = _ensure_pkg("ray._private.state") +if not hasattr(rp_state, "GlobalState"): + class GlobalState: + def __init__(self, *a, **k): ... + def initialize_global_state(self, *a, **k): ... + def _initialize_global_state(self, *a, **k): ... + def disconnect(self, *a, **k): ... + def node_table(self, *a, **k): return [] + def job_table(self, *a, **k): return [] + def cluster_resources(self, *a, **k): return {} + def available_resources(self, *a, **k): return {} + rp_state.GlobalState = GlobalState + +# 2c) ray._raylet.GcsClientOptions +raylet = _ensure_pkg("ray._raylet") +if not hasattr(raylet, "GcsClientOptions"): + class GcsClientOptions: + def __init__(self, *a, **k): ... + raylet.GcsClientOptions = GcsClientOptions + +# 3) Public helpers your code imports +# 3a) ray.util.state.list_nodes +util_state = _ensure_pkg("ray.util.state") +if not hasattr(util_state, "list_nodes"): + def list_nodes(*a, **k): return [] + util_state.list_nodes = list_nodes + +# 3b) from ray import serve (provide an empty module-like object) +serve_mod = _ensure_pkg("ray.serve") +# if your unit tests later need specific attributes (e.g., serve.deployment), +# add minimal dummies here, e.g.: +# if not hasattr(serve_mod, "deployment"): +# def deployment(func=None, *a, **k): +# def wrapper(f): return f +# return wrapper if func is None else func +# serve_mod.deployment = deployment + # Utility fixture you already had @pytest.fixture From 0da0a8d8c61cd15468fd0f2c09022b462a49350a Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 15:57:34 +0100 Subject: [PATCH 11/17] create a small package to host shared types so not clash with stdlib --- src/services/ray/src/ndif_shared/__init__.py | 0 src/services/ray/src/ndif_shared/types.py | 1 + 2 files changed, 1 insertion(+) create mode 100644 src/services/ray/src/ndif_shared/__init__.py create mode 120000 src/services/ray/src/ndif_shared/types.py diff --git a/src/services/ray/src/ndif_shared/__init__.py b/src/services/ray/src/ndif_shared/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/services/ray/src/ndif_shared/types.py b/src/services/ray/src/ndif_shared/types.py new file mode 120000 index 00000000..eab5f910 --- /dev/null +++ b/src/services/ray/src/ndif_shared/types.py @@ -0,0 +1 @@ +../../../../common/types.py \ No newline at end of file From d665f3ac21c833d3cda1afc8cb64a20c11f8e290 Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 15:59:58 +0100 Subject: [PATCH 12/17] change import to using the package name created to host the shared types --- .../ray/src/ndif_ray/deployments/controller/cluster/cluster.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/services/ray/src/ndif_ray/deployments/controller/cluster/cluster.py b/src/services/ray/src/ndif_ray/deployments/controller/cluster/cluster.py index 63e1ced2..d2c860c6 100755 --- a/src/services/ray/src/ndif_ray/deployments/controller/cluster/cluster.py +++ b/src/services/ray/src/ndif_ray/deployments/controller/cluster/cluster.py @@ -9,7 +9,8 @@ from ray._raylet import GcsClientOptions from ray.util.state import list_nodes -from .....types import MODEL_KEY +#from .....types import MODEL_KEY +from ndif_shared.types import MODEL_KEY from .evaluator import ModelEvaluator from .node import CandidateLevel, Node, Resources From e17785ee6964111071e0734b5827c8c50cce82e5 Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 16:16:15 +0100 Subject: [PATCH 13/17] fix assertion error --- .../controller/cluster/test_deployment.py | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 src/services/ray/tests/unit/deployments/controller/cluster/test_deployment.py diff --git a/src/services/ray/tests/unit/deployments/controller/cluster/test_deployment.py b/src/services/ray/tests/unit/deployments/controller/cluster/test_deployment.py new file mode 100644 index 00000000..40a02a82 --- /dev/null +++ b/src/services/ray/tests/unit/deployments/controller/cluster/test_deployment.py @@ -0,0 +1,154 @@ +import types +from datetime import datetime, timezone + +import pytest + + +# ---- Helpers --------------------------------------------------------------- + +@pytest.fixture(autouse=True) +def patch_model_key(monkeypatch): + """ + The module calls MODEL_KEY(model_key) in __init__. + Patch it to a simple coercion so we don't depend on the real ndif types. + """ + # Import the module *once* so we can patch its symbols + import ndif_ray.deployments.controller.cluster.deployment as depmod + monkeypatch.setattr(depmod, "MODEL_KEY", lambda x: f"MK:{x}", raising=True) + return depmod + + +@pytest.fixture +def fixed_time(monkeypatch): + """Freeze time.time() so deployed timestamps are stable.""" + import time as _time + monkeypatch.setattr(_time, "time", lambda: 1_000.0, raising=True) + return 1_000.0 + + +@pytest.fixture +def module(monkeypatch, patch_model_key): + """Expose the imported deployment module (already has MODEL_KEY patched).""" + return patch_model_key + + +@pytest.fixture +def fake_logger(mocker, module): + lg = mocker.Mock() + module.logger = lg # replace module-level logger + return lg + + +@pytest.fixture +def fake_ray(mocker, module): + """Replace the ray module inside deployment.py with a stubbed namespace.""" + fake = types.SimpleNamespace() + fake.get_actor = mocker.Mock() + fake.kill = mocker.Mock() + module.ray = fake + return fake + + +# ---- Tests ----------------------------------------------------------------- + +def test_deployment_level_values(module): + # Ensure enum wiring is correct and values are serialized as expected + assert module.DeploymentLevel.HOT.value == "hot" + assert module.DeploymentLevel.WARM.value == "warm" + assert module.DeploymentLevel.COLD.value == "cold" + + +def test_init_and_get_state_casts_model_key_and_sets_fields(module, fixed_time): + d = module.Deployment( + model_key="my/model@v1", + deployment_level=module.DeploymentLevel.HOT, + gpus_required=2, + size_bytes=123456, + dedicated=True, + cached=False, + ) + + st = d.get_state() + # MODEL_KEY was patched to prefix with MK: + assert st["model_key"] == "MK:my/model@v1" + assert st["deployment_level"] == "hot" + assert st["gpus_required"] == 2 + assert st["size_bytes"] == 123456 + assert st["dedicated"] is True + assert st["cached"] is False + # deployed should be the frozen time + assert st["deployed"] == pytest.approx(1_000.0, rel=0, abs=0) + + +def test_end_time_uses_minimum_seconds(module, fixed_time): + d = module.Deployment( + model_key="k", + deployment_level=module.DeploymentLevel.WARM, + gpus_required=0, + size_bytes=0, + ) + dt = d.end_time(60) + assert dt == datetime.fromtimestamp(1_060.0, tz=timezone.utc) + + +def test_delete_kills_actor_on_success(module, fake_ray, fake_logger): + # Arrange: get_actor returns a fake actor object + actor = object() + fake_ray.get_actor.return_value = actor + + d = module.Deployment("k", module.DeploymentLevel.COLD, 0, 0) + d.delete() + + fake_ray.get_actor.assert_called_once_with("ModelActor:MK:k") + fake_ray.kill.assert_called_once_with(actor) + fake_logger.exception.assert_not_called() + + +def test_delete_logs_on_failure(module, fake_ray, fake_logger): + # Arrange: get_actor raises (e.g., actor not found) + fake_ray.get_actor.side_effect = RuntimeError("not found") + + d = module.Deployment("k", module.DeploymentLevel.COLD, 0, 0) + d.delete() + + fake_ray.kill.assert_not_called() + fake_logger.exception.assert_called_once() + # Optional: check message contains model key + msg = fake_logger.exception.call_args[0][0] + #assert "ModelActor" in msg and "MK:k" in msg + assert "Error removing actor" in msg + assert "MK:k" in msg + # don't assert "ModelActor" here + + +def test_cache_returns_object_ref_on_success(module, fake_ray, fake_logger, mocker): + # Fake actor with to_cache.remote() + class FakeHandle: + def to_cache(self): + return self + def remote(self): + return "OBJECT_REF" + + fake_ray.get_actor.return_value = FakeHandle() + + d = module.Deployment("k", module.DeploymentLevel.HOT, 1, 1) + ref = d.cache() + + fake_ray.get_actor.assert_called_once_with("ModelActor:MK:k") + assert ref == "OBJECT_REF" + fake_logger.exception.assert_not_called() + + +def test_cache_logs_and_returns_none_on_failure(module, fake_ray, fake_logger): + fake_ray.get_actor.side_effect = RuntimeError("boom") + + d = module.Deployment("k", module.DeploymentLevel.HOT, 1, 1) + out = d.cache() + + assert out is None + fake_logger.exception.assert_called_once() + + # 👇 Add these lines to verify message content + msg = fake_logger.exception.call_args[0][0] + assert "Error adding actor" in msg + assert "MK:k" in msg \ No newline at end of file From 8b12eed9dd424ebbe48f3365e891874a197eb586 Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 16:20:55 +0100 Subject: [PATCH 14/17] fix test code --- .../controller/cluster/test_deployment.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/services/ray/tests/unit/deployments/controller/cluster/test_deployment.py b/src/services/ray/tests/unit/deployments/controller/cluster/test_deployment.py index 40a02a82..3abb80c1 100644 --- a/src/services/ray/tests/unit/deployments/controller/cluster/test_deployment.py +++ b/src/services/ray/tests/unit/deployments/controller/cluster/test_deployment.py @@ -122,13 +122,16 @@ def test_delete_logs_on_failure(module, fake_ray, fake_logger): def test_cache_returns_object_ref_on_success(module, fake_ray, fake_logger, mocker): - # Fake actor with to_cache.remote() - class FakeHandle: - def to_cache(self): - return self + # Fake Ray-style actor method proxy + class _ActorMethod: def remote(self): return "OBJECT_REF" + class FakeHandle: + def __init__(self): + # Ray-style: attribute that has a .remote() method + self.to_cache = _ActorMethod() + fake_ray.get_actor.return_value = FakeHandle() d = module.Deployment("k", module.DeploymentLevel.HOT, 1, 1) @@ -139,6 +142,7 @@ def remote(self): fake_logger.exception.assert_not_called() + def test_cache_logs_and_returns_none_on_failure(module, fake_ray, fake_logger): fake_ray.get_actor.side_effect = RuntimeError("boom") From e6b5f06b0ca4f77df0b065d027f5d423bb101dfb Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 16:23:53 +0100 Subject: [PATCH 15/17] minor mod --- .../src/ndif_ray/deployments/controller/cluster/deployment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/ray/src/ndif_ray/deployments/controller/cluster/deployment.py b/src/services/ray/src/ndif_ray/deployments/controller/cluster/deployment.py index df168afb..080407f5 100755 --- a/src/services/ray/src/ndif_ray/deployments/controller/cluster/deployment.py +++ b/src/services/ray/src/ndif_ray/deployments/controller/cluster/deployment.py @@ -5,8 +5,8 @@ from typing import Any, Dict import ray -from .....types import MODEL_KEY - +#from .....types import MODEL_KEY +from ndif_shared.types import MODEL_KEY logger = logging.getLogger("ndif") class DeploymentLevel(Enum): From 9744299d778b50a955f80f3b5a05e3604b2f0155 Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 16:33:57 +0100 Subject: [PATCH 16/17] update import statement after creating a small shared package ndif_shared to host types.py to fix relative import error, src/services/ray/tests/unit/deployments/controller/cluster/test_deployment.py 100% success --- .../src/ndif_ray/deployments/controller/cluster/evaluator.py | 3 ++- .../ray/src/ndif_ray/deployments/controller/cluster/node.py | 3 ++- .../ray/src/ndif_ray/deployments/controller/controller.py | 3 ++- .../ray/src/ndif_ray/deployments/controller/gcal/controller.py | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/services/ray/src/ndif_ray/deployments/controller/cluster/evaluator.py b/src/services/ray/src/ndif_ray/deployments/controller/cluster/evaluator.py index 00ea94f4..e6283258 100755 --- a/src/services/ray/src/ndif_ray/deployments/controller/cluster/evaluator.py +++ b/src/services/ray/src/ndif_ray/deployments/controller/cluster/evaluator.py @@ -5,7 +5,8 @@ from nnsight.modeling.mixins import RemoteableMixin -from .....types import MODEL_KEY +#from .....types import MODEL_KEY +from ndif_shared.types import MODEL_KEY logger = logging.getLogger("ndif") diff --git a/src/services/ray/src/ndif_ray/deployments/controller/cluster/node.py b/src/services/ray/src/ndif_ray/deployments/controller/cluster/node.py index aea01f9d..079256ae 100755 --- a/src/services/ray/src/ndif_ray/deployments/controller/cluster/node.py +++ b/src/services/ray/src/ndif_ray/deployments/controller/cluster/node.py @@ -6,7 +6,8 @@ import ray -from .....types import MODEL_KEY, NODE_ID +#from .....types import MODEL_KEY, NODE_ID +from ndif_shared.types import MODEL_KEY, NODE_ID from .deployment import Deployment, DeploymentLevel logger = logging.getLogger("ndif") diff --git a/src/services/ray/src/ndif_ray/deployments/controller/controller.py b/src/services/ray/src/ndif_ray/deployments/controller/controller.py index e3c947cd..4b19ab33 100755 --- a/src/services/ray/src/ndif_ray/deployments/controller/controller.py +++ b/src/services/ray/src/ndif_ray/deployments/controller/controller.py @@ -15,7 +15,8 @@ ServeDeploySchema, ServeInstanceDetails, ) -from ....types import MODEL_KEY, RAY_APP_NAME, NODE_ID +#from ....types import MODEL_KEY, RAY_APP_NAME, NODE_ID +from ndif_shared.types import MODEL_KEY, RAY_APP_NAME, NODE_ID from ....logging.logger import set_logger from ....providers.objectstore import ObjectStoreProvider from ....providers.socketio import SioProvider diff --git a/src/services/ray/src/ndif_ray/deployments/controller/gcal/controller.py b/src/services/ray/src/ndif_ray/deployments/controller/gcal/controller.py index a3f43c14..a1149b7d 100755 --- a/src/services/ray/src/ndif_ray/deployments/controller/gcal/controller.py +++ b/src/services/ray/src/ndif_ray/deployments/controller/gcal/controller.py @@ -2,7 +2,8 @@ import time from ray import ray, serve -from .....types import MODEL_KEY, RAY_APP_NAME +#from .....types import MODEL_KEY, RAY_APP_NAME +from ndif_shared.types import MODEL_KEY, RAY_APP_NAME from ..controller import ControllerDeploymentArgs, _ControllerDeployment from .scheduler import SchedulingActor From dfb87626d138acd3928923a802b011c0aec6475f Mon Sep 17 00:00:00 2001 From: Ruihua Date: Sun, 9 Nov 2025 19:38:51 +0100 Subject: [PATCH 17/17] instruction for running pytest on a module or function --- src/services/ray/README.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/services/ray/README.md diff --git a/src/services/ray/README.md b/src/services/ray/README.md new file mode 100644 index 00000000..ff008254 --- /dev/null +++ b/src/services/ray/README.md @@ -0,0 +1,6 @@ +#running pytest +cd ndif_root + +pytest -q src/services/ray/tests/unit/deployments/controller/cluster/test_deployment.py + +pytest -q src/services/ray/tests/unit/deployments/controller/cluster/test_deployment.py::test_cache_logs_and_returns_none_on_failure \ No newline at end of file